Fix: CRITICAL double-allocation bug in trc_linear_carve()
Root Cause: trc_linear_carve() used meta->used as cursor, but meta->used decrements on free, causing already-allocated blocks to be re-carved. Evidence: - [LINEAR_CARVE] used=61 batch=1 → block 61 created - (blocks freed, used decrements 62→59) - [LINEAR_CARVE] used=59 batch=3 → blocks 59,60,61 RE-CREATED! - Result: double-allocation → memory corruption → SEGV Fix Implementation: 1. Added TinySlabMeta.carved (monotonic counter, never decrements) 2. Changed trc_linear_carve() to use carved instead of used 3. carved tracks carve progress, used tracks active count Files Modified: - core/superslab/superslab_types.h: Add carved field - core/tiny_refill_opt.h: Use carved in trc_linear_carve() - core/hakmem_tiny_superslab.c: Initialize carved=0 - core/tiny_alloc_fast.inc.h: Add next pointer validation - core/hakmem_tiny_free.inc: Add drain/free validation Test Results: ✅ bench_random_mixed: 950,037 ops/s (no crash) ✅ Fail-fast mode: 651,627 ops/s (with diagnostic logs) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -94,11 +94,17 @@ static inline int sll_refill_batch_from_ss(int class_idx, int max_take) {
|
||||
|
||||
// === P0 Batch Carving Loop ===
|
||||
while (want > 0) {
|
||||
// Calculate slab base for validation (accounts for 2048 offset in slab 0)
|
||||
uintptr_t ss_base = 0;
|
||||
uintptr_t ss_limit = 0;
|
||||
if (tls->ss) {
|
||||
ss_base = (uintptr_t)tls->ss;
|
||||
ss_limit = ss_base + ((size_t)1ULL << tls->ss->lg_size);
|
||||
if (tls->ss && tls->slab_idx >= 0) {
|
||||
uint8_t* slab_base = tiny_slab_base_for(tls->ss, tls->slab_idx);
|
||||
ss_base = (uintptr_t)slab_base;
|
||||
// Limit is end of current slab
|
||||
ss_limit = ss_base + SLAB_SIZE;
|
||||
if (tls->slab_idx == 0) {
|
||||
ss_limit = ss_base + (SLAB_SIZE - SUPERSLAB_SLAB0_DATA_OFFSET);
|
||||
}
|
||||
}
|
||||
// Handle freelist items first (usually 0)
|
||||
TinyRefillChain chain;
|
||||
@ -132,6 +138,17 @@ static inline int sll_refill_batch_from_ss(int class_idx, int max_take) {
|
||||
// Get slab base
|
||||
uint8_t* slab_base = tls->slab_base ? tls->slab_base
|
||||
: tiny_slab_base_for(tls->ss, tls->slab_idx);
|
||||
|
||||
// Diagnostic log (one-shot)
|
||||
static _Atomic int g_carve_log_printed = 0;
|
||||
if (atomic_load(&g_carve_log_printed) == 0 &&
|
||||
atomic_exchange(&g_carve_log_printed, 1) == 0) {
|
||||
fprintf(stderr, "[BATCH_CARVE] cls=%u slab=%d used=%u cap=%u batch=%u base=%p bs=%zu\n",
|
||||
class_idx, tls->slab_idx, meta->used, meta->capacity, batch,
|
||||
(void*)slab_base, bs);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
TinyRefillChain carve;
|
||||
trc_linear_carve(slab_base, bs, meta, batch, &carve);
|
||||
trc_splice_to_sll(class_idx, &carve, &g_tls_sll_head[class_idx], &g_tls_sll_count[class_idx]);
|
||||
|
||||
Reference in New Issue
Block a user