Skip to content

Commit

Permalink
Run Miri on CI
Browse files Browse the repository at this point in the history
  • Loading branch information
taiki-e committed Jan 7, 2022
1 parent 59a313f commit 0039ef5
Show file tree
Hide file tree
Showing 25 changed files with 412 additions and 36 deletions.
10 changes: 10 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,15 @@ jobs:
- name: clippy
run: ./ci/clippy.sh

# Run miri.
miri:
name: miri
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: miri
run: ./ci/miri.sh

# Run sanitizers.
san:
name: san
Expand Down Expand Up @@ -174,6 +183,7 @@ jobs:
- codegen
- rustfmt
- clippy
- miri
- san
- loom
- docs
Expand Down
54 changes: 54 additions & 0 deletions ci/miri.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/bin/bash

cd "$(dirname "$0")"/..
set -ex

toolchain=nightly-$(curl -s https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/miri)
rustup set profile minimal
rustup default "$toolchain"
rustup component add miri

MIRIFLAGS="-Zmiri-tag-raw-pointers -Zmiri-disable-isolation" \
cargo miri test \
-p crossbeam-utils \
-p crossbeam-queue

# -Zmiri-ignore-leaks is needed because we use detached threads in tests/docs: https://github.com/rust-lang/miri/issues/1371
# When enable -Zmiri-tag-raw-pointers, the following error is reported:
# error: Undefined Behavior: trying to reborrow for SharedReadWrite at alloc3637744, but parent tag <untagged> does not have an appropriate item in the borrow stack
# --> /Users/taiki/projects/crossbeam/crossbeam-channel/src/flavors/zero.rs:137:22
# |
# 137 | let packet = &*(token.zero as *const Packet<T>);
# | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to reborrow for SharedReadWrite at alloc3637744, but parent tag <untagged> does not have an appropriate item in the borrow stack
# |
# = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental
# = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
#
# = note: inside `crossbeam_channel::flavors::zero::Channel::<i32>::write` at /Users/taiki/projects/crossbeam/crossbeam-channel/src/flavors/zero.rs:137:22
# = note: inside `crossbeam_channel::flavors::zero::Channel::<i32>::send` at /Users/taiki/projects/crossbeam/crossbeam-channel/src/flavors/zero.rs:219:17
# = note: inside `crossbeam_channel::Sender::<i32>::send` at /Users/taiki/projects/crossbeam/crossbeam-channel/src/channel.rs:428:41
# note: inside `SyncSender::<i32>::send` at crossbeam-channel/tests/mpsc.rs:54:9
# --> crossbeam-channel/tests/mpsc.rs:54:9
# |
# 54 | self.inner.send(t).map_err(|cc::SendError(m)| SendError(m))
# | ^^^^^^^^^^^^^^^^^^
# note: inside closure at crossbeam-channel/tests/mpsc.rs:2097:13
# --> crossbeam-channel/tests/mpsc.rs:2097:13
# |
# 2097 | tx.send(1).unwrap();
# | ^^^^^^^^^^
MIRIFLAGS="-Zmiri-disable-isolation -Zmiri-ignore-leaks" \
cargo miri test \
-p crossbeam-channel

# -Zmiri-ignore-leaks is needed for https://github.com/crossbeam-rs/crossbeam/issues/579
# -Zmiri-disable-stacked-borrows is needed for https://github.com/crossbeam-rs/crossbeam/issues/545
MIRIFLAGS="-Zmiri-disable-isolation -Zmiri-ignore-leaks -Zmiri-disable-stacked-borrows" \
cargo miri test \
-p crossbeam-epoch \
-p crossbeam-skiplist \
-p crossbeam

MIRIFLAGS="-Zmiri-disable-isolation -Zmiri-ignore-leaks -Zmiri-disable-stacked-borrows -Zmiri-compare-exchange-weak-failure-rate=1.0" \
cargo miri test \
-p crossbeam-deque
8 changes: 3 additions & 5 deletions crossbeam-channel/src/flavors/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
use std::cell::UnsafeCell;
use std::marker::PhantomData;
use std::mem::{self, MaybeUninit};
use std::mem::MaybeUninit;
use std::ptr;
use std::sync::atomic::{self, AtomicUsize, Ordering};
use std::time::Instant;
Expand Down Expand Up @@ -110,7 +110,7 @@ impl<T> Channel<T> {
// Allocate a buffer of `cap` slots initialized
// with stamps.
let buffer = {
let mut boxed: Box<[Slot<T>]> = (0..cap)
let boxed: Box<[Slot<T>]> = (0..cap)
.map(|i| {
// Set the stamp to `{ lap: 0, mark: 0, index: i }`.
Slot {
Expand All @@ -119,9 +119,7 @@ impl<T> Channel<T> {
}
})
.collect();
let ptr = boxed.as_mut_ptr();
mem::forget(boxed);
ptr
Box::into_raw(boxed) as *mut Slot<T>
};

Channel {
Expand Down
2 changes: 2 additions & 0 deletions crossbeam-channel/tests/after.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! Tests for the after channel flavor.
#![cfg(not(miri))] // TODO: many assertions failed due to Miri is slow

use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;
use std::thread;
Expand Down
2 changes: 2 additions & 0 deletions crossbeam-channel/tests/array.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! Tests for the array channel flavor.
#![cfg(not(miri))] // TODO: many assertions failed due to Miri is slow

use std::any::Any;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;
Expand Down
59 changes: 51 additions & 8 deletions crossbeam-channel/tests/golang.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,9 @@ macro_rules! go {
mod doubleselect {
use super::*;

#[cfg(miri)]
const ITERATIONS: i32 = 100;
#[cfg(not(miri))]
const ITERATIONS: i32 = 10_000;

fn sender(n: i32, c1: Chan<i32>, c2: Chan<i32>, c3: Chan<i32>, c4: Chan<i32>) {
Expand Down Expand Up @@ -691,6 +694,11 @@ mod select {
mod select2 {
use super::*;

#[cfg(miri)]
const N: i32 = 1000;
#[cfg(not(miri))]
const N: i32 = 100000;

#[test]
fn main() {
fn sender(c: &Chan<i32>, n: i32) {
Expand All @@ -717,15 +725,18 @@ mod select2 {

ALLOCATED.store(0, SeqCst);

go!(c, sender(&c, 100000));
receiver(&c, &dummy, 100000);
go!(c, sender(&c, N));
receiver(&c, &dummy, N);

let alloc = ALLOCATED.load(SeqCst);

go!(c, sender(&c, 100000));
receiver(&c, &dummy, 100000);
go!(c, sender(&c, N));
receiver(&c, &dummy, N);

assert!(!(ALLOCATED.load(SeqCst) > alloc && (ALLOCATED.load(SeqCst) - alloc) > 110000))
assert!(
!(ALLOCATED.load(SeqCst) > alloc
&& (ALLOCATED.load(SeqCst) - alloc) > (N as usize + 10000))
)
}
}

Expand Down Expand Up @@ -913,6 +924,9 @@ mod chan_test {

#[test]
fn test_chan() {
#[cfg(miri)]
const N: i32 = 20;
#[cfg(not(miri))]
const N: i32 = 200;

for cap in 0..N {
Expand Down Expand Up @@ -1052,6 +1066,9 @@ mod chan_test {

#[test]
fn test_nonblock_recv_race() {
#[cfg(miri)]
const N: usize = 100;
#[cfg(not(miri))]
const N: usize = 1000;

for _ in 0..N {
Expand All @@ -1073,6 +1090,9 @@ mod chan_test {

#[test]
fn test_nonblock_select_race() {
#[cfg(miri)]
const N: usize = 100;
#[cfg(not(miri))]
const N: usize = 1000;

let done = make::<bool>(1);
Expand Down Expand Up @@ -1106,6 +1126,9 @@ mod chan_test {

#[test]
fn test_nonblock_select_race2() {
#[cfg(miri)]
const N: usize = 100;
#[cfg(not(miri))]
const N: usize = 1000;

let done = make::<bool>(1);
Expand Down Expand Up @@ -1142,6 +1165,11 @@ mod chan_test {
// Ensure that send/recv on the same chan in select
// does not crash nor deadlock.

#[cfg(miri)]
const N: usize = 100;
#[cfg(not(miri))]
const N: usize = 1000;

for &cap in &[0, 10] {
let wg = WaitGroup::new();
wg.add(2);
Expand All @@ -1151,7 +1179,7 @@ mod chan_test {
let p = p;
go!(wg, p, c, {
defer! { wg.done() }
for i in 0..1000 {
for i in 0..N {
if p == 0 || i % 2 == 0 {
select! {
send(c.tx(), p) -> _ => {}
Expand Down Expand Up @@ -1180,15 +1208,18 @@ mod chan_test {

#[test]
fn test_select_stress() {
#[cfg(miri)]
const N: usize = 100;
#[cfg(not(miri))]
const N: usize = 10000;

let c = vec![
make::<i32>(0),
make::<i32>(0),
make::<i32>(2),
make::<i32>(3),
];

const N: usize = 10000;

// There are 4 goroutines that send N values on each of the chans,
// + 4 goroutines that receive N values on each of the chans,
// + 1 goroutine that sends N values on each of the chans in a single select,
Expand Down Expand Up @@ -1286,6 +1317,9 @@ mod chan_test {

#[test]
fn test_select_fairness() {
#[cfg(miri)]
const TRIALS: usize = 100;
#[cfg(not(miri))]
const TRIALS: usize = 10000;

let c1 = make::<u8>(TRIALS + 1);
Expand Down Expand Up @@ -1369,6 +1403,9 @@ mod chan_test {

#[test]
fn test_pseudo_random_send() {
#[cfg(miri)]
const N: usize = 20;
#[cfg(not(miri))]
const N: usize = 100;

for cap in 0..N {
Expand Down Expand Up @@ -1412,6 +1449,9 @@ mod chan_test {
#[test]
fn test_multi_consumer() {
const NWORK: usize = 23;
#[cfg(miri)]
const NITER: usize = 100;
#[cfg(not(miri))]
const NITER: usize = 271828;

let pn = [2, 3, 7, 11, 13, 17, 19, 23, 27, 31];
Expand Down Expand Up @@ -1510,6 +1550,9 @@ mod chan1 {
use super::*;

// sent messages
#[cfg(miri)]
const N: usize = 100;
#[cfg(not(miri))]
const N: usize = 1000;
// receiving "goroutines"
const M: usize = 10;
Expand Down
29 changes: 28 additions & 1 deletion crossbeam-channel/tests/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,9 @@ fn disconnect_wakes_receiver() {

#[test]
fn spsc() {
#[cfg(miri)]
const COUNT: usize = 100;
#[cfg(not(miri))]
const COUNT: usize = 100_000;

let (s, r) = unbounded();
Expand All @@ -261,6 +264,9 @@ fn spsc() {

#[test]
fn mpmc() {
#[cfg(miri)]
const COUNT: usize = 100;
#[cfg(not(miri))]
const COUNT: usize = 25_000;
const THREADS: usize = 4;

Expand Down Expand Up @@ -295,6 +301,9 @@ fn mpmc() {

#[test]
fn stress_oneshot() {
#[cfg(miri)]
const COUNT: usize = 100;
#[cfg(not(miri))]
const COUNT: usize = 10_000;

for _ in 0..COUNT {
Expand All @@ -310,6 +319,9 @@ fn stress_oneshot() {

#[test]
fn stress_iter() {
#[cfg(miri)]
const COUNT: usize = 100;
#[cfg(not(miri))]
const COUNT: usize = 100_000;

let (request_s, request_r) = unbounded();
Expand Down Expand Up @@ -371,8 +383,11 @@ fn stress_timeout_two_threads() {
.unwrap();
}

#[cfg_attr(miri, ignore)] // Miri is too slow
#[test]
fn drops() {
const RUNS: usize = 100;

static DROPS: AtomicUsize = AtomicUsize::new(0);

#[derive(Debug, PartialEq)]
Expand All @@ -386,7 +401,7 @@ fn drops() {

let mut rng = thread_rng();

for _ in 0..100 {
for _ in 0..RUNS {
let steps = rng.gen_range(0..10_000);
let additional = rng.gen_range(0..1000);

Expand Down Expand Up @@ -421,6 +436,9 @@ fn drops() {

#[test]
fn linearizable() {
#[cfg(miri)]
const COUNT: usize = 100;
#[cfg(not(miri))]
const COUNT: usize = 25_000;
const THREADS: usize = 4;

Expand All @@ -441,6 +459,9 @@ fn linearizable() {

#[test]
fn fairness() {
#[cfg(miri)]
const COUNT: usize = 100;
#[cfg(not(miri))]
const COUNT: usize = 10_000;

let (s1, r1) = unbounded::<()>();
Expand All @@ -463,6 +484,9 @@ fn fairness() {

#[test]
fn fairness_duplicates() {
#[cfg(miri)]
const COUNT: usize = 100;
#[cfg(not(miri))]
const COUNT: usize = 10_000;

let (s, r) = unbounded();
Expand Down Expand Up @@ -496,6 +520,9 @@ fn recv_in_send() {

#[test]
fn channel_through_channel() {
#[cfg(miri)]
const COUNT: usize = 100;
#[cfg(not(miri))]
const COUNT: usize = 1000;

type T = Box<dyn Any + Send>;
Expand Down
Loading

0 comments on commit 0039ef5

Please sign in to comment.