Skip to content

Commit

Permalink
Merge #968
Browse files Browse the repository at this point in the history
968: channel: Extend panic_on_drop test r=taiki-e a=taiki-e

Include rust-lang/rust#107466 's case.
cc rust-lang/rust#108164


Co-authored-by: Taiki Endo <[email protected]>
  • Loading branch information
bors[bot] and taiki-e authored Mar 11, 2023
2 parents e094a1a + 3ab7476 commit 599e975
Show file tree
Hide file tree
Showing 2 changed files with 153 additions and 18 deletions.
79 changes: 61 additions & 18 deletions crossbeam-channel/tests/array.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Tests for the array channel flavor.
use std::any::Any;
use std::cell::Cell;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;
use std::thread;
Expand Down Expand Up @@ -692,53 +693,95 @@ fn channel_through_channel() {

#[test]
fn panic_on_drop() {
struct Msg1<'a>(&'a mut bool);
struct Msg1<'a>(&'a Cell<bool>);
impl Drop for Msg1<'_> {
fn drop(&mut self) {
if *self.0 && !std::thread::panicking() {
if self.0.get() && !std::thread::panicking() {
panic!("double drop");
} else {
*self.0 = true;
self.0.set(true);
}
}
}

struct Msg2<'a>(&'a mut bool);
struct Msg2<'a>(&'a Cell<bool>);
impl Drop for Msg2<'_> {
fn drop(&mut self) {
if *self.0 {
if self.0.get() {
panic!("double drop");
} else {
*self.0 = true;
self.0.set(true);
panic!("first drop");
}
}
}

// normal
// normal (sender first)
let (s, r) = bounded(2);
let (mut a, mut b) = (false, false);
s.send(Msg1(&mut a)).unwrap();
s.send(Msg1(&mut b)).unwrap();
let (a, b) = (Cell::new(false), Cell::new(false));
s.send(Msg1(&a)).unwrap();
s.send(Msg1(&b)).unwrap();
drop(s);
assert!(!a.get());
assert!(!b.get());
drop(r);
assert!(a);
assert!(b);
assert!(a.get());
assert!(b.get());

// panic on drop
// normal (receiver first)
let (s, r) = bounded(2);
let (mut a, mut b) = (false, false);
s.send(Msg2(&mut a)).unwrap();
s.send(Msg2(&mut b)).unwrap();
let (a, b) = (Cell::new(false), Cell::new(false));
s.send(Msg1(&a)).unwrap();
s.send(Msg1(&b)).unwrap();
drop(r);
// TODO: should be dropped eagerly: https://github.com/rust-lang/rust/issues/107466
assert!(!a.get());
assert!(!b.get());
drop(s);
assert!(a.get());
assert!(b.get());

// panic on drop (sender first)
let (s, r) = bounded(2);
let (a, b) = (Cell::new(false), Cell::new(false));
s.send(Msg2(&a)).unwrap();
s.send(Msg2(&b)).unwrap();
drop(s);
assert!(!a.get());
assert!(!b.get());
let res = std::panic::catch_unwind(move || {
drop(r);
});
assert_eq!(
*res.unwrap_err().downcast_ref::<&str>().unwrap(),
"first drop"
);
assert!(a);
assert!(a.get());
// Elements after the panicked element will leak.
assert!(!b.get());

// panic on drop (receiver first)
let (s, r) = bounded(2);
let (a, b) = (Cell::new(false), Cell::new(false));
s.send(Msg2(&a)).unwrap();
s.send(Msg2(&b)).unwrap();
let res = std::panic::catch_unwind(move || {
drop(r);
});
// This currently doesn't panic, but it should panic when a fix for
// https://github.com/rust-lang/rust/issues/107466 is implemented.
assert!(res.is_ok());
// TODO: `a` should be dropped eagerly: https://github.com/rust-lang/rust/issues/107466
assert!(!a.get());
assert!(!b.get());
let res = std::panic::catch_unwind(move || {
drop(s);
});
assert_eq!(
*res.unwrap_err().downcast_ref::<&str>().unwrap(),
"first drop"
);
assert!(a.get());
// Elements after the panicked element will leak.
assert!(!b);
assert!(!b.get());
}
92 changes: 92 additions & 0 deletions crossbeam-channel/tests/list.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Tests for the list channel flavor.
use std::any::Any;
use std::cell::Cell;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;
use std::thread;
Expand Down Expand Up @@ -580,3 +581,94 @@ fn channel_through_channel() {
})
.unwrap();
}

#[test]
fn panic_on_drop() {
struct Msg1<'a>(&'a Cell<bool>);
impl Drop for Msg1<'_> {
fn drop(&mut self) {
if self.0.get() && !std::thread::panicking() {
panic!("double drop");
} else {
self.0.set(true);
}
}
}

struct Msg2<'a>(&'a Cell<bool>);
impl Drop for Msg2<'_> {
fn drop(&mut self) {
if self.0.get() {
panic!("double drop");
} else {
self.0.set(true);
panic!("first drop");
}
}
}

// normal (sender first)
let (s, r) = unbounded();
let (a, b) = (Cell::new(false), Cell::new(false));
s.send(Msg1(&a)).unwrap();
s.send(Msg1(&b)).unwrap();
drop(s);
assert!(!a.get());
assert!(!b.get());
drop(r);
assert!(a.get());
assert!(b.get());

// normal (receiver first)
let (s, r) = unbounded();
let (a, b) = (Cell::new(false), Cell::new(false));
s.send(Msg1(&a)).unwrap();
s.send(Msg1(&b)).unwrap();
drop(r);
// When the receiver is dropped, messages are dropped eagerly.
assert!(a.get());
assert!(b.get());
drop(s);
assert!(a.get());
assert!(b.get());

// panic on drop (sender first)
let (s, r) = unbounded();
let (a, b) = (Cell::new(false), Cell::new(false));
s.send(Msg2(&a)).unwrap();
s.send(Msg2(&b)).unwrap();
drop(s);
assert!(!a.get());
assert!(!b.get());
let res = std::panic::catch_unwind(move || {
drop(r);
});
assert_eq!(
*res.unwrap_err().downcast_ref::<&str>().unwrap(),
"first drop"
);
assert!(a.get());
// Elements after the panicked element will leak.
assert!(!b.get());

// panic on drop (receiver first)
let (s, r) = unbounded();
let (a, b) = (Cell::new(false), Cell::new(false));
s.send(Msg2(&a)).unwrap();
s.send(Msg2(&b)).unwrap();
let res = std::panic::catch_unwind(move || {
drop(r);
});
assert_eq!(
*res.unwrap_err().downcast_ref::<&str>().unwrap(),
"first drop"
);
// When the receiver is dropped, messages are dropped eagerly.
assert!(a.get());
// Elements after the panicked element will leak.
assert!(!b.get());
drop(s);
assert!(a.get());
// Elements after the panicked element will leak.
assert!(!b.get());
}

0 comments on commit 599e975

Please sign in to comment.