根治修正: unified_cache_refill SEGVAULT + コンパイラ最適化対策
問題:
- リリース版sh8benchでunified_cache_refill+0x46fでSEGVAULT
- コンパイラ最適化により、ヘッダー書き込みとtiny_next_read()の
順序が入れ替わり、破損したポインタをout[]に格納
根本原因:
- ヘッダー書き込みがtiny_next_read()の後にあった
- volatile barrierがなく、コンパイラが自由に順序を変更
- ASan版では最適化が制限されるため問題が隠蔽されていた
修正内容(P1-P3):
P1: unified_cache_refill SEGVAULT修正 (core/front/tiny_unified_cache.c:341-350)
- ヘッダー書き込みをtiny_next_read()の前に移動
- __atomic_thread_fence(__ATOMIC_RELEASE)追加
- コンパイラ最適化による順序入れ替えを防止
P2: 二重書き込み削除 (core/box/tiny_front_cold_box.h:75-82)
- tiny_region_id_write_header()削除
- unified_cache_refillが既にヘッダー書き込み済み
- 不要なメモリ操作を削除して効率化
P3: tiny_next_read()安全性強化 (core/tiny_nextptr.h:73-86)
- __atomic_thread_fence(__ATOMIC_ACQUIRE)追加
- メモリ操作の順序を保証
P4: ヘッダー書き込みデフォルトON (core/tiny_region_id.h - ChatGPT修正)
- g_write_headerのデフォルトを1に変更
- HAKMEM_TINY_WRITE_HEADER=0で旧挙動に戻せる
テスト結果:
✅ unified_cache_refill SEGVAULT: 解消(sh8bench実行可能に)
❌ TLS_SLL_HDR_RESET: まだ発生中(別の根本原因、調査継続)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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));
|
||||
|
||||
Reference in New Issue
Block a user