Skip to content

Update jemalloc to 5.3.1#161

Merged
BusyJay merged 5 commits intotikv:mainfrom
sticnarf:upgrade-5.3.1
Apr 16, 2026
Merged

Update jemalloc to 5.3.1#161
BusyJay merged 5 commits intotikv:mainfrom
sticnarf:upgrade-5.3.1

Conversation

@sticnarf
Copy link
Copy Markdown

@sticnarf sticnarf commented Apr 14, 2026

Merge the nightly branch and upgrade jemalloc to upstream 5.3.1.

Upstream v5.3.1 already includes the patches previously carried in tikv/jemalloc, so the submodule now points directly to https://github.com/jemalloc/jemalloc.

New functions or mallctl options introduced in 5.3.1 are not added yet. These can be added in follow-up PRs.

Summary by CodeRabbit

  • New Features

    • Added new build-time configuration options for customized builds.
    • Exposed sized deallocation APIs for FFI consumers.
  • Chores

    • Upgraded bundled memory allocator to 5.3.1.
    • Updated package version and README to reflect the new allocator version.
    • Updated vendored repository reference to the new upstream source.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 14, 2026

Warning

Rate limit exceeded

@sticnarf has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 51 minutes and 23 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 51 minutes and 23 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e85389d7-e821-4ac6-9427-bb86cdf05ca0

📥 Commits

Reviewing files that changed from the base of the PR and between 32b7af2 and c2ad8f7.

📒 Files selected for processing (5)
  • .gitmodules
  • jemalloc-sys/Cargo.toml
  • jemalloc-sys/README.md
  • jemalloc-sys/configure/configure
  • jemalloc-sys/jemalloc
📝 Walkthrough

Walkthrough

Bumps vendored jemalloc to 5.3.1, switches submodule URL to the official jemalloc repo, expands configure-time options and checks, adds two new sized-free FFI symbols, updates unsafe raw value handling, and refactors macro-generated tests for control interface options and background-thread tests.

Changes

Cohort / File(s) Summary
Submodule / repo config
\.gitmodules, jemalloc-sys/jemalloc
Changed submodule remote URL from the tikv fork to https://github.com/jemalloc/jemalloc and advanced the vendored submodule commit to include jemalloc 5.3.1.
Version metadata
jemalloc-sys/Cargo.toml, jemalloc-sys/README.md
Bumped crate/package version string and README’s “Current jemalloc version” to 5.3.1.
Build/configure script
jemalloc-sys/configure/configure
Added many new configure flags and validations (e.g., force_getenv, experimental_sdt, user_config, prof_frameptr, dss, pageid, tsan, ubsan, with_cxx_stdlib, with_experimental_sys_process_madvise), expanded feature/capability checks and confdefs macros, adjusted LDFLAGS handling and symbol/override lists. (Large, logic-heavy edits.)
jemalloc-ctl docs & macros
jemalloc-ctl/src/lib.rs, jemalloc-ctl/src/macros.rs
Clarified epoch docs wording; removed per-op standalone read/write tests in macros, introduced make_test! and combined read/write/update tests per option, and centralized test generation (preserves macOS skip logic inside combined tests).
Raw unsafe API handling
jemalloc-ctl/src/raw.rs
Replaced ad-hoc union MaybeUninit usage with crate::mem::MaybeUninit, tightened update/update_mib signatures to T: Copy, and adjusted logic to return the prior value via properly-sized MaybeUninit handling.
New FFI exports (sized free)
jemalloc-sys/src/lib.rs
Added two exported declarations for sized deallocation: free_sized(ptr, size) and free_aligned_sized(ptr, alignment, size) (linked to _rjem_* when prefixed).
Test adjustments
jemallocator/tests/ffi.rs
test_basic_alloc extended to exercise free_sized and free_aligned_sized (malloc+free_sized, aligned_alloc+free_aligned_sized) in addition to existing dealloc tests.
CI trigger
.github/workflows/main.yml
Expanded GitHub Actions branch filters to include the nightly branch for push/pull_request events.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰
I hopped through code and found a spring,
Submodules tuned and new bells ring,
Sized frees scurry, tests unite,
Configure blooms in morning light,
A joyful hop for version five-point-three.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Update jemalloc to 5.3.1' directly and clearly reflects the main objective of the pull request, which is to upgrade the jemalloc dependency from version 5.3.0 to 5.3.1 across all affected files and components.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
jemalloc-sys/configure/configure (1)

6951-7019: ⚠️ Potential issue | 🟠 Major

Add linkability validation to explicit --with-cxx-stdlib selections.

The explicit libstdc++ and libcxx branches append to LIBS without validating linkability, while the default branch performs a linkability test and rolls back on failure. This asymmetry allows an explicitly selected C++ stdlib to pass configure even if unavailable, deferring the failure to the link step. The same validation logic from the default branch should be applied to explicit selections.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@jemalloc-sys/configure/configure` around lines 6951 - 7019, The libstdc++ and
libcxx case arms append T_APPEND_V to LIBS without performing the linkability
check that the default branch does; update the libstdc++ and libcxx branches in
the with_cxx_stdlib case to mirror the default branch: set T_APPEND_V (e.g.
-lstdc++ or -lc++), append it to LIBS temporarily (using the same SAVED_LIBS
pattern), run the existing conftest/linkability routine (invoke ac_fn_c_try_link
to set je_cv_libstdcxx), and if je_cv_libstdcxx is "no" restore SAVED_LIBS
(SAVED_LIBS, LIBS, T_APPEND_V, je_cv_libstdcxx and ac_fn_c_try_link are the
symbols to touch) so explicit selections fail at configure time like the default
branch.
🧹 Nitpick comments (1)
jemalloc-ctl/src/lib.rs (1)

244-247: Also cover the background_thread update path here.

jemalloc-ctl/src/macros.rs now skips the autogenerated background_thread update test, so this module is the only remaining coverage for that API. Right now it never calls either background_thread::update() or bg_mib.update().

Possible addition
         background_thread::write(!bg_orig).unwrap();
         assert_eq!(background_thread::read().unwrap(), !bg_orig);
+        let old = bg_mib.update(bg_orig).unwrap();
+        assert_eq!(old, !bg_orig);
+        let old = background_thread::update(!bg_orig).unwrap();
+        assert_eq!(old, bg_orig);
         bg_mib.write(bg_orig).unwrap();
         assert_eq!(bg_mib.read().unwrap(), bg_orig);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@jemalloc-ctl/src/lib.rs` around lines 244 - 247, The test currently toggles
background_thread and bg_mib using write/read but never exercises their update
paths; add calls to background_thread::update() and bg_mib.update() after the
write/read assertions to verify the update API toggles the value and that
subsequent read() returns the updated state. Specifically, after
background_thread::write(!bg_orig) and
assert_eq!(background_thread::read().unwrap(), !bg_orig), call
background_thread::update().unwrap() and
assert_eq!(background_thread::read().unwrap(), bg_orig); similarly after
bg_mib.write(bg_orig) and assert_eq!(bg_mib.read().unwrap(), bg_orig), call
bg_mib.update().unwrap() and assert_eq!(bg_mib.read().unwrap(), !bg_orig),
ensuring you reference the background_thread::write/read/update and
bg_mib.write/read/update symbols.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@jemalloc-ctl/src/lib.rs`:
- Around line 239-261: The test read_write_update currently mutates
process-global allocator state and doesn't always restore originals; snapshot
the original values from background_thread::mib().read() and
max_background_threads::mib().read() at the start of the test and ensure both
are restored on all exit paths (use a scoped cleanup/guard or defer) by calling
background_thread::write(original_bg) / bg_mib.write(original_bg) and
max_background_threads::write(original_mt) / mt_mib.write(original_mt) (and/or
their .update counterparts) so failures cannot leak modified state to other
tests.

In `@jemalloc-sys/configure/configure`:
- Around line 11718-11737: The platform check currently uses `uname -s` at the
top of the block (the line starting with if test `uname -s` = "Linux") which
inspects the build machine instead of the target; change that conditional to
check the cross-build target variable (use `${host_os}` or `${host}` as used
elsewhere) — e.g. replace the `uname -s` test with a test against `host_os`
(e.g. test "x${host_os}" = "xLinux") so the logic that sets
`enable_prof_frameptr` and the subsequent checks that reference
`enable_prof_frameptr`, `enable_prof`, `backtrace_method`, and `GCC` follow
target-platform semantics. Ensure the rest of the block remains unchanged.
- Around line 14828-14995: The linker probe blocks for sanitizers (the
-fsanitize=thread and UBSAN -fsanitize=undefined sections) currently roll back
CONFIGURE_LDFLAGS on link failure but do not restore CONFIGURE_CFLAGS and
CONFIGURE_CXXFLAGS, leaving instrumented objects without matching linker flags;
update the failure branches (where je_cv_ldflags_added is cleared) to also
restore CONFIGURE_CFLAGS to T_CONFIGURE_CFLAGS and CONFIGURE_CXXFLAGS to
T_CONFIGURE_CXXFLAGS (mirror how CONFIGURE_LDFLAGS is reset), and ensure the
same fix is applied in both the ThreadSanitizer and UBSan linker-probe blocks
(refer to symbols je_cv_cflags_added, je_cv_cxxflags_added, je_cv_ldflags_added,
T_CONFIGURE_CFLAGS, T_CONFIGURE_CXXFLAGS, and T_CONFIGURE_LDFLAGS).

---

Outside diff comments:
In `@jemalloc-sys/configure/configure`:
- Around line 6951-7019: The libstdc++ and libcxx case arms append T_APPEND_V to
LIBS without performing the linkability check that the default branch does;
update the libstdc++ and libcxx branches in the with_cxx_stdlib case to mirror
the default branch: set T_APPEND_V (e.g. -lstdc++ or -lc++), append it to LIBS
temporarily (using the same SAVED_LIBS pattern), run the existing
conftest/linkability routine (invoke ac_fn_c_try_link to set je_cv_libstdcxx),
and if je_cv_libstdcxx is "no" restore SAVED_LIBS (SAVED_LIBS, LIBS, T_APPEND_V,
je_cv_libstdcxx and ac_fn_c_try_link are the symbols to touch) so explicit
selections fail at configure time like the default branch.

---

Nitpick comments:
In `@jemalloc-ctl/src/lib.rs`:
- Around line 244-247: The test currently toggles background_thread and bg_mib
using write/read but never exercises their update paths; add calls to
background_thread::update() and bg_mib.update() after the write/read assertions
to verify the update API toggles the value and that subsequent read() returns
the updated state. Specifically, after background_thread::write(!bg_orig) and
assert_eq!(background_thread::read().unwrap(), !bg_orig), call
background_thread::update().unwrap() and
assert_eq!(background_thread::read().unwrap(), bg_orig); similarly after
bg_mib.write(bg_orig) and assert_eq!(bg_mib.read().unwrap(), bg_orig), call
bg_mib.update().unwrap() and assert_eq!(bg_mib.read().unwrap(), !bg_orig),
ensuring you reference the background_thread::write/read/update and
bg_mib.write/read/update symbols.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: da4a971c-55d0-4ecd-aad8-cc00ca8ab672

📥 Commits

Reviewing files that changed from the base of the PR and between baae33d and 2476a95.

📒 Files selected for processing (7)
  • .gitmodules
  • jemalloc-ctl/src/lib.rs
  • jemalloc-ctl/src/macros.rs
  • jemalloc-sys/Cargo.toml
  • jemalloc-sys/README.md
  • jemalloc-sys/configure/configure
  • jemalloc-sys/jemalloc

Comment thread jemalloc-ctl/src/lib.rs Outdated
Comment on lines +239 to +261
fn read_write_update() {
// -- background_thread --
let bg_mib = background_thread::mib().unwrap();
let bg_orig = bg_mib.read().unwrap();

background_thread::write(!bg_orig).unwrap();
assert_eq!(background_thread::read().unwrap(), !bg_orig);
bg_mib.write(bg_orig).unwrap();
assert_eq!(bg_mib.read().unwrap(), bg_orig);

// -- max_background_threads --
// jemalloc 5.3.1+ rejects writing 0 (EINVAL), so use 1.
let mt_mib = max_background_threads::mib().unwrap();
let _ = max_background_threads::read().unwrap();
let _ = mt_mib.read().unwrap();
max_background_threads::write(1).unwrap();
assert_eq!(max_background_threads::read().unwrap(), 1);
mt_mib.write(1).unwrap();
assert_eq!(mt_mib.read().unwrap(), 1);
let old = max_background_threads::update(1).unwrap();
assert_eq!(old, 1);
let old = mt_mib.update(1).unwrap();
assert_eq!(old, 1);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Restore the original control values before this test exits.

background_thread_tests::read_write_update mutates process-global allocator state. max_background_threads is left at 1, and background_thread is only restored on the happy path, so a failure here can contaminate later tests in the same binary. Please snapshot both originals and restore them in scoped cleanup.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@jemalloc-ctl/src/lib.rs` around lines 239 - 261, The test read_write_update
currently mutates process-global allocator state and doesn't always restore
originals; snapshot the original values from background_thread::mib().read() and
max_background_threads::mib().read() at the start of the test and ensure both
are restored on all exit paths (use a scoped cleanup/guard or defer) by calling
background_thread::write(original_bg) / bg_mib.write(original_bg) and
max_background_threads::write(original_mt) / mt_mib.write(original_mt) (and/or
their .update counterparts) so failures cannot leak modified state to other
tests.

Comment on lines +11718 to +11737
if test `uname -s` = "Linux"
then
# Check whether --enable-prof-frameptr was given.
if test "${enable_prof_frameptr+set}" = set; then :
enableval=$enable_prof_frameptr; if test "x$enable_prof_frameptr" = "xno" ; then
enable_prof_frameptr="0"
else
enable_prof_frameptr="1"
if test "x$enable_prof" = "x0" ; then
as_fn_error $? "--enable-prof-frameptr should only be used with --enable-prof" "$LINENO" 5
fi
fi

else
enable_prof_frameptr="0"

fi

if test "x$backtrace_method" = "x" -a "x$enable_prof_frameptr" = "x1" \
-a "x$GCC" = "xyes" ; then
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Use host_os here instead of uname -s.

Line 11718 keys this block off the build machine, not the target. Cross builds can therefore disable --enable-prof-frameptr for a Linux target, or enable Linux-specific profiling config for a non-Linux target. This needs to follow ${host_os} / ${host} like the rest of the platform logic.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@jemalloc-sys/configure/configure` around lines 11718 - 11737, The platform
check currently uses `uname -s` at the top of the block (the line starting with
if test `uname -s` = "Linux") which inspects the build machine instead of the
target; change that conditional to check the cross-build target variable (use
`${host_os}` or `${host}` as used elsewhere) — e.g. replace the `uname -s` test
with a test against `host_os` (e.g. test "x${host_os}" = "xLinux") so the logic
that sets `enable_prof_frameptr` and the subsequent checks that reference
`enable_prof_frameptr`, `enable_prof`, `backtrace_method`, and `GCC` follow
target-platform semantics. Ensure the rest of the block remains unchanged.

Comment on lines +14828 to +14995
if test "x$enable_tsan" = "x1" ; then

{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler supports -fsanitize=thread" >&5
$as_echo_n "checking whether compiler supports -fsanitize=thread... " >&6; }
T_CONFIGURE_CFLAGS="${CONFIGURE_CFLAGS}"
T_APPEND_V=-fsanitize=thread
if test "x${CONFIGURE_CFLAGS}" = "x" -o "x${T_APPEND_V}" = "x" ; then
CONFIGURE_CFLAGS="${CONFIGURE_CFLAGS}${T_APPEND_V}"
else
CONFIGURE_CFLAGS="${CONFIGURE_CFLAGS} ${T_APPEND_V}"
fi


if test "x${CONFIGURE_CFLAGS}" = "x" -o "x${SPECIFIED_CFLAGS}" = "x" ; then
CFLAGS="${CONFIGURE_CFLAGS}${SPECIFIED_CFLAGS}"
else
CFLAGS="${CONFIGURE_CFLAGS} ${SPECIFIED_CFLAGS}"
fi

cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */


int
main ()
{

return 0;

;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
je_cv_cflags_added=-fsanitize=thread
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
je_cv_cflags_added=
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
CONFIGURE_CFLAGS="${T_CONFIGURE_CFLAGS}"

fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
if test "x${CONFIGURE_CFLAGS}" = "x" -o "x${SPECIFIED_CFLAGS}" = "x" ; then
CFLAGS="${CONFIGURE_CFLAGS}${SPECIFIED_CFLAGS}"
else
CFLAGS="${CONFIGURE_CFLAGS} ${SPECIFIED_CFLAGS}"
fi



{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler supports -fsanitize=thread" >&5
$as_echo_n "checking whether compiler supports -fsanitize=thread... " >&6; }
T_CONFIGURE_CXXFLAGS="${CONFIGURE_CXXFLAGS}"
T_APPEND_V=-fsanitize=thread
if test "x${CONFIGURE_CXXFLAGS}" = "x" -o "x${T_APPEND_V}" = "x" ; then
CONFIGURE_CXXFLAGS="${CONFIGURE_CXXFLAGS}${T_APPEND_V}"
else
CONFIGURE_CXXFLAGS="${CONFIGURE_CXXFLAGS} ${T_APPEND_V}"
fi


if test "x${CONFIGURE_CXXFLAGS}" = "x" -o "x${SPECIFIED_CXXFLAGS}" = "x" ; then
CXXFLAGS="${CONFIGURE_CXXFLAGS}${SPECIFIED_CXXFLAGS}"
else
CXXFLAGS="${CONFIGURE_CXXFLAGS} ${SPECIFIED_CXXFLAGS}"
fi

ac_ext=cpp
ac_cpp='$CXXCPP $CPPFLAGS'
ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_cxx_compiler_gnu

cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */

#include <sys/mman.h>

int
main ()
{

mprotect((void *)0, 0, PROT_NONE);
return 0;

;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
je_cv_mprotect=yes
if ac_fn_cxx_try_compile "$LINENO"; then :
je_cv_cxxflags_added=-fsanitize=thread
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
je_cv_mprotect=no
je_cv_cxxflags_added=
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
CONFIGURE_CXXFLAGS="${T_CONFIGURE_CXXFLAGS}"

fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu

if test "x${CONFIGURE_CXXFLAGS}" = "x" -o "x${SPECIFIED_CXXFLAGS}" = "x" ; then
CXXFLAGS="${CONFIGURE_CXXFLAGS}${SPECIFIED_CXXFLAGS}"
else
CXXFLAGS="${CONFIGURE_CXXFLAGS} ${SPECIFIED_CXXFLAGS}"
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $je_cv_mprotect" >&5
$as_echo "$je_cv_mprotect" >&6; }

if test "x${je_cv_mprotect}" = "xyes" ; then

$as_echo "#define JEMALLOC_HAVE_MPROTECT " >>confdefs.h

{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether linker supports -fsanitize=thread" >&5
$as_echo_n "checking whether linker supports -fsanitize=thread... " >&6; }
T_CONFIGURE_LDFLAGS="${CONFIGURE_LDFLAGS}"
T_APPEND_V=-fsanitize=thread
if test "x${CONFIGURE_LDFLAGS}" = "x" -o "x${T_APPEND_V}" = "x" ; then
CONFIGURE_LDFLAGS="${CONFIGURE_LDFLAGS}${T_APPEND_V}"
else
CONFIGURE_LDFLAGS="${CONFIGURE_LDFLAGS} ${T_APPEND_V}"
fi


{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __builtin_clz" >&5
$as_echo_n "checking for __builtin_clz... " >&6; }
if ${je_cv_builtin_clz+:} false; then :
$as_echo_n "(cached) " >&6
if test "x${CONFIGURE_LDFLAGS}" = "x" -o "x${SPECIFIED_LDFLAGS}" = "x" ; then
LDFLAGS="${CONFIGURE_LDFLAGS}${SPECIFIED_LDFLAGS}"
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
LDFLAGS="${CONFIGURE_LDFLAGS} ${SPECIFIED_LDFLAGS}"
fi

cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */


int
main ()
{

{
unsigned x = 0;
int y = __builtin_clz(x);
}
{
unsigned long x = 0;
int y = __builtin_clzl(x);
}
{
unsigned long long x = 0;
int y = __builtin_clzll(x);
}
return 0;

;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
je_cv_builtin_clz=yes
je_cv_ldflags_added=-fsanitize=thread
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
je_cv_builtin_clz=no
je_cv_ldflags_added=
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
CONFIGURE_LDFLAGS="${T_CONFIGURE_LDFLAGS}"

fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
if test "x${CONFIGURE_LDFLAGS}" = "x" -o "x${SPECIFIED_LDFLAGS}" = "x" ; then
LDFLAGS="${CONFIGURE_LDFLAGS}${SPECIFIED_LDFLAGS}"
else
LDFLAGS="${CONFIGURE_LDFLAGS} ${SPECIFIED_LDFLAGS}"
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $je_cv_builtin_clz" >&5
$as_echo "$je_cv_builtin_clz" >&6; }

if test "x${je_cv_builtin_clz}" = "xyes" ; then

$as_echo "#define JEMALLOC_HAVE_BUILTIN_CLZ " >>confdefs.h
fi
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's locate and examine the configure file
fd -t f "configure" jemalloc-sys/ | head -5

Repository: tikv/jemallocator

Length of output: 93


🏁 Script executed:

# Get the file size to determine how to read it
wc -l jemalloc-sys/configure/configure

Repository: tikv/jemallocator

Length of output: 99


🏁 Script executed:

# Extract the TSAN section (lines 14828-14995)
sed -n '14828,14995p' jemalloc-sys/configure/configure | cat -n

Repository: tikv/jemallocator

Length of output: 5877


🏁 Script executed:

# Extract the section that "also applies to" (lines 14997-15177)
sed -n '14997,15177p' jemalloc-sys/configure/configure | cat -n

Repository: tikv/jemallocator

Length of output: 6234


Sanitizer compile flags must be rolled back when the linker probe fails.

When the linker probe for -fsanitize=thread or -fsanitize=undefined fails, CONFIGURE_CFLAGS and CONFIGURE_CXXFLAGS are not reset. This leaves instrumented object files without matching runtime support at link time, causing late build failures instead of clean configure-time rejection. The code correctly rolls back CONFIGURE_LDFLAGS on linker failure (lines 156, 169), but must do the same for CONFIGURE_CFLAGS and CONFIGURE_CXXFLAGS.

Also applies to: 14997-15177 (UBSAN section)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@jemalloc-sys/configure/configure` around lines 14828 - 14995, The linker
probe blocks for sanitizers (the -fsanitize=thread and UBSAN
-fsanitize=undefined sections) currently roll back CONFIGURE_LDFLAGS on link
failure but do not restore CONFIGURE_CFLAGS and CONFIGURE_CXXFLAGS, leaving
instrumented objects without matching linker flags; update the failure branches
(where je_cv_ldflags_added is cleared) to also restore CONFIGURE_CFLAGS to
T_CONFIGURE_CFLAGS and CONFIGURE_CXXFLAGS to T_CONFIGURE_CXXFLAGS (mirror how
CONFIGURE_LDFLAGS is reset), and ensure the same fix is applied in both the
ThreadSanitizer and UBSan linker-probe blocks (refer to symbols
je_cv_cflags_added, je_cv_cxxflags_added, je_cv_ldflags_added,
T_CONFIGURE_CFLAGS, T_CONFIGURE_CXXFLAGS, and T_CONFIGURE_LDFLAGS).

@BusyJay
Copy link
Copy Markdown
Member

BusyJay commented Apr 14, 2026

How about merge nightly back to main and then switch to 5.3.1 instead?

@sticnarf
Copy link
Copy Markdown
Author

How about merge nightly back to main and then switch to 5.3.1 instead?

Yes, I can rebase this commit onto the nightly head.

I didn't realize there's a nightly branch which fixes some bugs and adapts new features early. (Actually I also encounter the broken update bug when making this PR.)

BusyJay added 4 commits April 15, 2026 02:22
oldp should not be the same as newp, otherwise jemalloc may write to oldp first
and the new value will be lost.

Also fix invalid test value for max_background_threads and epoch.

Signed-off-by: Jay Lee <busyjaylee@gmail.com>
Signed-off-by: Jay Lee <busyjaylee@gmail.com>
Signed-off-by: Jay Lee <busyjaylee@gmail.com>
Signed-off-by: Jay Lee <busyjaylee@gmail.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
jemalloc-sys/src/lib.rs (1)

256-289: Keep allocator-override symbol pinning in sync with newly exported deallocators.

With free_sized / free_aligned_sized added here, set_up_statics (Line 974-987) should also pin these symbols under override_allocator_on_supported_platforms to preserve the file’s “force all allocator symbols visible to linker” guarantee.

♻️ Proposed update in set_up_statics
 mod set_up_statics {
     use super::*;
@@
     #[used]
     static USED_FREE: unsafe extern "C" fn(*mut c_void) = free;
+    #[used]
+    static USED_FREE_SIZED: unsafe extern "C" fn(*mut c_void, usize) = free_sized;
+    #[used]
+    static USED_FREE_ALIGNED_SIZED: unsafe extern "C" fn(*mut c_void, usize, usize) =
+        free_aligned_sized;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@jemalloc-sys/src/lib.rs` around lines 256 - 289, set_up_statics must also pin
the newly exported deallocators so the allocator-override symbol set remains
complete: add entries for free_sized and free_aligned_sized to the list of
symbols registered under override_allocator_on_supported_platforms inside
set_up_statics (the same place other allocator symbols are pinned) so the file’s
“force all allocator symbols visible to linker” guarantee is preserved;
reference the functions named free_sized and free_aligned_sized and the
configuration block/function
set_up_statics/override_allocator_on_supported_platforms when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@jemalloc-ctl/src/raw.rs`:
- Around line 188-201: The update function should enforce the same T: Copy bound
as update_mib to prevent constructing non-Copy types from raw bytes; modify the
signature of pub unsafe fn update<T>(...) to pub unsafe fn update<T: Copy>(...)
and ensure any uses of T in the function (old_value, value, sizes) remain the
same so the unsafe mallctl call and the assert_eq!(old_len, mem::size_of::<T>())
still compile; this makes update consistent with update_mib and the function’s
safety contract.

In `@jemallocator/tests/ffi.rs`:
- Around line 26-29: The aligned allocation call violates its precondition and
lacks a null check; change the size passed to ffi::aligned_alloc from 127 to a
multiple of 16 (e.g., 128) and update the matching ffi::free_aligned_sized call
accordingly, and add null-pointer assertions for both allocations (after
ffi::malloc and after ffi::aligned_alloc) so the test checks ptr.is_null() (or
uses the file's existing assert pattern) before freeing; reference: ffi::malloc,
ffi::free_sized, ffi::aligned_alloc, ffi::free_aligned_sized.

---

Nitpick comments:
In `@jemalloc-sys/src/lib.rs`:
- Around line 256-289: set_up_statics must also pin the newly exported
deallocators so the allocator-override symbol set remains complete: add entries
for free_sized and free_aligned_sized to the list of symbols registered under
override_allocator_on_supported_platforms inside set_up_statics (the same place
other allocator symbols are pinned) so the file’s “force all allocator symbols
visible to linker” guarantee is preserved; reference the functions named
free_sized and free_aligned_sized and the configuration block/function
set_up_statics/override_allocator_on_supported_platforms when making the change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 241e1c0c-cf5d-4b41-b774-61f4d24b3fe3

📥 Commits

Reviewing files that changed from the base of the PR and between 2476a95 and 32b7af2.

📒 Files selected for processing (11)
  • .github/workflows/main.yml
  • .gitmodules
  • jemalloc-ctl/src/lib.rs
  • jemalloc-ctl/src/macros.rs
  • jemalloc-ctl/src/raw.rs
  • jemalloc-sys/Cargo.toml
  • jemalloc-sys/README.md
  • jemalloc-sys/configure/configure
  • jemalloc-sys/jemalloc
  • jemalloc-sys/src/lib.rs
  • jemallocator/tests/ffi.rs
✅ Files skipped from review due to trivial changes (6)
  • jemalloc-sys/README.md
  • .github/workflows/main.yml
  • jemalloc-ctl/src/lib.rs
  • jemalloc-sys/jemalloc
  • .gitmodules
  • jemalloc-sys/Cargo.toml

Comment thread jemalloc-ctl/src/raw.rs
Comment on lines 188 to +201
pub unsafe fn update<T>(name: &[u8], mut value: T) -> Result<T> {
validate_name(name);

let mut len = mem::size_of::<T>();
let mut old_len = mem::size_of::<T>();
let mut old_value = MaybeUninit::<T>::uninit();
cvt(tikv_jemalloc_sys::mallctl(
name as *const _ as *const c_char,
old_value.as_mut_ptr() as *mut _,
&mut old_len,
&mut value as *mut _ as *mut _,
&mut len,
&mut value as *mut _ as *mut _,
len,
mem::size_of::<T>(),
))?;
assert_eq!(len, mem::size_of::<T>());
Ok(value)
assert_eq!(old_len, mem::size_of::<T>());
Ok(old_value.assume_init())
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the two update signatures side-by-side.
sed -n '160,205p' jemalloc-ctl/src/raw.rs

# Scan for obvious explicit instantiations that would rely on a non-Copy T.
rg -nP --type=rust '\bupdate::<\s*(String|Vec<|Box<|PathBuf|CString)' .

Repository: tikv/jemallocator

Length of output: 1770


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find all calls to the update() function
rg -nP --type=rust '\bupdate\(' jemalloc-ctl/src/ | head -20

# Also check for update::<T> generic instantiations with any type
rg -nP --type=rust 'update::<' . | head -20

Repository: tikv/jemallocator

Length of output: 1742


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Look at the full keys.rs file to understand type parameters
cat -n jemalloc-ctl/src/keys.rs

Repository: tikv/jemallocator

Length of output: 16436


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Get the complete raw.rs file
wc -l jemalloc-ctl/src/raw.rs

# Then read it in sections
head -400 jemalloc-ctl/src/raw.rs | tail -250

Repository: tikv/jemallocator

Length of output: 10115


Add the T: Copy bound to the string-path update function to match update_mib.

The update function on line 188 currently lacks the T: Copy bound that update_mib (line 164) enforces. Both functions perform the same unsafe operation via mallctl/mallctlbymib and share identical safety documentation regarding construction of arbitrary types from raw bytes. The two entry points should enforce the same bounds.

All current call sites pass Copy types (u32, u64, isize, usize, u8, and pointers), so adding this bound is not breaking.

Suggested fix
-pub unsafe fn update<T>(name: &[u8], mut value: T) -> Result<T> {
+pub unsafe fn update<T: Copy>(name: &[u8], mut value: T) -> Result<T> {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
pub unsafe fn update<T>(name: &[u8], mut value: T) -> Result<T> {
validate_name(name);
let mut len = mem::size_of::<T>();
let mut old_len = mem::size_of::<T>();
let mut old_value = MaybeUninit::<T>::uninit();
cvt(tikv_jemalloc_sys::mallctl(
name as *const _ as *const c_char,
old_value.as_mut_ptr() as *mut _,
&mut old_len,
&mut value as *mut _ as *mut _,
&mut len,
&mut value as *mut _ as *mut _,
len,
mem::size_of::<T>(),
))?;
assert_eq!(len, mem::size_of::<T>());
Ok(value)
assert_eq!(old_len, mem::size_of::<T>());
Ok(old_value.assume_init())
pub unsafe fn update<T: Copy>(name: &[u8], mut value: T) -> Result<T> {
validate_name(name);
let mut old_len = mem::size_of::<T>();
let mut old_value = MaybeUninit::<T>::uninit();
cvt(tikv_jemalloc_sys::mallctl(
name as *const _ as *const c_char,
old_value.as_mut_ptr() as *mut _,
&mut old_len,
&mut value as *mut _ as *mut _,
mem::size_of::<T>(),
))?;
assert_eq!(old_len, mem::size_of::<T>());
Ok(old_value.assume_init())
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@jemalloc-ctl/src/raw.rs` around lines 188 - 201, The update function should
enforce the same T: Copy bound as update_mib to prevent constructing non-Copy
types from raw bytes; modify the signature of pub unsafe fn update<T>(...) to
pub unsafe fn update<T: Copy>(...) and ensure any uses of T in the function
(old_value, value, sizes) remain the same so the unsafe mallctl call and the
assert_eq!(old_len, mem::size_of::<T>()) still compile; this makes update
consistent with update_mib and the function’s safety contract.

Comment thread jemallocator/tests/ffi.rs
Comment on lines +26 to +29
ptr = ffi::malloc(100);
ffi::free_sized(ptr, 100);
ptr = ffi::aligned_alloc(16, 127);
ffi::free_aligned_sized(ptr, 16, 127);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify the contract in FFI docs and the violating test callsite.
rg -n "pub fn aligned_alloc|integral multiple of `alignment`|size is not an integral multiple" jemalloc-sys/src/lib.rs
rg -n "aligned_alloc\\(" jemallocator/tests/ffi.rs

Repository: tikv/jemallocator

Length of output: 313


🏁 Script executed:

# Get broader context around the unsafe documentation and function signature
sed -n '195,205p' jemalloc-sys/src/lib.rs

# Check test patterns - are non-null assertions used elsewhere in this test file?
rg -B2 -A2 "assert.*is_null|is_null.*assert" jemallocator/tests/ffi.rs | head -30

Repository: tikv/jemallocator

Length of output: 754


🏁 Script executed:

# View lines around the change to verify exact formatting and context
sed -n '20,35p' jemallocator/tests/ffi.rs

Repository: tikv/jemallocator

Length of output: 515


Fix undefined behavior in aligned allocation test.

Line 28 calls ffi::aligned_alloc(16, 127), but the documented precondition requires size to be an integral multiple of alignment. Since 127 ÷ 16 = 7.9375, this violates the safety contract. Additionally, both new allocations lack null assertions unlike other allocation tests in this file.

Proposed fix
        ptr = ffi::malloc(100);
+       assert!(!ptr.is_null());
        ffi::free_sized(ptr, 100);
        ptr = ffi::aligned_alloc(16, 128);
+       assert!(!ptr.is_null());
-       ffi::free_aligned_sized(ptr, 16, 127);
+       ffi::free_aligned_sized(ptr, 16, 128);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ptr = ffi::malloc(100);
ffi::free_sized(ptr, 100);
ptr = ffi::aligned_alloc(16, 127);
ffi::free_aligned_sized(ptr, 16, 127);
ptr = ffi::malloc(100);
assert!(!ptr.is_null());
ffi::free_sized(ptr, 100);
ptr = ffi::aligned_alloc(16, 128);
assert!(!ptr.is_null());
ffi::free_aligned_sized(ptr, 16, 128);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@jemallocator/tests/ffi.rs` around lines 26 - 29, The aligned allocation call
violates its precondition and lacks a null check; change the size passed to
ffi::aligned_alloc from 127 to a multiple of 16 (e.g., 128) and update the
matching ffi::free_aligned_sized call accordingly, and add null-pointer
assertions for both allocations (after ffi::malloc and after ffi::aligned_alloc)
so the test checks ptr.is_null() (or uses the file's existing assert pattern)
before freeing; reference: ffi::malloc, ffi::free_sized, ffi::aligned_alloc,
ffi::free_aligned_sized.

Signed-off-by: Yilin Chen <sticnarf@gmail.com>
Copy link
Copy Markdown
Member

@BusyJay BusyJay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@BusyJay BusyJay merged commit c7101ce into tikv:main Apr 16, 2026
12 checks passed
@philjb
Copy link
Copy Markdown

philjb commented Apr 20, 2026

When might you release this in a new release of tikv-jemalloc? Looking for a rough schedule or plan. ta

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants