Phase E1-CORRECT: Fix USER/BASE pointer conversion bugs in slab_index_for calls

CRITICAL BUG FIX: Phase E1 introduced 1-byte headers for ALL size classes (C0-C7),
changing the pointer contract. However, many locations still called slab_index_for()
with USER pointers (storage+1) instead of BASE pointers (storage), causing off-by-one
slab index calculations that corrupted memory.

Root Cause:
- USER pointer = BASE + 1 (returned by malloc, points past header)
- BASE pointer = storage start (where 1-byte header is written)
- slab_index_for() expects BASE pointer for correct slab boundary calculations
- Passing USER pointer → wrong slab_idx → wrong metadata → freelist corruption

Impact Before Fix:
- bench_random_mixed crashes at ~14K iterations with SEGV
- Massive C7 alignment check failures (wrong slab classification)
- Memory corruption from writing to wrong slab freelists

Fixes Applied (8 locations):

1. core/hakmem_tiny_free.inc:137
   - Added USER→BASE conversion before slab_index_for()

2. core/hakmem_tiny_ultra_simple.inc:148
   - Added USER→BASE conversion before slab_index_for()

3. core/tiny_free_fast.inc.h:220
   - Added USER→BASE conversion before slab_index_for()

4-5. core/tiny_free_magazine.inc.h:126,315
   - Added USER→BASE conversion before slab_index_for() (2 locations)

6. core/box/free_local_box.c:14,22,62
   - Added USER→BASE conversion before slab_index_for()
   - Fixed delta calculation to use BASE instead of USER
   - Fixed debug logging to use BASE instead of USER

7. core/hakmem_tiny.c:448,460,473 (tiny_debug_track_alloc_ret)
   - Added USER→BASE conversion before slab_index_for() (2 calls)
   - Fixed delta calculation to use BASE instead of USER
   - This function is called on EVERY allocation in debug builds

Results After Fix:
 bench_random_mixed stable up to 66K iterations (~4.7x improvement)
 C7 alignment check failures eliminated (was: 100% failure rate)
 Front Gate "Unknown" classification dropped to 0% (was: 1.67%)
 No segfaults for workloads up to ~33K allocations

Remaining Issue:
 Segfault still occurs at iteration 66152 (allocs=33137, frees=33014)
   - Different bug from USER/BASE conversion issues
   - Likely capacity/boundary condition (further investigation needed)

Testing:
- bench_random_mixed_hakmem 1K-66K iterations: PASS
- bench_random_mixed_hakmem 67K+ iterations: FAIL (different bug)
- bench_fixed_size_hakmem 200K iterations: PASS

🤖 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-13 05:21:36 +09:00
parent 6552bb5d86
commit 855ea7223c
6 changed files with 113 additions and 71 deletions

View File

@ -440,12 +440,14 @@ extern int g_use_superslab;
#if !HAKMEM_BUILD_RELEASE
static inline void tiny_debug_track_alloc_ret(int cls, void* ptr) {
if (!ptr) return;
// ✅ Phase E1-CORRECT: ptr is USER pointer, convert to BASE
void* base_ptr = ptr ? (void*)((uint8_t*)ptr - 1) : NULL;
if (g_use_superslab && __builtin_expect(tiny_refill_failfast_level() >= 2, 0)) {
SuperSlab* ss = hak_super_lookup(ptr);
if (!(ss && ss->magic == SUPERSLAB_MAGIC)) {
tiny_failfast_abort_ptr("alloc_ret_lookup", ss, -1, ptr, "lookup_fail");
} else {
int slab_idx = slab_index_for(ss, ptr);
int slab_idx = slab_index_for(ss, base_ptr);
if (slab_idx < 0) {
tiny_failfast_abort_ptr("alloc_ret_slabidx", ss, slab_idx, ptr, "slab_idx_mismatch");
} else {
@ -455,7 +457,7 @@ static inline void tiny_debug_track_alloc_ret(int cls, void* ptr) {
}
size_t blk = g_tiny_class_sizes[cls];
uintptr_t base = (uintptr_t)tiny_slab_base_for(ss, slab_idx);
uintptr_t delta = (uintptr_t)ptr - base;
uintptr_t delta = (uintptr_t)base_ptr - base;
if (blk == 0 || (delta % blk) != 0) {
tiny_failfast_abort_ptr("alloc_ret_align", ss, slab_idx, ptr, "misaligned");
} else if (delta / blk >= ss->slabs[slab_idx].capacity) {
@ -468,7 +470,7 @@ static inline void tiny_debug_track_alloc_ret(int cls, void* ptr) {
if (!g_use_superslab) return;
SuperSlab* ss = hak_super_lookup(ptr);
if (!(ss && ss->magic == SUPERSLAB_MAGIC)) return;
int slab_idx = slab_index_for(ss, ptr);
int slab_idx = slab_index_for(ss, base_ptr);
if (slab_idx >= 0) {
tiny_remote_track_on_alloc(ss, slab_idx, ptr, "alloc_ret", 0);
}