// 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_layout_box.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_user_offset() from tiny_layout_box.h // - offset=0 → header overwritten by next pointer → false // - offset!=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_layout_box.h specification (Single Source of Truth) // user_offset=0 → header overwritten (C0, C7) // user_offset=1 → header preserved (C1-C6) return tiny_user_offset(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