Fix: malloc 初期化デッドロックを解消
**問題:**
- 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 <noreply@anthropic.com>
This commit is contained in:
144
core/box/hak_wrappers.inc.h
Normal file
144
core/box/hak_wrappers.inc.h
Normal file
@ -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
|
||||
|
||||
Reference in New Issue
Block a user