// external_guard_box.h - Box ExternalGuard: Last Resort Safety Check // Purpose: Handle pointers not recognized by Tiny/Pool/Mid boxes // Design: ChatGPT consultation Phase 15 - Box Separation // // Responsibilities: // 1. mincore safety check (ENV controlled for debug) // 2. AllocHeader dispatch (for LD_PRELOAD / external allocations) // 3. Logging (detect Box Tiny/Pool/Mid misses) // // ENV Flags: // - HAKMEM_EXTERNAL_GUARD_MINCORE=0 # Default: OFF (bench optimization) // - HAKMEM_EXTERNAL_GUARD_MINCORE=1 # Debug: ON (safety check) // - HAKMEM_EXTERNAL_GUARD_LOG=0 # Default: Silent // - HAKMEM_EXTERNAL_GUARD_LOG=1 # Debug: Log all calls // // Expected behavior: // - Bench workload: Called 0-10 times (all hakmem managed) // - If called frequently: Box Tiny/Pool/Mid has leak! #ifndef HAK_BOX_EXTERNAL_GUARD_H #define HAK_BOX_EXTERNAL_GUARD_H #include #include #include #include #include "../hakmem_stats_master.h" // Phase 4d: Master stats control #include "front_gate_v2.h" // Phase 15: For fg_classification_t types #include "ss_slab_meta_box.h" // Phase 3d-A: SlabMeta Box boundary // ENV control: mincore enable/disable static inline int external_guard_mincore_enabled(void) { static int g_enabled = -1; if (g_enabled == -1) { const char* e = getenv("HAKMEM_EXTERNAL_GUARD_MINCORE"); g_enabled = (e && *e == '1') ? 1 : 0; // Default: OFF } return g_enabled; } // ENV control: logging static inline int external_guard_log_enabled(void) { static int g_enabled = -1; if (g_enabled == -1) { const char* e = getenv("HAKMEM_EXTERNAL_GUARD_LOG"); g_enabled = (e && *e == '1') ? 1 : 0; // Default: OFF } return g_enabled; } // Statistics typedef struct { uint64_t total_calls; uint64_t mincore_checks; uint64_t mincore_failed; uint64_t alloc_header_dispatch; uint64_t unknown_ptr; } external_guard_stats_t; static __thread external_guard_stats_t g_external_guard_stats = {0}; // Phase 3 (2025-11-29): mincore removed - assume all pointers are mapped // Returns: Always 1 (mapped) // // Note: This is a debug/diagnostic function. In production, we rely on: // - SuperSlab registry for Tiny allocations (Phase 1b/2) // - Headers for Mid/Large allocations // - FrontGate classifier for routing static inline int external_guard_is_mapped(void* ptr) { (void)ptr; // Unused return 1; // Always assume mapped } // External guard entry point // Contract: // - Input: ptr (unknown origin) // - Output: 1 if handled (freed), 0 if unrecognized (caller must handle) // - Side effect: May call libc free, or return 0 for caller fallback static inline int external_guard_try_free(void* ptr) { g_external_guard_stats.total_calls++; if (external_guard_log_enabled()) { // 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 // Note: hak_super_lookup() is defined in hakmem_super_registry.h (included transitively) 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_slab_meta_class_idx_get(ss, 0) : -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); } // Phase 15 FIX: CONSERVATIVE unknown pointer handling // CRITICAL: If we reached ExternalGuard, ALL hakmem lookups failed: // - Box Tiny: TLS SLL miss // - Box Pool: Pool TLS miss // - Box Mid: Mid registry miss // - Box L25: L25 registry miss // - SuperSlab registry: lookup miss // // This pointer is UNKNOWN origin. It could be: // A) hakmem pointer that failed lookup (registry bug/collision) // B) External pointer (__libc_malloc, static data, etc.) // // SAFEST ACTION: Do NOT free it (leak vs crash tradeoff). // Delegating to __libc_free(A) will crash. Leaking (B) is acceptable. g_external_guard_stats.unknown_ptr++; if (external_guard_log_enabled()) { int is_mapped = external_guard_is_mapped(ptr); fprintf(stderr, "[ExternalGuard] WARNING: Unknown pointer %p (mincore=%s) - IGNORED (leak prevention)\n", ptr, is_mapped ? "MAPPED" : "UNMAPPED"); } // Return 1 (handled) to prevent wrapper from calling __libc_free() return 1; } // Print statistics (called at program exit) static inline void external_guard_print_stats(void) { static int g_stats_enable = -1; if (g_stats_enable == -1) { g_stats_enable = hak_stats_check("HAKMEM_EXTERNAL_GUARD_STATS", "guard"); } if (!g_stats_enable) return; fprintf(stderr, "\n=== Box ExternalGuard Statistics ===\n"); fprintf(stderr, "Total calls: %lu\n", g_external_guard_stats.total_calls); fprintf(stderr, "mincore checks: %lu\n", g_external_guard_stats.mincore_checks); fprintf(stderr, "mincore failed: %lu\n", g_external_guard_stats.mincore_failed); fprintf(stderr, "AllocHeader dispatch:%lu\n", g_external_guard_stats.alloc_header_dispatch); fprintf(stderr, "Unknown ptrs: %lu\n", g_external_guard_stats.unknown_ptr); if (g_external_guard_stats.total_calls > 100) { fprintf(stderr, "\n⚠️ WARNING: ExternalGuard called %lu times!\n", g_external_guard_stats.total_calls); fprintf(stderr, " This suggests Box Tiny/Pool/Mid is missing pointers.\n"); fprintf(stderr, " Enable HAKMEM_EXTERNAL_GUARD_LOG=1 to debug.\n"); } fprintf(stderr, "=====================================\n\n"); } #endif // HAK_BOX_EXTERNAL_GUARD_H