Larson crash investigation: Add freelist header write + abort() on duplicate
## Changes 1. **TLS SLL duplicate detection** (core/box/tls_sll_box.h:381) - Changed 'return true' to 'abort()' to get backtrace on double-free - Enables precise root cause identification 2. **Freelist header write fix** (core/tiny_superslab_alloc.inc.h:159-169) - Added tiny_region_id_write_header() call in freelist allocation path - Previously only linear carve wrote headers → stale headers on reuse - Now both paths write headers consistently ## Root Cause Analysis Backtrace revealed true double-free pattern: - last_push_from=hak_tiny_free_fast_v2 (freed once) - last_pop_from=(null) (never allocated) - where=hak_tiny_free_fast_v2 (freed again!) Same pointer freed twice WITHOUT reallocation in between. ## Status - Freelist header fix: ✅ Implemented (necessary but not sufficient) - Double-free still occurs: ❌ Deeper investigation needed - Possible causes: User code bug, TLS drain race, remote free issue Next: Investigate allocation/free flow with enhanced tracing
This commit is contained in:
@ -377,8 +377,8 @@ static inline bool tls_sll_push_impl(int class_idx, void* ptr, uint32_t capacity
|
|||||||
g_tls_sll_last_writer[class_idx] ? g_tls_sll_last_writer[class_idx] : "(null)",
|
g_tls_sll_last_writer[class_idx] ? g_tls_sll_last_writer[class_idx] : "(null)",
|
||||||
where ? where : "(null)");
|
where ? where : "(null)");
|
||||||
ptr_trace_dump_now("tls_sll_dup");
|
ptr_trace_dump_now("tls_sll_dup");
|
||||||
// Treat as already free; do not push again.
|
// ABORT to get backtrace showing exact double-free location
|
||||||
return true;
|
abort();
|
||||||
}
|
}
|
||||||
void* next;
|
void* next;
|
||||||
PTR_NEXT_READ("tls_sll_scan", class_idx, scan, 0, next);
|
PTR_NEXT_READ("tls_sll_scan", class_idx, scan, 0, next);
|
||||||
|
|||||||
@ -155,7 +155,18 @@ static inline void* superslab_alloc_from_slab(SuperSlab* ss, int slab_idx) {
|
|||||||
tiny_remote_track_on_alloc(ss, slab_idx, block, "freelist_alloc", 0);
|
tiny_remote_track_on_alloc(ss, slab_idx, block, "freelist_alloc", 0);
|
||||||
tiny_remote_assert_not_remote(ss, slab_idx, block, "freelist_alloc_ret", 0);
|
tiny_remote_assert_not_remote(ss, slab_idx, block, "freelist_alloc_ret", 0);
|
||||||
}
|
}
|
||||||
return block;
|
|
||||||
|
// CRITICAL FIX (Larson double-free): Write header for freelist allocations
|
||||||
|
// Problem: Freelist path was returning BASE without writing header
|
||||||
|
// Result: Stale headers from previous allocations → double-free on next free
|
||||||
|
// Solution: Always write header before returning (same as linear carve path)
|
||||||
|
void* user =
|
||||||
|
#if HAKMEM_TINY_HEADER_CLASSIDX
|
||||||
|
tiny_region_id_write_header(block, meta->class_idx);
|
||||||
|
#else
|
||||||
|
block;
|
||||||
|
#endif
|
||||||
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|||||||
Reference in New Issue
Block a user