11 KiB
TLS_SLL_HDR_RESET Root Cause Investigation (Gemini Edition)
背景
hakmemメモリアロケータのsh8benchで[TLS_SLL_HDR_RESET]エラーが継続発生しています。
これまでClaude Code、ChatGPT、Task agentが調査しましたが根治に至っていません。
Geminiに最終調査をお願いします。
現在の状況(2025-12-03 commit 6154e7656)
✅ 解決済み問題
-
unified_cache_refill SEGVAULT (commit
6154e7656)- 根本原因: コンパイラ最適化による操作順序入れ替え
- 修正: ヘッダー書き込みをtiny_next_read()の前に移動 + atomic fence
- 状態: 完全解決、sh8bench実行可能に
-
LRU registry未登録 (commit
4cc2d8add)- 根本原因: LRU pop時にhak_super_register()未呼び出し
- 修正: LRU pop後に明示的に再登録
- 状態: 解決
-
ChatGPTの「8bit右シフト圧縮ポインタ」仮説
- Task agentが否定: 意図的な圧縮スキームは存在しない
- 真の原因: unified_cache_refillのコンパイラ最適化問題(既に解決済み)
❌ 未解決問題
TLS_SLL_HDR_RESET エラー - sh8benchで継続発生
[TLS_SLL_HDR_RESET] cls=1 base=0x71bcf31bd858 got=0x51 expect=0xa1 count=0
- 発生箇所:
core/box/tls_sll_box.h:585(TLS SLL pop時のヘッダー検証失敗) - 期待値:
0xa1(class_idx=1のヘッダーマーカー) - 実際値:
0x51,0x61など(破損) - 動作: SLL全体をリセット(安全だが非効率)
エラーの詳細
ヘッダーフォーマット
期待値: 0xa1
bit 7-4: 0xa (固定マーカー)
bit 3-0: 0x1 (サイズクラスインデックス)
破損パターン
got=0x51: 01010001 (未初期化メモリ?)
got=0x61: 01100001 ('a' ASCII文字?)
got=0x00: 00000000 (mmap zero初期値?)
発生パターン
- ✅ sh8bench: ほぼ毎回発生
- ✅ リリース版: 発生
- ❌ cfrac, larson: 発生しない
- ❓ ASan版: Task agent報告では未再現
これまでの調査と既知の修正
既に修正済みの境界(commit 3c6c76cb1, a94344c1a)
以下の経路でのヘッダー復元は実装済み:
-
box_carve_and_push_with_freelist() (commit
3c6c76cb1)void* p = meta->freelist; meta->freelist = tiny_next_read(class_idx, p); tiny_header_write_if_preserved(p, class_idx); // ← 修正済み if (!tls_sll_push(class_idx, p, sll_cap)) { ... } -
tiny_drain_freelist_to_sll_once() (commit
a94344c1a)void* p = m->freelist; m->freelist = tiny_next_read(class_idx, p); tiny_header_write_if_preserved(p, class_idx); // ← 修正済み if (tls_sll_push(class_idx, HAK_BASE_FROM_RAW(p), sll_capacity)) { ... }
現在の設定(commit 6154e7656)
- ✅ ヘッダー書き込みデフォルトON (
g_write_header=1) - ✅ HAKMEM_TINY_WRITE_HEADER=0 で旧挙動に戻せるA/B切替
Geminiへの調査依頼
調査の焦点
「なぜsh8benchだけでTLS_SLL_HDR_RESETが発生するのか?」
cfrac/larsonでは発生しないことから、sh8bench固有のアクセスパターンに起因する経路がある可能性が高いです。
仮説(優先度順)
仮説1: TLS SLL push時のヘッダー未書き込み(最有力)
コード箇所: core/box/tls_sll_box.h の tiny_tls_sll_push()
確認すべきこと:
-
push時に本当にヘッダーを書き込んでいるか?
*(uint8_t*)raw_base = (uint8_t)(0xa0 | (class_idx & 0x0f)); -
書き込み順序は正しいか?
- next pointer書き込みの前にヘッダー書き込み
- atomic fence有無
-
条件分岐で書き込みをスキップしていないか?
調査方法:
grep -n "static inline.*tiny_tls_sll_push" -A 100 core/box/tls_sll_box.h | \
grep -E "raw_base.*=.*0xa0|class_idx"
仮説2: unified_cache経由の未発見経路
背景:
- unified_cache_refillでヘッダーを書き込み済み(P1修正)
- しかしその後、別の経路でTLS SLLに入る可能性
確認すべきこと:
- unified_cache_refillで返されたポインタがfree時にどの経路を通るか
- その経路でヘッダーが保持されているか
- TLS SLLに入る直前で破損していないか
調査方法:
# unified_cache関連のfree/drain経路
grep -n "unified_cache.*drain\|unified_cache.*free" \
core/front/tiny_unified_cache.c core/box/tiny_front_cold_box.h
仮説3: sh8bench固有のマルチスレッド競合
背景:
- sh8benchは8スレッド並行
- 小さいブロック(class 1など)を高速にalloc/free
確認すべきこと:
- TLS SLL pushがスレッドセーフか
- ヘッダー書き込みとnext pointer書き込みの間に競合窓がないか
__atomic_thread_fenceの配置は適切か
調査方法:
# TLS SLL実装の同期機構確認
grep -n "thread_fence\|atomic\|mutex\|lock" core/box/tls_sll_box.h
具体的な調査手順
Step 1: TLS SLL push実装の精査
cd /mnt/workdisk/public_share/hakmem
# push実装を確認
cat -n core/box/tls_sll_box.h | sed -n '450,550p'
チェックポイント:
*(uint8_t*)raw_base = 0xa0 | clsが実行されているかtiny_class_preserves_header(class_idx)条件は正しいか__atomic_thread_fence(__ATOMIC_RELEASE)があるか- next pointer書き込みより前に実行されているか
Step 2: 詳細ログで経路追跡
# デバッグビルド
find . -name "*.o" -delete && find . -name "*.so" -delete
make shared -j8 EXTRA_CFLAGS="-g -O1"
# リング有効化で実行
HAKMEM_TINY_SLL_RING=1 HAKMEM_DEBUG_LEVEL=3 \
LD_PRELOAD=./libhakmem.so ./mimalloc-bench/out/bench/sh8bench \
2>&1 | tee sh8bench_gemini_debug.log
# push/pop/resetの順序を確認
grep -E "TLS_SLL_PUSH|TLS_SLL_POP|TLS_SLL_HDR_RESET" \
sh8bench_gemini_debug.log | head -100
Step 3: コード修正テスト
TLS SLL push強制ヘッダー書き込みを試してください:
// core/box/tls_sll_box.h の tiny_tls_sll_push() に追加
static inline bool tiny_tls_sll_push(int class_idx, void* raw_base, uint32_t capacity) {
// GEMINI FIX: Always write header before push
#if HAKMEM_TINY_HEADER_CLASSIDX
if (tiny_class_preserves_header(class_idx)) {
*(uint8_t*)raw_base = (uint8_t)(0xa0 | (class_idx & 0x0f));
__atomic_thread_fence(__ATOMIC_RELEASE);
}
#endif
// 既存のpush処理...
}
テスト:
find . -name "*.o" -delete && make shared -j8
# 5回テスト
for i in {1..5}; do
echo "=== Run $i ==="
LD_PRELOAD=./libhakmem.so ./mimalloc-bench/out/bench/sh8bench 2>&1 | \
grep -E "TLS_SLL_HDR_RESET|Total elapsed"
done
Step 4: SAFEHEADER検証
HAKMEM_TINY_SLL_SAFEHEADER=1 HAKMEM_TINY_SLL_VALIDATE_HDR=1 \
HAKMEM_TINY_SLL_RING=1 HAKMEM_DEBUG_LEVEL=3 \
LD_PRELOAD=./libhakmem.so ./mimalloc-bench/out/bench/sh8bench \
2>&1 | tee sh8bench_gemini_safeheader.log
# push時の不正検出
grep -E "TLS_SLL_PUSH_BAD_HDR|TLS_SLL_REJECT" sh8bench_gemini_safeheader.log
期待される成果物
1. 根本原因の特定
以下のいずれかを明確に:
-
パターンA: TLS SLL push時にヘッダー未書き込み
- どの条件でスキップされているか
- 修正箇所の特定
-
パターンB: 未発見の経路が存在
- どの経路か(コールスタック)
- その経路でのヘッダー復元漏れ
-
パターンC: マルチスレッド競合
- 競合が発生する箇所
- atomic fence不足の箇所
2. 修正コード
修正が必要なファイルと具体的なコード変更を提示してください:
// 例: core/box/tls_sll_box.h
// 修正前:
static inline bool tiny_tls_sll_push(...) {
// 既存コード
}
// 修正後:
static inline bool tiny_tls_sll_push(...) {
// GEMINI FIX: ヘッダー復元を追加
#if HAKMEM_TINY_HEADER_CLASSIDX
if (tiny_class_preserves_header(class_idx)) {
*(uint8_t*)raw_base = (uint8_t)(0xa0 | (class_idx & 0x0f));
__atomic_thread_fence(__ATOMIC_RELEASE);
}
#endif
// 既存のpush処理
}
3. テスト結果
修正後のsh8bench実行結果:
# 期待される結果
=== Run 1 ===
Total elapsed time for 8 threads: XX.XX (XXX.XXXX CPU)
# [TLS_SLL_HDR_RESET] なし
=== Run 2 ===
Total elapsed time for 8 threads: XX.XX (XXX.XXXX CPU)
# [TLS_SLL_HDR_RESET] なし
... (10回連続でエラーなし)
重要な調査対象ファイル
最優先:
core/box/tls_sll_box.h- TLS SLL push/pop実装(行450-610)
次点:
core/front/tiny_unified_cache.c- unified cache実装core/box/tiny_front_cold_box.h- cold drain処理core/hakmem_tiny_free.inc- free経路
参考:
core/tiny_region_id.h- ヘッダー書き込み設定core/box/tiny_header_box.h- ヘッダー管理API
環境変数・ビルド方法
デバッグフラグ
HAKMEM_TINY_SLL_RING=1 # TLS SLLイベントログ
HAKMEM_TINY_SLL_VALIDATE_HDR=1 # push時ヘッダー検証
HAKMEM_TINY_SLL_SAFEHEADER=1 # 不正ヘッダーでpush拒否
HAKMEM_DEBUG_LEVEL=3 # 詳細ログ
HAKMEM_TINY_WRITE_HEADER=1 # ヘッダー書き込み強制(既定でON)
ビルド
cd /mnt/workdisk/public_share/hakmem
# クリーンビルド(リリース版)
find . -name "*.o" -delete && find . -name "*.so" -delete
make shared -j8
# デバッグビルド
make shared -j8 EXTRA_CFLAGS="-g -O1 -UHAKMEM_BUILD_RELEASE"
参考資料
関連コミット
6154e7656- unified_cache_refill SEGVAULT根治修正(最新)4cc2d8add- LRU registry未登録修正f7d0d236e- malloc_count最適化(17s→10s)3c6c76cb1- box_carve_and_push_with_freelistヘッダー復元a94344c1a- tiny_drain_freelist_to_sll_onceヘッダー復元
ドキュメント
docs/tls_sll_header_corruption_investigation.md- ChatGPT初回調査docs/tls_sll_hdr_reset_investigation_v2.md- 更新版調査指示書docs/sh8bench_debug_instruction.md- sh8benchデバッグ手順
Geminiへのお願い
-
Step 1-2で原因を特定してください
- 特にTLS SLL push実装の精査が重要です
-
Step 3で修正を実装してください
- 修正後は必ずsh8benchで10回連続テストしてください
-
根治であることを証明してください
- 対処療法ではなく、真の根本原因を解決してください
-
結果を報告してください
- 修正したファイル、変更内容、テスト結果を明記してください
よろしくお願いします!🙏