// superslab_lookup_box.h - Box: SuperSlab Lookup // Purpose: Provide multiple contract levels for SuperSlab lookup with clear safety guarantees // // Design Philosophy (Box Pattern): // - Single Responsibility: SuperSlab pointer resolution from arbitrary pointers // - Multiple Contracts: UNSAFE (fast), SAFE (recommended), GUARDED (debug) // - Clear Preconditions: Each API documents required invariants // // Background: // - Phase 12: Tried UNSAFE mask+dereference (5-10 cycles) → 12% crash rate // - Phase 1b: Fixed with SAFE registry lookup (50-100 cycles) → 0% crash rate // - Phase 2: Box化 to formalize contracts and enable future optimization // // Performance Trade-offs: // - UNSAFE: ~5-10 cycles, requires validated pointer (internal use only) // - SAFE: ~50-100 cycles, works with arbitrary pointers (recommended) // - GUARDED: ~100-200 cycles, adds integrity checks (debug builds) #pragma once #include #include // Forward declarations to avoid circular include dependency // (superslab_lookup_box.h ↔ hakmem_super_registry.h ↔ hakmem_tiny_superslab.h) typedef struct SuperSlab SuperSlab; typedef struct TinySlabMeta TinySlabMeta; // Constants from hakmem_tiny_superslab.h (copied to avoid include dependency) #ifndef SUPERSLAB_MAGIC #define SUPERSLAB_MAGIC 0xA110CA7EDBEEF000ULL #endif #ifndef SUPERSLAB_SIZE_MIN #define SUPERSLAB_SIZE_MIN (1UL << 20) // 1MB #endif #ifndef SLAB_SIZE #define SLAB_SIZE (64 * 1024) // 64KB #endif // Forward declaration of registry lookup (implemented in hakmem_super_registry.h) SuperSlab* hak_super_lookup(void* ptr); // ============================================================================ // Contract Level 1: UNSAFE - Fast but dangerous (internal use only) // ============================================================================ // // Preconditions: // - ptr MUST be a valid Tiny allocation pointer (already validated) // - ptr MUST be within a mapped SuperSlab region // - Violation of preconditions → SEGFAULT // // Use cases: // - After header magic validation (LARSON_FIX paths) // - Internal paths where pointer origin is known // // Performance: ~5-10 cycles // Safety: ⚠️ UNSAFE - caller must ensure preconditions // static inline SuperSlab* ss_lookup_unsafe(void* ptr) { if (__builtin_expect(!ptr, 0)) return NULL; uintptr_t p = (uintptr_t)ptr; // Step 1: Mask with minimum SuperSlab size (1MB alignment) // Note: 2MB SuperSlabs are also 1MB aligned, so this works for both SuperSlab* ss = (SuperSlab*)(p & ~((uintptr_t)SUPERSLAB_SIZE_MIN - 1u)); // Step 2: Validate magic (quick reject for non-SuperSlab memory) // ⚠️ DANGER: This dereference can SEGFAULT if preconditions not met if (__builtin_expect(ss->magic != SUPERSLAB_MAGIC, 0)) { return NULL; } // Step 3: Range check (ptr must be within this SuperSlab) size_t ss_size = (size_t)1 << ss->lg_size; if (__builtin_expect(p >= (uintptr_t)ss + ss_size, 0)) { return NULL; } return ss; } // ============================================================================ // Contract Level 2: SAFE - Registry-based (recommended) // ============================================================================ // // Preconditions: None (works with arbitrary pointers) // // Guarantees: // - Never dereferences unmapped memory // - Returns NULL for invalid pointers (stack, heap, garbage, etc.) // - Thread-safe (lock-free reads) // // Use cases: // - Free paths with arbitrary pointers (hak_tiny_free_fast_v2) // - External API boundaries // - Default choice for unknown pointer origin // // Performance: ~50-100 cycles (hash table + linear probing) // Safety: ✓ SAFE - guaranteed crash-free // static inline SuperSlab* ss_lookup_safe(void* ptr) { // Delegate to registry-based lookup // This uses hash table + linear probing + atomic validation // Never dereferences arbitrary masked pointer → crash-free return hak_super_lookup(ptr); } // ============================================================================ // Contract Level 3: GUARDED - Full validation (debug builds) // ============================================================================ // // Preconditions: None (works with arbitrary pointers) // // Guarantees: // - All SAFE guarantees // - Additional integrity checks (refcount, slab metadata consistency) // - Verbose logging in debug mode // // Use cases: // - Debugging memory corruption // - Detecting use-after-free // - Validation in test builds // // Performance: ~100-200 cycles (SAFE + extra checks) // Safety: ✓ SAFE + integrity validation // static inline SuperSlab* ss_lookup_guarded(void* ptr) { // Start with safe lookup SuperSlab* ss = ss_lookup_safe(ptr); if (!ss) return NULL; #if !HAKMEM_BUILD_RELEASE // Debug mode: additional integrity checks // Check 1: Refcount sanity uint32_t refcount = atomic_load_explicit(&ss->refcount, memory_order_relaxed); if (refcount == 0 || refcount > 1000000) { fprintf(stderr, "[SS_LOOKUP_GUARDED] WARNING: ptr=%p ss=%p refcount=%u (suspicious)\n", ptr, (void*)ss, refcount); // Don't return NULL - refcount might be in transition } // Check 2: Magic revalidation (detect use-after-free) if (ss->magic != SUPERSLAB_MAGIC) { fprintf(stderr, "[SS_LOOKUP_GUARDED] ERROR: ptr=%p ss=%p magic=%llx (corrupted!)\n", ptr, (void*)ss, (unsigned long long)ss->magic); return NULL; // Corrupted - possibly freed } // Check 3: Active blocks sanity uint32_t active = atomic_load_explicit(&ss->total_active_blocks, memory_order_relaxed); uint32_t capacity = (uint32_t)((1 << ss->lg_size) / SLAB_SIZE) * 254; // Max possible if (active > capacity) { fprintf(stderr, "[SS_LOOKUP_GUARDED] WARNING: ptr=%p ss=%p active=%u capacity=%u (overflow!)\n", ptr, (void*)ss, active, capacity); // Don't return NULL - might be in transition } // Optional: ENV-gated verbose logging static __thread int s_verbose = -1; if (__builtin_expect(s_verbose == -1, 0)) { const char* e = getenv("HAKMEM_SS_LOOKUP_VERBOSE"); s_verbose = (e && *e && *e != '0') ? 1 : 0; } if (s_verbose) { fprintf(stderr, "[SS_LOOKUP_GUARDED] OK: ptr=%p ss=%p refcount=%u active=%u\n", ptr, (void*)ss, refcount, active); } #endif return ss; } // ============================================================================ // Backward Compatibility // ============================================================================ // Legacy API: ss_fast_lookup() → ss_lookup_safe() // All existing callers get SAFE contract (0% crash rate) #define ss_fast_lookup(ptr) ss_lookup_safe(ptr) // ============================================================================ // Usage Guidelines // ============================================================================ // // 1. DEFAULT: Use ss_lookup_safe() // - Safest choice for unknown pointer origin // - 0% crash rate guaranteed // - Performance: 50-100 cycles (acceptable for most paths) // // 2. OPTIMIZATION: Use ss_lookup_unsafe() only if: // - Pointer is already validated (header magic checked) // - Hot path where 50-100 cycles is too slow // - Careful code review + testing required // - Document preconditions clearly // // 3. DEBUGGING: Use ss_lookup_guarded() // - Investigating memory corruption // - Test builds / CI validation // - ENV: HAKMEM_SS_LOOKUP_VERBOSE=1 for logging // // ============================================================================ // Future Optimization Opportunities // ============================================================================ // // 1. Hybrid Lookup (Phase 2.1): // - Try UNSAFE first (optimistic fast path) // - If magic check fails, fallback to SAFE // - Best of both worlds: 5-10 cycles (hit), 50-100 cycles (miss) // // 2. Per-Thread Cache (Phase 2.2): // - Cache last N lookups in TLS (ptr → SuperSlab) // - Hit rate: 80-90% for typical workloads // - Cost: 1-2 cycles (cache hit), 50-100 cycles (miss) // // 3. Hardware-Assisted Validation (Phase 2.3): // - Use x86 CPUID / ARM PAC for pointer tagging // - Validate pointer origin without registry lookup // - Requires kernel support / specific hardware //