diff --git a/core/box/tiny_front_cold_box.h b/core/box/tiny_front_cold_box.h index 608fad0d..b1de8596 100644 --- a/core/box/tiny_front_cold_box.h +++ b/core/box/tiny_front_cold_box.h @@ -72,9 +72,10 @@ static inline void* tiny_cold_refill_and_alloc(int class_idx) { return NULL; } - // Success: Write header + return USER pointer + // Success: return USER pointer + // NOTE: Header already written by unified_cache_refill() + // (Removed redundant tiny_region_id_write_header() - P2 fix) #ifdef HAKMEM_TINY_HEADER_CLASSIDX - tiny_region_id_write_header(base, class_idx); return (void*)((char*)base + 1); // USER pointer #else return base; diff --git a/core/front/tiny_unified_cache.c b/core/front/tiny_unified_cache.c index 58f2ef98..2297ab37 100644 --- a/core/front/tiny_unified_cache.c +++ b/core/front/tiny_unified_cache.c @@ -337,6 +337,17 @@ void* unified_cache_refill(int class_idx) { if (m->freelist) { // Freelist pop void* p = m->freelist; + + // ROOT CAUSE FIX: Write header BEFORE tiny_next_read() + // Without this, compiler can reorder header write after out[] assignment + // causing SEGVAULT in release builds (unified_cache_refill+0x46f) + #if HAKMEM_TINY_HEADER_CLASSIDX + *(uint8_t*)p = (uint8_t)(0xa0 | (class_idx & 0x0f)); + + // Prevent compiler from reordering operations + __atomic_thread_fence(__ATOMIC_RELEASE); + #endif + m->freelist = tiny_next_read(class_idx, p); unified_refill_validate_base(class_idx, tls, m, p, @@ -345,11 +356,6 @@ void* unified_cache_refill(int class_idx) { // PageFaultTelemetry: record page touch for this BASE pagefault_telemetry_touch(class_idx, p); - // ✅ CRITICAL: Restore header (overwritten by freelist link) - #if HAKMEM_TINY_HEADER_CLASSIDX - *(uint8_t*)p = (uint8_t)(0xa0 | (class_idx & 0x0f)); - #endif - m->used++; out[produced++] = p; diff --git a/core/tiny_nextptr.h b/core/tiny_nextptr.h index 52763c7d..22472a7f 100644 --- a/core/tiny_nextptr.h +++ b/core/tiny_nextptr.h @@ -68,7 +68,11 @@ static inline __attribute__((always_inline)) void* tiny_next_load(const void* ba if (off == 0) { // Aligned access at base (header無し or C7 freelist時) - return *(void* const*)base; + void* next = *(void* const*)base; + + // P3: Prevent compiler from reordering this load + __atomic_thread_fence(__ATOMIC_ACQUIRE); + return next; } // off != 0: use memcpy to avoid UB on architectures that forbid unaligned loads. @@ -76,6 +80,9 @@ static inline __attribute__((always_inline)) void* tiny_next_load(const void* ba void* next = NULL; const uint8_t* p = (const uint8_t*)base + off; memcpy(&next, p, sizeof(void*)); + + // P3: Prevent compiler from reordering this load + __atomic_thread_fence(__ATOMIC_ACQUIRE); return next; } diff --git a/core/tiny_region_id.h b/core/tiny_region_id.h index be3b010e..5cf99e0a 100644 --- a/core/tiny_region_id.h +++ b/core/tiny_region_id.h @@ -238,16 +238,16 @@ static inline void* tiny_region_id_write_header(void* base, int class_idx) { } while (0); #endif // !HAKMEM_BUILD_RELEASE - // P3: Skip header write when class_map is active (default) - // class_map provides class_idx lookup, so header byte is no longer needed - // ENV: HAKMEM_TINY_WRITE_HEADER=1 to force header write (legacy mode) - // Memory layout preserved: user = base + 1 (1B unused when skipped) + // P3: Header writeをデフォルトON(TLS SLL向けに常時復元、ENVでOFF可能) + // class_map があっても TLS SLL 境界でヘッダーが必要になるため、A/B 切替は + // HAKMEM_TINY_WRITE_HEADER=0 でのみ OFF(旧デフォルト)にする。 + // Memory layout preserved: user = base + 1(ヘッダー領域は常に予約) static int g_write_header = -1; if (__builtin_expect(g_write_header == -1, 0)) { const char* e = getenv("HAKMEM_TINY_WRITE_HEADER"); - g_write_header = (e && *e && *e != '0') ? 1 : 0; + g_write_header = (e && *e && *e == '0') ? 0 : 1; } - if (__builtin_expect(g_write_header, 0)) { + if (__builtin_expect(g_write_header, 1)) { // Legacy mode: write header for debugging or compatibility *header_ptr = HEADER_MAGIC | (class_idx & HEADER_CLASS_MASK); PTR_TRACK_HEADER_WRITE(base, HEADER_MAGIC | (class_idx & HEADER_CLASS_MASK));