#2969·jemalloc

[coredump] Segment fault in FreeBSD 15.1

Author: yanboerCreated Jul 28, 2026Updated Aug 21, 2026

Problem Description

On FreeBSD 15.1 (shipping with jemalloc 5.3.0), our custom program crashes with a Segmentation Fault when statically linked against jemalloc.

Steps to Reproduce We use a minimal multi-threaded test program that spawns multiple threads, each performing a single malloc() and free() call.

Test Program (test_jemalloc_tsd.c):

c
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

#define N_THREADS 8
#define N_ROUNDS  4

static void *thread_func(void *arg) {
    void *p = malloc(64 + 1 * 32);
    free(p);
    return NULL;
}

int main(void) {
    fprintf(stderr, "Running %d rounds of %d threads (libc malloc)...\n", N_ROUNDS, N_THREADS);

    for (int r = 0; r < N_ROUNDS; r++) {
        pthread_t threads[N_THREADS];
        for (int i = 0; i < N_THREADS; i++) {
            int ret = pthread_create(&threads[i], NULL, thread_func, NULL);
            if (ret != 0) {
                fprintf(stderr, "pthread_create(%d) in round %d failed: %d\n", i, r, ret);
                return 1;
            }
        }
        for (int i = 0; i < N_THREADS; i++) {
            pthread_join(threads[i], NULL);
        }
        fprintf(stderr, "  Round %d complete\n", r);
    }

    fprintf(stderr, "SUCCESS: No crash.\n");
    return 0;
}

Build and Run:

bash
$ cc -pthread -O0 -g \
   -I deps/jemalloc/include \
   -o test_jemalloc_tsd test_jemalloc_tsd.c \
   deps/jemalloc/lib/libjemalloc.a -lm

$ ./test_jemalloc_tsd
Initializing static jemalloc...
Running 4 rounds of 8 threads (libc malloc)...
  Round 0 complete
  Round 1 complete
Segmentation fault
The crash occurs during the second round of thread creation.

Backtrace
Thread 20 received signal SIGSEGV, Segmentation fault.
Address not mapped to object.
[Switching to LWP 100536 of process 4631]
0x00000000405cbe54 in __je_tcache_arena_associate (tsdn=<optimized out>, tsdn@entry=0x408a5570, tcache_slow=0x408a5670, tcache=0x408a58c8, arena=arena@entry=0x41a01000) at jemalloc_tcache.c:591
warning: 591    jemalloc_tcache.c: No such file or directory
(gdb) bt
#0  0x00000000405cbe54 in __je_tcache_arena_associate (tsdn=<optimized out>, tsdn@entry=0x408a5570, tcache_slow=0x408a5670, tcache=0x408a58c8, arena=arena@entry=0x41a01000) at jemalloc_tcache.c:591
#1  0x00000000405cdb08 in arena_choose_impl (tsd=tsd@entry=0x408a5570, arena=0x0, internal=<optimized out>) at /usr/src/contrib/jemalloc/include/jemalloc/internal/jemalloc_internal_inlines_b.h:60
#2  0x00000000405cc314 in arena_choose (tsd=0x408a5570, arena=0x0) at /usr/src/contrib/jemalloc/include/jemalloc/internal/jemalloc_internal_inlines_b.h:88
#3  __je_tsd_tcache_data_init (tsd=tsd@entry=0x408a5570) at jemalloc_tcache.c:740
#4  0x00000000405cc0c0 in __je_tsd_tcache_enabled_data_init (tsd=tsd@entry=0x408a5570) at jemalloc_tcache.c:644
#5  0x00000000405ce570 in tsd_data_init (tsd=<optimized out>) at jemalloc_tsd.c:244
#6  0x00000000405ce570 in __je_tsd_fetch_slow (tsd=tsd@entry=0x408a5570, minimal=<optimized out>) from /lib/libc.so.7
#7  0x0000000040581bdc in tsd_fetch_impl (init=true, minimal=false) at /usr/src/contrib/jemalloc/include/jemalloc/internal/tsd.h:423
#8  tsd_fetch () at /usr/src/contrib/jemalloc/include/jemalloc/internal/tsd.h:449
#9  imalloc (sopts=<optimized out>, dopts=<optimized out>) at jemalloc_jemalloc.c:2685
#10 __je_malloc_default (size=96) at jemalloc_jemalloc.c:2726
#11 0x000000000022a6c4 in thread_func (arg=0x0) at test_jemalloc_tsd.c:11
#12 0x00000000403c03ec in thread_start (curthread=0x408ba810) at /usr/src/lib/libthr/thread/thr_create.c:299
#13 0x0000000000000000 in ?? ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
The crash occurs in tcache_arena_associate, where the program attempts to access thread-local tcache and arena data via TSD (Thread-Specific Data), but hits an unmapped memory address.

Investigation

We found a related upstream PR: Fix FreeBSD system jemalloc TSD cleanup #2232. It addresses TSD cleanup issues on FreeBSD for the system jemalloc.

During debugging, we examined the TSD cleanup registration in our statically linked binary:

(gdb) p ncleanups
$1 = 1
(gdb) p cleanups
$2 = {0x2926c8 <tsd_cleanup_wrapper>, 0x0, 0x0, 0x0}
(gdb) p cleanups[0]
$3 = (malloc_tsd_cleanup_t) 0x2926c8 <tsd_cleanup_wrapper>
(gdb) info symbol cleanups[0]
tsd_cleanup_wrapper in section .text of /root/redis-build/redis-7.2.10/test_jemalloc_tsd

It shows that ncleanups = 1, and cleanups[0] points to tsd_cleanup_wrapper in our statically linked jemalloc. It seems that tsd cleanup is not working as expected.

Environment

OS: FreeBSD 15.1

System jemalloc version: 5.3.0-0-g54eaed1d8b56b1aa528be3bdd1877e59c56fa90c (from man free)

Static library jemalloc version: 5.3.0-0-g0 (from deps/jemalloc/VERSION)

Questions

Is static linking against jemalloc on FreeBSD expected to work with the TSD cleanup mechanism?

Could there be a conflict between the system libc's jemalloc TSD handling and a statically linked jemalloc instance?

Are there any known workarounds for this issue?

Any insights or suggestions would be greatly appreciated. Thanks in advance!