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(all(not(windows), not(target_family = "wasm")))]
38        _run_cxa_atexit(cb);
39        #[cfg(any(windows, target_family = "wasm"))]
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(all(not(miri), not(target_family = "wasm")))]
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#[cfg(all(not(miri), target_family = "wasm"))]
68#[inline(always)]
69unsafe fn _run_atexit(cb: unsafe extern "C" fn()) {
70    #[allow(missing_unsafe_on_extern)] // MSRV
71    #[cfg_attr(target_os = "unknown", link(wasm_import_module = "env"))]
72    extern "C" {
73        fn atexit(cb: unsafe extern "C" fn()) -> i32;
74    }
75    unsafe {
76        atexit(cb);
77    }
78}
79
80/// Register a function scoped to the current dynamic shared object.
81#[cfg(all(not(miri), not(windows), not(target_family = "wasm")))]
82#[inline(always)]
83unsafe fn _run_cxa_atexit(cb: extern "C" fn()) {
84    #[allow(missing_unsafe_on_extern)] // MSRV
85    extern "C" {
86        static __dso_handle: *const u8;
87        fn __cxa_atexit(
88            cb: /*unsafe*/ extern "C" fn(_: *const u8),
89            arg: *const u8,
90            dso_handle: *const u8,
91        );
92    }
93    extern "C" fn exit_fn(fn_ptr: *const u8) {
94        let f: fn() = unsafe { ::core::mem::transmute(fn_ptr) };
95        f()
96    }
97    unsafe {
98        __cxa_atexit(exit_fn, cb as _, __dso_handle);
99    }
100}
101
102#[cfg(miri)]
103#[inline(always)]
104unsafe fn _run_atexit(_cb: extern "C" fn()) {
105    // no-op on miri
106}
107
108#[cfg(miri)]
109#[inline(always)]
110unsafe fn _run_cxa_atexit(_cb: extern "C" fn()) {
111    // no-op on miri
112}