Skip to content

Commit 4b949c2

Browse files
bors[bot]RalfJungtaiki-e
authored
Merge #855 #858
855: Miri: enable preemption again r=taiki-e a=RalfJung Miri has a [work-around](rust-lang/miri#2248) for rust-lang/rust#55005 now. Also, "check-number-validity" is on by default these days. And I am not sure why "compare-exchange-weak-failure-rate=0.0" was set so let's see what happens when we remove it. :) 858: Ignore clippy::let_unit_value lint r=taiki-e a=taiki-e Co-authored-by: Ralf Jung <[email protected]> Co-authored-by: Taiki Endo <[email protected]>
3 parents f12133c + 93148ad + e718229 commit 4b949c2

File tree

12 files changed

+70
-109
lines changed

12 files changed

+70
-109
lines changed

ci/miri.sh

+18-15
Original file line numberDiff line numberDiff line change
@@ -3,37 +3,40 @@ set -euxo pipefail
33
IFS=$'\n\t'
44
cd "$(dirname "$0")"/..
55

6+
# We need 'ts' for the per-line timing
7+
sudo apt-get -y install moreutils
8+
echo
9+
610
export RUSTFLAGS="${RUSTFLAGS:-} -Z randomize-layout"
711

8-
# disable preemption due to https://github.com/rust-lang/rust/issues/55005
9-
MIRIFLAGS="-Zmiri-strict-provenance -Zmiri-symbolic-alignment-check -Zmiri-disable-isolation -Zmiri-preemption-rate=0" \
12+
# -Zmiri-ignore-leaks is needed because we use detached threads in tests/docs: https://github.com/rust-lang/miri/issues/1371
13+
MIRIFLAGS="-Zmiri-symbolic-alignment-check -Zmiri-disable-isolation -Zmiri-ignore-leaks" \
1014
cargo miri test \
1115
-p crossbeam-queue \
12-
-p crossbeam-utils
16+
-p crossbeam-utils 2>&1 | ts -i '%.s '
1317

1418
# -Zmiri-ignore-leaks is needed because we use detached threads in tests/docs: https://github.com/rust-lang/miri/issues/1371
15-
# disable preemption due to https://github.com/rust-lang/rust/issues/55005
16-
MIRIFLAGS="-Zmiri-strict-provenance -Zmiri-symbolic-alignment-check -Zmiri-disable-isolation -Zmiri-ignore-leaks -Zmiri-preemption-rate=0" \
19+
MIRIFLAGS="-Zmiri-symbolic-alignment-check -Zmiri-disable-isolation -Zmiri-ignore-leaks" \
1720
cargo miri test \
18-
-p crossbeam-channel
21+
-p crossbeam-channel 2>&1 | ts -i '%.s '
1922

2023
# -Zmiri-ignore-leaks is needed for https://github.com/crossbeam-rs/crossbeam/issues/579
2124
# -Zmiri-disable-stacked-borrows is needed for https://github.com/crossbeam-rs/crossbeam/issues/545
22-
# disable preemption due to https://github.com/rust-lang/rust/issues/55005
23-
MIRIFLAGS="-Zmiri-check-number-validity -Zmiri-symbolic-alignment-check -Zmiri-disable-isolation -Zmiri-disable-stacked-borrows -Zmiri-ignore-leaks -Zmiri-preemption-rate=0" \
25+
MIRIFLAGS="-Zmiri-symbolic-alignment-check -Zmiri-disable-isolation -Zmiri-disable-stacked-borrows -Zmiri-ignore-leaks" \
2426
cargo miri test \
2527
-p crossbeam-epoch \
26-
-p crossbeam-skiplist
28+
-p crossbeam-skiplist 2>&1 | ts -i '%.s '
2729

2830
# -Zmiri-ignore-leaks is needed for https://github.com/crossbeam-rs/crossbeam/issues/579
2931
# -Zmiri-disable-stacked-borrows is needed for https://github.com/crossbeam-rs/crossbeam/issues/545
30-
# disable preemption due to https://github.com/rust-lang/rust/issues/55005
31-
MIRIFLAGS="-Zmiri-check-number-validity -Zmiri-symbolic-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-ignore-leaks -Zmiri-compare-exchange-weak-failure-rate=0.0 -Zmiri-preemption-rate=0" \
32+
# -Zmiri-compare-exchange-weak-failure-rate=0.0 is needed because some sequential tests (e.g.,
33+
# doctest of Stealer::steal) incorrectly assume that sequential weak CAS will never fail.
34+
# -Zmiri-preemption-rate=0 is needed because this code technically has UB and Miri catches that.
35+
MIRIFLAGS="-Zmiri-symbolic-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-ignore-leaks -Zmiri-compare-exchange-weak-failure-rate=0.0 -Zmiri-preemption-rate=0" \
3236
cargo miri test \
33-
-p crossbeam-deque
37+
-p crossbeam-deque 2>&1 | ts -i '%.s '
3438

3539
# -Zmiri-ignore-leaks is needed for https://github.com/crossbeam-rs/crossbeam/issues/579
36-
# disable preemption due to https://github.com/rust-lang/rust/issues/55005
37-
MIRIFLAGS="-Zmiri-check-number-validity -Zmiri-symbolic-alignment-check -Zmiri-ignore-leaks -Zmiri-preemption-rate=0" \
40+
MIRIFLAGS="-Zmiri-symbolic-alignment-check -Zmiri-ignore-leaks" \
3841
cargo miri test \
39-
-p crossbeam
42+
-p crossbeam 2>&1 | ts -i '%.s '

crossbeam-channel/tests/array.rs

+1-5
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ fn spsc() {
377377
#[test]
378378
fn mpmc() {
379379
#[cfg(miri)]
380-
const COUNT: usize = 100;
380+
const COUNT: usize = 50;
381381
#[cfg(not(miri))]
382382
const COUNT: usize = 25_000;
383383
const THREADS: usize = 4;
@@ -532,16 +532,12 @@ fn drops() {
532532
scope.spawn(|_| {
533533
for _ in 0..steps {
534534
r.recv().unwrap();
535-
#[cfg(miri)]
536-
std::thread::yield_now(); // https://github.com/rust-lang/miri/issues/1388
537535
}
538536
});
539537

540538
scope.spawn(|_| {
541539
for _ in 0..steps {
542540
s.send(DropCounter).unwrap();
543-
#[cfg(miri)]
544-
std::thread::yield_now(); // https://github.com/rust-lang/miri/issues/1388
545541
}
546542
});
547543
})

crossbeam-channel/tests/golang.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -959,7 +959,7 @@ mod chan_test {
959959
#[test]
960960
fn test_chan() {
961961
#[cfg(miri)]
962-
const N: i32 = 20;
962+
const N: i32 = 12;
963963
#[cfg(not(miri))]
964964
const N: i32 = 200;
965965

@@ -1489,7 +1489,7 @@ mod chan_test {
14891489
fn test_multi_consumer() {
14901490
const NWORK: usize = 23;
14911491
#[cfg(miri)]
1492-
const NITER: usize = 100;
1492+
const NITER: usize = 50;
14931493
#[cfg(not(miri))]
14941494
const NITER: usize = 271828;
14951495

crossbeam-channel/tests/list.rs

-2
Original file line numberDiff line numberDiff line change
@@ -433,8 +433,6 @@ fn drops() {
433433
scope.spawn(|_| {
434434
for _ in 0..steps {
435435
r.recv().unwrap();
436-
#[cfg(miri)]
437-
std::thread::yield_now(); // https://github.com/rust-lang/miri/issues/1388
438436
}
439437
});
440438

crossbeam-channel/tests/mpsc.rs

+6-9
Original file line numberDiff line numberDiff line change
@@ -339,25 +339,22 @@ mod channel_tests {
339339

340340
#[test]
341341
fn stress_shared() {
342-
#[cfg(miri)]
343-
const AMT: u32 = 100;
344-
#[cfg(not(miri))]
345-
const AMT: u32 = 10000;
346-
const NTHREADS: u32 = 8;
342+
let amt: u32 = if cfg!(miri) { 100 } else { 10_000 };
343+
let nthreads: u32 = if cfg!(miri) { 4 } else { 8 };
347344
let (tx, rx) = channel::<i32>();
348345

349346
let t = thread::spawn(move || {
350-
for _ in 0..AMT * NTHREADS {
347+
for _ in 0..amt * nthreads {
351348
assert_eq!(rx.recv().unwrap(), 1);
352349
}
353350
assert!(rx.try_recv().is_err());
354351
});
355352

356-
let mut ts = Vec::with_capacity(NTHREADS as usize);
357-
for _ in 0..NTHREADS {
353+
let mut ts = Vec::with_capacity(nthreads as usize);
354+
for _ in 0..nthreads {
358355
let tx = tx.clone();
359356
let t = thread::spawn(move || {
360-
for _ in 0..AMT {
357+
for _ in 0..amt {
361358
tx.send(1).unwrap();
362359
}
363360
});

crossbeam-channel/tests/thread_locals.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Tests that make sure accessing thread-locals while exiting the thread doesn't cause panics.
22
3-
#![cfg(not(miri))] // error: abnormal termination: the evaluated program aborted execution
3+
#![cfg(not(miri))] // Miri detects that this test is buggy: the destructor of `FOO` uses `std::thread::current()`!
44

55
use std::thread;
66
use std::time::Duration;

crossbeam-channel/tests/zero.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ fn drops() {
403403
#[cfg(not(miri))]
404404
const RUNS: usize = 100;
405405
#[cfg(miri)]
406-
const STEPS: usize = 500;
406+
const STEPS: usize = 100;
407407
#[cfg(not(miri))]
408408
const STEPS: usize = 10_000;
409409

crossbeam-deque/src/deque.rs

+20-23
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ impl<T> Buffer<T> {
5353
/// Returns a pointer to the task at the specified `index`.
5454
unsafe fn at(&self, index: isize) -> *mut T {
5555
// `self.cap` is always a power of two.
56+
// We do all the loads at `MaybeUninit` because we might realize, after loading, that we
57+
// don't actually have the right to access this memory.
5658
self.ptr.offset(index & (self.cap - 1) as isize)
5759
}
5860

@@ -62,18 +64,18 @@ impl<T> Buffer<T> {
6264
/// technically speaking a data race and therefore UB. We should use an atomic store here, but
6365
/// that would be more expensive and difficult to implement generically for all types `T`.
6466
/// Hence, as a hack, we use a volatile write instead.
65-
unsafe fn write(&self, index: isize, task: T) {
66-
ptr::write_volatile(self.at(index), task)
67+
unsafe fn write(&self, index: isize, task: MaybeUninit<T>) {
68+
ptr::write_volatile(self.at(index) as *mut MaybeUninit<T>, task)
6769
}
6870

6971
/// Reads a task from the specified `index`.
7072
///
7173
/// This method might be concurrently called with another `write` at the same index, which is
7274
/// technically speaking a data race and therefore UB. We should use an atomic load here, but
7375
/// that would be more expensive and difficult to implement generically for all types `T`.
74-
/// Hence, as a hack, we use a volatile write instead.
75-
unsafe fn read(&self, index: isize) -> T {
76-
ptr::read_volatile(self.at(index))
76+
/// Hence, as a hack, we use a volatile load instead.
77+
unsafe fn read(&self, index: isize) -> MaybeUninit<T> {
78+
ptr::read_volatile(self.at(index) as *mut MaybeUninit<T>)
7779
}
7880
}
7981

@@ -406,7 +408,7 @@ impl<T> Worker<T> {
406408

407409
// Write `task` into the slot.
408410
unsafe {
409-
buffer.write(b, task);
411+
buffer.write(b, MaybeUninit::new(task));
410412
}
411413

412414
atomic::fence(Ordering::Release);
@@ -461,7 +463,7 @@ impl<T> Worker<T> {
461463
unsafe {
462464
// Read the popped task.
463465
let buffer = self.buffer.get();
464-
let task = buffer.read(f);
466+
let task = buffer.read(f).assume_init();
465467

466468
// Shrink the buffer if `len - 1` is less than one fourth of the capacity.
467469
if buffer.cap > MIN_CAP && len <= buffer.cap as isize / 4 {
@@ -509,8 +511,8 @@ impl<T> Worker<T> {
509511
)
510512
.is_err()
511513
{
512-
// Failed. We didn't pop anything.
513-
mem::forget(task.take());
514+
// Failed. We didn't pop anything. Reset to `None`.
515+
task.take();
514516
}
515517

516518
// Restore the back index to the original task.
@@ -524,7 +526,7 @@ impl<T> Worker<T> {
524526
}
525527
}
526528

527-
task
529+
task.map(|t| unsafe { t.assume_init() })
528530
}
529531
}
530532
}
@@ -661,12 +663,11 @@ impl<T> Stealer<T> {
661663
.is_err()
662664
{
663665
// We didn't steal this task, forget it.
664-
mem::forget(task);
665666
return Steal::Retry;
666667
}
667668

668669
// Return the stolen task.
669-
Steal::Success(task)
670+
Steal::Success(unsafe { task.assume_init() })
670671
}
671672

672673
/// Steals a batch of tasks and pushes them into another worker.
@@ -821,7 +822,6 @@ impl<T> Stealer<T> {
821822
.is_err()
822823
{
823824
// We didn't steal this task, forget it and break from the loop.
824-
mem::forget(task);
825825
batch_size = i;
826826
break;
827827
}
@@ -975,7 +975,6 @@ impl<T> Stealer<T> {
975975
.is_err()
976976
{
977977
// We didn't steal this task, forget it.
978-
mem::forget(task);
979978
return Steal::Retry;
980979
}
981980

@@ -992,7 +991,6 @@ impl<T> Stealer<T> {
992991
.is_err()
993992
{
994993
// We didn't steal this task, forget it.
995-
mem::forget(task);
996994
return Steal::Retry;
997995
}
998996

@@ -1037,7 +1035,6 @@ impl<T> Stealer<T> {
10371035
.is_err()
10381036
{
10391037
// We didn't steal this task, forget it and break from the loop.
1040-
mem::forget(tmp);
10411038
batch_size = i;
10421039
break;
10431040
}
@@ -1077,7 +1074,7 @@ impl<T> Stealer<T> {
10771074
dest.inner.back.store(dest_b, Ordering::Release);
10781075

10791076
// Return with success.
1080-
Steal::Success(task)
1077+
Steal::Success(unsafe { task.assume_init() })
10811078
}
10821079
}
10831080

@@ -1535,7 +1532,7 @@ impl<T> Injector<T> {
15351532
// Read the task.
15361533
let slot = (*block).slots.get_unchecked(offset + i);
15371534
slot.wait_write();
1538-
let task = slot.task.get().read().assume_init();
1535+
let task = slot.task.get().read();
15391536

15401537
// Write it into the destination queue.
15411538
dest_buffer.write(dest_b.wrapping_add(i as isize), task);
@@ -1547,7 +1544,7 @@ impl<T> Injector<T> {
15471544
// Read the task.
15481545
let slot = (*block).slots.get_unchecked(offset + i);
15491546
slot.wait_write();
1550-
let task = slot.task.get().read().assume_init();
1547+
let task = slot.task.get().read();
15511548

15521549
// Write it into the destination queue.
15531550
dest_buffer.write(dest_b.wrapping_add((batch_size - 1 - i) as isize), task);
@@ -1689,7 +1686,7 @@ impl<T> Injector<T> {
16891686
// Read the task.
16901687
let slot = (*block).slots.get_unchecked(offset);
16911688
slot.wait_write();
1692-
let task = slot.task.get().read().assume_init();
1689+
let task = slot.task.get().read();
16931690

16941691
match dest.flavor {
16951692
Flavor::Fifo => {
@@ -1698,7 +1695,7 @@ impl<T> Injector<T> {
16981695
// Read the task.
16991696
let slot = (*block).slots.get_unchecked(offset + i + 1);
17001697
slot.wait_write();
1701-
let task = slot.task.get().read().assume_init();
1698+
let task = slot.task.get().read();
17021699

17031700
// Write it into the destination queue.
17041701
dest_buffer.write(dest_b.wrapping_add(i as isize), task);
@@ -1711,7 +1708,7 @@ impl<T> Injector<T> {
17111708
// Read the task.
17121709
let slot = (*block).slots.get_unchecked(offset + i + 1);
17131710
slot.wait_write();
1714-
let task = slot.task.get().read().assume_init();
1711+
let task = slot.task.get().read();
17151712

17161713
// Write it into the destination queue.
17171714
dest_buffer.write(dest_b.wrapping_add((batch_size - 1 - i) as isize), task);
@@ -1744,7 +1741,7 @@ impl<T> Injector<T> {
17441741
}
17451742
}
17461743

1747-
Steal::Success(task)
1744+
Steal::Success(task.assume_init())
17481745
}
17491746
}
17501747

0 commit comments

Comments
 (0)