Files
hakmem/core/box/external_guard_box.h

175 lines
6.8 KiB
C
Raw Normal View History

// 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 <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#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};
// Check if pointer is safe to dereference (mincore-based, optional)
// Returns: 1 if mapped, 0 if not mapped
static inline int external_guard_is_mapped(void* ptr) {
if (!external_guard_mincore_enabled()) {
// Fast path: mincore disabled, assume mapped
return 1;
}
g_external_guard_stats.mincore_checks++;
#ifdef __linux__
unsigned char vec;
void* page = (void*)((uintptr_t)ptr & ~0xFFFUL);
if (mincore(page, 1, &vec) == 0) {
return 1; // Mapped
}
#endif
g_external_guard_stats.mincore_failed++;
return 0; // Not 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
Refactor: Phase 2 Box化 - SuperSlab Lookup Box with multiple contract levels Purpose: Formalize SuperSlab lookup responsibilities with clear safety guarantees Evolution: - Phase 12: UNSAFE mask+dereference (5-10 cycles) → 12% crash rate - Phase 1b: SAFE registry lookup (50-100 cycles) → 0% crash rate - Phase 2: Box化 - multiple contracts (UNSAFE/SAFE/GUARDED) Box Pattern Benefits: 1. Clear Contracts: Each API documents preconditions and guarantees 2. Multiple Levels: Choose speed vs safety based on context 3. Future-Proof: Enables optimizations without breaking existing code API Design: - ss_lookup_unsafe(): 5-10 cycles, requires validated pointer (internal use only) - ss_lookup_safe(): 50-100 cycles, works with arbitrary pointers (recommended) - ss_lookup_guarded(): 100-200 cycles, adds integrity checks (debug only) - ss_fast_lookup(): Backward compatible (→ ss_lookup_safe) Implementation: - Created core/box/superslab_lookup_box.h with full contract documentation - Integrated into core/superslab/superslab_inline.h - ss_lookup_safe() implemented as macro to avoid circular dependency - ss_lookup_guarded() only available in debug builds - Removed conflicting extern declarations from 3 locations Testing: - Build: Success (all warnings resolved) - Crash rate: 0% (50/50 iterations passed) - Backward compatibility: Maintained via ss_fast_lookup() macro Future Optimization Opportunities (documented in Box): - Phase 2.1: Hybrid lookup (try UNSAFE first, fallback to SAFE) - Phase 2.2: Per-thread cache (1-2 cycles hit rate) - Phase 2.3: Hardware-assisted validation (PAC/CPUID) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 08:44:29 +09:00
// 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) {
const char* e = getenv("HAKMEM_EXTERNAL_GUARD_STATS");
g_stats_enable = (e && *e && *e != '0') ? 1 : 0;
}
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