fix: guard Tiny FG misclass and add fg_tiny_gate box
This commit is contained in:
@ -9,6 +9,7 @@
|
||||
#include "../ptr_trace.h" // Debug: pointer trace immediate dump on libc fallback
|
||||
#include "front_gate_v2.h" // Phase 15: Box FG V2 - 1-byte header classification
|
||||
#include "external_guard_box.h" // Phase 15: Box ExternalGuard - mincore (ENV controlled)
|
||||
#include "fg_tiny_gate_box.h" // Tiny gate guard box (Superslab check)
|
||||
|
||||
#ifdef HAKMEM_POOL_TLS_PHASE1
|
||||
#include "../pool_tls.h"
|
||||
@ -82,6 +83,7 @@ void hak_free_at(void* ptr, size_t size, hak_callsite_t site) {
|
||||
HKM_TIME_START(t0);
|
||||
#endif
|
||||
(void)site; (void)size;
|
||||
int fg_misclass = 0; // Set when FG said Tiny but registry rejects
|
||||
// Optional lightweight trace of early free calls (first few only)
|
||||
#if !HAKMEM_BUILD_RELEASE
|
||||
static int free_trace_en = -1; static _Atomic int free_trace_count = 0;
|
||||
@ -129,6 +131,11 @@ void hak_free_at(void* ptr, size_t size, hak_callsite_t site) {
|
||||
fg_classification_t fg = fg_classify_domain(ptr);
|
||||
hak_free_route_log(fg_domain_name(fg.domain), ptr);
|
||||
|
||||
// Fail-Fast: Tiny判定は Superslab 登録が必須。無ければ MIDCAND に戻す(箱化)。
|
||||
fg_tiny_gate_result_t fg_guard = fg_tiny_gate(ptr, fg);
|
||||
fg = fg_guard.fg;
|
||||
fg_misclass = fg_guard.misclassified;
|
||||
|
||||
switch (fg.domain) {
|
||||
case FG_DOMAIN_TINY: {
|
||||
// Fast path: Tiny (C0-C7) with 1-byte header (0xa0 | class_idx)
|
||||
@ -199,18 +206,6 @@ void hak_free_at(void* ptr, size_t size, hak_callsite_t site) {
|
||||
}
|
||||
}
|
||||
|
||||
// ========== Box ExternalGuard: Last Resort ==========
|
||||
// PHASE 15: Delegate to ExternalGuard (mincore + libc fallback)
|
||||
// Expected: Called 0-10 times in bench (if >100 → box leak!)
|
||||
{
|
||||
if (external_guard_try_free(ptr)) {
|
||||
goto done;
|
||||
}
|
||||
// ExternalGuard failed (unmapped) → skip free (leak)
|
||||
hak_free_route_log("external_guard_skip", ptr);
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Raw header dispatch(mmap/malloc/BigCacheなど)
|
||||
{
|
||||
void* raw = (char*)ptr - HEADER_SIZE;
|
||||
@ -232,14 +227,7 @@ void hak_free_at(void* ptr, size_t size, hak_callsite_t site) {
|
||||
if (!is_mapped) {
|
||||
// Memory not accessible, ptr likely has no header
|
||||
hak_free_route_log("unmapped_header_fallback", ptr);
|
||||
|
||||
// In direct-link mode, try tiny_free (handles headerless Tiny allocs)
|
||||
if (!g_ldpreload_mode && g_invalid_free_mode) {
|
||||
hak_tiny_free(ptr);
|
||||
goto done;
|
||||
}
|
||||
|
||||
// LD_PRELOAD mode: route to libc (might be libc allocation)
|
||||
// Always punt to libc; never route unmapped/unknown pointers to Tiny
|
||||
extern void __libc_free(void*);
|
||||
ptr_trace_dump_now("free_api_libc_invalid_hdr");
|
||||
__libc_free(ptr);
|
||||
@ -259,31 +247,32 @@ void hak_free_at(void* ptr, size_t size, hak_callsite_t site) {
|
||||
// One-shot request-trace to help diagnose SS registry lookups
|
||||
hak_super_reg_reqtrace_dump(ptr);
|
||||
|
||||
// In direct-link mode, try routing to tiny free as best-effort recovery
|
||||
// This handles case #1 where SuperSlab lookup failed but allocation is valid
|
||||
if (!g_ldpreload_mode && g_invalid_free_mode) {
|
||||
// Attempt tiny free (will validate internally and handle gracefully if invalid)
|
||||
hak_free_route_log("invalid_magic_tiny_recovery", ptr);
|
||||
hak_tiny_free(ptr);
|
||||
goto done;
|
||||
// Fail-fast diagnostics: never hand bad headers to Tiny or libc silently
|
||||
SuperSlab* ss_diag = hak_super_lookup(ptr);
|
||||
int slab_diag = ss_diag ? slab_index_for(ss_diag, ptr) : -1;
|
||||
fprintf(stderr,
|
||||
"[INVALID_MAGIC_FREE] ptr=%p magic=0x%X mode=%d ss=%p slab=%d\n",
|
||||
ptr, hdr->magic, g_invalid_free_mode, (void*)ss_diag, slab_diag);
|
||||
tiny_guard_on_invalid(ptr, hdr->magic);
|
||||
|
||||
// If this pointer was a misclassified Tiny header miss, punt to libc to avoid corrupting TLS
|
||||
if (fg_misclass) {
|
||||
fprintf(stderr, "[FREE_MISCLASS_SKIP] ptr=%p hdr=0x%x (ignored to avoid corruption)\n",
|
||||
ptr, hdr->magic);
|
||||
goto done; // leak-safe skip: not our allocation
|
||||
}
|
||||
|
||||
// LD_PRELOAD mode or fallback mode: route to libc
|
||||
// IMPORTANT: Use ptr (not raw), as NO header exists
|
||||
// Never route invalid headers into Tiny; fail-fast by default
|
||||
if (g_invalid_free_mode) {
|
||||
// Skip mode: leak memory (original behavior, but logged)
|
||||
static int leak_warn = 0;
|
||||
if (!leak_warn) {
|
||||
fprintf(stderr, "[hakmem] WARNING: Skipping free of invalid pointer %p (may leak memory)\n", ptr);
|
||||
leak_warn = 1;
|
||||
}
|
||||
goto done;
|
||||
abort();
|
||||
} else {
|
||||
// Fallback mode: route to libc
|
||||
extern void __libc_free(void*);
|
||||
ptr_trace_dump_now("free_api_libc_invalid_magic_fallback");
|
||||
__libc_free(ptr); // Use ptr, not raw!
|
||||
goto done;
|
||||
ptr_trace_dump_now("free_api_invalid_magic_failfast");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
// Phase 5-Step3: Use Mid/Large Config Box (compile-time constant in PGO mode)
|
||||
@ -305,6 +294,8 @@ void hak_free_at(void* ptr, size_t size, hak_callsite_t site) {
|
||||
hak_free_route_log("malloc_hdr", ptr);
|
||||
extern void __libc_free(void*);
|
||||
ptr_trace_dump_now("free_api_libc_malloc_hdr");
|
||||
fprintf(stderr, "[FREE_LIBC_HDR] raw=%p user=%p size=%zu method=%d magic=0x%X\n",
|
||||
raw, ptr, hdr->size, (int)hdr->method, hdr->magic);
|
||||
__libc_free(raw);
|
||||
break;
|
||||
case ALLOC_METHOD_MMAP:
|
||||
|
||||
Reference in New Issue
Block a user