From 8f5c66c6a30cb770da3da953fa911b6c7a5769bb Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Thu, 23 Apr 2020 22:25:50 +0200 Subject: [PATCH 01/10] Introduce BTreeMap benches of iter itself --- src/liballoc/benches/btree/map.rs | 118 ++++++++++++++++++------------ 1 file changed, 72 insertions(+), 46 deletions(-) diff --git a/src/liballoc/benches/btree/map.rs b/src/liballoc/benches/btree/map.rs index 83cdebf0e3f4a..38d19c59ad186 100644 --- a/src/liballoc/benches/btree/map.rs +++ b/src/liballoc/benches/btree/map.rs @@ -1,6 +1,6 @@ use std::collections::BTreeMap; use std::iter::Iterator; -use std::ops::Bound::{Excluded, Unbounded}; +use std::ops::RangeBounds; use std::vec::Vec; use rand::{seq::SliceRandom, thread_rng, Rng}; @@ -117,7 +117,7 @@ map_find_rand_bench! {find_rand_10_000, 10_000, BTreeMap} map_find_seq_bench! {find_seq_100, 100, BTreeMap} map_find_seq_bench! {find_seq_10_000, 10_000, BTreeMap} -fn bench_iter(b: &mut Bencher, size: i32) { +fn bench_iteration(b: &mut Bencher, size: i32) { let mut map = BTreeMap::::new(); let mut rng = thread_rng(); @@ -133,21 +133,21 @@ fn bench_iter(b: &mut Bencher, size: i32) { } #[bench] -pub fn iter_20(b: &mut Bencher) { - bench_iter(b, 20); +pub fn iteration_20(b: &mut Bencher) { + bench_iteration(b, 20); } #[bench] -pub fn iter_1000(b: &mut Bencher) { - bench_iter(b, 1000); +pub fn iteration_1000(b: &mut Bencher) { + bench_iteration(b, 1000); } #[bench] -pub fn iter_100000(b: &mut Bencher) { - bench_iter(b, 100000); +pub fn iteration_100000(b: &mut Bencher) { + bench_iteration(b, 100000); } -fn bench_iter_mut(b: &mut Bencher, size: i32) { +fn bench_iteration_mut(b: &mut Bencher, size: i32) { let mut map = BTreeMap::::new(); let mut rng = thread_rng(); @@ -163,18 +163,18 @@ fn bench_iter_mut(b: &mut Bencher, size: i32) { } #[bench] -pub fn iter_mut_20(b: &mut Bencher) { - bench_iter_mut(b, 20); +pub fn iteration_mut_20(b: &mut Bencher) { + bench_iteration_mut(b, 20); } #[bench] -pub fn iter_mut_1000(b: &mut Bencher) { - bench_iter_mut(b, 1000); +pub fn iteration_mut_1000(b: &mut Bencher) { + bench_iteration_mut(b, 1000); } #[bench] -pub fn iter_mut_100000(b: &mut Bencher) { - bench_iter_mut(b, 100000); +pub fn iteration_mut_100000(b: &mut Bencher) { + bench_iteration_mut(b, 100000); } fn bench_first_and_last(b: &mut Bencher, size: i32) { @@ -202,57 +202,83 @@ pub fn first_and_last_10k(b: &mut Bencher) { bench_first_and_last(b, 10_000); } -#[bench] -pub fn range_excluded_excluded(b: &mut Bencher) { - let size = 144; - let map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect(); +const BENCH_RANGE_SIZE: i32 = 145; +const BENCH_RANGE_COUNT: i32 = BENCH_RANGE_SIZE * (BENCH_RANGE_SIZE - 1) / 2; + +fn bench_range(b: &mut Bencher, f: F) +where + F: Fn(i32, i32) -> R, + R: RangeBounds, +{ + let map: BTreeMap<_, _> = (0..BENCH_RANGE_SIZE).map(|i| (i, i)).collect(); b.iter(|| { - for first in 0..size { - for last in first + 1..size { - black_box(map.range((Excluded(first), Excluded(last)))); + let mut c = 0; + for i in 0..BENCH_RANGE_SIZE { + for j in i + 1..BENCH_RANGE_SIZE { + black_box(map.range(f(i, j))); + c += 1; } } + debug_assert_eq!(c, BENCH_RANGE_COUNT); }); } #[bench] -pub fn range_excluded_unbounded(b: &mut Bencher) { - let size = 144; - let map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect(); - b.iter(|| { - for first in 0..size { - black_box(map.range((Excluded(first), Unbounded))); - } - }); +pub fn range_included_excluded(b: &mut Bencher) { + bench_range(b, |i, j| i..j); } #[bench] pub fn range_included_included(b: &mut Bencher) { - let size = 144; - let map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect(); - b.iter(|| { - for first in 0..size { - for last in first..size { - black_box(map.range(first..=last)); - } - } - }); + bench_range(b, |i, j| i..=j); } #[bench] pub fn range_included_unbounded(b: &mut Bencher) { - let size = 144; + bench_range(b, |i, _| i..); +} + +#[bench] +pub fn range_unbounded_unbounded(b: &mut Bencher) { + bench_range(b, |_, _| ..); +} + +fn bench_iter(b: &mut Bencher, repeats: i32, size: i32) { let map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect(); b.iter(|| { - for first in 0..size { - black_box(map.range(first..)); + for _ in 0..repeats { + black_box(map.iter()); } }); } +/// Contrast range_unbounded_unbounded with `iter()`. #[bench] -pub fn range_unbounded_unbounded(b: &mut Bencher) { - let size = 144; - let map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect(); - b.iter(|| map.range(..)); +pub fn range_unbounded_vs_iter(b: &mut Bencher) { + bench_iter(b, BENCH_RANGE_COUNT, BENCH_RANGE_SIZE); +} + +#[bench] +pub fn iter_0(b: &mut Bencher) { + bench_iter(b, 1_000, 0); +} + +#[bench] +pub fn iter_1(b: &mut Bencher) { + bench_iter(b, 1_000, 1); +} + +#[bench] +pub fn iter_100(b: &mut Bencher) { + bench_iter(b, 1_000, 100); +} + +#[bench] +pub fn iter_10k(b: &mut Bencher) { + bench_iter(b, 1_000, 10_000); +} + +#[bench] +pub fn iter_1m(b: &mut Bencher) { + bench_iter(b, 1_000, 1_000_000); } From 873022797ae7f09872738c7367d8d658a1a34ad5 Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Wed, 22 Apr 2020 13:06:24 +0200 Subject: [PATCH 02/10] Speed up BTreeMap iteration by intertwined descend to the initial leaf edges --- src/liballoc/collections/btree/map.rs | 76 +++++++++++++++++---------- 1 file changed, 47 insertions(+), 29 deletions(-) diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index 91d93a1be1c98..b3158c97bfc51 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -1545,16 +1545,10 @@ impl IntoIterator for BTreeMap { fn into_iter(self) -> IntoIter { let mut me = ManuallyDrop::new(self); - if let Some(root) = me.root.as_mut() { - let root1 = unsafe { ptr::read(root).into_ref() }; - let root2 = unsafe { ptr::read(root).into_ref() }; - let len = me.length; - - IntoIter { - front: Some(root1.first_leaf_edge()), - back: Some(root2.last_leaf_edge()), - length: len, - } + if let Some(root) = me.root.take() { + let (f, b) = full_range_search(root.into_ref()); + + IntoIter { front: Some(f), back: Some(b), length: me.length } } else { IntoIter { front: None, back: None, length: 0 } } @@ -2042,6 +2036,7 @@ where } } +/// Finds the leaf edges delimiting a specified range in or underneath a node. fn range_search>( root1: NodeRef, root2: NodeRef, @@ -2126,6 +2121,33 @@ where } } +/// Equivalent to `range_search(k, v, ..)` without the `Ord` bound. +fn full_range_search( + root: NodeRef, +) -> ( + Handle, marker::Edge>, + Handle, marker::Edge>, +) { + // We duplicate the root NodeRef here -- we will never access it in a way + // that overlaps references obtained from the root. + let mut min_node = unsafe { ptr::read(&root) }; + let mut max_node = root; + loop { + let front = min_node.first_edge(); + let back = max_node.last_edge(); + match (front.force(), back.force()) { + (Leaf(f), Leaf(b)) => { + return (f, b); + } + (Internal(min_int), Internal(max_int)) => { + min_node = min_int.descend(); + max_node = max_int.descend(); + } + _ => unreachable!("BTreeMap has different depths"), + }; + } +} + impl BTreeMap { /// Gets an iterator over the entries of the map, sorted by key. /// @@ -2150,12 +2172,12 @@ impl BTreeMap { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn iter(&self) -> Iter<'_, K, V> { - Iter { - range: Range { - front: self.root.as_ref().map(|r| r.as_ref().first_leaf_edge()), - back: self.root.as_ref().map(|r| r.as_ref().last_leaf_edge()), - }, - length: self.length, + if let Some(root) = &self.root { + let (f, b) = full_range_search(root.as_ref()); + + Iter { range: Range { front: Some(f), back: Some(b) }, length: self.length } + } else { + Iter { range: Range { front: None, back: None }, length: 0 } } } @@ -2182,19 +2204,15 @@ impl BTreeMap { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn iter_mut(&mut self) -> IterMut<'_, K, V> { - IterMut { - range: if let Some(root) = &mut self.root { - let root1 = root.as_mut(); - let root2 = unsafe { ptr::read(&root1) }; - RangeMut { - front: Some(root1.first_leaf_edge()), - back: Some(root2.last_leaf_edge()), - _marker: PhantomData, - } - } else { - RangeMut { front: None, back: None, _marker: PhantomData } - }, - length: self.length, + if let Some(root) = &mut self.root { + let (f, b) = full_range_search(root.as_mut()); + + IterMut { + range: RangeMut { front: Some(f), back: Some(b), _marker: PhantomData }, + length: self.length, + } + } else { + IterMut { range: RangeMut { front: None, back: None, _marker: PhantomData }, length: 0 } } } From 19e5da902bf6ade2c0558383051215459754b73d Mon Sep 17 00:00:00 2001 From: Hanif Bin Ariffin Date: Thu, 30 Apr 2020 20:41:51 -0400 Subject: [PATCH 03/10] SipHasher::new() is literally with SipHasher with both keys being 0 --- src/test/ui/deriving/deriving-hash.rs | 2 +- src/test/ui/issues/issue-16530.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/ui/deriving/deriving-hash.rs b/src/test/ui/deriving/deriving-hash.rs index 68c68c235ef4a..8b51370bca502 100644 --- a/src/test/ui/deriving/deriving-hash.rs +++ b/src/test/ui/deriving/deriving-hash.rs @@ -24,7 +24,7 @@ struct Person { enum E { A=1, B } fn hash(t: &T) -> u64 { - let mut s = SipHasher::new_with_keys(0, 0); + let mut s = SipHasher::new(); t.hash(&mut s); s.finish() } diff --git a/src/test/ui/issues/issue-16530.rs b/src/test/ui/issues/issue-16530.rs index 22a6ef7fa091f..25817a2a63d60 100644 --- a/src/test/ui/issues/issue-16530.rs +++ b/src/test/ui/issues/issue-16530.rs @@ -7,9 +7,9 @@ use std::hash::{SipHasher, Hasher, Hash}; struct Empty; pub fn main() { - let mut s1 = SipHasher::new_with_keys(0, 0); + let mut s1 = SipHasher::new(); Empty.hash(&mut s1); - let mut s2 = SipHasher::new_with_keys(0, 0); + let mut s2 = SipHasher::new(); Empty.hash(&mut s2); assert_eq!(s1.finish(), s2.finish()); } From 61fdd3e2bee1ea0f517ff0bfe16f3816decab99a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 May 2020 19:17:58 +0200 Subject: [PATCH 04/10] expand comment on default mutex behavior --- src/libstd/sys/unix/mutex.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/libstd/sys/unix/mutex.rs b/src/libstd/sys/unix/mutex.rs index 103d87e3d2f91..185615d01dd50 100644 --- a/src/libstd/sys/unix/mutex.rs +++ b/src/libstd/sys/unix/mutex.rs @@ -28,14 +28,18 @@ impl Mutex { // // A pthread mutex initialized with PTHREAD_MUTEX_INITIALIZER will have // a type of PTHREAD_MUTEX_DEFAULT, which has undefined behavior if you - // try to re-lock it from the same thread when you already hold a lock. + // try to re-lock it from the same thread when you already hold a lock + // (https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_init.html). // // In practice, glibc takes advantage of this undefined behavior to // implement hardware lock elision, which uses hardware transactional - // memory to avoid acquiring the lock. While a transaction is in + // memory to avoid acquiring the lock. + // This is the case even if PTHREAD_MUTEX_DEFAULT == PTHREAD_MUTEX_NORMAL + // (https://github.com/rust-lang/rust/issues/33770#issuecomment-220847521). + // As a consequence, while a transaction is in // progress, the lock appears to be unlocked. This isn't a problem for // other threads since the transactional memory will abort if a conflict - // is detected, however no abort is generated if re-locking from the + // is detected, however no abort is generated when re-locking from the // same thread. // // Since locking the same mutex twice will result in two aliasing &mut From 40a6b8c339376b7879016d5d2a015b6ac43c4c0c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 May 2020 19:37:55 +0200 Subject: [PATCH 05/10] explain our rwlock implementation (and fix a potential data race) --- src/libstd/sys/unix/rwlock.rs | 44 +++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/src/libstd/sys/unix/rwlock.rs b/src/libstd/sys/unix/rwlock.rs index 079dea671ef76..3e3a01b4ea395 100644 --- a/src/libstd/sys/unix/rwlock.rs +++ b/src/libstd/sys/unix/rwlock.rs @@ -22,27 +22,26 @@ impl RWLock { pub unsafe fn read(&self) { let r = libc::pthread_rwlock_rdlock(self.inner.get()); - // According to the pthread_rwlock_rdlock spec, this function **may** - // fail with EDEADLK if a deadlock is detected. On the other hand - // pthread mutexes will *never* return EDEADLK if they are initialized - // as the "fast" kind (which ours always are). As a result, a deadlock - // situation may actually return from the call to pthread_rwlock_rdlock - // instead of blocking forever (as mutexes and Windows rwlocks do). Note - // that not all unix implementations, however, will return EDEADLK for - // their rwlocks. + // According to POSIX, when a thread tries to acquire this read lock + // while it already holds the write lock + // (or vice versa, or tries to acquire the write lock twice), + // "the call shall either deadlock or return [EDEADLK]" + // (https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_rwlock_wrlock.html, + // https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_rwlock_rdlock.html). + // So, in principle, all we have to do here is check `r == 0` to be sure we properly + // got the lock. // - // We roughly maintain the deadlocking behavior by panicking to ensure - // that this lock acquisition does not succeed. - // - // We also check whether this lock is already write locked. This - // is only possible if it was write locked by the current thread and - // the implementation allows recursive locking. The POSIX standard - // doesn't require recursively locking a rwlock to deadlock, but we can't - // allow that because it could lead to aliasing issues. + // However, (at least) glibc before version 2.25 does not conform to this spec, + // and can return `r == 0` even when this thread already holds the write lock. + // We thus check for this situation ourselves and panic when detecting that a thread + // got the write lock more than once, or got a read and a write lock. if r == libc::EAGAIN { panic!("rwlock maximum reader count exceeded"); } else if r == libc::EDEADLK || (r == 0 && *self.write_locked.get()) { + // Above, we make sure to only access `write_locked` when `r == 0` to avoid + // data races. if r == 0 { + // `pthread_rwlock_rdlock` succeeded when it should not have. self.raw_unlock(); } panic!("rwlock read lock would result in deadlock"); @@ -56,6 +55,7 @@ impl RWLock { let r = libc::pthread_rwlock_tryrdlock(self.inner.get()); if r == 0 { if *self.write_locked.get() { + // `pthread_rwlock_tryrdlock` succeeded when it should not have. self.raw_unlock(); false } else { @@ -69,18 +69,21 @@ impl RWLock { #[inline] pub unsafe fn write(&self) { let r = libc::pthread_rwlock_wrlock(self.inner.get()); - // See comments above for why we check for EDEADLK and write_locked. We - // also need to check that num_readers is 0. + // See comments above for why we check for EDEADLK and write_locked. For the same reason, + // we also need to check that there are no readers (tracked in `num_readers`). if r == libc::EDEADLK - || *self.write_locked.get() + || (r == 0 && *self.write_locked.get()) || self.num_readers.load(Ordering::Relaxed) != 0 { + // Above, we make sure to only access `write_locked` when `r == 0` to avoid + // data races. if r == 0 { + // `pthread_rwlock_wrlock` succeeded when it should not have. self.raw_unlock(); } panic!("rwlock write lock would result in deadlock"); } else { - debug_assert_eq!(r, 0); + assert_eq!(r, 0); } *self.write_locked.get() = true; } @@ -89,6 +92,7 @@ impl RWLock { let r = libc::pthread_rwlock_trywrlock(self.inner.get()); if r == 0 { if *self.write_locked.get() || self.num_readers.load(Ordering::Relaxed) != 0 { + // `pthread_rwlock_trywrlock` succeeded when it should not have. self.raw_unlock(); false } else { From 3f50292edce92fb889bcd7318fead1a8905b6342 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 May 2020 20:47:46 +0200 Subject: [PATCH 06/10] edit Mutex comment --- src/libstd/sys/unix/mutex.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/libstd/sys/unix/mutex.rs b/src/libstd/sys/unix/mutex.rs index 185615d01dd50..45c600f75f5cf 100644 --- a/src/libstd/sys/unix/mutex.rs +++ b/src/libstd/sys/unix/mutex.rs @@ -30,13 +30,15 @@ impl Mutex { // a type of PTHREAD_MUTEX_DEFAULT, which has undefined behavior if you // try to re-lock it from the same thread when you already hold a lock // (https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_init.html). + // This is the case even if PTHREAD_MUTEX_DEFAULT == PTHREAD_MUTEX_NORMAL + // (https://github.com/rust-lang/rust/issues/33770#issuecomment-220847521) -- in that + // case, `pthread_mutexattr_settype(PTHREAD_MUTEX_DEFAULT)` will of course be the same + // as setting it to `PTHREAD_MUTEX_NORMAL`, but not setting any mode will result in + // a Mutex where re-locking is UB. // // In practice, glibc takes advantage of this undefined behavior to // implement hardware lock elision, which uses hardware transactional - // memory to avoid acquiring the lock. - // This is the case even if PTHREAD_MUTEX_DEFAULT == PTHREAD_MUTEX_NORMAL - // (https://github.com/rust-lang/rust/issues/33770#issuecomment-220847521). - // As a consequence, while a transaction is in + // memory to avoid acquiring the lock. While a transaction is in // progress, the lock appears to be unlocked. This isn't a problem for // other threads since the transactional memory will abort if a conflict // is detected, however no abort is generated when re-locking from the From b83853d61725a6de7f5563275733daa6a61accca Mon Sep 17 00:00:00 2001 From: mibac138 <5672750+mibac138@users.noreply.github.com> Date: Tue, 5 May 2020 00:31:37 +0200 Subject: [PATCH 07/10] Add command aliases from Cargo to x.py commands --- src/bootstrap/flags.rs | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 5d6e401d5b3fb..fb380af0a47e7 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -106,18 +106,18 @@ impl Flags { Usage: x.py [options] [...] Subcommands: - build Compile either the compiler or libraries - check Compile either the compiler or libraries, using cargo check + build, b Compile either the compiler or libraries + check, c Compile either the compiler or libraries, using cargo check clippy Run clippy (uses rustup/cargo-installed clippy binary) fix Run cargo fix fmt Run rustfmt - test Build and run some test suites + test, t Build and run some test suites bench Build and run some benchmarks doc Build documentation clean Clean out build directories dist Build distribution artifacts install Install distribution artifacts - run Run tools contained in this repository + run, r Run tools contained in this repository To learn more about a subcommand, run `./x.py -h`", ); @@ -184,17 +184,21 @@ To learn more about a subcommand, run `./x.py -h`", // there on out. let subcommand = args.iter().find(|&s| { (s == "build") + || (s == "b") || (s == "check") + || (s == "c") || (s == "clippy") || (s == "fix") || (s == "fmt") || (s == "test") + || (s == "t") || (s == "bench") || (s == "doc") || (s == "clean") || (s == "dist") || (s == "install") || (s == "run") + || (s == "r") }); let subcommand = match subcommand { Some(s) => s, @@ -210,7 +214,7 @@ To learn more about a subcommand, run `./x.py -h`", // Some subcommands get extra options match subcommand.as_str() { - "test" => { + "test" | "t" => { opts.optflag("", "no-fail-fast", "Run all tests regardless of failure"); opts.optmulti("", "test-args", "extra arguments", "ARGS"); opts.optmulti( @@ -285,7 +289,7 @@ To learn more about a subcommand, run `./x.py -h`", } // Extra help text for some commands match subcommand.as_str() { - "build" => { + "build" | "b" => { subcommand_help.push_str( "\n Arguments: @@ -312,7 +316,7 @@ Arguments: Once this is done, build/$ARCH/stage1 contains a usable compiler.", ); } - "check" => { + "check" | "c" => { subcommand_help.push_str( "\n Arguments: @@ -362,7 +366,7 @@ Arguments: ./x.py fmt --check", ); } - "test" => { + "test" | "t" => { subcommand_help.push_str( "\n Arguments: @@ -407,7 +411,7 @@ Arguments: ./x.py doc --stage 1", ); } - "run" => { + "run" | "r" => { subcommand_help.push_str( "\n Arguments: @@ -453,11 +457,11 @@ Arguments: } let cmd = match subcommand.as_str() { - "build" => Subcommand::Build { paths }, - "check" => Subcommand::Check { paths }, + "build" | "b" => Subcommand::Build { paths }, + "check" | "c" => Subcommand::Check { paths }, "clippy" => Subcommand::Clippy { paths }, "fix" => Subcommand::Fix { paths }, - "test" => Subcommand::Test { + "test" | "t" => Subcommand::Test { paths, bless: matches.opt_present("bless"), compare_mode: matches.opt_str("compare-mode"), @@ -487,7 +491,7 @@ Arguments: "fmt" => Subcommand::Format { check: matches.opt_present("check") }, "dist" => Subcommand::Dist { paths }, "install" => Subcommand::Install { paths }, - "run" => { + "run" | "r" => { if paths.is_empty() { println!("\nrun requires at least a path!\n"); usage(1, &opts, &subcommand_help, &extra_help); From f9866f95afad4ea97b975631c6016aa951fd4f83 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 May 2020 09:08:00 +0200 Subject: [PATCH 08/10] rely on rdlock/wrlock not returning anything but the specified error codes --- src/libstd/sys/unix/rwlock.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libstd/sys/unix/rwlock.rs b/src/libstd/sys/unix/rwlock.rs index 3e3a01b4ea395..2b5067a34f648 100644 --- a/src/libstd/sys/unix/rwlock.rs +++ b/src/libstd/sys/unix/rwlock.rs @@ -46,7 +46,9 @@ impl RWLock { } panic!("rwlock read lock would result in deadlock"); } else { - assert_eq!(r, 0); + // According to POSIX, for a properly initialized rwlock this can only + // return EAGAIN or EDEADLK or 0. We rely on that. + debug_assert_eq!(r, 0); self.num_readers.fetch_add(1, Ordering::Relaxed); } } @@ -83,7 +85,9 @@ impl RWLock { } panic!("rwlock write lock would result in deadlock"); } else { - assert_eq!(r, 0); + // According to POSIX, for a properly initialized rwlock this can only + // return EDEADLK or 0. We rely on that. + debug_assert_eq!(r, 0); } *self.write_locked.get() = true; } From 3857506be56736d40b6aa70d4f278f5ee90d26a0 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 1 May 2020 13:18:15 -0700 Subject: [PATCH 09/10] backport 1.43.1 release notes --- RELEASES.md | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 36597b1864f25..8ea481f7e18cd 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,15 @@ +Version 1.43.1 (2020-05-07) +=========================== + +* [Updated openssl-src to 1.1.1g for CVE-2020-1967.][71430] +* [Fixed the stabilization of AVX-512 features.][71473] +* [Fixed `cargo package --list` not working with unpublished dependencies.][cargo/8151] + +[71430]: https://github.com/rust-lang/rust/pull/71430 +[71473]: https://github.com/rust-lang/rust/issues/71473 +[cargo/8151]: https://github.com/rust-lang/cargo/issues/8151 + + Version 1.43.0 (2020-04-23) ========================== @@ -14,7 +26,7 @@ Language - [Merge `fn` syntax + cleanup item parsing.][68728] - [`item` macro fragments can be interpolated into `trait`s, `impl`s, and `extern` blocks.][69366] For example, you may now write: - ```rust + ```rust macro_rules! mac_trait { ($i:item) => { trait T { $i } @@ -82,7 +94,7 @@ Misc - [Certain checks in the `const_err` lint were deemed unrelated to const evaluation][69185], and have been moved to the `unconditional_panic` and `arithmetic_overflow` lints. - + Compatibility Notes ------------------- @@ -173,7 +185,7 @@ Language (e.g. `type Foo: Ord;`). - `...` (the C-variadic type) may occur syntactically directly as the type of any function parameter. - + These are still rejected *semantically*, so you will likely receive an error but these changes can be seen and parsed by procedural macros and conditional compilation. @@ -465,7 +477,7 @@ Compatibility Notes - [Using `#[inline]` on function prototypes and consts now emits a warning under `unused_attribute` lint.][65294] Using `#[inline]` anywhere else inside traits or `extern` blocks now correctly emits a hard error. - + [65294]: https://github.com/rust-lang/rust/pull/65294/ [66103]: https://github.com/rust-lang/rust/pull/66103/ [65843]: https://github.com/rust-lang/rust/pull/65843/ From fbf791bd5259ebbf7575db245a2cffd0f59a15a8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 May 2020 16:43:57 +0200 Subject: [PATCH 10/10] explain the types used in the open64 call --- src/libstd/sys/unix/fs.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 2cfc63d94922d..80cf6a5dbc27b 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -703,6 +703,10 @@ impl File { | opts.get_access_mode()? | opts.get_creation_mode()? | (opts.custom_flags as c_int & !libc::O_ACCMODE); + // The third argument of `open64` is documented to have type `mode_t`. On + // some platforms (like macOS, where `open64` is actually `open`), `mode_t` is `u16`. + // However, since this is a variadic function, C integer promotion rules mean that on + // the ABI level, this still gets passed as `c_int` (aka `u32` on Unix platforms). let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, opts.mode as c_int) })?; let fd = FileDesc::new(fd);