// tiny_nextptr.h - Authoritative next-pointer offset/load/store for tiny boxes // // Finalized Phase E1-CORRECT spec (物理制約込み): // // HAKMEM_TINY_HEADER_CLASSIDX != 0 のとき: // // Class 0: // [1B header][7B payload] (total 8B) // → offset 1 に 8B ポインタは入らないため不可能 // → freelist中は header を潰して next を base+0 に格納 // → next_off = 0 // // Class 1〜6: // [1B header][payload >= 8B] // → headerは保持し、next は header直後 base+1 に格納 // → next_off = 1 // // Class 7: // [1B header][payload 2047B] // → C7アップグレード後も header保持、next は base+1 に格納 // → next_off = 1 // // HAKMEM_TINY_HEADER_CLASSIDX == 0 のとき: // // 全クラス headerなし → next_off = 0 // // このヘッダは上記仕様を唯一の真実として提供する。 // すべての tiny freelist / TLS / fast-cache / refill / SLL で // tiny_next_off/tiny_next_load/tiny_next_store を経由すること。 // 直接の *(void**) アクセスやローカルな offset 分岐は使用禁止。 #ifndef TINY_NEXTPTR_H #define TINY_NEXTPTR_H #include #include #include "hakmem_build_flags.h" #include "tiny_region_id.h" // HEADER_MAGIC/HEADER_CLASS_MASK for header repair/logging #include "hakmem_super_registry.h" // hak_super_lookup #include "superslab/superslab_inline.h" // slab_index_for #include #include #include #include // backtrace for rare misalign diagnostics // 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; #else (void)class_idx; return 0u; #endif } // Safe load of next pointer from a block base. static inline __attribute__((always_inline)) void* tiny_next_load(const void* base, int class_idx) { size_t off = tiny_next_off(class_idx); if (off == 0) { // Aligned access at base (header無し or C0/C7 freelist時) return *(void* const*)base; } // off != 0: use memcpy to avoid UB on architectures that forbid unaligned loads. void* next = NULL; const uint8_t* p = (const uint8_t*)base + off; memcpy(&next, p, sizeof(void*)); return next; } // Safe store of next pointer into a block base. static inline __attribute__((always_inline)) void tiny_next_store(void* base, int class_idx, void* next) { size_t off = tiny_next_off(class_idx); #if HAKMEM_TINY_HEADER_CLASSIDX if (class_idx != 0) { uint8_t expected = (uint8_t)(HEADER_MAGIC | (class_idx & HEADER_CLASS_MASK)); uint8_t got = *(uint8_t*)base; if (__builtin_expect(got != expected, 0)) { static _Atomic uint32_t g_next_hdr_diag = 0; uint32_t n = atomic_fetch_add_explicit(&g_next_hdr_diag, 1, memory_order_relaxed); if (n < 16) { fprintf(stderr, "[NXT_HDR_MISMATCH] cls=%d base=%p got=0x%02x expect=0x%02x\n", class_idx, base, got, expected); } } *(uint8_t*)base = expected; // Always restore header before writing next } #endif // Misalignment detector: class stride vs base offset do { static _Atomic uint32_t g_next_misalign_log = 0; extern const size_t g_tiny_class_sizes[]; size_t stride = (class_idx >= 0 && class_idx < 8) ? g_tiny_class_sizes[class_idx] : 0; if (stride > 0) { uintptr_t delta = ((uintptr_t)base) % stride; if (__builtin_expect(delta != 0, 0)) { void* ra = __builtin_return_address(0); const char* sym = "(unknown)"; #ifdef __GLIBC__ do { Dl_info info; if (dladdr(ra, &info) && info.dli_sname) { sym = info.dli_sname; } } while (0); #endif uint32_t n = atomic_fetch_add_explicit(&g_next_misalign_log, 1, memory_order_relaxed); int meta_cls = -1; int slab_idx = -1; struct SuperSlab* ss = NULL; if (class_idx >= 0 && class_idx < 8) { ss = hak_super_lookup(base); if (ss) { slab_idx = slab_index_for(ss, base); if (slab_idx >= 0) { struct TinySlabMeta* m = &ss->slabs[slab_idx]; meta_cls = m->class_idx; } } } if (n < 16) { fprintf(stderr, "[NXT_MISALIGN] cls=%d base=%p stride=%zu delta_mod=%zu next=%p ra=%p fn=%s meta_cls=%d slab_idx=%d ss=%p\n", class_idx, base, stride, (size_t)delta, next, ra, sym, meta_cls, slab_idx, (void*)ss); if (n < 4) { void* bt[8]; int frames = backtrace(bt, 8); backtrace_symbols_fd(bt, frames, fileno(stderr)); } fflush(stderr); } } } } while (0); if (off == 0) { // Aligned access at base. *(void**)base = next; return; } // off != 0: use memcpy for portability / UB-avoidance. uint8_t* p = (uint8_t*)base + off; memcpy(p, &next, sizeof(void*)); } #endif // TINY_NEXTPTR_H