diff --git a/libmimalloc-sys/src/lib.rs b/libmimalloc-sys/src/lib.rs index 7ca66f1..ff2442e 100644 --- a/libmimalloc-sys/src/lib.rs +++ b/libmimalloc-sys/src/lib.rs @@ -67,6 +67,47 @@ extern "C" { pub fn mi_free(p: *mut c_void); } +/// When using the `"override"` feature flag, the user wants us to globally +/// override the system allocator. +/// +/// However, since we build and link `mimalloc` as a static library/archive, +/// the linker may decide to not care about our overrides if it can't directly +/// see references to the symbols, see the following link for details: +/// +/// +/// This is problematic if `mimalloc` is used from a library that by itself +/// doesn't allocate, yet invokes other shared libraries that do, since then +/// the linker wouldn't see any references to `malloc`/`free`, and the symbols +/// would not be overridden. +/// +/// To avoid this problem, we make sure that the allocator functions are +/// visible to the linker. +/// +/// To avoid this problem, we reference `mi_malloc` in a `#[used]` static. +/// This makes it known to `rustc`, which will create a reference to it in a +/// `symbols.o` stub file that is later passed directly to the linker (instead +/// of being in an archive). See the following link for details on how this +/// works: +/// +/// NOTE: This works because `mimalloc` is compiled into a single object file +/// in `static.c`. If it was split across multiple files, we'd need to +/// reference each symbol. See also the comment at the top of `static.c`. +/// +/// NOTE: On macOS, mimalloc doesn't just override malloc/free, but also +/// registers itself with the allocator's zone APIs in a ctor +/// (`_mi_macos_override_malloc`, marked with `__attribute__((constructor))`). +/// Similarly to above, for the Mach-O linker to actually consider ctors as +/// "used" when defined in an archive member in a static library, so we need +/// to explicitly reference something in the object file. The constructor +/// symbol itself is static, so we can't get a reference to that, so instead +/// we reference `mi_malloc` here too). +#[cfg(feature = "override")] +mod set_up_statics { + use super::*; + #[used] // Could be `#[used(linker)]` once stable + static USED: unsafe extern "C" fn(usize) -> *mut c_void = mi_malloc; +} + #[cfg(test)] mod tests { use super::*;