| 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 | pub unsafe fn register(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { |
| 16 | /// This is necessary because the __cxa_thread_atexit_impl implementation |
| 17 | /// std links to by default may be a C or C++ implementation that was not |
| 18 | /// compiled using the Clang integer normalization option. |
| 19 | #[cfg (sanitizer_cfi_normalize_integers)] |
| 20 | use core::ffi::c_int; |
| 21 | #[cfg (not(sanitizer_cfi_normalize_integers))] |
| 22 | #[cfi_encoding = "i" ] |
| 23 | #[repr (transparent)] |
| 24 | #[allow (non_camel_case_types)] |
| 25 | pub struct c_int(#[allow (dead_code)] pub core::ffi::c_int); |
| 26 | |
| 27 | unsafe extern "C" { |
| 28 | #[linkage = "extern_weak" ] |
| 29 | static __dso_handle: *mut u8; |
| 30 | #[linkage = "extern_weak" ] |
| 31 | static __cxa_thread_atexit_impl: Option< |
| 32 | extern "C" fn( |
| 33 | unsafe extern "C" fn(*mut libc::c_void), |
| 34 | *mut libc::c_void, |
| 35 | *mut libc::c_void, |
| 36 | ) -> c_int, |
| 37 | >; |
| 38 | } |
| 39 | |
| 40 | if let Some(f) = unsafe { __cxa_thread_atexit_impl } { |
| 41 | unsafe { |
| 42 | f( |
| 43 | transmute::<unsafe extern "C" fn(*mut u8), unsafe extern "C" fn(*mut libc::c_void)>( |
| 44 | dtor, |
| 45 | ), |
| 46 | t.cast(), |
| 47 | (&raw const __dso_handle) as *mut _, |
| 48 | ); |
| 49 | } |
| 50 | } else { |
| 51 | unsafe { |
| 52 | super::list::register(t, dtor); |
| 53 | } |
| 54 | } |
| 55 | } |
| 56 | |