diff --git a/core/superslab/superslab_inline.h b/core/superslab/superslab_inline.h index 6e81573a..f741c2aa 100644 --- a/core/superslab/superslab_inline.h +++ b/core/superslab/superslab_inline.h @@ -15,6 +15,12 @@ extern _Atomic uint64_t g_ss_active_dec_calls; // Purpose: Replace expensive hak_super_lookup() with O(1) mask calculation // Invariant: All SuperSlabs are aligned to at least SUPERSLAB_SIZE_MIN (1MB) // Cost: ~5-10 cycles (vs 50-100 cycles for registry lookup) +// +// ⚠️ SAFETY: Only use when pointer is ALREADY VALIDATED as Tiny allocation! +// This function masks to 1MB boundary and reads memory at that address. +// If the masked address is unmapped, it will SEGFAULT. +// Safe to use: After header magic (0xA0) validation in LARSON_FIX paths +// NOT safe: In tiny_free_fast() or other paths with arbitrary pointers static inline SuperSlab* ss_fast_lookup(void* ptr) { if (__builtin_expect(!ptr, 0)) return NULL; diff --git a/core/tiny_free_fast.inc.h b/core/tiny_free_fast.inc.h index e3fb54d3..6188873f 100644 --- a/core/tiny_free_fast.inc.h +++ b/core/tiny_free_fast.inc.h @@ -215,11 +215,12 @@ static inline void tiny_free_fast(void* ptr) { } // 1. SuperSlab-backed tiny pointer? if (__builtin_expect(g_use_superslab != 0, 1)) { - // Phase 12 optimization: Use fast mask-based lookup instead of registry - // ss_fast_lookup does: mask + magic check + range check (~5-10 cycles vs 50-100) - void* base = (void*)((uint8_t*)ptr - 1); // Convert USER → BASE first - SuperSlab* ss = ss_fast_lookup(base); - if (__builtin_expect(ss != NULL, 1)) { + // NOTE: Use safe hak_super_lookup here (not ss_fast_lookup) because + // tiny_free_fast() can receive arbitrary pointers without prior validation. + // ss_fast_lookup masks to 1MB boundary and reads magic - would crash on unmapped memory. + SuperSlab* ss = hak_super_lookup(ptr); + if (__builtin_expect(ss != NULL && ss->magic == SUPERSLAB_MAGIC, 0)) { + void* base = (void*)((uint8_t*)ptr - 1); // Convert USER → BASE int slab_idx = slab_index_for(ss, base); uint32_t self_tid = tiny_self_u32();