| //! Destructor registration for Linux-like systems. | |
| //! | |
| //! Since what appears to be version 2.18, glibc has shipped the | |
| //! `__cxa_thread_atexit_impl` symbol which GCC and clang both use to invoke | |
| //! destructors in C++ thread_local globals. This function does exactly what | |
| //! we want: it schedules a callback which will be run at thread exit with the | |
| //! provided argument. | |
| //! | |
| //! Unfortunately, our minimum supported glibc version (at the time of writing) | |
| //! is 2.17, so we can only link this symbol weakly and need to use the | |
| //! [`list`](super::list) destructor implementation as fallback. | |
| use crate::mem::transmute; | |
| pub unsafe fn register(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { | |
| /// This is necessary because the __cxa_thread_atexit_impl implementation | |
| /// std links to by default may be a C or C++ implementation that was not | |
| /// compiled using the Clang integer normalization option. | |
| #[cfg(sanitizer_cfi_normalize_integers)] | |
| use core::ffi::c_int; | |
| #[cfg(not(sanitizer_cfi_normalize_integers))] | |
| #[cfi_encoding = "i"] | |
| #[repr(transparent)] | |
| #[allow(non_camel_case_types)] | |
| pub struct c_int(#[allow(dead_code)] pub core::ffi::c_int); | |
| unsafe extern "C" { | |
| #[linkage = "extern_weak"] | |
| static __dso_handle: *mut u8; | |
| #[linkage = "extern_weak"] | |
| static __cxa_thread_atexit_impl: Option< | |
| extern "C" fn( | |
| unsafe extern "C" fn(*mut libc::c_void), | |
| *mut libc::c_void, | |
| *mut libc::c_void, | |
| ) -> c_int, | |
| >; | |
| } | |
| if let Some(f) = unsafe { __cxa_thread_atexit_impl } { | |
| unsafe { | |
| f( | |
| transmute::<unsafe extern "C" fn(*mut u8), unsafe extern "C" fn(*mut libc::c_void)>( | |
| dtor, | |
| ), | |
| t.cast(), | |
| (&raw const __dso_handle) as *mut _, | |
| ); | |
| } | |
| } else { | |
| unsafe { | |
| super::list::register(t, dtor); | |
| } | |
| } | |
| } |