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:
@ -24,6 +24,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
#include "front_gate_v2.h" // Phase 15: For fg_classification_t types
|
||||
|
||||
// ENV control: mincore enable/disable
|
||||
static inline int external_guard_mincore_enabled(void) {
|
||||
@ -87,8 +88,34 @@ static inline int external_guard_try_free(void* ptr) {
|
||||
g_external_guard_stats.total_calls++;
|
||||
|
||||
if (external_guard_log_enabled()) {
|
||||
fprintf(stderr, "[ExternalGuard] ptr=%p (call #%lu)\n",
|
||||
ptr, g_external_guard_stats.total_calls);
|
||||
// PHASE 15: Track caller address for debugging (ChatGPT advice)
|
||||
void* caller0 = __builtin_return_address(0);
|
||||
void* caller1 = __builtin_return_address(1);
|
||||
fprintf(stderr, "[ExternalGuard] ptr=%p offset_in_page=0x%lx (call #%lu)\n",
|
||||
ptr, (uintptr_t)ptr & 0xFFF, g_external_guard_stats.total_calls);
|
||||
fprintf(stderr, "[ExternalGuard] Stack: [0]=%p [1]=%p\n", caller0, caller1);
|
||||
|
||||
// Debug: Read header at ptr-1
|
||||
if ((uintptr_t)ptr >= 4096 && ((uintptr_t)ptr & 0xFFF) != 0) {
|
||||
uint8_t header = *((uint8_t*)ptr - 1);
|
||||
fprintf(stderr, "[ExternalGuard] header at ptr-1 = 0x%02x (magic=0x%02x class=%d)\n",
|
||||
header, header & 0xf0, header & 0x0f);
|
||||
}
|
||||
|
||||
// Debug: Check if this looks like a HAKMEM allocation
|
||||
extern SuperSlab* hak_super_lookup(void*);
|
||||
SuperSlab* ss = hak_super_lookup(ptr);
|
||||
fprintf(stderr, "[ExternalGuard] hak_super_lookup(ptr) = %p\n", (void*)ss);
|
||||
if (ss) {
|
||||
fprintf(stderr, "[ExternalGuard] HAKMEM SS FOUND! ptr=%p ss=%p magic=0x%x class=%d\n",
|
||||
ptr, (void*)ss, ss->magic, ss->slabs ? ss->slabs[0].class_idx : -1);
|
||||
}
|
||||
|
||||
// Debug: Check FrontGate classification (types defined in front_gate_v2.h)
|
||||
fg_classification_t fg = fg_classify_domain(ptr);
|
||||
const char* domain_name[] = {"TINY", "POOL", "MIDCAND", "EXTERNAL"};
|
||||
fprintf(stderr, "[ExternalGuard] FrontGate classification: domain=%s class_idx=%d\n",
|
||||
domain_name[fg.domain], fg.class_idx);
|
||||
}
|
||||
|
||||
// Safety check: is memory mapped?
|
||||
|
||||
@ -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