From db833142f121351cd2de1961a9029e9c635101a3 Mon Sep 17 00:00:00 2001 From: "Moe Charm (CI)" Date: Fri, 7 Nov 2025 00:37:33 +0900 Subject: [PATCH] =?UTF-8?q?Fix:=20malloc=20=E5=88=9D=E6=9C=9F=E5=8C=96?= =?UTF-8?q?=E3=83=87=E3=83=83=E3=83=89=E3=83=AD=E3=83=83=E3=82=AF=E3=82=92?= =?UTF-8?q?=E8=A7=A3=E6=B6=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **問題:** - Larson ベンチマークが起動時に futex でハング - 全プロセスが FUTEX_WAIT_PRIVATE で永遠に待機 - 初期化が完了せず、何も出力されない **根本原因:** `core/box/hak_wrappers.inc.h` の `malloc()` 関数で、 Line 42 の `getenv("HAKMEM_SFC_DEBUG")` が `g_initializing` チェックより前に実行される → `getenv()` が内部で malloc を呼ぶ → 無限再帰 → pthread_once デッドロック **修正内容:** `g_initializing` チェックを malloc() の最初に移動 (Line 41-44) - 初期化中の再帰呼び出しを即座に libc にフォールバック - getenv() などの init 関数が malloc を呼んでも安全 **効果:** - デッドロック完全解消 ✅ - Larson ベンチマーク正常起動 - 性能維持: 4,192,124 ops/s (4.19M baseline) **テスト:** ```bash ./larson_hakmem 1 8 128 128 1 1 1 # → 367,082 ops/s ✅ ./larson_hakmem 2 8 128 1024 1 12345 4 # → 4,192,124 ops/s ✅ ``` 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- core/box/hak_wrappers.inc.h | 144 ++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 core/box/hak_wrappers.inc.h diff --git a/core/box/hak_wrappers.inc.h b/core/box/hak_wrappers.inc.h new file mode 100644 index 00000000..375c8580 --- /dev/null +++ b/core/box/hak_wrappers.inc.h @@ -0,0 +1,144 @@ +// hak_wrappers.inc.h — malloc/free/calloc/realloc wrappers (LD_PRELOAD-aware) +#ifndef HAK_WRAPPERS_INC_H +#define HAK_WRAPPERS_INC_H + +#ifdef HAKMEM_FORCE_LIBC_ALLOC_BUILD + +// Sanitizer/diagnostic builds: bypass hakmem allocator completely. +void* malloc(size_t size) { + extern void* __libc_malloc(size_t); + return __libc_malloc(size); +} + +void free(void* ptr) { + if (!ptr) return; + extern void __libc_free(void*); + __libc_free(ptr); +} + +void* calloc(size_t nmemb, size_t size) { + extern void* __libc_calloc(size_t, size_t); + return __libc_calloc(nmemb, size); +} + +void* realloc(void* ptr, size_t size) { + extern void* __libc_realloc(void*, size_t); + return __libc_realloc(ptr, size); +} + +#else + +// malloc wrapper - intercepts system malloc() calls +__thread uint64_t g_malloc_total_calls = 0; +__thread uint64_t g_malloc_tiny_size_match = 0; +__thread uint64_t g_malloc_fast_path_tried = 0; +__thread uint64_t g_malloc_fast_path_null = 0; +__thread uint64_t g_malloc_slow_path = 0; + +extern __thread void* g_tls_sll_head[TINY_NUM_CLASSES]; + +void* malloc(size_t size) { + // Guard against recursion during initialization FIRST! + if (__builtin_expect(g_initializing != 0, 0)) { + extern void* __libc_malloc(size_t); + return __libc_malloc(size); + } + + static _Atomic int debug_count = 0; + if (getenv("HAKMEM_SFC_DEBUG") && debug_count < 100) { + int n = atomic_fetch_add(&debug_count, 1); + if (n < 20) fprintf(stderr, "[SFC_DEBUG] malloc(%zu)\n", size); + } + + if (__builtin_expect(hak_force_libc_alloc(), 0)) { + extern void* __libc_malloc(size_t); + return __libc_malloc(size); + } + + int ld_mode = hak_ld_env_mode(); + if (ld_mode) { + if (hak_ld_block_jemalloc() && hak_jemalloc_loaded()) { + extern void* __libc_malloc(size_t); + return __libc_malloc(size); + } + if (!g_initialized) { hak_init(); } + if (g_initializing) { + extern void* __libc_malloc(size_t); + return __libc_malloc(size); + } + const char* lds = getenv("HAKMEM_LD_SAFE"); + int mode = (lds ? atoi(lds) : 1); + if (mode >= 2 || size > TINY_MAX_SIZE) { + extern void* __libc_malloc(size_t); + return __libc_malloc(size); + } + } + + g_hakmem_lock_depth++; + void* ptr = hak_alloc_at(size, HAK_CALLSITE()); + g_hakmem_lock_depth--; + return ptr; +} + +void free(void* ptr) { + atomic_fetch_add_explicit(&g_free_wrapper_calls, 1, memory_order_relaxed); + if (!ptr) return; + if (g_hakmem_lock_depth > 0) { extern void __libc_free(void*); __libc_free(ptr); return; } + if (__builtin_expect(g_initializing != 0, 0)) { extern void __libc_free(void*); __libc_free(ptr); return; } + if (__builtin_expect(hak_force_libc_alloc(), 0)) { extern void __libc_free(void*); __libc_free(ptr); return; } + if (hak_ld_env_mode()) { + if (hak_ld_block_jemalloc() && hak_jemalloc_loaded()) { extern void __libc_free(void*); __libc_free(ptr); return; } + if (!g_initialized) { hak_init(); } + if (g_initializing) { extern void __libc_free(void*); __libc_free(ptr); return; } + } + g_hakmem_lock_depth++; + hak_free_at(ptr, 0, HAK_CALLSITE()); + g_hakmem_lock_depth--; +} + +void* calloc(size_t nmemb, size_t size) { + if (g_hakmem_lock_depth > 0) { extern void* __libc_calloc(size_t, size_t); return __libc_calloc(nmemb, size); } + if (__builtin_expect(g_initializing != 0, 0)) { extern void* __libc_calloc(size_t, size_t); return __libc_calloc(nmemb, size); } + if (size != 0 && nmemb > (SIZE_MAX / size)) { errno = ENOMEM; return NULL; } + if (__builtin_expect(hak_force_libc_alloc(), 0)) { extern void* __libc_calloc(size_t, size_t); return __libc_calloc(nmemb, size); } + int ld_mode = hak_ld_env_mode(); + if (ld_mode) { + if (hak_ld_block_jemalloc() && hak_jemalloc_loaded()) { extern void* __libc_calloc(size_t, size_t); return __libc_calloc(nmemb, size); } + if (!g_initialized) { hak_init(); } + if (g_initializing) { extern void* __libc_calloc(size_t, size_t); return __libc_calloc(nmemb, size); } + const char* lds = getenv("HAKMEM_LD_SAFE"); + int mode = (lds ? atoi(lds) : 1); + size_t total = nmemb * size; + if (mode >= 2 || total > TINY_MAX_SIZE) { extern void* __libc_calloc(size_t, size_t); return __libc_calloc(nmemb, size); } + } + g_hakmem_lock_depth++; + size_t total_size = nmemb * size; + void* ptr = hak_alloc_at(total_size, HAK_CALLSITE()); + if (ptr) { memset(ptr, 0, total_size); } + g_hakmem_lock_depth--; + return ptr; +} + +void* realloc(void* ptr, size_t size) { + if (g_hakmem_lock_depth > 0) { extern void* __libc_realloc(void*, size_t); return __libc_realloc(ptr, size); } + if (__builtin_expect(g_initializing != 0, 0)) { extern void* __libc_realloc(void*, size_t); return __libc_realloc(ptr, size); } + if (__builtin_expect(hak_force_libc_alloc(), 0)) { extern void* __libc_realloc(void*, size_t); return __libc_realloc(ptr, size); } + int ld_mode = hak_ld_env_mode(); + if (ld_mode) { + if (hak_ld_block_jemalloc() && hak_jemalloc_loaded()) { extern void* __libc_realloc(void*, size_t); return __libc_realloc(ptr, size); } + if (!g_initialized) { hak_init(); } + if (g_initializing) { extern void* __libc_realloc(void*, size_t); return __libc_realloc(ptr, size); } + } + if (ptr == NULL) { return malloc(size); } + if (size == 0) { free(ptr); return NULL; } + void* new_ptr = malloc(size); + if (!new_ptr) return NULL; + memcpy(new_ptr, ptr, size); + free(ptr); + return new_ptr; +} + +#endif // HAKMEM_FORCE_LIBC_ALLOC_BUILD + +#endif // HAK_WRAPPERS_INC_H +