1 | //! Destructor registration for Linux-like systems. |
2 | //! |
3 | //! Since what appears to be version 2.18, glibc has shipped the |
4 | //! `__cxa_thread_atexit_impl` symbol which GCC and clang both use to invoke |
5 | //! destructors in C++ thread_local globals. This function does exactly what |
6 | //! we want: it schedules a callback which will be run at thread exit with the |
7 | //! provided argument. |
8 | //! |
9 | //! Unfortunately, our minimum supported glibc version (at the time of writing) |
10 | //! is 2.17, so we can only link this symbol weakly and need to use the |
11 | //! [`list`](super::list) destructor implementation as fallback. |
12 | |
13 | use crate::mem::transmute; |
14 | |
15 | // FIXME: The Rust compiler currently omits weakly function definitions (i.e., |
16 | // __cxa_thread_atexit_impl) and its metadata from LLVM IR. |
17 | #[no_sanitize (cfi, kcfi)] |
18 | pub unsafe fn register(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { |
19 | /// This is necessary because the __cxa_thread_atexit_impl implementation |
20 | /// std links to by default may be a C or C++ implementation that was not |
21 | /// compiled using the Clang integer normalization option. |
22 | #[cfg (sanitizer_cfi_normalize_integers)] |
23 | use core::ffi::c_int; |
24 | #[cfg (not(sanitizer_cfi_normalize_integers))] |
25 | #[cfi_encoding = "i" ] |
26 | #[repr (transparent)] |
27 | #[allow (non_camel_case_types)] |
28 | pub struct c_int(#[allow (dead_code)] pub core::ffi::c_int); |
29 | |
30 | unsafe extern "C" { |
31 | #[linkage = "extern_weak" ] |
32 | static __dso_handle: *mut u8; |
33 | #[linkage = "extern_weak" ] |
34 | static __cxa_thread_atexit_impl: Option< |
35 | extern "C" fn( |
36 | unsafe extern "C" fn(*mut libc::c_void), |
37 | *mut libc::c_void, |
38 | *mut libc::c_void, |
39 | ) -> c_int, |
40 | >; |
41 | } |
42 | |
43 | if let Some(f) = unsafe { __cxa_thread_atexit_impl } { |
44 | unsafe { |
45 | f( |
46 | transmute::<unsafe extern "C" fn(*mut u8), unsafe extern "C" fn(*mut libc::c_void)>( |
47 | dtor, |
48 | ), |
49 | t.cast(), |
50 | (&raw const __dso_handle) as *mut _, |
51 | ); |
52 | } |
53 | } else { |
54 | unsafe { |
55 | super::list::register(t, dtor); |
56 | } |
57 | } |
58 | } |
59 | |