// 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<magic==SUPERSLAB_MAGIC) { int sidx=slab_index_for(guess,ptr); int cap=ss_slabs_capacity(guess); if (sidx>=0&&sidxmagic != 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: When magic is invalid, allocation came from LIBC (NO header) // Therefore ptr IS the allocated address, not raw (ptr - HEADER_SIZE) // MUST use __libc_free to avoid infinite recursion through free() wrapper if (g_invalid_free_mode) { goto done; } else { extern void __libc_free(void*); __libc_free(ptr); 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: // CRITICAL FIX: raw was allocated with __libc_malloc, so free with __libc_free // Using free(raw) would go through wrapper → infinite recursion hak_free_route_log("malloc_hdr", ptr); extern void __libc_free(void*); __libc_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 // CRITICAL FIX: Same as ALLOC_METHOD_MALLOC extern void __libc_free(void*); __libc_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