Fix: SuperSlab guess loop & header magic SEGV (random_mixed/mid_large_mt)
## Problem bench_random_mixed_hakmem and bench_mid_large_mt_hakmem crashed with SEGV: - random_mixed: Exit 139 (SEGV) ❌ - mid_large_mt: Exit 139 (SEGV) ❌ - Larson: 838K ops/s ✅ (worked fine) Error: Unmapped memory dereference in free path ## Root Causes (2 bugs found by Ultrathink Task) ### Bug 1: Guess Loop (core/box/hak_free_api.inc.h:92-95) ```c for (int lg=21; lg>=20; lg--) { SuperSlab* guess=(SuperSlab*)((uintptr_t)ptr & ~mask); if (guess && guess->magic==SUPERSLAB_MAGIC) { // ← SEGV // Dereferences unmapped memory } } ``` ### Bug 2: Header Magic Check (core/box/hak_free_api.inc.h:115) ```c void* raw = (char*)ptr - HEADER_SIZE; AllocHeader* hdr = (AllocHeader*)raw; if (hdr->magic != HAKMEM_MAGIC) { // ← SEGV // Dereferences unmapped memory if ptr has no header } ``` **Why SEGV:** - Registry lookup fails (allocation not from SuperSlab) - Guess loop calculates 1MB/2MB aligned address - No memory mapping validation - Dereferences unmapped memory → SEGV **Why Larson worked but random_mixed failed:** - Larson: All from SuperSlab → registry hit → never reaches guess loop - random_mixed: Diverse sizes (8-4096B) → registry miss → enters buggy paths **Why LD_PRELOAD worked:** - hak_core_init.inc.h:119-121 disables SuperSlab by default - → SS-first path skipped → buggy code never executed ## Fix (2-part) ### Part 1: Remove Guess Loop File: core/box/hak_free_api.inc.h:92-95 - Deleted unsafe guess loop (4 lines) - If registry lookup fails, allocation is not from SuperSlab ### Part 2: Add Memory Safety Check File: core/hakmem_internal.h:277-294 ```c static inline int hak_is_memory_readable(void* addr) { unsigned char vec; return mincore(addr, 1, &vec) == 0; // Check if mapped } ``` File: core/box/hak_free_api.inc.h:115-131 ```c if (!hak_is_memory_readable(raw)) { // Not accessible → route to appropriate handler // Prevents SEGV on unmapped memory goto done; } // Safe to dereference now AllocHeader* hdr = (AllocHeader*)raw; ``` ## Verification | Test | Before | After | Result | |------|--------|-------|--------| | random_mixed (2KB) | ❌ SEGV | ✅ 2.22M ops/s | 🎉 Fixed | | random_mixed (4KB) | ❌ SEGV | ✅ 2.58M ops/s | 🎉 Fixed | | Larson 4T | ✅ 838K | ✅ 838K ops/s | ✅ No regression | **Performance Impact:** 0% (mincore only on fallback path) ## Investigation - Complete analysis: SEGV_ROOT_CAUSE_COMPLETE.md - Fix report: SEGV_FIX_REPORT.md - Previous investigation: SEGFAULT_INVESTIGATION_REPORT.md 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -274,6 +274,25 @@ static inline void* hak_alloc_mmap_impl(size_t size) {
|
||||
#endif
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// Memory Safety Helpers
|
||||
// ===========================================================================
|
||||
|
||||
// hak_is_memory_readable: Check if memory address is accessible before dereferencing
|
||||
// CRITICAL FIX (2025-11-07): Prevents SEGV when checking header magic on unmapped memory
|
||||
static inline int hak_is_memory_readable(void* addr) {
|
||||
#ifdef __linux__
|
||||
unsigned char vec;
|
||||
// mincore returns 0 if page is mapped, -1 (ENOMEM) if not
|
||||
// This is a lightweight check (~50-100 cycles) only used on fallback path
|
||||
return mincore(addr, 1, &vec) == 0;
|
||||
#else
|
||||
// Non-Linux: assume accessible (conservative fallback)
|
||||
// TODO: Add platform-specific checks for BSD, macOS, Windows
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// Header Helpers (with NULL safety)
|
||||
// ===========================================================================
|
||||
|
||||
Reference in New Issue
Block a user