Skip to content

Commit 9f769b0

Browse files
committed
Fix drop order of last dtor w.r.t. GlobalAlloc TLS var
1 parent eae5cd9 commit 9f769b0

File tree

1 file changed

+16
-13
lines changed
  • library/std/src/sys/thread_local/destructors

1 file changed

+16
-13
lines changed

library/std/src/sys/thread_local/destructors/list.rs

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ static REENTRANT_DTOR: Cell<Option<(*mut u8, unsafe extern "C" fn(*mut u8))>> =
88
static DTORS: RefCell<Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>> = RefCell::new(Vec::new());
99

1010
pub unsafe fn register(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
11-
// Borrow DTORS can only fail if the global allocator calls this
11+
// Borrowing DTORS can only fail if the global allocator calls this
1212
// function again.
1313
if let Ok(mut dtors) = DTORS.try_borrow_mut() {
1414
guard::enable();
@@ -33,18 +33,21 @@ pub unsafe fn register(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
3333
pub unsafe fn run() {
3434
loop {
3535
let mut dtors = DTORS.borrow_mut();
36-
match dtors.pop() {
37-
Some((t, dtor)) => {
38-
drop(dtors);
39-
unsafe {
40-
dtor(t);
41-
}
42-
}
43-
None => {
44-
// Free the list memory.
45-
*dtors = Vec::new();
46-
break;
47-
}
36+
let Some((t, dtor)) = dtors.pop() else { break };
37+
38+
// If the global allocator has allocated a thread-local variable
39+
// it will always be the first in the dtors list (if an alloc came
40+
// before the first regular register()), or be the REENTRANT_DTOR
41+
// (if a register() came before the first alloc). In the former
42+
// case we have to make sure not to touch the global (de)allocator again
43+
// on this thread, so free dtors now, before calling the last dtor.
44+
if dtors.is_empty() {
45+
*dtors = Vec::new();
46+
}
47+
48+
drop(dtors);
49+
unsafe {
50+
dtor(t);
4851
}
4952
}
5053

0 commit comments

Comments
 (0)