Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Panic when the global allocator tries to register a TLS destructor #116402

Merged
merged 4 commits into from
Oct 19, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions library/std/src/sys/hermit/thread_local_dtor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,22 @@
// The this solution works like the implementation of macOS and
// doesn't additional OS support

use crate::mem;
use crate::cell::RefCell;

#[thread_local]
static mut DTORS: Vec<(*mut u8, unsafe extern "C" fn(*mut u8))> = Vec::new();
static DTORS: RefCell<Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>> = RefCell::new(Vec::new());

pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
let list = &mut DTORS;
list.push((t, dtor));
DTORS.try_borrow_mut().expect("global allocator may not use TLS").push((t, dtor));
joboet marked this conversation as resolved.
Show resolved Hide resolved
}

// every thread call this function to run through all possible destructors
pub unsafe fn run_dtors() {
let mut list = mem::take(&mut DTORS);
let mut list = DTORS.take();
while !list.is_empty() {
for (ptr, dtor) in list {
dtor(ptr);
}
list = mem::take(&mut DTORS);
list = DTORS.take();
}
}
12 changes: 5 additions & 7 deletions library/std/src/sys/solid/thread_local_dtor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@
// Simplify dtor registration by using a list of destructors.

use super::{abi, itron::task};
use crate::cell::Cell;
use crate::mem;
use crate::cell::{Cell, RefCell};

#[thread_local]
static REGISTERED: Cell<bool> = Cell::new(false);

#[thread_local]
static mut DTORS: Vec<(*mut u8, unsafe extern "C" fn(*mut u8))> = Vec::new();
static DTORS: RefCell<Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>> = RefCell::new(Vec::new());

pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
if !REGISTERED.get() {
Expand All @@ -22,18 +21,17 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
REGISTERED.set(true);
}

let list = unsafe { &mut DTORS };
list.push((t, dtor));
DTORS.try_borrow_mut().expect("global allocator may not use TLS").push((t, dtor));
}

pub unsafe fn run_dtors() {
let mut list = mem::take(unsafe { &mut DTORS });
let mut list = DTORS.take();
while !list.is_empty() {
for (ptr, dtor) in list {
unsafe { dtor(ptr) };
}

list = mem::take(unsafe { &mut DTORS });
list = DTORS.take();
}
}

Expand Down
12 changes: 5 additions & 7 deletions library/std/src/sys/unix/thread_local_dtor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,14 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
// _tlv_atexit.
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
use crate::cell::Cell;
use crate::mem;
use crate::cell::{Cell, RefCell};
use crate::ptr;

#[thread_local]
static REGISTERED: Cell<bool> = Cell::new(false);

#[thread_local]
static mut DTORS: Vec<(*mut u8, unsafe extern "C" fn(*mut u8))> = Vec::new();
static DTORS: RefCell<Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>> = RefCell::new(Vec::new());

if !REGISTERED.get() {
_tlv_atexit(run_dtors, ptr::null_mut());
Expand All @@ -69,16 +68,15 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
fn _tlv_atexit(dtor: unsafe extern "C" fn(*mut u8), arg: *mut u8);
}

let list = &mut DTORS;
list.push((t, dtor));
DTORS.try_borrow_mut().expect("global allocator may not use TLS").push((t, dtor));

unsafe extern "C" fn run_dtors(_: *mut u8) {
let mut list = mem::take(&mut DTORS);
let mut list = DTORS.take();
while !list.is_empty() {
for (ptr, dtor) in list {
dtor(ptr);
}
list = mem::take(&mut DTORS);
list = DTORS.take();
}
}
}
Expand Down
9 changes: 5 additions & 4 deletions library/std/src/sys/windows/thread_local_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@ static HAS_DTORS: AtomicBool = AtomicBool::new(false);
// Using a per-thread list avoids the problems in synchronizing global state.
#[thread_local]
#[cfg(target_thread_local)]
static mut DESTRUCTORS: Vec<(*mut u8, unsafe extern "C" fn(*mut u8))> = Vec::new();
static DESTRUCTORS: crate::cell::RefCell<Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>> =
crate::cell::RefCell::new(Vec::new());

// Ensure this can never be inlined because otherwise this may break in dylibs.
// See #44391.
#[inline(never)]
#[cfg(target_thread_local)]
pub unsafe fn register_keyless_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
DESTRUCTORS.push((t, dtor));
DESTRUCTORS.try_borrow_mut().expect("global allocator may not use TLS").push((t, dtor));
HAS_DTORS.store(true, Relaxed);
}

Expand All @@ -37,11 +38,11 @@ unsafe fn run_keyless_dtors() {
// the case that this loop always terminates because we provide the
// guarantee that a TLS key cannot be set after it is flagged for
// destruction.
while let Some((ptr, dtor)) = DESTRUCTORS.pop() {
while let Some((ptr, dtor)) = DESTRUCTORS.borrow_mut().pop() {
(dtor)(ptr);
}
// We're done so free the memory.
DESTRUCTORS = Vec::new();
DESTRUCTORS.replace(Vec::new());
}

type Key = c::DWORD;
Expand Down
14 changes: 9 additions & 5 deletions library/std/src/sys_common/thread_local_dtor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#![unstable(feature = "thread_local_internals", issue = "none")]
#![allow(dead_code)]

use crate::cell::RefCell;
use crate::ptr;
use crate::sys_common::thread_local_key::StaticKey;

Expand All @@ -28,17 +29,20 @@ pub unsafe fn register_dtor_fallback(t: *mut u8, dtor: unsafe extern "C" fn(*mut
// flagged for destruction.

static DTORS: StaticKey = StaticKey::new(Some(run_dtors));
type List = Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>;
// FIXME(joboet): integrate RefCell into pointer to avoid infinite recursion
// when the global allocator tries to register a destructor and just panic
// instead.
type List = RefCell<Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>>;
if DTORS.get().is_null() {
let v: Box<List> = Box::new(Vec::new());
let v: Box<List> = Box::new(RefCell::new(Vec::new()));
DTORS.set(Box::into_raw(v) as *mut u8);
}
let list: &mut List = &mut *(DTORS.get() as *mut List);
list.push((t, dtor));
let list = &*(DTORS.get() as *const List);
list.try_borrow_mut().expect("global allocator may not use TLS").push((t, dtor));

unsafe extern "C" fn run_dtors(mut ptr: *mut u8) {
while !ptr.is_null() {
let list: Box<List> = Box::from_raw(ptr as *mut List);
let list = Box::from_raw(ptr as *mut List).into_inner();
for (ptr, dtor) in list.into_iter() {
dtor(ptr);
}
Expand Down
Loading