Files
hakmem/core/box/hak_free_api.inc.h
Moe Charm (CI) 9f32de4892 Fix: free() invalid pointer crash (partial fix - 0% → 60% success)
**問題:**
- 100% crash rate: "free(): invalid pointer"
- 全実行で glibc abort

**根本原因 (Task agent ultrathink 発見):**
`core/box/hak_free_api.inc.h:84`
```c
if (hdr->magic != HAKMEM_MAGIC) {
    __libc_free(ptr);  // ← BUG! ptr is user pointer (after header)
}
```

**メモリレイアウト:**
```
Allocation: malloc(HEADER_SIZE + size) → returns (raw + HEADER_SIZE)
           [Header][User Data............]
           ^raw    ^ptr

Free: __libc_free(ptr) ← ✗ 間違い! raw を free すべき
```

**修正内容:**
Line 84: `__libc_free(ptr)` → `free(raw)`
- Header corruption 時に正しいアドレスを free

**効果:**
```
Before: 0/5 success (100% crash)
After:  3/5 success (60% crash)
```

**残存問題:**
- まだ 40% でクラッシュする
- 別のバグが存在(double-free or cross-thread corruption?)
- 次: ASan + Task agent ultrathink で追加調査

**テスト結果:**
```bash
Run 1: 4.19M ops/s 
Run 2: 4.19M ops/s 
Run 3: crash 
Run 4: 4.19M ops/s 
Run 5: crash 
```

**調査協力:** Task agent (ultrathink mode)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 02:25:12 +09:00

120 lines
5.1 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// hak_free_api.inc.h — Box: hak_free_at() implementation
#ifndef HAK_FREE_API_INC_H
#define HAK_FREE_API_INC_H
// Optional route trace: print first N classification lines when enabled by env
static inline int hak_free_route_trace_on(void) {
static int g_trace = -1;
if (__builtin_expect(g_trace == -1, 0)) {
const char* e = getenv("HAKMEM_FREE_ROUTE_TRACE");
g_trace = (e && *e && *e != '0') ? 1 : 0;
}
return g_trace;
}
static inline int* hak_free_route_budget_ptr(void) {
static int g_budget = 32; // first 32 frees only
return &g_budget;
}
static inline void hak_free_route_log(const char* tag, void* p) {
if (!hak_free_route_trace_on()) return;
int* budget = hak_free_route_budget_ptr();
if (*budget <= 0) return;
(*budget)--;
fprintf(stderr, "[FREE_ROUTE] %s ptr=%p\n", tag, p);
}
#ifndef HAKMEM_TINY_PHASE6_BOX_REFACTOR
__attribute__((always_inline))
inline
#endif
void hak_free_at(void* ptr, size_t size, hak_callsite_t site) {
#if HAKMEM_DEBUG_TIMING
HKM_TIME_START(t0);
#endif
(void)site; (void)size;
if (!ptr) {
#if HAKMEM_DEBUG_TIMING
HKM_TIME_END(HKM_CAT_HAK_FREE, t0);
#endif
return;
}
// SS-first free既定ON
{
static int s_free_to_ss = -2;
if (s_free_to_ss == -2) {
const char* e = getenv("HAKMEM_TINY_FREE_TO_SS");
s_free_to_ss = (e && *e) ? ((*e!='0')?1:0) : 1;
}
if (s_free_to_ss) {
extern int g_use_superslab;
if (__builtin_expect(g_use_superslab != 0, 1)) {
SuperSlab* ss = hak_super_lookup(ptr);
if (ss && ss->magic == SUPERSLAB_MAGIC) {
int sidx = slab_index_for(ss, ptr);
int cap = ss_slabs_capacity(ss);
if (__builtin_expect(sidx >= 0 && sidx < cap, 1)) { hak_free_route_log("ss_hit", ptr); hak_tiny_free(ptr); goto done; }
}
for (int lg=21; lg>=20; lg--) {
uintptr_t mask=((uintptr_t)1<<lg)-1; SuperSlab* guess=(SuperSlab*)((uintptr_t)ptr & ~mask);
if (guess && guess->magic==SUPERSLAB_MAGIC) { int sidx=slab_index_for(guess,ptr); int cap=ss_slabs_capacity(guess); if (sidx>=0&&sidx<cap){ hak_free_route_log("ss_guess", ptr); hak_tiny_free(ptr); goto done; }}
}
}
}
}
// Mid/L25 headerless経路
{
extern int hak_pool_mid_lookup(void* ptr, size_t* out_size);
extern void hak_pool_free_fast(void* ptr, uintptr_t site_id);
size_t mid_sz = 0; if (hak_pool_mid_lookup(ptr, &mid_sz)) { hak_free_route_log("mid_hit", ptr); hak_pool_free_fast(ptr, (uintptr_t)site); goto done; }
}
{
extern int hak_l25_lookup(void* ptr, size_t* out_size);
extern void hak_l25_pool_free_fast(void* ptr, uintptr_t site_id);
size_t l25_sz = 0; if (hak_l25_lookup(ptr, &l25_sz)) { hak_free_route_log("l25_hit", ptr); hkm_ace_stat_large_free(); hak_l25_pool_free_fast(ptr, (uintptr_t)site); goto done; }
}
// Raw header dispatchmmap/malloc/BigCacheなど
{
void* raw = (char*)ptr - HEADER_SIZE;
AllocHeader* hdr = (AllocHeader*)raw;
if (hdr->magic != HAKMEM_MAGIC) {
if (g_invalid_free_log) fprintf(stderr, "[hakmem] ERROR: Invalid magic 0x%X (expected 0x%X)\n", hdr->magic, HAKMEM_MAGIC);
// CRITICAL FIX: Free raw (allocated address), not ptr (user pointer after header)
if (g_invalid_free_mode) { goto done; } else { free(raw); goto done; }
}
if (HAK_ENABLED_CACHE(HAKMEM_FEATURE_BIGCACHE) && hdr->class_bytes >= 2097152) {
if (hak_bigcache_put(ptr, hdr->size, hdr->alloc_site)) goto done;
}
{
static int g_bc_l25_en_free = -1; if (g_bc_l25_en_free == -1) { const char* e = getenv("HAKMEM_BIGCACHE_L25"); g_bc_l25_en_free = (e && atoi(e) != 0) ? 1 : 0; }
if (g_bc_l25_en_free && HAK_ENABLED_CACHE(HAKMEM_FEATURE_BIGCACHE) && hdr->size >= 524288 && hdr->size < 2097152) {
if (hak_bigcache_put(ptr, hdr->size, hdr->alloc_site)) goto done;
}
}
switch (hdr->method) {
case ALLOC_METHOD_POOL: if (HAK_ENABLED_ALLOC(HAKMEM_FEATURE_POOL)) { hkm_ace_stat_mid_free(); hak_pool_free(ptr, hdr->size, hdr->alloc_site); goto done; } break;
case ALLOC_METHOD_L25_POOL: hkm_ace_stat_large_free(); hak_l25_pool_free(ptr, hdr->size, hdr->alloc_site); goto done;
case ALLOC_METHOD_MALLOC: hak_free_route_log("malloc_hdr", ptr); free(raw); break;
case ALLOC_METHOD_MMAP:
#ifdef __linux__
if (HAK_ENABLED_MEMORY(HAKMEM_FEATURE_BATCH_MADVISE) && hdr->size >= BATCH_MIN_SIZE) { hak_batch_add(raw, hdr->size); goto done; }
if (hkm_whale_put(raw, hdr->size) != 0) { hkm_sys_munmap(raw, hdr->size); }
#else
free(raw);
#endif
break;
default: fprintf(stderr, "[hakmem] ERROR: Unknown allocation method: %d\n", hdr->method); break;
}
}
done:
#if HAKMEM_DEBUG_TIMING
HKM_TIME_END(HKM_CAT_HAK_FREE, t0);
#endif
return;
}
#endif // HAK_FREE_API_INC_H