diff --git a/core/box/tls_sll_drain_box.h b/core/box/tls_sll_drain_box.h index 6806010c..a8a2da7b 100644 --- a/core/box/tls_sll_drain_box.h +++ b/core/box/tls_sll_drain_box.h @@ -179,20 +179,14 @@ static inline uint32_t tiny_tls_sll_drain(int class_idx, uint32_t batch_size) { drained++; - // CRITICAL: Check if slab became empty and release to shared pool - // (This logic is in tiny_superslab_free.inc.h:223-236) - if (meta->used == 0) { - // Debug: Log when used reaches 0 (slab becomes empty) - if (g_debug) { - fprintf(stderr, "[TLS_SLL_DRAIN] EMPTY: class=%d ss=%p slab=%d (meta->used=0) -> releasing to pool\n", - class_idx, (void*)ss, slab_idx); - } - - // Release empty slab to shared pool - // This will eventually free the SuperSlab and add to LRU cache - extern void shared_pool_release_slab(SuperSlab* ss, int slab_idx); - shared_pool_release_slab(ss, slab_idx); - } + // BUG FIX: DO NOT release slab here even if meta->used == 0 + // Reason: Other blocks from the same slab may still be queued in TLS SLL + // waiting to be drained. Releasing the slab prematurely causes: + // 1. SuperSlab reused for different class + // 2. hak_super_lookup() returns NULL for remaining blocks + // 3. TLS_SLL_POP_INVALID errors and corruption + // Solution: Let LRU eviction and normal lifecycle handle empty slab release. + // Empty slabs will naturally be reclaimed when SuperSlab is idle. } if (g_debug && drained > 0) { diff --git a/core/tiny_nextptr.h b/core/tiny_nextptr.h index 5fa5c90f..264f31ac 100644 --- a/core/tiny_nextptr.h +++ b/core/tiny_nextptr.h @@ -46,11 +46,12 @@ // Compute freelist next-pointer offset within a block for the given class. static inline __attribute__((always_inline)) size_t tiny_next_off(int class_idx) { #if HAKMEM_TINY_HEADER_CLASSIDX - // Phase E1-CORRECT REVISED (C7 corruption fix): - // Class 0 → offset 0 (8B block、header後に8Bポインタは入らない) - // Class 1-7 → offset 1 (header保持、nextはheader直後) - // C7も header を保持して class 判別を壊さないことを優先 - return (class_idx == 0) ? 0u : 1u; + // Phase E1-CORRECT FINAL (C7 user data corruption fix): + // Class 0, 7 → offset 0 (freelist中はheader潰す - next pointerをuser dataから保護) + // - C0: 8B block, header後に8Bポインタ入らない (物理制約) + // - C7: 2048B block, nextを base[0] に格納してuser accessible領域から隔離 (設計選択) + // Class 1-6 → offset 1 (header保持 - 十分なpayloadあり、user dataと干渉しない) + return (class_idx == 0 || class_idx == 7) ? 0u : 1u; #else (void)class_idx; return 0u; @@ -78,7 +79,9 @@ static inline __attribute__((always_inline)) void tiny_next_store(void* base, in size_t off = tiny_next_off(class_idx); #if HAKMEM_TINY_HEADER_CLASSIDX - if (class_idx != 0) { + // Only restore header for C1-C6 (offset=1 classes) + // C0, C7 use offset=0, so header will be overwritten by next pointer + if (class_idx != 0 && class_idx != 7) { uint8_t expected = (uint8_t)(HEADER_MAGIC | (class_idx & HEADER_CLASS_MASK)); uint8_t got = *(uint8_t*)base; if (__builtin_expect(got != expected, 0)) {