diff --git a/core/box/tls_sll_box.h b/core/box/tls_sll_box.h index 58f0167d..8537723d 100644 --- a/core/box/tls_sll_box.h +++ b/core/box/tls_sll_box.h @@ -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)", where ? where : "(null)"); ptr_trace_dump_now("tls_sll_dup"); - // Treat as already free; do not push again. - return true; + // ABORT to get backtrace showing exact double-free location + abort(); } void* next; PTR_NEXT_READ("tls_sll_scan", class_idx, scan, 0, next); diff --git a/core/tiny_superslab_alloc.inc.h b/core/tiny_superslab_alloc.inc.h index 9a9ec60c..d5f37e1e 100644 --- a/core/tiny_superslab_alloc.inc.h +++ b/core/tiny_superslab_alloc.inc.h @@ -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_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;