Skip to content

Commit 80fa648

Browse files
authored
Rollup merge of rust-lang#100129 - RalfJung:miri-test-libstd, r=thomcc
add miri-test-libstd support to libstd - The first commit mirrors what we already have in liballoc. - The second commit adds some regression tests that only really make sense to be run in Miri, since they rely on Miri's extra checks to detect anything. - The third commit makes the MPSC tests work in reasonable time in Miri by reducing iteration counts. - The fourth commit silences some warnings due to code being disabled with `cfg(miri)`
2 parents 6c2ff7c + fbcdf2a commit 80fa648

File tree

14 files changed

+105
-37
lines changed

14 files changed

+105
-37
lines changed

library/alloc/src/lib.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,6 @@
5656
//! [`Rc`]: rc
5757
//! [`RefCell`]: core::cell
5858
59-
// To run liballoc tests without x.py without ending up with two copies of liballoc, Miri needs to be
60-
// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
61-
// rustc itself never sets the feature, so this line has no affect there.
62-
#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
6359
#![allow(unused_attributes)]
6460
#![stable(feature = "alloc", since = "1.36.0")]
6561
#![doc(
@@ -77,6 +73,10 @@
7773
))]
7874
#![no_std]
7975
#![needs_allocator]
76+
// To run liballoc tests without x.py without ending up with two copies of liballoc, Miri needs to be
77+
// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
78+
// rustc itself never sets the feature, so this line has no affect there.
79+
#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
8080
//
8181
// Lints:
8282
#![deny(unsafe_op_in_unsafe_fn)]

library/alloc/src/sync/tests.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -618,3 +618,22 @@ fn test_arc_cyclic_two_refs() {
618618
assert_eq!(Arc::strong_count(&two_refs), 3);
619619
assert_eq!(Arc::weak_count(&two_refs), 2);
620620
}
621+
622+
/// Test for Arc::drop bug (https://github.com/rust-lang/rust/issues/55005)
623+
#[test]
624+
#[cfg(miri)] // relies on Stacked Borrows in Miri
625+
fn arc_drop_dereferenceable_race() {
626+
// The bug seems to take up to 700 iterations to reproduce with most seeds (tested 0-9).
627+
for _ in 0..750 {
628+
let arc_1 = Arc::new(());
629+
let arc_2 = arc_1.clone();
630+
let thread = thread::spawn(|| drop(arc_2));
631+
// Spin a bit; makes the race more likely to appear
632+
let mut i = 0;
633+
while i < 256 {
634+
i += 1;
635+
}
636+
drop(arc_1);
637+
thread.join().unwrap();
638+
}
639+
}

library/std/src/collections/hash/map/tests.rs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -268,53 +268,56 @@ fn test_lots_of_insertions() {
268268

269269
// Try this a few times to make sure we never screw up the hashmap's
270270
// internal state.
271-
for _ in 0..10 {
271+
let loops = if cfg!(miri) { 2 } else { 10 };
272+
for _ in 0..loops {
272273
assert!(m.is_empty());
273274

274-
for i in 1..1001 {
275+
let count = if cfg!(miri) { 101 } else { 1001 };
276+
277+
for i in 1..count {
275278
assert!(m.insert(i, i).is_none());
276279

277280
for j in 1..=i {
278281
let r = m.get(&j);
279282
assert_eq!(r, Some(&j));
280283
}
281284

282-
for j in i + 1..1001 {
285+
for j in i + 1..count {
283286
let r = m.get(&j);
284287
assert_eq!(r, None);
285288
}
286289
}
287290

288-
for i in 1001..2001 {
291+
for i in count..(2 * count) {
289292
assert!(!m.contains_key(&i));
290293
}
291294

292295
// remove forwards
293-
for i in 1..1001 {
296+
for i in 1..count {
294297
assert!(m.remove(&i).is_some());
295298

296299
for j in 1..=i {
297300
assert!(!m.contains_key(&j));
298301
}
299302

300-
for j in i + 1..1001 {
303+
for j in i + 1..count {
301304
assert!(m.contains_key(&j));
302305
}
303306
}
304307

305-
for i in 1..1001 {
308+
for i in 1..count {
306309
assert!(!m.contains_key(&i));
307310
}
308311

309-
for i in 1..1001 {
312+
for i in 1..count {
310313
assert!(m.insert(i, i).is_none());
311314
}
312315

313316
// remove backwards
314-
for i in (1..1001).rev() {
317+
for i in (1..count).rev() {
315318
assert!(m.remove(&i).is_some());
316319

317-
for j in i..1001 {
320+
for j in i..count {
318321
assert!(!m.contains_key(&j));
319322
}
320323

@@ -817,6 +820,7 @@ fn test_retain() {
817820
}
818821

819822
#[test]
823+
#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
820824
#[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc
821825
fn test_try_reserve() {
822826
let mut empty_bytes: HashMap<u8, u8> = HashMap::new();

library/std/src/io/tests.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ fn read_to_end() {
9494
assert_eq!(c.read_to_end(&mut v).unwrap(), 1);
9595
assert_eq!(v, b"1");
9696

97-
let cap = 1024 * 1024;
97+
let cap = if cfg!(miri) { 1024 } else { 1024 * 1024 };
9898
let data = (0..cap).map(|i| (i / 3) as u8).collect::<Vec<_>>();
9999
let mut v = Vec::new();
100100
let (a, b) = data.split_at(data.len() / 2);
@@ -309,6 +309,7 @@ fn chain_zero_length_read_is_not_eof() {
309309

310310
#[bench]
311311
#[cfg_attr(target_os = "emscripten", ignore)]
312+
#[cfg_attr(miri, ignore)] // Miri isn't fast...
312313
fn bench_read_to_end(b: &mut test::Bencher) {
313314
b.iter(|| {
314315
let mut lr = repeat(1).take(10000000);

library/std/src/lib.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@
187187
//! [rust-discord]: https://discord.gg/rust-lang
188188
//! [array]: prim@array
189189
//! [slice]: prim@slice
190+
190191
#![cfg_attr(not(feature = "restricted-std"), stable(feature = "rust1", since = "1.0.0"))]
191192
#![cfg_attr(feature = "restricted-std", unstable(feature = "restricted_std", issue = "none"))]
192193
#![doc(
@@ -201,25 +202,35 @@
201202
no_global_oom_handling,
202203
not(no_global_oom_handling)
203204
))]
205+
// To run libstd tests without x.py without ending up with two copies of libstd, Miri needs to be
206+
// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
207+
// rustc itself never sets the feature, so this line has no affect there.
208+
#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
209+
// miri-test-libstd also prefers to make std use the sysroot versions of the dependencies.
210+
#![cfg_attr(feature = "miri-test-libstd", feature(rustc_private))]
204211
// Don't link to std. We are std.
205212
#![no_std]
213+
// Tell the compiler to link to either panic_abort or panic_unwind
214+
#![needs_panic_runtime]
215+
//
216+
// Lints:
206217
#![warn(deprecated_in_future)]
207218
#![warn(missing_docs)]
208219
#![warn(missing_debug_implementations)]
209220
#![allow(explicit_outlives_requirements)]
210221
#![allow(unused_lifetimes)]
211-
// Tell the compiler to link to either panic_abort or panic_unwind
212-
#![needs_panic_runtime]
222+
#![deny(rustc::existing_doc_keyword)]
213223
// Ensure that std can be linked against panic_abort despite compiled with `-C panic=unwind`
214224
#![deny(ffi_unwind_calls)]
215225
// std may use features in a platform-specific way
216226
#![allow(unused_features)]
227+
//
228+
// Features:
217229
#![cfg_attr(test, feature(internal_output_capture, print_internals, update_panic_count, rt))]
218230
#![cfg_attr(
219231
all(target_vendor = "fortanix", target_env = "sgx"),
220232
feature(slice_index_methods, coerce_unsized, sgx_platform)
221233
)]
222-
#![deny(rustc::existing_doc_keyword)]
223234
//
224235
// Language features:
225236
#![feature(alloc_error_handler)]

library/std/src/path/tests.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1768,6 +1768,7 @@ fn test_windows_absolute() {
17681768
}
17691769

17701770
#[bench]
1771+
#[cfg_attr(miri, ignore)] // Miri isn't fast...
17711772
fn bench_path_cmp_fast_path_buf_sort(b: &mut test::Bencher) {
17721773
let prefix = "my/home";
17731774
let mut paths: Vec<_> =
@@ -1781,6 +1782,7 @@ fn bench_path_cmp_fast_path_buf_sort(b: &mut test::Bencher) {
17811782
}
17821783

17831784
#[bench]
1785+
#[cfg_attr(miri, ignore)] // Miri isn't fast...
17841786
fn bench_path_cmp_fast_path_long(b: &mut test::Bencher) {
17851787
let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/";
17861788
let paths: Vec<_> =
@@ -1799,6 +1801,7 @@ fn bench_path_cmp_fast_path_long(b: &mut test::Bencher) {
17991801
}
18001802

18011803
#[bench]
1804+
#[cfg_attr(miri, ignore)] // Miri isn't fast...
18021805
fn bench_path_cmp_fast_path_short(b: &mut test::Bencher) {
18031806
let prefix = "my/home";
18041807
let paths: Vec<_> =
@@ -1817,6 +1820,7 @@ fn bench_path_cmp_fast_path_short(b: &mut test::Bencher) {
18171820
}
18181821

18191822
#[bench]
1823+
#[cfg_attr(miri, ignore)] // Miri isn't fast...
18201824
fn bench_path_hashset(b: &mut test::Bencher) {
18211825
let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/";
18221826
let paths: Vec<_> =
@@ -1835,6 +1839,7 @@ fn bench_path_hashset(b: &mut test::Bencher) {
18351839
}
18361840

18371841
#[bench]
1842+
#[cfg_attr(miri, ignore)] // Miri isn't fast...
18381843
fn bench_path_hashset_miss(b: &mut test::Bencher) {
18391844
let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/";
18401845
let paths: Vec<_> =

library/std/src/sync/mpsc/mpsc_queue/tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ fn test_full() {
1313
#[test]
1414
fn test() {
1515
let nthreads = 8;
16-
let nmsgs = 1000;
16+
let nmsgs = if cfg!(miri) { 100 } else { 1000 };
1717
let q = Queue::new();
1818
match q.pop() {
1919
Empty => {}

library/std/src/sync/mpsc/spsc_queue/tests.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,13 @@ fn stress() {
7777
}
7878

7979
unsafe fn stress_bound(bound: usize) {
80+
let count = if cfg!(miri) { 1000 } else { 100000 };
8081
let q = Arc::new(Queue::with_additions(bound, (), ()));
8182

8283
let (tx, rx) = channel();
8384
let q2 = q.clone();
8485
let _t = thread::spawn(move || {
85-
for _ in 0..100000 {
86+
for _ in 0..count {
8687
loop {
8788
match q2.pop() {
8889
Some(1) => break,
@@ -93,7 +94,7 @@ fn stress() {
9394
}
9495
tx.send(()).unwrap();
9596
});
96-
for _ in 0..100000 {
97+
for _ in 0..count {
9798
q.push(1);
9899
}
99100
rx.recv().unwrap();

library/std/src/sync/mpsc/sync_tests.rs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -113,23 +113,25 @@ fn chan_gone_concurrent() {
113113

114114
#[test]
115115
fn stress() {
116+
let count = if cfg!(miri) { 100 } else { 10000 };
116117
let (tx, rx) = sync_channel::<i32>(0);
117118
thread::spawn(move || {
118-
for _ in 0..10000 {
119+
for _ in 0..count {
119120
tx.send(1).unwrap();
120121
}
121122
});
122-
for _ in 0..10000 {
123+
for _ in 0..count {
123124
assert_eq!(rx.recv().unwrap(), 1);
124125
}
125126
}
126127

127128
#[test]
128129
fn stress_recv_timeout_two_threads() {
130+
let count = if cfg!(miri) { 100 } else { 10000 };
129131
let (tx, rx) = sync_channel::<i32>(0);
130132

131133
thread::spawn(move || {
132-
for _ in 0..10000 {
134+
for _ in 0..count {
133135
tx.send(1).unwrap();
134136
}
135137
});
@@ -146,12 +148,12 @@ fn stress_recv_timeout_two_threads() {
146148
}
147149
}
148150

149-
assert_eq!(recv_count, 10000);
151+
assert_eq!(recv_count, count);
150152
}
151153

152154
#[test]
153155
fn stress_recv_timeout_shared() {
154-
const AMT: u32 = 1000;
156+
const AMT: u32 = if cfg!(miri) { 100 } else { 1000 };
155157
const NTHREADS: u32 = 8;
156158
let (tx, rx) = sync_channel::<i32>(0);
157159
let (dtx, drx) = sync_channel::<()>(0);
@@ -191,7 +193,7 @@ fn stress_recv_timeout_shared() {
191193

192194
#[test]
193195
fn stress_shared() {
194-
const AMT: u32 = 1000;
196+
const AMT: u32 = if cfg!(miri) { 100 } else { 1000 };
195197
const NTHREADS: u32 = 8;
196198
let (tx, rx) = sync_channel::<i32>(0);
197199
let (dtx, drx) = sync_channel::<()>(0);
@@ -438,12 +440,13 @@ fn stream_send_recv_stress() {
438440

439441
#[test]
440442
fn recv_a_lot() {
443+
let count = if cfg!(miri) { 1000 } else { 10000 };
441444
// Regression test that we don't run out of stack in scheduler context
442-
let (tx, rx) = sync_channel(10000);
443-
for _ in 0..10000 {
445+
let (tx, rx) = sync_channel(count);
446+
for _ in 0..count {
444447
tx.send(()).unwrap();
445448
}
446-
for _ in 0..10000 {
449+
for _ in 0..count {
447450
rx.recv().unwrap();
448451
}
449452
}

library/std/src/sync/mpsc/tests.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -120,21 +120,22 @@ fn chan_gone_concurrent() {
120120

121121
#[test]
122122
fn stress() {
123+
let count = if cfg!(miri) { 100 } else { 10000 };
123124
let (tx, rx) = channel::<i32>();
124125
let t = thread::spawn(move || {
125-
for _ in 0..10000 {
126+
for _ in 0..count {
126127
tx.send(1).unwrap();
127128
}
128129
});
129-
for _ in 0..10000 {
130+
for _ in 0..count {
130131
assert_eq!(rx.recv().unwrap(), 1);
131132
}
132133
t.join().ok().expect("thread panicked");
133134
}
134135

135136
#[test]
136137
fn stress_shared() {
137-
const AMT: u32 = 10000;
138+
const AMT: u32 = if cfg!(miri) { 100 } else { 10000 };
138139
const NTHREADS: u32 = 8;
139140
let (tx, rx) = channel::<i32>();
140141

@@ -504,12 +505,13 @@ fn very_long_recv_timeout_wont_panic() {
504505

505506
#[test]
506507
fn recv_a_lot() {
508+
let count = if cfg!(miri) { 1000 } else { 10000 };
507509
// Regression test that we don't run out of stack in scheduler context
508510
let (tx, rx) = channel();
509-
for _ in 0..10000 {
511+
for _ in 0..count {
510512
tx.send(()).unwrap();
511513
}
512-
for _ in 0..10000 {
514+
for _ in 0..count {
513515
rx.recv().unwrap();
514516
}
515517
}

library/std/src/sync/rwlock/tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ fn smoke() {
1919
#[test]
2020
fn frob() {
2121
const N: u32 = 10;
22-
const M: usize = 1000;
22+
const M: usize = if cfg!(miri) { 100 } else { 1000 };
2323

2424
let r = Arc::new(RwLock::new(()));
2525

library/std/src/sys/unix/fs.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -829,6 +829,7 @@ impl DirEntry {
829829
target_os = "fuchsia",
830830
target_os = "redox"
831831
)))]
832+
#[cfg_attr(miri, allow(unused))]
832833
fn name_cstr(&self) -> &CStr {
833834
unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) }
834835
}
@@ -840,6 +841,7 @@ impl DirEntry {
840841
target_os = "fuchsia",
841842
target_os = "redox"
842843
))]
844+
#[cfg_attr(miri, allow(unused))]
843845
fn name_cstr(&self) -> &CStr {
844846
&self.name
845847
}

0 commit comments

Comments
 (0)