Skip to content

Commit 79372e9

Browse files
committed
reproduce double free
Signed-off-by: Petros Angelatos <[email protected]>
1 parent 48f89e7 commit 79372e9

File tree

3 files changed

+39
-0
lines changed

3 files changed

+39
-0
lines changed

library/std/src/sync/mpmc/list.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ impl<T> Channel<T> {
213213
.compare_exchange(block, new, Ordering::Release, Ordering::Relaxed)
214214
.is_ok()
215215
{
216+
crate::thread::sleep(core::time::Duration::from_secs(2));
216217
self.head.block.store(new, Ordering::Release);
217218
block = new;
218219
} else {

library/std/tests/sync/mpmc.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,24 @@ fn smoke() {
1616
assert_eq!(rx.recv().unwrap(), 1);
1717
}
1818

19+
#[test]
20+
fn gh_139553() {
21+
let (s1, r) = channel::<u64>();
22+
let s2 = s1.clone();
23+
// This thread will sleep for 2000ms at the critical moment
24+
let t1 = thread::spawn(move || assert!(s1.send(42).is_err()));
25+
// Give some time for thread 1 to reach the critical state
26+
thread::sleep(Duration::from_millis(100));
27+
// Send another value which see the tail is not null and will just advance the tail offset to 1
28+
// and write the value.
29+
s2.send(42).unwrap();
30+
// Now drop the receiver which will attempt to drop a message by reading it since head != tail
31+
// but head is still a null pointer because the thread t1 is still preempted leading to a
32+
// segfault.
33+
drop(r);
34+
t1.join().unwrap();
35+
}
36+
1937
#[test]
2038
fn drop_full() {
2139
let (tx, _rx) = channel::<Box<isize>>();
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
use std::sync::mpsc::channel;
2+
use std::thread;
3+
use std::time::Duration;
4+
5+
pub fn main() {
6+
let (s1, r) = channel::<u64>();
7+
let s2 = s1.clone();
8+
// This thread will sleep for 2000ms at the critical moment
9+
let t1 = thread::spawn(move || assert!(s1.send(42).is_err()));
10+
// Give some time for thread 1 to reach the critical state
11+
thread::sleep(Duration::from_millis(100));
12+
// Send another value which see the tail is not null and will just advance the tail offset to 1
13+
// and write the value.
14+
s2.send(42).unwrap();
15+
// Now drop the receiver which will attempt to drop a message by reading it since head != tail
16+
// but head is still a null pointer because the thread t1 is still preempted leading to a
17+
// segfault.
18+
drop(r);
19+
t1.join().unwrap();
20+
}

0 commit comments

Comments
 (0)