diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 8b6f4054851dd..aea84ac90c1bc 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -56,10 +56,6 @@ //! [`Rc`]: rc //! [`RefCell`]: core::cell -// To run liballoc tests without x.py without ending up with two copies of liballoc, Miri needs to be -// able to "empty" this crate. See . -// rustc itself never sets the feature, so this line has no affect there. -#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))] #![allow(unused_attributes)] #![stable(feature = "alloc", since = "1.36.0")] #![doc( @@ -77,6 +73,10 @@ ))] #![no_std] #![needs_allocator] +// To run liballoc tests without x.py without ending up with two copies of liballoc, Miri needs to be +// able to "empty" this crate. See . +// rustc itself never sets the feature, so this line has no affect there. +#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))] // // Lints: #![deny(unsafe_op_in_unsafe_fn)] diff --git a/library/alloc/src/sync/tests.rs b/library/alloc/src/sync/tests.rs index 202d0e7f02057..0fae8953aa2c7 100644 --- a/library/alloc/src/sync/tests.rs +++ b/library/alloc/src/sync/tests.rs @@ -618,3 +618,22 @@ fn test_arc_cyclic_two_refs() { assert_eq!(Arc::strong_count(&two_refs), 3); assert_eq!(Arc::weak_count(&two_refs), 2); } + +/// Test for Arc::drop bug (https://github.com/rust-lang/rust/issues/55005) +#[test] +#[cfg(miri)] // relies on Stacked Borrows in Miri +fn arc_drop_dereferenceable_race() { + // The bug seems to take up to 700 iterations to reproduce with most seeds (tested 0-9). + for _ in 0..750 { + let arc_1 = Arc::new(()); + let arc_2 = arc_1.clone(); + let thread = thread::spawn(|| drop(arc_2)); + // Spin a bit; makes the race more likely to appear + let mut i = 0; + while i < 256 { + i += 1; + } + drop(arc_1); + thread.join().unwrap(); + } +} diff --git a/library/std/src/collections/hash/map/tests.rs b/library/std/src/collections/hash/map/tests.rs index 7ebc41588b3df..cb3032719fa64 100644 --- a/library/std/src/collections/hash/map/tests.rs +++ b/library/std/src/collections/hash/map/tests.rs @@ -268,10 +268,13 @@ fn test_lots_of_insertions() { // Try this a few times to make sure we never screw up the hashmap's // internal state. - for _ in 0..10 { + let loops = if cfg!(miri) { 2 } else { 10 }; + for _ in 0..loops { assert!(m.is_empty()); - for i in 1..1001 { + let count = if cfg!(miri) { 101 } else { 1001 }; + + for i in 1..count { assert!(m.insert(i, i).is_none()); for j in 1..=i { @@ -279,42 +282,42 @@ fn test_lots_of_insertions() { assert_eq!(r, Some(&j)); } - for j in i + 1..1001 { + for j in i + 1..count { let r = m.get(&j); assert_eq!(r, None); } } - for i in 1001..2001 { + for i in count..(2 * count) { assert!(!m.contains_key(&i)); } // remove forwards - for i in 1..1001 { + for i in 1..count { assert!(m.remove(&i).is_some()); for j in 1..=i { assert!(!m.contains_key(&j)); } - for j in i + 1..1001 { + for j in i + 1..count { assert!(m.contains_key(&j)); } } - for i in 1..1001 { + for i in 1..count { assert!(!m.contains_key(&i)); } - for i in 1..1001 { + for i in 1..count { assert!(m.insert(i, i).is_none()); } // remove backwards - for i in (1..1001).rev() { + for i in (1..count).rev() { assert!(m.remove(&i).is_some()); - for j in i..1001 { + for j in i..count { assert!(!m.contains_key(&j)); } @@ -817,6 +820,7 @@ fn test_retain() { } #[test] +#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM #[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc fn test_try_reserve() { let mut empty_bytes: HashMap = HashMap::new(); diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs index f357f33ec52c5..68a19eccc0e7c 100644 --- a/library/std/src/io/tests.rs +++ b/library/std/src/io/tests.rs @@ -94,7 +94,7 @@ fn read_to_end() { assert_eq!(c.read_to_end(&mut v).unwrap(), 1); assert_eq!(v, b"1"); - let cap = 1024 * 1024; + let cap = if cfg!(miri) { 1024 } else { 1024 * 1024 }; let data = (0..cap).map(|i| (i / 3) as u8).collect::>(); let mut v = Vec::new(); let (a, b) = data.split_at(data.len() / 2); @@ -309,6 +309,7 @@ fn chain_zero_length_read_is_not_eof() { #[bench] #[cfg_attr(target_os = "emscripten", ignore)] +#[cfg_attr(miri, ignore)] // Miri isn't fast... fn bench_read_to_end(b: &mut test::Bencher) { b.iter(|| { let mut lr = repeat(1).take(10000000); diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index a8d6645794ae5..ead06f40d87c4 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -187,6 +187,7 @@ //! [rust-discord]: https://discord.gg/rust-lang //! [array]: prim@array //! [slice]: prim@slice + #![cfg_attr(not(feature = "restricted-std"), stable(feature = "rust1", since = "1.0.0"))] #![cfg_attr(feature = "restricted-std", unstable(feature = "restricted_std", issue = "none"))] #![doc( @@ -201,25 +202,35 @@ no_global_oom_handling, not(no_global_oom_handling) ))] +// To run libstd tests without x.py without ending up with two copies of libstd, Miri needs to be +// able to "empty" this crate. See . +// rustc itself never sets the feature, so this line has no affect there. +#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))] +// miri-test-libstd also prefers to make std use the sysroot versions of the dependencies. +#![cfg_attr(feature = "miri-test-libstd", feature(rustc_private))] // Don't link to std. We are std. #![no_std] +// Tell the compiler to link to either panic_abort or panic_unwind +#![needs_panic_runtime] +// +// Lints: #![warn(deprecated_in_future)] #![warn(missing_docs)] #![warn(missing_debug_implementations)] #![allow(explicit_outlives_requirements)] #![allow(unused_lifetimes)] -// Tell the compiler to link to either panic_abort or panic_unwind -#![needs_panic_runtime] +#![deny(rustc::existing_doc_keyword)] // Ensure that std can be linked against panic_abort despite compiled with `-C panic=unwind` #![deny(ffi_unwind_calls)] // std may use features in a platform-specific way #![allow(unused_features)] +// +// Features: #![cfg_attr(test, feature(internal_output_capture, print_internals, update_panic_count, rt))] #![cfg_attr( all(target_vendor = "fortanix", target_env = "sgx"), feature(slice_index_methods, coerce_unsized, sgx_platform) )] -#![deny(rustc::existing_doc_keyword)] // // Language features: #![feature(alloc_error_handler)] diff --git a/library/std/src/path/tests.rs b/library/std/src/path/tests.rs index 351cf698810f1..dd307022c6d05 100644 --- a/library/std/src/path/tests.rs +++ b/library/std/src/path/tests.rs @@ -1768,6 +1768,7 @@ fn test_windows_absolute() { } #[bench] +#[cfg_attr(miri, ignore)] // Miri isn't fast... fn bench_path_cmp_fast_path_buf_sort(b: &mut test::Bencher) { let prefix = "my/home"; let mut paths: Vec<_> = @@ -1781,6 +1782,7 @@ fn bench_path_cmp_fast_path_buf_sort(b: &mut test::Bencher) { } #[bench] +#[cfg_attr(miri, ignore)] // Miri isn't fast... fn bench_path_cmp_fast_path_long(b: &mut test::Bencher) { let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/"; let paths: Vec<_> = @@ -1799,6 +1801,7 @@ fn bench_path_cmp_fast_path_long(b: &mut test::Bencher) { } #[bench] +#[cfg_attr(miri, ignore)] // Miri isn't fast... fn bench_path_cmp_fast_path_short(b: &mut test::Bencher) { let prefix = "my/home"; let paths: Vec<_> = @@ -1817,6 +1820,7 @@ fn bench_path_cmp_fast_path_short(b: &mut test::Bencher) { } #[bench] +#[cfg_attr(miri, ignore)] // Miri isn't fast... fn bench_path_hashset(b: &mut test::Bencher) { let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/"; let paths: Vec<_> = @@ -1835,6 +1839,7 @@ fn bench_path_hashset(b: &mut test::Bencher) { } #[bench] +#[cfg_attr(miri, ignore)] // Miri isn't fast... fn bench_path_hashset_miss(b: &mut test::Bencher) { let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/"; let paths: Vec<_> = diff --git a/library/std/src/sync/mpsc/mpsc_queue/tests.rs b/library/std/src/sync/mpsc/mpsc_queue/tests.rs index 9f4f31ed05145..34b2a9a98ac36 100644 --- a/library/std/src/sync/mpsc/mpsc_queue/tests.rs +++ b/library/std/src/sync/mpsc/mpsc_queue/tests.rs @@ -13,7 +13,7 @@ fn test_full() { #[test] fn test() { let nthreads = 8; - let nmsgs = 1000; + let nmsgs = if cfg!(miri) { 100 } else { 1000 }; let q = Queue::new(); match q.pop() { Empty => {} diff --git a/library/std/src/sync/mpsc/spsc_queue/tests.rs b/library/std/src/sync/mpsc/spsc_queue/tests.rs index 467ef3dbdcbbd..eb6d5c2cf66d8 100644 --- a/library/std/src/sync/mpsc/spsc_queue/tests.rs +++ b/library/std/src/sync/mpsc/spsc_queue/tests.rs @@ -77,12 +77,13 @@ fn stress() { } unsafe fn stress_bound(bound: usize) { + let count = if cfg!(miri) { 1000 } else { 100000 }; let q = Arc::new(Queue::with_additions(bound, (), ())); let (tx, rx) = channel(); let q2 = q.clone(); let _t = thread::spawn(move || { - for _ in 0..100000 { + for _ in 0..count { loop { match q2.pop() { Some(1) => break, @@ -93,7 +94,7 @@ fn stress() { } tx.send(()).unwrap(); }); - for _ in 0..100000 { + for _ in 0..count { q.push(1); } rx.recv().unwrap(); diff --git a/library/std/src/sync/mpsc/sync_tests.rs b/library/std/src/sync/mpsc/sync_tests.rs index e58649bab6e42..63c79436974d5 100644 --- a/library/std/src/sync/mpsc/sync_tests.rs +++ b/library/std/src/sync/mpsc/sync_tests.rs @@ -113,23 +113,25 @@ fn chan_gone_concurrent() { #[test] fn stress() { + let count = if cfg!(miri) { 100 } else { 10000 }; let (tx, rx) = sync_channel::(0); thread::spawn(move || { - for _ in 0..10000 { + for _ in 0..count { tx.send(1).unwrap(); } }); - for _ in 0..10000 { + for _ in 0..count { assert_eq!(rx.recv().unwrap(), 1); } } #[test] fn stress_recv_timeout_two_threads() { + let count = if cfg!(miri) { 100 } else { 10000 }; let (tx, rx) = sync_channel::(0); thread::spawn(move || { - for _ in 0..10000 { + for _ in 0..count { tx.send(1).unwrap(); } }); @@ -146,12 +148,12 @@ fn stress_recv_timeout_two_threads() { } } - assert_eq!(recv_count, 10000); + assert_eq!(recv_count, count); } #[test] fn stress_recv_timeout_shared() { - const AMT: u32 = 1000; + const AMT: u32 = if cfg!(miri) { 100 } else { 1000 }; const NTHREADS: u32 = 8; let (tx, rx) = sync_channel::(0); let (dtx, drx) = sync_channel::<()>(0); @@ -191,7 +193,7 @@ fn stress_recv_timeout_shared() { #[test] fn stress_shared() { - const AMT: u32 = 1000; + const AMT: u32 = if cfg!(miri) { 100 } else { 1000 }; const NTHREADS: u32 = 8; let (tx, rx) = sync_channel::(0); let (dtx, drx) = sync_channel::<()>(0); @@ -438,12 +440,13 @@ fn stream_send_recv_stress() { #[test] fn recv_a_lot() { + let count = if cfg!(miri) { 1000 } else { 10000 }; // Regression test that we don't run out of stack in scheduler context - let (tx, rx) = sync_channel(10000); - for _ in 0..10000 { + let (tx, rx) = sync_channel(count); + for _ in 0..count { tx.send(()).unwrap(); } - for _ in 0..10000 { + for _ in 0..count { rx.recv().unwrap(); } } diff --git a/library/std/src/sync/mpsc/tests.rs b/library/std/src/sync/mpsc/tests.rs index 4deb3e5961577..f6d0796f604fa 100644 --- a/library/std/src/sync/mpsc/tests.rs +++ b/library/std/src/sync/mpsc/tests.rs @@ -120,13 +120,14 @@ fn chan_gone_concurrent() { #[test] fn stress() { + let count = if cfg!(miri) { 100 } else { 10000 }; let (tx, rx) = channel::(); let t = thread::spawn(move || { - for _ in 0..10000 { + for _ in 0..count { tx.send(1).unwrap(); } }); - for _ in 0..10000 { + for _ in 0..count { assert_eq!(rx.recv().unwrap(), 1); } t.join().ok().expect("thread panicked"); @@ -134,7 +135,7 @@ fn stress() { #[test] fn stress_shared() { - const AMT: u32 = 10000; + const AMT: u32 = if cfg!(miri) { 100 } else { 10000 }; const NTHREADS: u32 = 8; let (tx, rx) = channel::(); @@ -504,12 +505,13 @@ fn very_long_recv_timeout_wont_panic() { #[test] fn recv_a_lot() { + let count = if cfg!(miri) { 1000 } else { 10000 }; // Regression test that we don't run out of stack in scheduler context let (tx, rx) = channel(); - for _ in 0..10000 { + for _ in 0..count { tx.send(()).unwrap(); } - for _ in 0..10000 { + for _ in 0..count { rx.recv().unwrap(); } } diff --git a/library/std/src/sync/rwlock/tests.rs b/library/std/src/sync/rwlock/tests.rs index 08255c985f5eb..b5b3ad9898edb 100644 --- a/library/std/src/sync/rwlock/tests.rs +++ b/library/std/src/sync/rwlock/tests.rs @@ -19,7 +19,7 @@ fn smoke() { #[test] fn frob() { const N: u32 = 10; - const M: usize = 1000; + const M: usize = if cfg!(miri) { 100 } else { 1000 }; let r = Arc::new(RwLock::new(())); diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 7778033eaa98c..f38d2fd3d704e 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -829,6 +829,7 @@ impl DirEntry { target_os = "fuchsia", target_os = "redox" )))] + #[cfg_attr(miri, allow(unused))] fn name_cstr(&self) -> &CStr { unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) } } @@ -840,6 +841,7 @@ impl DirEntry { target_os = "fuchsia", target_os = "redox" ))] + #[cfg_attr(miri, allow(unused))] fn name_cstr(&self) -> &CStr { &self.name } diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs index ec68b52918802..130e47c8d44f0 100644 --- a/library/std/src/thread/tests.rs +++ b/library/std/src/thread/tests.rs @@ -329,3 +329,22 @@ fn test_scoped_threads_nll() { let x = 42_u8; foo(&x); } + +// Regression test for https://github.com/rust-lang/rust/issues/98498. +#[test] +#[cfg(miri)] // relies on Miri's data race detector +fn scope_join_race() { + for _ in 0..100 { + let a_bool = AtomicBool::new(false); + + thread::scope(|s| { + for _ in 0..5 { + s.spawn(|| a_bool.load(Ordering::Relaxed)); + } + + for _ in 0..5 { + s.spawn(|| a_bool.load(Ordering::Relaxed)); + } + }); + } +} diff --git a/library/std/src/time/tests.rs b/library/std/src/time/tests.rs index d710a574465ce..6229556c85fee 100644 --- a/library/std/src/time/tests.rs +++ b/library/std/src/time/tests.rs @@ -31,7 +31,8 @@ fn instant_monotonic_concurrent() -> crate::thread::Result<()> { .map(|_| { crate::thread::spawn(|| { let mut old = Instant::now(); - for _ in 0..5_000_000 { + let count = if cfg!(miri) { 1_000 } else { 5_000_000 }; + for _ in 0..count { let new = Instant::now(); assert!(new >= old); old = new;