Skip to content

Commit 64e5327

Browse files
author
Vytautas Astrauskas
committed
Fix double-free and undefined behaviour in libstd::syn::unix::Thread::new.
1 parent 2113659 commit 64e5327

File tree

5 files changed

+43
-18
lines changed

5 files changed

+43
-18
lines changed

src/libstd/sys/cloudabi/thread.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,21 +22,28 @@ unsafe impl Sync for Thread {}
2222
impl Thread {
2323
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
2424
pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
25-
let p = box p;
25+
let mut p = mem::ManuallyDrop::new(box p);
2626
let mut native: libc::pthread_t = mem::zeroed();
2727
let mut attr: libc::pthread_attr_t = mem::zeroed();
2828
assert_eq!(libc::pthread_attr_init(&mut attr), 0);
2929

3030
let stack_size = cmp::max(stack, min_stack_size(&attr));
3131
assert_eq!(libc::pthread_attr_setstacksize(&mut attr, stack_size), 0);
3232

33-
let ret = libc::pthread_create(&mut native, &attr, thread_start, &*p as *const _ as *mut _);
33+
let ret = libc::pthread_create(
34+
&mut native,
35+
&attr,
36+
thread_start,
37+
&mut *p as &mut Box<dyn FnOnce()> as *mut _ as *mut _,
38+
);
3439
assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
3540

3641
return if ret != 0 {
42+
// The thread failed to start and as a result p was not consumed. Therefore, it is
43+
// safe to manually drop it.
44+
mem::ManuallyDrop::drop(&mut p);
3745
Err(io::Error::from_raw_os_error(ret))
3846
} else {
39-
mem::forget(p); // ownership passed to pthread_create
4047
Ok(Thread { id: native })
4148
};
4249

src/libstd/sys/hermit/thread.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,21 +49,23 @@ impl Thread {
4949
p: Box<dyn FnOnce()>,
5050
core_id: isize,
5151
) -> io::Result<Thread> {
52-
let p = box p;
52+
let mut p = mem::ManuallyDrop::new(box p);
5353
let mut tid: Tid = u32::MAX;
5454
let ret = abi::spawn(
5555
&mut tid as *mut Tid,
5656
thread_start,
57-
&*p as *const _ as *const u8 as usize,
57+
&mut *p as &mut Box<dyn FnOnce()> as *mut _ as *mut u8 as usize,
5858
Priority::into(NORMAL_PRIO),
5959
core_id,
6060
);
6161

62-
return if ret == 0 {
63-
mem::forget(p); // ownership passed to pthread_create
64-
Ok(Thread { tid: tid })
65-
} else {
62+
return if ret != 0 {
63+
// The thread failed to start and as a result p was not consumed. Therefore, it is
64+
// safe to manually drop it.
65+
mem::ManuallyDrop::drop(&mut p);
6666
Err(io::Error::new(io::ErrorKind::Other, "Unable to create thread!"))
67+
} else {
68+
Ok(Thread { tid: tid })
6769
};
6870

6971
extern "C" fn thread_start(main: usize) {

src/libstd/sys/unix/thread.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ unsafe fn pthread_attr_setstacksize(
4343
impl Thread {
4444
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
4545
pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
46-
let p = box p;
46+
let mut p = mem::ManuallyDrop::new(box p);
4747
let mut native: libc::pthread_t = mem::zeroed();
4848
let mut attr: libc::pthread_attr_t = mem::zeroed();
4949
assert_eq!(libc::pthread_attr_init(&mut attr), 0);
@@ -65,13 +65,20 @@ impl Thread {
6565
}
6666
};
6767

68-
let ret = libc::pthread_create(&mut native, &attr, thread_start, &*p as *const _ as *mut _);
68+
let ret = libc::pthread_create(
69+
&mut native,
70+
&attr,
71+
thread_start,
72+
&mut *p as &mut Box<dyn FnOnce()> as *mut _ as *mut _,
73+
);
6974
assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
7075

7176
return if ret != 0 {
77+
// The thread failed to start and as a result p was not consumed. Therefore, it is
78+
// safe to manually drop it.
79+
mem::ManuallyDrop::drop(&mut p);
7280
Err(io::Error::from_raw_os_error(ret))
7381
} else {
74-
mem::forget(p); // ownership passed to pthread_create
7582
Ok(Thread { id: native })
7683
};
7784

src/libstd/sys/vxworks/thread.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ unsafe fn pthread_attr_setstacksize(
3131
impl Thread {
3232
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
3333
pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
34-
let p = box p;
34+
let mut p = mem::ManuallyDrop::new(box p);
3535
let mut native: libc::pthread_t = mem::zeroed();
3636
let mut attr: libc::pthread_attr_t = mem::zeroed();
3737
assert_eq!(libc::pthread_attr_init(&mut attr), 0);
@@ -53,13 +53,20 @@ impl Thread {
5353
}
5454
};
5555

56-
let ret = libc::pthread_create(&mut native, &attr, thread_start, &*p as *const _ as *mut _);
56+
let ret = libc::pthread_create(
57+
&mut native,
58+
&attr,
59+
thread_start,
60+
&mut *p as &mut Box<dyn FnOnce()> as *mut _ as *mut _,
61+
);
5762
assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
5863

5964
return if ret != 0 {
65+
// The thread failed to start and as a result p was not consumed. Therefore, it is
66+
// safe to manually drop it.
67+
mem::ManuallyDrop::drop(&mut p);
6068
Err(io::Error::from_raw_os_error(ret))
6169
} else {
62-
mem::forget(p); // ownership passed to pthread_create
6370
Ok(Thread { id: native })
6471
};
6572

src/libstd/sys/windows/thread.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub struct Thread {
2020
impl Thread {
2121
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
2222
pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
23-
let p = box p;
23+
let mut p = mem::ManuallyDrop::new(box p);
2424

2525
// FIXME On UNIX, we guard against stack sizes that are too small but
2626
// that's because pthreads enforces that stacks are at least
@@ -34,15 +34,17 @@ impl Thread {
3434
ptr::null_mut(),
3535
stack_size,
3636
thread_start,
37-
&*p as *const _ as *mut _,
37+
&mut *p as &mut Box<dyn FnOnce()> as *mut _ as *mut _,
3838
c::STACK_SIZE_PARAM_IS_A_RESERVATION,
3939
ptr::null_mut(),
4040
);
4141

4242
return if ret as usize == 0 {
43+
// The thread failed to start and as a result p was not consumed. Therefore, it is
44+
// safe to manually drop it.
45+
mem::ManuallyDrop::drop(&mut p);
4346
Err(io::Error::last_os_error())
4447
} else {
45-
mem::forget(p); // ownership passed to CreateThread
4648
Ok(Thread { handle: Handle::new(ret) })
4749
};
4850

0 commit comments

Comments
 (0)