Skip to main content

dtor/
native.rs

1#![allow(unsafe_code, unused_unsafe, unknown_lints)]
2
3/// Registers a raw function to be called at binary exit time.
4///
5/// Corresponds to `atexit` in C.
6///
7/// Unsupported on Windows platforms: the platform's libc `atexit` tracks a set
8/// of functions per module.
9///
10/// # Safety
11///
12/// Rust does not provide any safety guarantees about life-before-main or
13/// life-after-main. Ordering of destructors is not guaranteed, nor that a
14/// destructor will be called at all.
15#[inline(always)]
16#[cfg(not(windows))]
17pub unsafe fn at_binary_exit(cb: extern "C" fn()) {
18    unsafe {
19        _run_atexit(cb);
20    }
21}
22
23/// Registers a raw function to be called at library (libc calls this a DSO
24/// or "dynamic shared object") exit time.
25///
26/// Corresponds to `__cxa_atexit` in C, though the exit function argument is
27/// not available.
28///
29/// # Safety
30///
31/// Rust does not provide any safety guarantees about life-before-main or
32/// life-after-main. Ordering of destructors is not guaranteed, nor that a
33/// destructor will be called at all.
34#[inline(always)]
35pub unsafe fn at_module_exit(cb: extern "C" fn()) {
36    unsafe {
37        #[cfg(not(windows))]
38        _run_cxa_atexit(cb);
39        #[cfg(windows)]
40        _run_atexit(cb);
41    }
42}
43
44/// Use `at_module_exit` instead.
45#[doc(hidden)]
46#[deprecated(since = "0.11.0", note = "Use `at_module_exit` instead")]
47#[inline(always)]
48pub unsafe fn at_library_exit(cb: extern "C" fn()) {
49    unsafe {
50        at_module_exit(cb);
51    }
52}
53
54/// Register a function to be called at libc exit time.
55#[cfg(not(miri))]
56#[inline(always)]
57unsafe fn _run_atexit(cb: unsafe extern "C" fn()) {
58    #[allow(missing_unsafe_on_extern)] // MSRV
59    extern "C" {
60        fn atexit(cb: unsafe extern "C" fn());
61    }
62    unsafe {
63        atexit(cb);
64    }
65}
66
67/// Register a function scoped to the current dynamic shared object.
68#[cfg(all(not(miri), not(windows)))]
69#[inline(always)]
70unsafe fn _run_cxa_atexit(cb: extern "C" fn()) {
71    #[allow(missing_unsafe_on_extern)] // MSRV
72    extern "C" {
73        static __dso_handle: *const u8;
74        fn __cxa_atexit(
75            cb: /*unsafe*/ extern "C" fn(_: *const u8),
76            arg: *const u8,
77            dso_handle: *const u8,
78        );
79    }
80    extern "C" fn exit_fn(fn_ptr: *const u8) {
81        let f: fn() = unsafe { ::core::mem::transmute(fn_ptr) };
82        f()
83    }
84    unsafe {
85        __cxa_atexit(exit_fn, cb as _, __dso_handle);
86    }
87}
88
89#[cfg(miri)]
90#[inline(always)]
91unsafe fn _run_atexit(_cb: extern "C" fn()) {
92    // no-op on miri
93}
94
95#[cfg(miri)]
96#[inline(always)]
97unsafe fn _run_cxa_atexit(_cb: extern "C" fn()) {
98    // no-op on miri
99}