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>
This commit is contained in:
Moe Charm (CI)
2025-11-29 08:44:29 +09:00
parent dea7ced429
commit 4f2bcb7d32
5 changed files with 349 additions and 20 deletions

View File

@ -11,27 +11,132 @@ void _ss_remote_drain_to_freelist_unsafe(SuperSlab* ss, int slab_idx, TinySlabMe
// Optional debug counter (defined in hakmem_tiny_superslab.c)
extern _Atomic uint64_t g_ss_active_dec_calls;
// ========== Fast SuperSlab Lookup via Registry (Phase 12 fix) ==========
// Purpose: Safe SuperSlab lookup that prevents SEGFAULT on arbitrary pointers
// Original Phase 12: Tried mask+dereference (5-10 cycles) but caused 12% crash rate
// Current Fix: Use registry-based lookup (50-100 cycles) for safety
// ========== SuperSlab Lookup Box (Phase 2: Box化) ==========
// Purpose: Formalize SuperSlab lookup contracts with clear safety guarantees
//
// BUGFIX (2025-11-29): Replaced unsafe mask+dereference with safe registry lookup
// Root Cause: hak_tiny_free_fast_v2() can receive arbitrary pointers (stack, garbage, etc.)
// Mask calculation could produce unmapped addressSEGFAULT on ss->magic read
// Phase 1a: Tried range checks → insufficient (still 10-12% crash rate)
// Phase 1b: Use hak_super_lookup() registry → 0% crash rate expected
// Trade-off: Rollback Phase 12 optimization (5-10x slower) but crash-free
// 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)
//
// Performance comparison:
// - Phase 12 (unsafe): ~5-10 cycles, 12% crash rate
// - Phase 1b (safe): ~50-100 cycles, 0% crash rate
// - Still faster than mincore() syscall (5000-10000 cycles)
// 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
//
// Note: Implemented as macro to avoid circular include dependency
// (superslab_inline.h ↔ hakmem_super_registry.h)
// APIs:
// - ss_lookup_unsafe() : 5-10 cycles, requires validated pointer
// - ss_lookup_safe() : 50-100 cycles, works with arbitrary pointers
// - ss_lookup_guarded() : 100-200 cycles, adds integrity checks
// - ss_fast_lookup() : Backward compatible (→ ss_lookup_safe)
//
// Note: hak_super_lookup() is implemented in hakmem_super_registry.h as static inline
// The circular dependency (this file ↔ hakmem_super_registry.h) is resolved because:
// - hakmem_super_registry.h is included before this file in hakmem_tiny_superslab.h
// - By the time functions here are instantiated, hak_super_lookup() is already defined
// ============================================================================
// 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)
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
//
// Note: Implemented as macro to avoid static/extern declaration conflicts
// hak_super_lookup() is defined in hakmem_super_registry.h
#define ss_fast_lookup(ptr) hak_super_lookup(ptr)
#define ss_lookup_safe(ptr) hak_super_lookup(ptr)
// ============================================================================
// Contract Level 3: GUARDED - Full validation (debug builds only)
// ============================================================================
//
// Note: This API is only available in debug builds to avoid circular dependency issues
// In release builds, use ss_lookup_safe() directly
//
#if !HAKMEM_BUILD_RELEASE
static inline SuperSlab* ss_lookup_guarded(void* ptr)
{
SuperSlab* ss = hak_super_lookup(ptr); // Direct call, not via macro
if (!ss) return NULL;
// Debug mode: additional integrity checks
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);
}
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;
}
return ss;
}
#else
// Release build: ss_lookup_guarded() not available, use ss_lookup_safe() instead
#define ss_lookup_guarded(ptr) ss_lookup_safe(ptr)
#endif
// ============================================================================
// Backward Compatibility
// ============================================================================
// Legacy API: ss_fast_lookup() → ss_lookup_safe()
#define ss_fast_lookup(ptr) ss_lookup_safe(ptr)
// Return maximum number of slabs for this SuperSlab based on lg_size.
static inline int ss_slabs_capacity(SuperSlab* ss)