From b859093d283c7a229233509f6bf0b452bed84c0d Mon Sep 17 00:00:00 2001 From: Farid Zakaria Date: Mon, 6 Jul 2026 11:03:51 -0700 Subject: [PATCH] Limit TSD bootstrap hook to tests --- Makefile.in | 3 +- include/jemalloc/internal/test_hooks.h | 2 + src/test_hooks.c | 2 + test/stress/tsd_reentrant.c | 140 ------------------------- 4 files changed, 5 insertions(+), 142 deletions(-) delete mode 100644 test/stress/tsd_reentrant.c diff --git a/Makefile.in b/Makefile.in index c161bccf..c7bab1a2 100644 --- a/Makefile.in +++ b/Makefile.in @@ -367,8 +367,7 @@ TESTS_ANALYZE := $(srcroot)test/analyze/prof_bias.c \ TESTS_STRESS := $(srcroot)test/stress/fill_flush.c \ $(srcroot)test/stress/large_microbench.c \ $(srcroot)test/stress/mallctl.c \ - $(srcroot)test/stress/microbench.c \ - $(srcroot)test/stress/tsd_reentrant.c + $(srcroot)test/stress/microbench.c ifeq (@enable_cxx@, 1) TESTS_STRESS_CPP := $(srcroot)test/stress/cpp/microbench.cpp else diff --git a/include/jemalloc/internal/test_hooks.h b/include/jemalloc/internal/test_hooks.h index a4c9d6c0..b87b0e3e 100644 --- a/include/jemalloc/internal/test_hooks.h +++ b/include/jemalloc/internal/test_hooks.h @@ -4,7 +4,9 @@ extern JEMALLOC_EXPORT void (*test_hooks_arena_new_hook)(void); extern JEMALLOC_EXPORT void (*test_hooks_libc_hook)(void); extern JEMALLOC_EXPORT void (*test_hooks_safety_check_abort)(const char *); +#if defined(JEMALLOC_JET) || defined(JEMALLOC_UNIT_TEST) extern JEMALLOC_EXPORT void (*test_hooks_tsd_bootstrap_hook)(void); +#endif #if defined(JEMALLOC_JET) || defined(JEMALLOC_UNIT_TEST) # define JEMALLOC_TEST_HOOK(fn, hook) \ diff --git a/src/test_hooks.c b/src/test_hooks.c index 3fc8534e..861102ca 100644 --- a/src/test_hooks.c +++ b/src/test_hooks.c @@ -14,5 +14,7 @@ void (*test_hooks_libc_hook)(void) = NULL; JEMALLOC_EXPORT void (*test_hooks_safety_check_abort)(const char *) = NULL; +#if defined(JEMALLOC_JET) || defined(JEMALLOC_UNIT_TEST) JEMALLOC_EXPORT void (*test_hooks_tsd_bootstrap_hook)(void) = NULL; +#endif diff --git a/test/stress/tsd_reentrant.c b/test/stress/tsd_reentrant.c deleted file mode 100644 index 220f1c3e..00000000 --- a/test/stress/tsd_reentrant.c +++ /dev/null @@ -1,140 +0,0 @@ -#include "test/jemalloc_test.h" - -#ifndef _WIN32 -#include -#include -#endif - -#ifndef _WIN32 - -extern void (*je_test_hooks_tsd_bootstrap_hook)(void); - -static atomic_zu_t handler_allocs; - -static atomic_b_t crash_reported; -static bool hook_ran; -static volatile sig_atomic_t in_reentrant_signal_alloc; - -static void *volatile signal_alloc; - -static void -on_crash(int signo) { -#define WRITE_LITERAL(s) (void)write(STDERR_FILENO, s, sizeof(s) - 1) - if (atomic_exchange_b(&crash_reported, true, ATOMIC_RELAXED)) { - _exit(128 + signo); - } - - WRITE_LITERAL("\n*** tsd_reentrant reproduced allocator crash ***\n"); - if (signo == SIGSEGV) { - WRITE_LITERAL("signal: SIGSEGV\n"); - } else if (signo == SIGBUS) { - WRITE_LITERAL("signal: SIGBUS\n"); - } - WRITE_LITERAL("inside SIGUSR1 handler malloc: "); - if (in_reentrant_signal_alloc) { - WRITE_LITERAL("yes\n"); - } else { - WRITE_LITERAL("no\n"); - } - WRITE_LITERAL("This matches recursive allocation during TSD/tcache " - "bootstrap.\n"); -#undef WRITE_LITERAL - - _exit(128 + signo); -} - -static void -on_signal(int signo) { - (void)signo; - in_reentrant_signal_alloc = 1; - - /* - * This intentionally models asynchronous interruption that allocates. - * jemalloc does not promise that arbitrary signal-handler allocation is - * safe, but the allocator should keep its own bootstrap state - * internally consistent if such reentrancy occurs. - */ - void *p = malloc(16); - if (p != NULL) { - signal_alloc = p; - atomic_load_add_store_zu(&handler_allocs, 1); - } - in_reentrant_signal_alloc = 0; -} - -static void -tsd_bootstrap_signal_hook(void) { - hook_ran = true; - je_test_hooks_tsd_bootstrap_hook = NULL; - /* - * The hook only selects the bootstrap window. The recursive allocation - * still enters through the process signal path and public malloc(). - */ - raise(SIGUSR1); -} - -static void * -worker_start(void *arg) { - (void)arg; - void *p = malloc(16); - expect_ptr_not_null(p, "Unexpected malloc() failure"); - if (p != NULL) { - memset(p, 0xa5, 16); - free(p); - } - - je_test_hooks_tsd_bootstrap_hook = NULL; - - return NULL; -} - -static void -init_signal_handler(void) { - struct sigaction sa; - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = on_signal; - sa.sa_flags = SA_RESTART; - sigemptyset(&sa.sa_mask); - expect_d_eq(sigaction(SIGUSR1, &sa, NULL), 0, - "Unexpected sigaction() failure"); - - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = on_crash; - sigemptyset(&sa.sa_mask); - expect_d_eq(sigaction(SIGSEGV, &sa, NULL), 0, - "Unexpected sigaction() failure"); - expect_d_eq(sigaction(SIGBUS, &sa, NULL), 0, - "Unexpected sigaction() failure"); -} - -TEST_BEGIN(test_tsd_bootstrap_signal_reentrant) { - thd_t worker; - - init_signal_handler(); - - atomic_store_b(&crash_reported, false, ATOMIC_RELEASE); - atomic_store_zu(&handler_allocs, 0, ATOMIC_RELEASE); - hook_ran = false; - - je_test_hooks_tsd_bootstrap_hook = tsd_bootstrap_signal_hook; - thd_create(&worker, worker_start, NULL); - thd_join(worker, NULL); - je_test_hooks_tsd_bootstrap_hook = NULL; - - expect_true(hook_ran, "TSD bootstrap hook should have executed"); - expect_zu_eq(atomic_load_zu(&handler_allocs, ATOMIC_ACQUIRE), 1, - "Signal handler should have allocated"); -} -TEST_END - -#endif - -int -main(void) { -#ifdef _WIN32 - test_skip("Signals are unavailable"); - return test_status_skip; -#else - return test_no_reentrancy(test_tsd_bootstrap_signal_reentrant); -#endif -}