Skip to content

Commit

Permalink
Miri: Handle more thread leaks in doctests
Browse files Browse the repository at this point in the history
  • Loading branch information
taiki-e committed Nov 5, 2023
1 parent a013780 commit efc566c
Show file tree
Hide file tree
Showing 13 changed files with 89 additions and 21 deletions.
6 changes: 4 additions & 2 deletions ci/miri.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,16 @@ export RUSTFLAGS="${RUSTFLAGS:-} -Z randomize-layout"
export RUSTDOCFLAGS="${RUSTDOCFLAGS:-} -Z randomize-layout"

MIRIFLAGS="-Zmiri-strict-provenance -Zmiri-symbolic-alignment-check -Zmiri-disable-isolation" \
MIRI_LEAK_CHECK='1' \
cargo miri test \
-p crossbeam-channel \
-p crossbeam-queue \
-p crossbeam-utils 2>&1 | ts -i '%.s '

# -Zmiri-ignore-leaks is needed because we use detached threads in tests/docs: https://github.com/rust-lang/miri/issues/1371
# -Zmiri-ignore-leaks is needed because we use detached threads in tests in tests/golang.rs: https://github.com/rust-lang/miri/issues/1371
MIRIFLAGS="-Zmiri-strict-provenance -Zmiri-symbolic-alignment-check -Zmiri-disable-isolation -Zmiri-ignore-leaks" \
cargo miri test \
-p crossbeam-channel 2>&1 | ts -i '%.s '
-p crossbeam-channel --test golang 2>&1 | ts -i '%.s '

# Use Tree Borrows instead of Stacked Borrows because epoch is not compatible with Stacked Borrows: https://github.com/crossbeam-rs/crossbeam/issues/545#issuecomment-1192785003
MIRIFLAGS="-Zmiri-strict-provenance -Zmiri-symbolic-alignment-check -Zmiri-disable-isolation -Zmiri-tree-borrows" \
Expand Down
6 changes: 6 additions & 0 deletions crossbeam-channel/src/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ pub fn at(when: Instant) -> Receiver<Instant> {
///
/// let (s, r) = unbounded();
///
/// # let t =
/// thread::spawn(move || {
/// thread::sleep(Duration::from_secs(1));
/// s.send(1).unwrap();
Expand All @@ -265,6 +266,7 @@ pub fn at(when: Instant) -> Receiver<Instant> {
/// recv(r) -> msg => assert_eq!(msg, Ok(1)),
/// recv(timeout) -> _ => println!("timed out"),
/// }
/// # t.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371
/// ```
pub fn never<T>() -> Receiver<T> {
Receiver {
Expand Down Expand Up @@ -1103,6 +1105,7 @@ impl<T> Receiver<T> {
///
/// let (s, r) = unbounded::<i32>();
///
/// # let t =
/// thread::spawn(move || {
/// s.send(1).unwrap();
/// thread::sleep(Duration::from_secs(1));
Expand All @@ -1118,6 +1121,7 @@ impl<T> Receiver<T> {
/// let v: Vec<_> = r.try_iter().collect();
///
/// assert_eq!(v, [1, 2]);
/// # t.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371
/// ```
pub fn try_iter(&self) -> TryIter<'_, T> {
TryIter { receiver: self }
Expand Down Expand Up @@ -1269,6 +1273,7 @@ impl<T> fmt::Debug for Iter<'_, T> {
///
/// let (s, r) = unbounded::<i32>();
///
/// # let t =
/// thread::spawn(move || {
/// s.send(1).unwrap();
/// thread::sleep(Duration::from_secs(1));
Expand All @@ -1284,6 +1289,7 @@ impl<T> fmt::Debug for Iter<'_, T> {
/// let v: Vec<_> = r.try_iter().collect();
///
/// assert_eq!(v, [1, 2]);
/// # t.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371
/// ```
pub struct TryIter<'a, T> {
receiver: &'a Receiver<T>,
Expand Down
4 changes: 4 additions & 0 deletions crossbeam-channel/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,9 @@
//! let (s1, r1) = unbounded();
//! let (s2, r2) = unbounded();
//!
//! # let t1 =
//! thread::spawn(move || s1.send(10).unwrap());
//! # let t2 =
//! thread::spawn(move || s2.send(20).unwrap());
//!
//! // At most one of these two receive operations will be executed.
Expand All @@ -282,6 +284,8 @@
//! recv(r2) -> msg => assert_eq!(msg, Ok(20)),
//! default(Duration::from_secs(1)) => println!("timed out"),
//! }
//! # t1.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371
//! # t2.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371
//! ```
//!
//! If you need to select over a dynamically created list of channel operations, use [`Select`]
Expand Down
24 changes: 24 additions & 0 deletions crossbeam-channel/src/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -791,10 +791,12 @@ impl<'a> Select<'a> {
/// let (s1, r1) = unbounded();
/// let (s2, r2) = unbounded();
///
/// # let t1 =
/// thread::spawn(move || {
/// thread::sleep(Duration::from_secs(1));
/// s1.send(10).unwrap();
/// });
/// # let t2 =
/// thread::spawn(move || s2.send(20).unwrap());
///
/// let mut sel = Select::new();
Expand All @@ -808,6 +810,8 @@ impl<'a> Select<'a> {
/// i if i == oper2 => assert_eq!(oper.recv(&r2), Ok(20)),
/// _ => unreachable!(),
/// }
/// # t1.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371
/// # t2.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371
/// ```
pub fn select(&mut self) -> SelectedOperation<'a> {
select(&mut self.handles)
Expand Down Expand Up @@ -835,10 +839,12 @@ impl<'a> Select<'a> {
/// let (s1, r1) = unbounded();
/// let (s2, r2) = unbounded();
///
/// # let t1 =
/// thread::spawn(move || {
/// thread::sleep(Duration::from_secs(1));
/// s1.send(10).unwrap();
/// });
/// # let t2 =
/// thread::spawn(move || s2.send(20).unwrap());
///
/// let mut sel = Select::new();
Expand All @@ -855,6 +861,8 @@ impl<'a> Select<'a> {
/// _ => unreachable!(),
/// }
/// }
/// # t1.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371
/// # t2.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371
/// ```
pub fn select_timeout(
&mut self,
Expand Down Expand Up @@ -885,10 +893,12 @@ impl<'a> Select<'a> {
/// let (s1, r1) = unbounded();
/// let (s2, r2) = unbounded();
///
/// # let t1 =
/// thread::spawn(move || {
/// thread::sleep(Duration::from_secs(1));
/// s1.send(10).unwrap();
/// });
/// # let t2 =
/// thread::spawn(move || s2.send(20).unwrap());
///
/// let mut sel = Select::new();
Expand All @@ -907,6 +917,8 @@ impl<'a> Select<'a> {
/// _ => unreachable!(),
/// }
/// }
/// # t1.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371
/// # t2.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371
/// ```
pub fn select_deadline(
&mut self,
Expand Down Expand Up @@ -982,10 +994,12 @@ impl<'a> Select<'a> {
/// let (s1, r1) = unbounded();
/// let (s2, r2) = unbounded();
///
/// # let t1 =
/// thread::spawn(move || {
/// thread::sleep(Duration::from_secs(1));
/// s1.send(10).unwrap();
/// });
/// # let t2 =
/// thread::spawn(move || s2.send(20).unwrap());
///
/// let mut sel = Select::new();
Expand All @@ -998,6 +1012,8 @@ impl<'a> Select<'a> {
/// i if i == oper2 => assert_eq!(r2.try_recv(), Ok(20)),
/// _ => unreachable!(),
/// }
/// # t1.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371
/// # t2.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371
/// ```
pub fn ready(&mut self) -> usize {
if self.handles.is_empty() {
Expand Down Expand Up @@ -1029,10 +1045,12 @@ impl<'a> Select<'a> {
/// let (s1, r1) = unbounded();
/// let (s2, r2) = unbounded();
///
/// # let t1 =
/// thread::spawn(move || {
/// thread::sleep(Duration::from_secs(1));
/// s1.send(10).unwrap();
/// });
/// # let t2 =
/// thread::spawn(move || s2.send(20).unwrap());
///
/// let mut sel = Select::new();
Expand All @@ -1046,6 +1064,8 @@ impl<'a> Select<'a> {
/// Ok(i) if i == oper2 => assert_eq!(r2.try_recv(), Ok(20)),
/// Ok(_) => unreachable!(),
/// }
/// # t1.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371
/// # t2.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371
/// ```
pub fn ready_timeout(&mut self, timeout: Duration) -> Result<usize, ReadyTimeoutError> {
match Instant::now().checked_add(timeout) {
Expand Down Expand Up @@ -1078,10 +1098,12 @@ impl<'a> Select<'a> {
/// let (s1, r1) = unbounded();
/// let (s2, r2) = unbounded();
///
/// # let t1 =
/// thread::spawn(move || {
/// thread::sleep(Duration::from_secs(1));
/// s1.send(10).unwrap();
/// });
/// # let t2 =
/// thread::spawn(move || s2.send(20).unwrap());
///
/// let mut sel = Select::new();
Expand All @@ -1095,6 +1117,8 @@ impl<'a> Select<'a> {
/// Ok(i) if i == oper2 => assert_eq!(r2.try_recv(), Ok(20)),
/// Ok(_) => unreachable!(),
/// }
/// # t1.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371
/// # t2.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371
/// ```
pub fn ready_deadline(&mut self, deadline: Instant) -> Result<usize, ReadyTimeoutError> {
match run_ready(&mut self.handles, Timeout::At(deadline)) {
Expand Down
12 changes: 12 additions & 0 deletions crossbeam-channel/src/select_macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1029,10 +1029,12 @@ macro_rules! crossbeam_channel_internal {
/// let (s1, r1) = unbounded();
/// let (s2, r2) = unbounded();
///
/// # let t1 =
/// thread::spawn(move || {
/// thread::sleep(Duration::from_secs(1));
/// s1.send(10).unwrap();
/// });
/// # let t2 =
/// thread::spawn(move || {
/// thread::sleep(Duration::from_millis(500));
/// s2.send(20).unwrap();
Expand All @@ -1044,6 +1046,8 @@ macro_rules! crossbeam_channel_internal {
/// recv(r2) -> msg => panic!(),
/// default => println!("not ready"),
/// }
/// # t1.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371
/// # t2.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371
/// ```
///
/// Select over a set of operations with a timeout:
Expand All @@ -1056,10 +1060,12 @@ macro_rules! crossbeam_channel_internal {
/// let (s1, r1) = unbounded();
/// let (s2, r2) = unbounded();
///
/// # let t1 =
/// thread::spawn(move || {
/// thread::sleep(Duration::from_secs(1));
/// s1.send(10).unwrap();
/// });
/// # let t2 =
/// thread::spawn(move || {
/// thread::sleep(Duration::from_millis(500));
/// s2.send(20).unwrap();
Expand All @@ -1071,6 +1077,8 @@ macro_rules! crossbeam_channel_internal {
/// recv(r2) -> msg => panic!(),
/// default(Duration::from_millis(100)) => println!("timed out"),
/// }
/// # t1.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371
/// # t2.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371
/// ```
///
/// Optionally add a receive operation to `select!` using [`never`]:
Expand All @@ -1083,10 +1091,12 @@ macro_rules! crossbeam_channel_internal {
/// let (s1, r1) = unbounded();
/// let (s2, r2) = unbounded();
///
/// # let t1 =
/// thread::spawn(move || {
/// thread::sleep(Duration::from_secs(1));
/// s1.send(10).unwrap();
/// });
/// # let t2 =
/// thread::spawn(move || {
/// thread::sleep(Duration::from_millis(500));
/// s2.send(20).unwrap();
Expand All @@ -1100,6 +1110,8 @@ macro_rules! crossbeam_channel_internal {
/// recv(r1) -> msg => panic!(),
/// recv(r2.unwrap_or(&never())) -> msg => assert_eq!(msg, Ok(20)),
/// }
/// # t1.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371
/// # t2.join().unwrap(); // join thread to avoid https://github.com/rust-lang/miri/issues/1371
/// ```
///
/// To optionally add a timeout to `select!`, see the [example] for [`never`].
Expand Down
17 changes: 16 additions & 1 deletion crossbeam-channel/tests/golang.rs
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,7 @@ mod select2 {
assert!(
!(ALLOCATED.load(SeqCst) > alloc
&& (ALLOCATED.load(SeqCst) - alloc) > (N as usize + 10000))
)
);
}
}

Expand Down Expand Up @@ -869,6 +869,11 @@ mod select7 {

#[test]
fn main() {
// https://github.com/rust-lang/miri/issues/1371
if option_env!("MIRI_LEAK_CHECK").is_some() {
return;
}

send1(recv1);
send2(recv1);
send3(recv1);
Expand Down Expand Up @@ -916,6 +921,11 @@ mod sieve1 {

#[test]
fn main() {
// https://github.com/rust-lang/miri/issues/1371
if option_env!("MIRI_LEAK_CHECK").is_some() {
return;
}

let primes = make::<i32>(1);
go!(primes, sieve(primes));

Expand Down Expand Up @@ -2125,6 +2135,11 @@ mod chan1 {

#[test]
fn main() {
// https://github.com/rust-lang/miri/issues/1371
if option_env!("MIRI_LEAK_CHECK").is_some() {
return;
}

let h = Arc::new(Mutex::new([0usize; N]));
let c = make::<usize>(W);
for m in 0..M {
Expand Down
14 changes: 7 additions & 7 deletions crossbeam-channel/tests/mpsc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ mod channel_tests {
for _ in 0..COUNT {
assert_eq!(rx.recv().unwrap(), 1);
}
t.join().ok().unwrap();
t.join().unwrap();
}

#[test]
Expand All @@ -357,7 +357,7 @@ mod channel_tests {
ts.push(t);
}
drop(tx);
t.join().ok().unwrap();
t.join().unwrap();
for t in ts {
t.join().unwrap();
}
Expand All @@ -379,8 +379,8 @@ mod channel_tests {
tx2.send(1).unwrap();
}
});
t1.join().ok().unwrap();
t2.join().ok().unwrap();
t1.join().unwrap();
t2.join().unwrap();
}

#[test]
Expand All @@ -394,7 +394,7 @@ mod channel_tests {
for _ in 0..40 {
tx.send(1).unwrap();
}
t.join().ok().unwrap();
t.join().unwrap();
}

#[test]
Expand All @@ -409,8 +409,8 @@ mod channel_tests {
tx1.send(1).unwrap();
assert_eq!(rx2.recv().unwrap(), 2);
});
t1.join().ok().unwrap();
t2.join().ok().unwrap();
t1.join().unwrap();
t2.join().unwrap();
}

#[test]
Expand Down
Loading

0 comments on commit efc566c

Please sign in to comment.