Skip to content

Commit 643451e

Browse files
committed
Ensure set_current is called early during thread init
1 parent 1708cd1 commit 643451e

File tree

9 files changed

+136
-136
lines changed

9 files changed

+136
-136
lines changed

library/std/src/sys/thread/hermit.rs

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::num::NonZero;
2+
use crate::thread::ThreadInit;
23
use crate::time::Duration;
34
use crate::{io, ptr};
45

@@ -16,50 +17,49 @@ pub const DEFAULT_MIN_STACK_SIZE: usize = 1 << 20;
1617
impl Thread {
1718
pub unsafe fn new_with_coreid(
1819
stack: usize,
19-
p: Box<dyn FnOnce()>,
20+
init: Box<ThreadInit>,
2021
core_id: isize,
2122
) -> io::Result<Thread> {
22-
let p = Box::into_raw(Box::new(p));
23+
let data = Box::into_raw(init);
2324
let tid = unsafe {
2425
hermit_abi::spawn2(
2526
thread_start,
26-
p.expose_provenance(),
27+
data.expose_provenance(),
2728
hermit_abi::Priority::into(hermit_abi::NORMAL_PRIO),
2829
stack,
2930
core_id,
3031
)
3132
};
3233

3334
return if tid == 0 {
34-
// The thread failed to start and as a result p was not consumed. Therefore, it is
35+
// The thread failed to start and as a result data was not consumed. Therefore, it is
3536
// safe to reconstruct the box so that it gets deallocated.
3637
unsafe {
37-
drop(Box::from_raw(p));
38+
drop(Box::from_raw(data));
3839
}
3940
Err(io::const_error!(io::ErrorKind::Uncategorized, "unable to create thread!"))
4041
} else {
4142
Ok(Thread { tid })
4243
};
4344

44-
extern "C" fn thread_start(main: usize) {
45-
unsafe {
46-
// Finally, let's run some code.
47-
Box::from_raw(ptr::with_exposed_provenance::<Box<dyn FnOnce()>>(main).cast_mut())();
45+
extern "C" fn thread_start(data: usize) {
46+
// SAFETY: we are simply recreating the box that was leaked earlier.
47+
let init =
48+
unsafe { Box::from_raw(ptr::with_exposed_provenance_mut::<ThreadInit>(data)) };
49+
let rust_start = init.init();
50+
rust_start();
4851

49-
// run all destructors
52+
// Run all destructors.
53+
unsafe {
5054
crate::sys::thread_local::destructors::run();
51-
crate::rt::thread_cleanup();
5255
}
56+
crate::rt::thread_cleanup();
5357
}
5458
}
5559

56-
pub unsafe fn new(
57-
stack: usize,
58-
_name: Option<&str>,
59-
p: Box<dyn FnOnce()>,
60-
) -> io::Result<Thread> {
60+
pub unsafe fn new(stack: usize, init: Box<ThreadInit>) -> io::Result<Thread> {
6161
unsafe {
62-
Thread::new_with_coreid(stack, p, -1 /* = no specific core */)
62+
Thread::new_with_coreid(stack, init, -1 /* = no specific core */)
6363
}
6464
}
6565

library/std/src/sys/thread/solid.rs

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use crate::sync::atomic::{Atomic, AtomicUsize, Ordering};
88
use crate::sys::pal::itron::error::{ItronError, expect_success, expect_success_aborting};
99
use crate::sys::pal::itron::time::dur2reltims;
1010
use crate::sys::pal::itron::{abi, task};
11+
use crate::thread::ThreadInit;
1112
use crate::time::Duration;
1213
use crate::{hint, io};
1314

@@ -27,9 +28,9 @@ unsafe impl Sync for Thread {}
2728
/// State data shared between a parent thread and child thread. It's dropped on
2829
/// a transition to one of the final states.
2930
struct ThreadInner {
30-
/// This field is used on thread creation to pass a closure from
31+
/// This field is used on thread creation to pass initialization data from
3132
/// `Thread::new` to the created task.
32-
start: UnsafeCell<ManuallyDrop<Box<dyn FnOnce()>>>,
33+
init: UnsafeCell<ManuallyDrop<Box<ThreadInit>>>,
3334

3435
/// A state machine. Each transition is annotated with `[...]` in the
3536
/// source code.
@@ -65,7 +66,7 @@ struct ThreadInner {
6566
lifecycle: Atomic<usize>,
6667
}
6768

68-
// Safety: The only `!Sync` field, `ThreadInner::start`, is only touched by
69+
// Safety: The only `!Sync` field, `ThreadInner::init`, is only touched by
6970
// the task represented by `ThreadInner`.
7071
unsafe impl Sync for ThreadInner {}
7172

@@ -84,13 +85,9 @@ impl Thread {
8485
/// # Safety
8586
///
8687
/// See `thread::Builder::spawn_unchecked` for safety requirements.
87-
pub unsafe fn new(
88-
stack: usize,
89-
_name: Option<&str>,
90-
p: Box<dyn FnOnce()>,
91-
) -> io::Result<Thread> {
88+
pub unsafe fn new(stack: usize, init: Box<ThreadInit>) -> io::Result<Thread> {
9289
let inner = Box::new(ThreadInner {
93-
start: UnsafeCell::new(ManuallyDrop::new(p)),
90+
init: UnsafeCell::new(ManuallyDrop::new(init)),
9491
lifecycle: AtomicUsize::new(LIFECYCLE_INIT),
9592
});
9693

@@ -100,10 +97,11 @@ impl Thread {
10097
let inner = unsafe { &*p_inner };
10198

10299
// Safety: Since `trampoline` is called only once for each
103-
// `ThreadInner` and only `trampoline` touches `start`,
104-
// `start` contains contents and is safe to mutably borrow.
105-
let p = unsafe { ManuallyDrop::take(&mut *inner.start.get()) };
106-
p();
100+
// `ThreadInner` and only `trampoline` touches `init`,
101+
// `init` contains contents and is safe to mutably borrow.
102+
let init = unsafe { ManuallyDrop::take(&mut *inner.init.get()) };
103+
let rust_start = init.init();
104+
rust_start();
107105

108106
// Fix the current thread's state just in case, so that the
109107
// destructors won't abort

library/std/src/sys/thread/teeos.rs

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::mem::{self, ManuallyDrop};
22
use crate::sys::os;
3+
use crate::thread::ThreadInit;
34
use crate::time::Duration;
45
use crate::{cmp, io, ptr};
56

@@ -24,12 +25,8 @@ unsafe impl Sync for Thread {}
2425

2526
impl Thread {
2627
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
27-
pub unsafe fn new(
28-
stack: usize,
29-
_name: Option<&str>,
30-
p: Box<dyn FnOnce()>,
31-
) -> io::Result<Thread> {
32-
let p = Box::into_raw(Box::new(p));
28+
pub unsafe fn new(stack: usize, init: Box<ThreadInit>) -> io::Result<Thread> {
29+
let data = Box::into_raw(init);
3330
let mut native: libc::pthread_t = unsafe { mem::zeroed() };
3431
let mut attr: libc::pthread_attr_t = unsafe { mem::zeroed() };
3532
assert_eq!(unsafe { libc::pthread_attr_init(&mut attr) }, 0);
@@ -62,16 +59,16 @@ impl Thread {
6259
}
6360
};
6461

65-
let ret = unsafe { libc::pthread_create(&mut native, &attr, thread_start, p as *mut _) };
66-
// Note: if the thread creation fails and this assert fails, then p will
62+
let ret = unsafe { libc::pthread_create(&mut native, &attr, thread_start, data as *mut _) };
63+
// Note: if the thread creation fails and this assert fails, then data will
6764
// be leaked. However, an alternative design could cause double-free
6865
// which is clearly worse.
6966
assert_eq!(unsafe { libc::pthread_attr_destroy(&mut attr) }, 0);
7067

7168
return if ret != 0 {
72-
// The thread failed to start and as a result p was not consumed. Therefore, it is
69+
// The thread failed to start and as a result data was not consumed. Therefore, it is
7370
// safe to reconstruct the box so that it gets deallocated.
74-
drop(unsafe { Box::from_raw(p) });
71+
drop(unsafe { Box::from_raw(data) });
7572
Err(io::Error::from_raw_os_error(ret))
7673
} else {
7774
// The new thread will start running earliest after the next yield.
@@ -80,15 +77,11 @@ impl Thread {
8077
Ok(Thread { id: native })
8178
};
8279

83-
extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {
84-
unsafe {
85-
// Next, set up our stack overflow handler which may get triggered if we run
86-
// out of stack.
87-
// this is not necessary in TEE.
88-
//let _handler = stack_overflow::Handler::new();
89-
// Finally, let's run some code.
90-
Box::from_raw(main as *mut Box<dyn FnOnce()>)();
91-
}
80+
extern "C" fn thread_start(data: *mut libc::c_void) -> *mut libc::c_void {
81+
// SAFETY: we are simply recreating the box that was leaked earlier.
82+
let init = unsafe { Box::from_raw(data as *mut ThreadInit) };
83+
let rust_start = init.init();
84+
rust_start();
9285
ptr::null_mut()
9386
}
9487
}

library/std/src/sys/thread/unix.rs

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use crate::sys::weak::dlsym;
1414
#[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto",))]
1515
use crate::sys::weak::weak;
1616
use crate::sys::{os, stack_overflow};
17+
use crate::thread::{ThreadInit, current};
1718
use crate::time::Duration;
1819
use crate::{cmp, io, ptr};
1920
#[cfg(not(any(
@@ -30,11 +31,6 @@ pub const DEFAULT_MIN_STACK_SIZE: usize = 256 * 1024;
3031
#[cfg(any(target_os = "espidf", target_os = "nuttx"))]
3132
pub const DEFAULT_MIN_STACK_SIZE: usize = 0; // 0 indicates that the stack size configured in the ESP-IDF/NuttX menuconfig system should be used
3233

33-
struct ThreadData {
34-
name: Option<Box<str>>,
35-
f: Box<dyn FnOnce()>,
36-
}
37-
3834
pub struct Thread {
3935
id: libc::pthread_t,
4036
}
@@ -47,12 +43,8 @@ unsafe impl Sync for Thread {}
4743
impl Thread {
4844
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
4945
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
50-
pub unsafe fn new(
51-
stack: usize,
52-
name: Option<&str>,
53-
f: Box<dyn FnOnce()>,
54-
) -> io::Result<Thread> {
55-
let data = Box::into_raw(Box::new(ThreadData { name: name.map(Box::from), f }));
46+
pub unsafe fn new(stack: usize, init: Box<ThreadInit>) -> io::Result<Thread> {
47+
let data = Box::into_raw(init);
5648
let mut native: libc::pthread_t = mem::zeroed();
5749
let mut attr: mem::MaybeUninit<libc::pthread_attr_t> = mem::MaybeUninit::uninit();
5850
assert_eq!(libc::pthread_attr_init(attr.as_mut_ptr()), 0);
@@ -118,12 +110,16 @@ impl Thread {
118110

119111
extern "C" fn thread_start(data: *mut libc::c_void) -> *mut libc::c_void {
120112
unsafe {
121-
let data = Box::from_raw(data as *mut ThreadData);
122-
// Next, set up our stack overflow handler which may get triggered if we run
123-
// out of stack.
124-
let _handler = stack_overflow::Handler::new(data.name);
125-
// Finally, let's run some code.
126-
(data.f)();
113+
// SAFETY: we are simply recreating the box that was leaked earlier.
114+
let init = Box::from_raw(data as *mut ThreadInit);
115+
let rust_start = init.init();
116+
117+
// Set up our thread name and stack overflow handler which may get triggered
118+
// if we run out of stack.
119+
let thread = current();
120+
let _handler = stack_overflow::Handler::new(thread.name().map(Box::from));
121+
122+
rust_start();
127123
}
128124
ptr::null_mut()
129125
}

library/std/src/sys/thread/unsupported.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::ffi::CStr;
22
use crate::io;
33
use crate::num::NonZero;
4+
use crate::thread::ThreadInit;
45
use crate::time::Duration;
56

67
pub struct Thread(!);
@@ -9,11 +10,7 @@ pub const DEFAULT_MIN_STACK_SIZE: usize = 64 * 1024;
910

1011
impl Thread {
1112
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
12-
pub unsafe fn new(
13-
_stack: usize,
14-
_name: Option<&str>,
15-
_p: Box<dyn FnOnce()>,
16-
) -> io::Result<Thread> {
13+
pub unsafe fn new(_stack: usize, _init: Box<ThreadInit>) -> io::Result<Thread> {
1714
Err(io::Error::UNSUPPORTED_PLATFORM)
1815
}
1916

library/std/src/sys/thread/wasip1.rs

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::mem;
77
use crate::num::NonZero;
88
#[cfg(target_feature = "atomics")]
99
use crate::sys::os;
10+
use crate::thread::ThreadInit;
1011
use crate::time::Duration;
1112
#[cfg(target_feature = "atomics")]
1213
use crate::{cmp, ptr};
@@ -73,12 +74,8 @@ pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024;
7374
#[cfg(target_feature = "atomics")]
7475
impl Thread {
7576
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
76-
pub unsafe fn new(
77-
stack: usize,
78-
_name: Option<&str>,
79-
p: Box<dyn FnOnce()>,
80-
) -> io::Result<Thread> {
81-
let p = Box::into_raw(Box::new(p));
77+
pub unsafe fn new(stack: usize, init: Box<ThreadInit>) -> io::Result<Thread> {
78+
let data = Box::into_raw(init);
8279
let mut native: libc::pthread_t = unsafe { mem::zeroed() };
8380
let mut attr: libc::pthread_attr_t = unsafe { mem::zeroed() };
8481
assert_eq!(unsafe { libc::pthread_attr_init(&mut attr) }, 0);
@@ -100,28 +97,28 @@ impl Thread {
10097
}
10198
};
10299

103-
let ret = unsafe { libc::pthread_create(&mut native, &attr, thread_start, p as *mut _) };
104-
// Note: if the thread creation fails and this assert fails, then p will
100+
let ret = unsafe { libc::pthread_create(&mut native, &attr, thread_start, data as *mut _) };
101+
// Note: if the thread creation fails and this assert fails, then data will
105102
// be leaked. However, an alternative design could cause double-free
106103
// which is clearly worse.
107104
assert_eq!(unsafe { libc::pthread_attr_destroy(&mut attr) }, 0);
108105

109106
return if ret != 0 {
110-
// The thread failed to start and as a result p was not consumed. Therefore, it is
107+
// The thread failed to start and as a result data was not consumed. Therefore, it is
111108
// safe to reconstruct the box so that it gets deallocated.
112109
unsafe {
113-
drop(Box::from_raw(p));
110+
drop(Box::from_raw(data));
114111
}
115112
Err(io::Error::from_raw_os_error(ret))
116113
} else {
117114
Ok(Thread { id: native })
118115
};
119116

120-
extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {
121-
unsafe {
122-
// Finally, let's run some code.
123-
Box::from_raw(main as *mut Box<dyn FnOnce()>)();
124-
}
117+
extern "C" fn thread_start(data: *mut libc::c_void) -> *mut libc::c_void {
118+
// SAFETY: we are simply recreating the box that was leaked earlier.
119+
let init = unsafe { Box::from_raw(data as *mut ThreadInit) };
120+
let rust_start = init.init();
121+
rust_start();
125122
ptr::null_mut()
126123
}
127124
}

0 commit comments

Comments
 (0)