[coredump] Segment fault in FreeBSD 15.1
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):
#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:
$ 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_tsdIt 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!
Source: jemalloc/jemalloc