diff --git a/core/box/carve_push_box.c b/core/box/carve_push_box.c index 4fe52eb9..ace1534e 100644 --- a/core/box/carve_push_box.c +++ b/core/box/carve_push_box.c @@ -12,6 +12,7 @@ #include "capacity_box.h" // box_cap_has_room() #include "tls_sll_box.h" // tls_sll_push() #include "tiny_next_ptr_box.h" // tiny_next_write() +#include "tiny_header_box.h" // Header Box: Single Source of Truth for header operations #include "../tiny_refill_opt.h" // TinyRefillChain, trc_linear_carve() #include "../tiny_box_geometry.h" // tiny_stride_for_class(), tiny_slab_base_for_geometry() @@ -193,10 +194,8 @@ uint32_t box_carve_and_push_with_freelist(int class_idx, uint32_t want) { // CRITICAL FIX: Restore header BEFORE pushing to TLS SLL // Freelist blocks may have stale data at offset 0 - // (same fix as in tiny_superslab_alloc.inc.h:159-169) -#if HAKMEM_TINY_HEADER_CLASSIDX - *(uint8_t*)p = HEADER_MAGIC | (class_idx & HEADER_CLASS_MASK); -#endif + // Uses Header Box API (C1-C6 only; C0/C7 skip) + tiny_header_write_if_preserved(p, class_idx); if (!tls_sll_push(class_idx, p, sll_cap)) { // Rollback diff --git a/core/box/tiny_header_box.h b/core/box/tiny_header_box.h new file mode 100644 index 00000000..232df6d1 --- /dev/null +++ b/core/box/tiny_header_box.h @@ -0,0 +1,185 @@ +// tiny_header_box.h - Header Box: Single Source of Truth for Header Operations +// +// Design Principles: +// 1. All header logic flows from tiny_nextptr.h specification +// 2. Encapsulates "which classes preserve headers" knowledge +// 3. Eliminates hardcoded class_idx checks (class_idx != 7, etc.) +// 4. Provides type-safe header read/write/validate operations +// +// Background: +// - C0 (8B): next_off=0 → header overwritten by next pointer +// - C1-C6 (16B-1024B): next_off=1 → header preserved in freelist +// - C7 (2048B): next_off=0 → header overwritten by next pointer +// +// Migration: +// ❌ FORBIDDEN: class_idx != 7, class_idx == 0 || class_idx == 7 +// ❌ FORBIDDEN: *(uint8_t*)base = HEADER_MAGIC | ... +// ✅ USE: tiny_class_preserves_header(class_idx) +// ✅ USE: tiny_header_write_if_preserved(base, class_idx) +// ✅ USE: tiny_header_validate(base, class_idx, ...) + +#ifndef TINY_HEADER_BOX_H +#define TINY_HEADER_BOX_H + +#include +#include +#include "../hakmem_build_flags.h" +#include "../tiny_nextptr.h" +#include "../tiny_region_id.h" + +// ============================================================================ +// Core Predicate: Does this class preserve headers in freelist? +// ============================================================================ +// +// This is the SINGLE SOURCE OF TRUTH for header preservation logic. +// All code must use this instead of hardcoded class_idx checks. +// +// Implementation: +// - Delegates to tiny_next_off() to avoid duplicating logic +// - next_off=0 → header overwritten by next pointer → false +// - next_off!=0 → header preserved → true +// +// Returns: +// true - C1-C6: Header preserved at offset 0, next at offset 1 +// false - C0, C7: Header overwritten by next pointer at offset 0 + +static inline bool tiny_class_preserves_header(int class_idx) { +#if HAKMEM_TINY_HEADER_CLASSIDX + // Delegate to tiny_nextptr.h specification (Single Source of Truth) + // next_off=0 → header overwritten (C0, C7) + // next_off=1 → header preserved (C1-C6) + return tiny_next_off(class_idx) != 0; +#else + // Headers disabled globally + (void)class_idx; + return false; +#endif +} + +// ============================================================================ +// Header Write (Conditional - for freelist/TLS SLL operations) +// ============================================================================ +// +// Writes header ONLY if this class preserves headers. +// For C0/C7, writing header is pointless (next pointer will overwrite it). +// +// Use this when: +// - Pushing blocks to TLS SLL +// - Moving blocks from freelist to TLS SLL +// - Splicing chains into TLS SLL +// +// DO NOT use this for: +// - Allocation path (use tiny_header_write_for_alloc instead) + +static inline void tiny_header_write_if_preserved(void* base, int class_idx) { +#if HAKMEM_TINY_HEADER_CLASSIDX + if (tiny_class_preserves_header(class_idx)) { + *(uint8_t*)base = HEADER_MAGIC | (class_idx & HEADER_CLASS_MASK); + } +#else + (void)base; + (void)class_idx; +#endif +} + +// ============================================================================ +// Header Validate (Conditional - for TLS SLL pop operations) +// ============================================================================ +// +// Validates header ONLY if this class preserves headers. +// For C0/C7, validation is impossible (next pointer is stored at offset 0). +// +// Arguments: +// base - BASE pointer (not user pointer) +// class_idx - Expected class index +// out_got - [optional] Store actual header byte read +// out_expect- [optional] Store expected header byte +// +// Returns: +// true - Header valid OR class doesn't preserve headers (C0/C7) +// false - Header mismatch (corruption detected) +// +// Use this when: +// - Popping blocks from TLS SLL +// - Validating freelist integrity + +static inline bool tiny_header_validate(const void* base, int class_idx, + uint8_t* out_got, uint8_t* out_expect) { +#if HAKMEM_TINY_HEADER_CLASSIDX + // C0/C7: Validation impossible (next pointer stored at offset 0) + if (!tiny_class_preserves_header(class_idx)) { + return true; // Always valid (no header to check) + } + + // C1-C6: Validate header + uint8_t got = *(const uint8_t*)base; + uint8_t expect = HEADER_MAGIC | (class_idx & HEADER_CLASS_MASK); + + if (out_got) *out_got = got; + if (out_expect) *out_expect = expect; + + return got == expect; +#else + (void)base; + (void)class_idx; + (void)out_got; + (void)out_expect; + return true; +#endif +} + +// ============================================================================ +// Header Write (Unconditional - for allocation path) +// ============================================================================ +// +// ALWAYS writes header, regardless of class. +// For C0/C7, header will be overwritten when block enters freelist, +// but must be valid when returned to user. +// +// Use this ONLY in allocation path: +// - HAK_RET_ALLOC_BLOCK macro +// - HAK_RET_ALLOC_BLOCK_TRACED macro +// - Before returning block to user +// +// DO NOT use this for: +// - Freelist operations (use tiny_header_write_if_preserved) +// - TLS SLL operations (use tiny_header_write_if_preserved) + +static inline void tiny_header_write_for_alloc(void* base, int class_idx) { +#if HAKMEM_TINY_HEADER_CLASSIDX + *(uint8_t*)base = HEADER_MAGIC | (class_idx & HEADER_CLASS_MASK); +#else + (void)base; + (void)class_idx; +#endif +} + +// ============================================================================ +// Header Read (for diagnostics/debugging) +// ============================================================================ +// +// Reads header byte without validation. +// Returns -1 if headers disabled or class doesn't preserve headers. +// +// Use this for: +// - Diagnostics +// - Debug logging +// - Corruption analysis +// +// DO NOT use this for: +// - Validation (use tiny_header_validate) + +static inline int tiny_header_read(const void* base, int class_idx) { +#if HAKMEM_TINY_HEADER_CLASSIDX + if (!tiny_class_preserves_header(class_idx)) { + return -1; // No header to read + } + return (int)(*(const uint8_t*)base); +#else + (void)base; + (void)class_idx; + return -1; +#endif +} + +#endif // TINY_HEADER_BOX_H diff --git a/core/box/tls_sll_box.h b/core/box/tls_sll_box.h index 0c48d26d..e44f111b 100644 --- a/core/box/tls_sll_box.h +++ b/core/box/tls_sll_box.h @@ -36,6 +36,7 @@ #include "../hakmem_super_registry.h" #include "../superslab/superslab_inline.h" #include "tiny_next_ptr_box.h" +#include "tiny_header_box.h" // Header Box: Single Source of Truth for header operations // Per-thread debug shadow: last successful push base per class (release-safe) static __thread void* s_tls_sll_last_push[TINY_NUM_CLASSES] = {0}; @@ -359,11 +360,10 @@ static inline bool tls_sll_push_impl(int class_idx, void* ptr, uint32_t capacity return false; } -#if HAKMEM_TINY_HEADER_CLASSIDX - // C0-C6: Restore header (offset=1 layout). C7: skip (offset=0 - header overwritten by next). + // Header restoration using Header Box (C1-C6 only; C0/C7 skip) // Safe mode (HAKMEM_TINY_SLL_SAFEHEADER=1): never overwrite header; reject on magic mismatch. // Default mode: restore expected header. - if (class_idx != 7) { + if (tiny_class_preserves_header(class_idx)) { static int g_sll_safehdr = -1; static int g_sll_ring_en = -1; // optional ring trace for TLS-SLL anomalies if (__builtin_expect(g_sll_safehdr == -1, 0)) { @@ -376,8 +376,8 @@ static inline bool tls_sll_push_impl(int class_idx, void* ptr, uint32_t capacity } // ptr is BASE pointer, header is at ptr+0 uint8_t* b = (uint8_t*)ptr; - uint8_t expected = (uint8_t)(HEADER_MAGIC | (class_idx & HEADER_CLASS_MASK)); - uint8_t got_pre = *b; + uint8_t got_pre, expected; + tiny_header_validate(b, class_idx, &got_pre, &expected); if (__builtin_expect(got_pre != expected, 0)) { tls_sll_log_hdr_mismatch(class_idx, ptr, got_pre, expected, "push_preheader"); } @@ -395,10 +395,9 @@ static inline bool tls_sll_push_impl(int class_idx, void* ptr, uint32_t capacity } else { PTR_TRACK_TLS_PUSH(b, class_idx); PTR_TRACK_HEADER_WRITE(b, expected); - *b = expected; + tiny_header_write_if_preserved(b, class_idx); } } -#endif tls_sll_debug_guard(class_idx, ptr, "push"); @@ -557,14 +556,13 @@ static inline bool tls_sll_pop_impl(int class_idx, void** out, const char* where tls_sll_debug_guard(class_idx, base, "pop"); -#if HAKMEM_TINY_HEADER_CLASSIDX - // C0-C6: Header validation (offset=1). C7: skip (offset=0 - header overwritten by next). - if (class_idx != 7) { - uint8_t got = *(uint8_t*)base; - uint8_t expect = (uint8_t)(HEADER_MAGIC | (class_idx & HEADER_CLASS_MASK)); + // Header validation using Header Box (C1-C6 only; C0/C7 skip) + if (tiny_class_preserves_header(class_idx)) { + uint8_t got, expect; PTR_TRACK_TLS_POP(base, class_idx); + bool valid = tiny_header_validate(base, class_idx, &got, &expect); PTR_TRACK_HEADER_READ(base, got); - if (__builtin_expect(got != expect, 0)) { + if (__builtin_expect(!valid, 0)) { #if !HAKMEM_BUILD_RELEASE fprintf(stderr, "[TLS_SLL_POP] CORRUPTED HEADER cls=%d base=%p got=0x%02x expect=0x%02x\n", @@ -599,7 +597,6 @@ static inline bool tls_sll_pop_impl(int class_idx, void** out, const char* where #endif } } -#endif // Read next via Box API. void* next; @@ -699,14 +696,8 @@ static inline uint32_t tls_sll_splice(int class_idx, tls_sll_debug_guard(class_idx, chain_head, "splice_head"); -#if HAKMEM_TINY_HEADER_CLASSIDX - // Restore header defensively on each node we touch (C0-C6 only; C7 uses offset=0). - if (class_idx != 7) { - uint8_t* b = (uint8_t*)chain_head; - uint8_t expected = (uint8_t)(HEADER_MAGIC | (class_idx & HEADER_CLASS_MASK)); - *b = expected; - } -#endif + // Restore header defensively on each node we touch (C1-C6 only; C0/C7 skip) + tiny_header_write_if_preserved(chain_head, class_idx); while (moved < to_move) { tls_sll_debug_guard(class_idx, tail, "splice_traverse"); @@ -727,13 +718,8 @@ static inline uint32_t tls_sll_splice(int class_idx, break; } -#if HAKMEM_TINY_HEADER_CLASSIDX - if (class_idx != 7) { - uint8_t* b = (uint8_t*)next; - uint8_t expected = (uint8_t)(HEADER_MAGIC | (class_idx & HEADER_CLASS_MASK)); - *b = expected; - } -#endif + // Restore header on each traversed node (C1-C6 only; C0/C7 skip) + tiny_header_write_if_preserved(next, class_idx); tail = next; moved++; diff --git a/core/hakmem_tiny_free.inc b/core/hakmem_tiny_free.inc index a0cf484b..66a6327b 100644 --- a/core/hakmem_tiny_free.inc +++ b/core/hakmem_tiny_free.inc @@ -7,6 +7,7 @@ #include "box/free_publish_box.h" #include "box/tls_sll_box.h" // Box TLS-SLL: C7-safe push/pop/splice #include "box/tiny_next_ptr_box.h" // Box API: next pointer read/write +#include "box/tiny_header_box.h" // Header Box: Single Source of Truth for header operations #include "tiny_region_id.h" // HEADER_MAGIC, HEADER_CLASS_MASK for freelist header restoration #include "mid_tcache.h" #include "front/tiny_heap_v2.h" @@ -73,10 +74,8 @@ static inline void tiny_drain_freelist_to_sll_once(SuperSlab* ss, int slab_idx, // CRITICAL FIX: Restore header BEFORE pushing to TLS SLL // Freelist blocks may have stale data at offset 0 - // (same fix as in box_carve_and_push_with_freelist and tiny_superslab_alloc.inc.h) -#if HAKMEM_TINY_HEADER_CLASSIDX - *(uint8_t*)p = HEADER_MAGIC | (class_idx & HEADER_CLASS_MASK); -#endif + // Uses Header Box API (C1-C6 only; C0/C7 skip) + tiny_header_write_if_preserved(p, class_idx); // Use Box TLS-SLL API (C7-safe push) // Note: C7 already rejected at line 34, so this always succeeds