Phase 15: Box BenchMeta separation + ExternalGuard debug + investigation report
- Implement Box BenchMeta pattern in bench_random_mixed.c (BENCH_META_CALLOC/FREE) - Add enhanced debug logging to external_guard_box.h (caller tracking, FG classification) - Document investigation in PHASE15_BUG_ANALYSIS.md Issue: Page-aligned MIDCAND pointer not in SuperSlab registry → ExternalGuard → crash Hypothesis: May be pre-existing SuperSlab bug (not Phase 15-specific) Next: Test in Phase 14-C to verify
This commit is contained in:
@ -1,4 +1,5 @@
|
||||
// hak_free_api.inc.h — Box: hak_free_at() implementation
|
||||
// Phase 15: Box Separation - One-way routing (FG → Domain boxes → ExternalGuard)
|
||||
#ifndef HAK_FREE_API_INC_H
|
||||
#define HAK_FREE_API_INC_H
|
||||
|
||||
@ -6,7 +7,8 @@
|
||||
#include "hakmem_tiny_superslab.h" // For SUPERSLAB_MAGIC, SuperSlab
|
||||
#include "../tiny_free_fast_v2.inc.h" // Phase 7: Header-based ultra-fast free
|
||||
#include "../ptr_trace.h" // Debug: pointer trace immediate dump on libc fallback
|
||||
#include "front_gate_classifier.h" // Box FG: Centralized pointer classification
|
||||
#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)
|
||||
|
||||
#ifdef HAKMEM_POOL_TLS_PHASE1
|
||||
#include "../pool_tls.h"
|
||||
@ -119,26 +121,22 @@ void hak_free_at(void* ptr, size_t size, hak_callsite_t site) {
|
||||
return;
|
||||
}
|
||||
|
||||
// ========== Box FG: Single Point of Classification ==========
|
||||
// Classify pointer once using Front Gate (safe header probe + Registry fallback)
|
||||
// This eliminates all scattered ptr-1 reads and centralizes classification logic
|
||||
ptr_classification_t classification = classify_ptr(ptr);
|
||||
// ========== Phase 15: Box FG V2 Classification ==========
|
||||
// One-way routing: FG → Domain boxes → ExternalGuard
|
||||
// Box FG V2: Ultra-fast 1-byte header classification (no mincore, no registry)
|
||||
fg_classification_t fg = fg_classify_domain(ptr);
|
||||
hak_free_route_log(fg_domain_name(fg.domain), ptr);
|
||||
|
||||
// Route based on classification result
|
||||
switch (classification.kind) {
|
||||
case PTR_KIND_TINY_HEADER: {
|
||||
// C0-C6: Has 1-byte header, class_idx already determined by Front Gate
|
||||
// Fast path: Use class_idx directly without SuperSlab lookup
|
||||
hak_free_route_log("tiny_header", ptr);
|
||||
switch (fg.domain) {
|
||||
case FG_DOMAIN_TINY: {
|
||||
// Fast path: Tiny (C0-C7) with 1-byte header (0xa0 | class_idx)
|
||||
#if HAKMEM_TINY_HEADER_CLASSIDX
|
||||
// Use ultra-fast free path with pre-determined class_idx
|
||||
if (__builtin_expect(hak_tiny_free_fast_v2(ptr), 1)) {
|
||||
#if !HAKMEM_BUILD_RELEASE
|
||||
hak_free_v2_track_fast();
|
||||
#endif
|
||||
goto done;
|
||||
}
|
||||
// Fallback to slow path if TLS cache full
|
||||
#if !HAKMEM_BUILD_RELEASE
|
||||
hak_free_v2_track_slow();
|
||||
#endif
|
||||
@ -147,45 +145,68 @@ void hak_free_at(void* ptr, size_t size, hak_callsite_t site) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
case PTR_KIND_TINY_HEADERLESS: {
|
||||
// C7: Headerless 1KB blocks, SuperSlab + slab_idx provided by Registry
|
||||
// Medium path: Use Registry result, no header read needed
|
||||
hak_free_route_log("tiny_headerless", ptr);
|
||||
hak_tiny_free(ptr);
|
||||
goto done;
|
||||
}
|
||||
|
||||
#ifdef HAKMEM_POOL_TLS_PHASE1
|
||||
case PTR_KIND_POOL_TLS: {
|
||||
// Pool TLS: 8KB-52KB allocations with 0xb0 magic
|
||||
hak_free_route_log("pool_tls", ptr);
|
||||
case FG_DOMAIN_POOL: {
|
||||
// Pool TLS: 8KB-52KB allocations with 1-byte header (0xb0 | class_idx)
|
||||
pool_free(ptr);
|
||||
goto done;
|
||||
}
|
||||
#endif
|
||||
|
||||
case PTR_KIND_UNKNOWN:
|
||||
default: {
|
||||
// Not Tiny or Pool - check 16-byte AllocHeader (Mid/Large/malloc/mmap)
|
||||
// This is the slow path for large allocations
|
||||
break; // Fall through to header dispatch below
|
||||
}
|
||||
case FG_DOMAIN_MIDCAND:
|
||||
case FG_DOMAIN_EXTERNAL:
|
||||
// Fall through to registry lookup + AllocHeader dispatch
|
||||
break;
|
||||
}
|
||||
|
||||
// ========== Slow Path: 16-byte AllocHeader Dispatch ==========
|
||||
// Handle Mid/Large allocations (malloc/mmap/Pool/L25)
|
||||
// Note: All Tiny allocations (C0-C7) already handled by Front Gate above
|
||||
|
||||
// Mid/L25 headerless経路
|
||||
// ========== Mid/L25/Tiny Registry Lookup (Headerless) ==========
|
||||
// MIDCAND: Could be Mid/Large/C7, needs registry lookup
|
||||
{
|
||||
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; }
|
||||
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; }
|
||||
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;
|
||||
}
|
||||
}
|
||||
// PHASE 15: C7 (1KB headerless) registry lookup
|
||||
// Box FG V2 cannot classify C7 (no header), so use registry
|
||||
{
|
||||
SuperSlab* ss = hak_super_lookup(ptr);
|
||||
if (ss && ss->magic == SUPERSLAB_MAGIC) {
|
||||
hak_free_route_log("tiny_c7_registry", ptr);
|
||||
hak_tiny_free(ptr);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 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など)
|
||||
|
||||
Reference in New Issue
Block a user