274 lines
6.9 KiB
Markdown
274 lines
6.9 KiB
Markdown
|
|
# 180秒クラッシュ修正指示書 (2025-12-04)
|
|||
|
|
|
|||
|
|
**Status**: 未解決(Pre-existing bug, not introduced by Release Guard Box)
|
|||
|
|
|
|||
|
|
**Crash Details**:
|
|||
|
|
- Time to crash: 180秒(安定)
|
|||
|
|
- Root cause: TLS SLL push操作中のSIGSEGV
|
|||
|
|
- Release Guard Box: クラッシュ前に呼ばれていない(別問題)
|
|||
|
|
- Current commit: 1ac502af5 (Release Guard Box)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 📋 調査フロー
|
|||
|
|
|
|||
|
|
### Phase 1: クラッシュポイント特定
|
|||
|
|
|
|||
|
|
**目標**: `SIGSEGV` の正確なアドレスと命令を特定
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 1. gdb でクラッシュ再現
|
|||
|
|
cd /mnt/workdisk/public_share/hakmem
|
|||
|
|
make clean && make RELEASE=0 # デバッグシンボル有効
|
|||
|
|
|
|||
|
|
# 2. gdb 実行
|
|||
|
|
gdb --args bash -c 'env LD_PRELOAD=/mnt/workdisk/public_share/hakmem/libhakmem.so /mnt/workdisk/public_share/hakmem/mimalloc-bench/out/bench/sh8bench'
|
|||
|
|
|
|||
|
|
# 3. gdb 内で:
|
|||
|
|
(gdb) run
|
|||
|
|
# ... 180秒待つ ...
|
|||
|
|
# クラッシュ時に自動停止
|
|||
|
|
|
|||
|
|
# 4. スタックトレース確認
|
|||
|
|
(gdb) bt
|
|||
|
|
(gdb) frame 0
|
|||
|
|
(gdb) disassemble
|
|||
|
|
(gdb) info registers
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**期待される出力**:
|
|||
|
|
- `#0 ... in tiny_alloc_fast_push ...` または
|
|||
|
|
- `#0 ... in tls_sll_push ...` または
|
|||
|
|
- `#0 ... in slab_index_for ...` などのTLS SLL関連
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Phase 2: クラッシュのコンテキスト分析
|
|||
|
|
|
|||
|
|
**目標**: クラッシュ前の状態を理解
|
|||
|
|
|
|||
|
|
```c
|
|||
|
|
// コアの質問:
|
|||
|
|
1. クラッシュしたポインタ (ptr) は何か?
|
|||
|
|
→ gdb: print ptr
|
|||
|
|
→ gdb: x/16x ptr (メモリダンプ)
|
|||
|
|
|
|||
|
|
2. SuperSlab* ss は有効か?
|
|||
|
|
→ gdb: print ss->magic (SUPERSLAB_MAGIC = 0x53535342 であるべき)
|
|||
|
|
→ gdb: print ss->refcount (> 0 であるべき)
|
|||
|
|
|
|||
|
|
3. slab_idx は有効か?
|
|||
|
|
→ gdb: print slab_idx
|
|||
|
|
→ gdb: print ss_slabs_capacity(ss)
|
|||
|
|
|
|||
|
|
4. TinySlabMeta* meta は有効か?
|
|||
|
|
→ gdb: print meta->class_idx
|
|||
|
|
→ gdb: print meta->capacity
|
|||
|
|
→ gdb: print meta->used
|
|||
|
|
|
|||
|
|
5. head ポインタは?
|
|||
|
|
→ gdb: print g_tls_sll[class_idx].head
|
|||
|
|
→ gdb: x/16x g_tls_sll[class_idx].head (メモリダンプ)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Phase 3: Reproducibility 検証
|
|||
|
|
|
|||
|
|
**目標**: クラッシュが100%再現するかを確認
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 環境変数をクリア(過去の診断ログ無効化)
|
|||
|
|
unset HAKMEM_TINY_SLL_NEXTCLS
|
|||
|
|
unset HAKMEM_TINY_SLL_NEXTTAG
|
|||
|
|
unset HAKMEM_TINY_SLL_HEADCLS
|
|||
|
|
unset HAKMEM_DEBUG_COUNTER
|
|||
|
|
unset HAK_DEBUG_LOG_FREQ
|
|||
|
|
|
|||
|
|
# 3回テスト
|
|||
|
|
for i in 1 2 3; do
|
|||
|
|
echo "=== Test $i ==="
|
|||
|
|
timeout 190 env LD_PRELOAD=/mnt/workdisk/public_share/hakmem/libhakmem.so \
|
|||
|
|
/mnt/workdisk/public_share/hakmem/mimalloc-bench/out/bench/sh8bench 2>&1 | tail -20
|
|||
|
|
echo "EXIT_CODE: $?"
|
|||
|
|
done
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**期待される結果**:
|
|||
|
|
- Test 1, 2, 3: すべて ~180秒でクラッシュ(100%再現性)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🔍 疑い容疑者リスト
|
|||
|
|
|
|||
|
|
前セッションの分析から、以下が候補:
|
|||
|
|
|
|||
|
|
### 候補1: TLS SLL next ポインタの破壊
|
|||
|
|
|
|||
|
|
**症状**: `next` が不正なアドレスを指している
|
|||
|
|
|
|||
|
|
**チェック方法**:
|
|||
|
|
```bash
|
|||
|
|
# Phase 2 の gdb コマンドで:
|
|||
|
|
(gdb) print g_tls_sll[class_idx].head->next
|
|||
|
|
# 0x0, NULL, または特定のメモリアドレス?
|
|||
|
|
# 有効な全体メモリ範囲外か?
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**修正アプローチ** (if 原因なら):
|
|||
|
|
- `tls_sll_push_impl()` での next ポインタ設定をチェック
|
|||
|
|
- `tiny_alloc_fast_push()` での pointer conversion をチェック
|
|||
|
|
- メモリバリアの不足?
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 候補2: SuperSlab refcount の不一致
|
|||
|
|
|
|||
|
|
**症状**: refcount が 0 になり、SuperSlab が free されてから TLS SLL が access している
|
|||
|
|
|
|||
|
|
**チェック方法**:
|
|||
|
|
```bash
|
|||
|
|
# Phase 2 の gdb コマンドで:
|
|||
|
|
(gdb) print ss->refcount
|
|||
|
|
# 0 なら??? → Layer 1 (refcount pinning) が機能していない可能性
|
|||
|
|
# > 0 なら OK
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**修正アプローチ** (if 原因なら):
|
|||
|
|
- `tiny_alloc_fast_push()` の atomic_fetch_add を確認
|
|||
|
|
- `tls_sll_pop_impl()` の atomic_fetch_sub を確認
|
|||
|
|
- Race condition?
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 候補3: slab_idx の計算エラー
|
|||
|
|
|
|||
|
|
**症状**: slab_idx が範囲外になり、`ss->slabs[slab_idx]` が不正なメモリを access
|
|||
|
|
|
|||
|
|
**チェック方法**:
|
|||
|
|
```bash
|
|||
|
|
# Phase 2 の gdb コマンドで:
|
|||
|
|
(gdb) print slab_idx
|
|||
|
|
(gdb) print ss_slabs_capacity(ss)
|
|||
|
|
# slab_idx >= capacity? → これが問題
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**修正アプローチ** (if 原因なら):
|
|||
|
|
- `slab_index_for(ss, ptr)` の実装を再確認
|
|||
|
|
- Boundary check の見落とし?
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 候補4: class_idx の不整合
|
|||
|
|
|
|||
|
|
**症状**: TLS SLL[class_idx] が破壊されている
|
|||
|
|
|
|||
|
|
**チェック方法**:
|
|||
|
|
```bash
|
|||
|
|
# Phase 2 の gdb コマンドで:
|
|||
|
|
(gdb) print class_idx
|
|||
|
|
(gdb) print meta->class_idx
|
|||
|
|
# 一致してるか?ズレてるか?
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**修正アプローチ** (if 原因なら):
|
|||
|
|
- `tiny_get_class_from_ss()` の返り値を確認
|
|||
|
|
- class_idx と meta->class_idx の関係を再確認
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 候補5: メモリレイアウトの仮定ずれ
|
|||
|
|
|
|||
|
|
**症状**: sizeof(TinySlabMeta) や stride が変わり、ポインタ計算がズレている
|
|||
|
|
|
|||
|
|
**チェック方法**:
|
|||
|
|
```bash
|
|||
|
|
# gdb で:
|
|||
|
|
(gdb) print sizeof(TinySlabMeta)
|
|||
|
|
(gdb) print sizeof(TinySlab)
|
|||
|
|
(gdb) print sizeof(SuperSlab)
|
|||
|
|
|
|||
|
|
# コンパイル時の定義と一致?
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 📊 デバッグ戦略
|
|||
|
|
|
|||
|
|
### ステップ1: スタックトレース取得(30分)
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
make clean && make RELEASE=0
|
|||
|
|
|
|||
|
|
# gdb でスタックトレース取得
|
|||
|
|
gdb --args bash -c '...'
|
|||
|
|
(gdb) run
|
|||
|
|
# クラッシュ待機
|
|||
|
|
(gdb) bt full
|
|||
|
|
(gdb) frame 0; disassemble
|
|||
|
|
# ファイルに出力
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### ステップ2: コンテキスト分析(1時間)
|
|||
|
|
|
|||
|
|
- gdb で各変数を print
|
|||
|
|
- メモリダンプで破壊パターンを特定
|
|||
|
|
- 前後のメモリ状態を記録
|
|||
|
|
|
|||
|
|
### ステップ3: 仮説検証(2時間)
|
|||
|
|
|
|||
|
|
- 候補ごとに検証コード追加
|
|||
|
|
- 特定のクラスやスレッド数で再現性確認
|
|||
|
|
- ログ出力で実行フロー追跡
|
|||
|
|
|
|||
|
|
### ステップ4: 修正実装(1-3時間)
|
|||
|
|
|
|||
|
|
- 根本原因に応じて修正
|
|||
|
|
- テスト:60秒 → 120秒 → 180秒 → 240秒
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🛠️ 実装チェックリスト
|
|||
|
|
|
|||
|
|
修正時には以下を確認:
|
|||
|
|
|
|||
|
|
- [ ] スタックトレースから特定の関数が明確か
|
|||
|
|
- [ ] 該当ファイルを読んで実装を理解した
|
|||
|
|
- [ ] 候補1-5から最も可能性高い仮説を選んだ
|
|||
|
|
- [ ] 修正方法を3つ以上考えた(安全性が高い順)
|
|||
|
|
- [ ] 修正実装後、180秒テストで確認
|
|||
|
|
- [ ] 240秒テストで追加マージンを確保
|
|||
|
|
- [ ] ドキュメント更新
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 📚 関連ファイル
|
|||
|
|
|
|||
|
|
**主要ファイル**:
|
|||
|
|
- `core/tiny_alloc_fast.inc.h` - tiny_alloc_fast_push (line 879)
|
|||
|
|
- `core/tiny_free_fast.inc.h` - tiny_free_fast (line 195)
|
|||
|
|
- `core/box/tls_sll_box.h` - TLS SLL 実装
|
|||
|
|
- `core/hakmem_tiny_superslab.h` - SuperSlab 定義
|
|||
|
|
|
|||
|
|
**ヘッダ**:
|
|||
|
|
- `core/tiny_atomic.h` - atomic 操作
|
|||
|
|
- `core/slab_handle.h` - slab_index_for()
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🎯 成功判定基準
|
|||
|
|
|
|||
|
|
修正が完了した → 以下をすべてPASS:
|
|||
|
|
|
|||
|
|
- ✅ 180秒テスト: EXIT_CODE 0, SIGSEGV 0件
|
|||
|
|
- ✅ 240秒テスト: EXIT_CODE 0, SIGSEGV 0件
|
|||
|
|
- ✅ スタックトレース: TLS SLL/alloc_fast_push 関連なし
|
|||
|
|
- ✅ ログ: [TLS_SLL_*], [ERROR] 無し
|
|||
|
|
- ✅ メモリ: RSS 安定 (increase < 10%)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
**作成日**: 2025-12-04
|
|||
|
|
**対象**: 180秒クラッシュの修正
|
|||
|
|
|