Skip to content

Commit 1deee1e

Browse files
committed
Make unprefixed consistently override the system allocator
Signed-off-by: Mads Marquart <[email protected]>
1 parent 876bc11 commit 1deee1e

File tree

4 files changed

+100
-20
lines changed

4 files changed

+100
-20
lines changed

jemalloc-sys/README.md

+35-15
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,11 @@ This crate provides following cargo feature flags:
4848
* `stats` (configure `jemalloc` with `--enable-stats`): Enable statistics
4949
gathering functionality. See the `jemalloc`'s "`opt.stats_print`" option
5050
documentation for usage details.
51-
51+
5252
* `debug` (configure `jemalloc` with `--enable-debug`): Enable assertions and
5353
validation code. This incurs a substantial performance hit, but is very useful
5454
during application development.
55-
55+
5656
* `background_threads_runtime_support` (enabled by default): enables
5757
background-threads run-time support when building `jemalloc-sys` on some POSIX
5858
targets supported by `jemalloc`. Background threads are disabled at run-time
@@ -72,16 +72,36 @@ This crate provides following cargo feature flags:
7272
* `unprefixed_malloc_on_supported_platforms`: when disabled, configure
7373
`jemalloc` with `--with-jemalloc-prefix=_rjem_`. Enabling this causes symbols
7474
like `malloc` to be emitted without a prefix, overriding the ones defined by
75-
libc. This usually causes C and C++ code linked in the same program to use
76-
`jemalloc` as well. On some platforms prefixes are always used because
77-
unprefixing is known to cause segfaults due to allocator mismatches.
78-
75+
libc. This usually causes C, Objective-C and C++ code linked in the same
76+
program to use `jemalloc` as well. On some platforms prefixes are always used
77+
because unprefixing is known to cause segfaults due to allocator mismatches.
78+
79+
Note that to use this, the `jemalloc-sys` crate must actually be visible to
80+
`rustc` (it is not enough to only declare it in `Cargo.toml`). This can be
81+
done with:
82+
```rust
83+
use jemalloc_sys as _;
84+
```
85+
86+
On macOS, you'll need to do a bit more to work around a bug in `rustc`:
87+
```rust
88+
// Workaround for https://github.com/rust-lang/rust/issues/133491
89+
#[cfg(target_vendor = "apple")]
90+
#[used]
91+
static USED_ZONE_REGISTER: unsafe extern "C" fn() = {
92+
extern "C" {
93+
fn _rjem_je_zone_register();
94+
}
95+
_rjem_je_zone_register
96+
};
97+
```
98+
7999
* `disable_initial_exec_tls` (disabled by default): when enabled, jemalloc is
80-
built with the `--disable-initial-exec-tls` option. It disables the
81-
initial-exec TLS model for jemalloc's internal thread-local storage (on those
82-
platforms that support explicit settings). This can allow jemalloc to be
100+
built with the `--disable-initial-exec-tls` option. It disables the
101+
initial-exec TLS model for jemalloc's internal thread-local storage (on those
102+
platforms that support explicit settings). This can allow jemalloc to be
83103
dynamically loaded after program startup (e.g. using dlopen). If you encounter
84-
the error `yourlib.so: cannot allocate memory in static TLS block`, you'll
104+
the error `yourlib.so: cannot allocate memory in static TLS block`, you'll
85105
likely want to enable this.
86106

87107
* `disable_cache_oblivious` (disabled by default): when enabled, jemalloc is
@@ -104,7 +124,7 @@ hyphens `-` are replaced with underscores `_`(see
104124
variable, the `/etc/malloc.conf` symlink, and the `MALLOC_CONF` environment
105125
variable (note: this variable might be prefixed as `_RJEM_MALLOC_CONF`). For
106126
example, to change the default decay time for dirty pages to 30 seconds:
107-
127+
108128
```
109129
JEMALLOC_SYS_WITH_MALLOC_CONF=dirty_decay_ms:30000
110130
```
@@ -115,17 +135,17 @@ hyphens `-` are replaced with underscores `_`(see
115135
allocator page size equal to the system page size, so this option need not be
116136
specified unless the system page size may change between configuration and
117137
execution, e.g. when cross compiling.
118-
138+
119139
* `JEMALLOC_SYS_WITH_LG_HUGEPAGE=<lg-hugepage>`: Specify the base 2 log of the
120140
system huge page size. This option is useful when cross compiling, or when
121141
overriding the default for systems that do not explicitly support huge pages.
122-
123-
142+
143+
124144
* `JEMALLOC_SYS_WITH_LG_QUANTUM=<lg-quantum>`: Specify the base 2 log of the
125145
minimum allocation alignment. jemalloc needs to know the minimum alignment
126146
that meets the following C standard requirement (quoted from the April 12,
127147
2011 draft of the C11 standard):
128-
148+
129149
> The pointer returned if the allocation succeeds is suitably aligned so that
130150
> it may be assigned to a pointer to any type of object with a fundamental
131151
> alignment requirement and then used to access such an object or an array of

jemalloc-sys/build.rs

+9-4
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,15 @@ fn main() {
111111
.iter()
112112
.any(|i| target.contains(i))
113113
{
114-
warning!(
115-
"Unprefixed `malloc` requested on unsupported platform `{}` => using prefixed `malloc`",
116-
target
117-
);
114+
// Apple targets don't support unprefixed, but they do support
115+
// overriding (if you do the `zone_register` trick), so no need to
116+
// warn there.
117+
if !target.contains("apple") {
118+
warning!(
119+
"Unprefixed `malloc` requested on unsupported platform `{}` => using prefixed `malloc`",
120+
target
121+
);
122+
}
118123
use_prefix = true;
119124
}
120125

jemalloc-sys/src/env.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@ pub static NO_BG_THREAD_TARGETS: &[&str] = &["musl"];
2121
// https://github.com/rust-lang/rust/commit/e3b414d8612314e74e2b0ebde1ed5c6997d28e8d
2222
// https://github.com/rust-lang/rust/commit/9f3de647326fbe50e0e283b9018ab7c41abccde3
2323
// https://github.com/rust-lang/rust/commit/ed015456a114ae907a36af80c06f81ea93182a24
24-
pub static NO_UNPREFIXED_MALLOC_TARGETS: &[&str] = &["android", "dragonfly", "darwin"];
24+
pub static NO_UNPREFIXED_MALLOC_TARGETS: &[&str] = &["android", "dragonfly", "apple"];

jemalloc-sys/src/lib.rs

+55
Original file line numberDiff line numberDiff line change
@@ -890,3 +890,58 @@ pub type extent_merge_t = unsafe extern "C" fn(
890890
mod env;
891891

892892
pub use env::*;
893+
894+
// When using the `"unprefixed_malloc_on_supported_platforms"` feature flag to
895+
// override the system allocator, make sure that all allocator functions are
896+
// visible to the linker, such that it will override all of them.
897+
//
898+
// For example, this would fail horribly if one used a dynamic library that
899+
// calls `malloc`, and then later `free`'d that in Rust code that used
900+
// jemalloc-sys, since then the linker might think that only `free` from
901+
// jemalloc is needed, and wouldn't override `malloc`.
902+
#[cfg(not(prefixed))]
903+
mod set_up_statics {
904+
use super::*;
905+
906+
#[used]
907+
static USED_MALLOC: unsafe extern "C" fn(usize) -> *mut c_void = malloc;
908+
#[used]
909+
static USED_CALLOC: unsafe extern "C" fn(usize, usize) -> *mut c_void = calloc;
910+
#[used]
911+
static USED_POSIX_MEMALIGN: unsafe extern "C" fn(*mut *mut c_void, usize, usize) -> c_int =
912+
posix_memalign;
913+
#[used]
914+
static USED_ALLOC: unsafe extern "C" fn(usize, usize) -> *mut c_void = aligned_alloc;
915+
#[used]
916+
static USED_REALLOC: unsafe extern "C" fn(*mut c_void, usize) -> *mut c_void = realloc;
917+
#[used]
918+
static USED_FREE: unsafe extern "C" fn(*mut c_void) = free;
919+
}
920+
921+
// On macOS, jemalloc doesn't directly override malloc/free, but instead
922+
// registers itself with the allocator's zone APIs in a ctor. However, ld64
923+
// doesn't consider ctors as "used" when defined in an object file / archive
924+
// member in a static library, so we need to explicitly depend on the function
925+
// using Rust's `#[used]`.
926+
//
927+
// NOTE: `#[used]` currently doesn't actually work on macOS, but that's an
928+
// upstream rustc issue, see https://github.com/rust-lang/rust/issues/133491.
929+
#[cfg(all(
930+
feature = "unprefixed_malloc_on_supported_platforms",
931+
target_vendor = "apple"
932+
))]
933+
#[used]
934+
static USED_ZONE_REGISTER: unsafe extern "C" fn() = {
935+
extern "C" {
936+
#[cfg_attr(prefixed, link_name = "_rjem_je_zone_register")]
937+
#[cfg_attr(not(prefixed), link_name = "je_zone_register")]
938+
fn zone_register();
939+
}
940+
941+
// NOTE: This internal function is marked as __attribute__((constructor)),
942+
// and thus we neither can nor should call it ourselves.
943+
//
944+
// Instead, we simply need to reference it in a `#[used]` static to get
945+
// the linker to see that it should be registering it as a constructor.
946+
zone_register
947+
};

0 commit comments

Comments
 (0)