Critical analysis: symptom suppression vs root cause elimination
Assessment of current approach: ✅ Stability achieved (no SIGSEGV) ❌ Symptoms proliferating ([TLS_SLL_NEXT_INVALID], [FREELIST_INVALID], etc.) ❌ Root causes remain untouched (multiple defensive layers accumulating) Warning Signs: - [TLS_SLL_NEXT_INVALID]: Freelist corruption happening frequently - refcount > 0 deferred releases: Memory accumulating - [NORMALIZE_USERPTR]: Pointer conversion bugs widespread Three Root Cause Hypotheses: A. Freelist next corruption (slab_idx calculation? bounds?) B. Pointer conversion inconsistency (user vs base mixing) C. SuperSlab reuse leaving garbage (lifecycle issue) Recommended Investigation Path: 1. Audit slab_index_for() calculation (potential off-by-one) 2. Add persistent prev/next validation to detect freelist corruption 3. Limit class 1 with forced base conversion (isolate userptr source) Key Insight: Current approach: Hide symptoms with layers of guards Better approach: Find and fix root cause (1-3 line fix expected) Risk Assessment: - Current: Stability OK, but memory safety uncertain - Long-term: Memory leak + efficiency degradation likely - Urgency: Move to root cause investigation NOW Timeline for root cause fix: - Task 1: slab_index_for audit (1-2h) - Task 2: freelist detection (1-2h) - Task 3: pointer audit (1h) - Final fix: (1-3 lines) Philosophy: Don't suppress symptoms forever. Find the disease. 🤖 Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
360
docs/ANALYSIS_SYMPTOM_PROLIFERATION.md
Normal file
360
docs/ANALYSIS_SYMPTOM_PROLIFERATION.md
Normal file
@ -0,0 +1,360 @@
|
|||||||
|
# 📊 警告: 対処療法が増殖している (2025-12-03)
|
||||||
|
|
||||||
|
**Status**: 🟡 **CAUTION** - 症状を増やしてる可能性
|
||||||
|
**Commit**: 19ce4c1ac (refcount pinning)
|
||||||
|
**Assessment**: 多層防御は安定性を得たが、根本原因に蓋をしてる
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚨 問題認識
|
||||||
|
|
||||||
|
### 現在の状況
|
||||||
|
|
||||||
|
```
|
||||||
|
✅ sh8bench: 60秒完走(SIGSEGV ゼロ)
|
||||||
|
❌ しかし: [TLS_SLL_NEXT_INVALID] / [UNIFIED_FREELIST_INVALID] が多発
|
||||||
|
❌ つまり: 対処療法で「症状を見えなくしてる」だけ
|
||||||
|
```
|
||||||
|
|
||||||
|
### 対処療法の積み重ね
|
||||||
|
|
||||||
|
| 層 | 対策 | 内容 | 評価 |
|
||||||
|
|----|----|------|------|
|
||||||
|
| 1 | refcount pinning | SuperSlab 解放を遅延 | ⚠️ 治してない |
|
||||||
|
| 2 | release guards | refcount > 0 なら skip | ⚠️ 隠蔽 |
|
||||||
|
| 3 | next validation | 無効pointer を drop | ⚠️ リスト喪失 |
|
||||||
|
| 4 | freelist validation | 無効head を drop | ⚠️ メモリ喪失 |
|
||||||
|
| 5 | early decrement fix | refcount 過剰デクリメント削除 | ⚠️ 延期しただけ |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔍 ログから見える本当の問題
|
||||||
|
|
||||||
|
### パターン1: 無効なスラブインデックス
|
||||||
|
|
||||||
|
```
|
||||||
|
[TLS_SLL_NEXT_INVALID]
|
||||||
|
head slab_idx=56
|
||||||
|
→ next が slab_idx=0x45c相当(範囲外!)
|
||||||
|
```
|
||||||
|
|
||||||
|
**解釈**:
|
||||||
|
- next ポインタが「同一 SuperSlab 内」だが「範囲外」
|
||||||
|
- SuperSlab 内メモリが「スラブ単位で破壊」されてる
|
||||||
|
- または「スラブインデックス計算が間違ってる」
|
||||||
|
|
||||||
|
### パターン2: 別スラブの混入
|
||||||
|
|
||||||
|
```
|
||||||
|
[UNIFIED_FREELIST_INVALID]
|
||||||
|
TLS スラブ(ss=0x…c00000, slab=3)のfreelist
|
||||||
|
→ ブロック pがss+0x1302(他スラブ相当)を指す
|
||||||
|
```
|
||||||
|
|
||||||
|
**解釈**:
|
||||||
|
- freelist の next が「別のスラブ」を指してる
|
||||||
|
- freelist が「スラブ境界を越えてリンク」されてる
|
||||||
|
- または「ポインタ計算が完全に狂ってる」
|
||||||
|
|
||||||
|
### パターン3: userptr の混入
|
||||||
|
|
||||||
|
```
|
||||||
|
[TLS_SLL_NORMALIZE_USERPTR] 多数
|
||||||
|
```
|
||||||
|
|
||||||
|
**解釈**:
|
||||||
|
- userptr(offset +1 したもの)が TLS SLL に push されてる
|
||||||
|
- base pointer として expected なのに user pointer が来てる
|
||||||
|
- 型変換の誤り が多発
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 根本原因の仮説(修正版)
|
||||||
|
|
||||||
|
### 仮説A: Freelist 自体が破壊されてる ⭐⭐⭐
|
||||||
|
|
||||||
|
```c
|
||||||
|
// どこかで freelist の next を誤って上書き?
|
||||||
|
tls_slab->freelist->next = GARBAGE;
|
||||||
|
```
|
||||||
|
|
||||||
|
**証拠**:
|
||||||
|
- [UNIFIED_FREELIST_INVALID] が多発
|
||||||
|
- スラブ境界を越えたポインタ
|
||||||
|
- unified_cache_refill で検出
|
||||||
|
|
||||||
|
**対処療法との関係**:
|
||||||
|
- validation で DROP → ✅ 安定
|
||||||
|
- 但し原因は未解決 → ❌ 対症療法
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 仮説B: Pointer 変換の一貫性崩壊 ⭐⭐⭐
|
||||||
|
|
||||||
|
```c
|
||||||
|
// push 時: user ptr で進む
|
||||||
|
tls_sll_push(user_ptr); // user offset = +1
|
||||||
|
|
||||||
|
// pop 時: base ptr で読む?
|
||||||
|
base = tls_sll_pop(); // base offset = +0
|
||||||
|
offset = base + 1; // 再度 +1 ← 二重適用?
|
||||||
|
```
|
||||||
|
|
||||||
|
**証拠**:
|
||||||
|
- [TLS_SLL_NORMALIZE_USERPTR] の多発
|
||||||
|
- class 1 限定で偏ってる?
|
||||||
|
|
||||||
|
**対処療法との関係**:
|
||||||
|
- refcount pinning で延期 → ❌ 根本じゃない
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 仮説C: Slab Index 計算の誤り ⭐⭐
|
||||||
|
|
||||||
|
```c
|
||||||
|
// slab_idx 計算で off-by-one?
|
||||||
|
int idx = slab_index_for(ss, ptr); // 誤計算 → 0x45c?
|
||||||
|
```
|
||||||
|
|
||||||
|
**証拠**:
|
||||||
|
- next が slab_idx=0x45c(明らかに範囲外)
|
||||||
|
- 同一 SuperSlab 内だが「計算が狂ってる」
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 仮説D: SuperSlab 再利用時のゴミ残し ⭐
|
||||||
|
|
||||||
|
```c
|
||||||
|
// 古い SuperSlab を解放
|
||||||
|
ss_free(ss_old);
|
||||||
|
|
||||||
|
// 新しい ss で同じアドレスが再割当
|
||||||
|
ss_new = ss_alloc(); // ss_old と同じアドレス
|
||||||
|
// → 古い freelist が残ってる?
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 次の調査(根本を目指す)
|
||||||
|
|
||||||
|
### Task 1: 無効 next の発生源特定 ⭐⭐⭐(**優先度最高**)
|
||||||
|
|
||||||
|
**実行内容**:
|
||||||
|
```bash
|
||||||
|
# [TLS_SLL_NEXT_INVALID] ログから:
|
||||||
|
# 1. head slab_idx を記録
|
||||||
|
# 2. next が指すアドレス (p) から slab_idx_expected を逆算
|
||||||
|
# 3. 実際の slab_index_for(ss, p) と比較
|
||||||
|
|
||||||
|
# 例:
|
||||||
|
# head p=0x... slab_idx=56
|
||||||
|
# next p=0x... slab_idx_expected=0x45c(範囲外)
|
||||||
|
# → slab_index_for() が何を返すか?
|
||||||
|
```
|
||||||
|
|
||||||
|
**期待成果**:
|
||||||
|
- slab_index_for() が間違ってるのか
|
||||||
|
- freelist が壊れてるのか
|
||||||
|
- 別の問題か
|
||||||
|
|
||||||
|
### Task 2: Freelist 破壊の瞬間検出 ⭐⭐⭐(**優先度最高**)
|
||||||
|
|
||||||
|
**実行内容**:
|
||||||
|
```c
|
||||||
|
// tiny_free_local_box に恒常的な prev 検証を追加:
|
||||||
|
// push 時に:
|
||||||
|
// prev_meta->next == current?
|
||||||
|
// current_meta->prev == prev?
|
||||||
|
//
|
||||||
|
// prev が合わないなら即座に:
|
||||||
|
// fprintf(stderr, "[FREELIST_CORRUPTION_DETECTED] ...");
|
||||||
|
// freelist を drop
|
||||||
|
```
|
||||||
|
|
||||||
|
**期待成果**:
|
||||||
|
- freelist が「いつ、どのタイミングで」破壊されるか
|
||||||
|
- どのコード経路で壊れるのか
|
||||||
|
|
||||||
|
### Task 3: userptr 混入源の絞込 ⭐⭐
|
||||||
|
|
||||||
|
**実行内容**:
|
||||||
|
```c
|
||||||
|
// クラス1限定で、TLS SLL push 前に強制base化:
|
||||||
|
hak_base_ptr_t base = ptr_user_to_base(ptr, class_idx);
|
||||||
|
if (!hak_base_is_valid(base)) {
|
||||||
|
// A/B test: drop か error か
|
||||||
|
fprintf(stderr, "[CLASS1_INVALID_BASE] ptr=%p", ptr);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**期待成果**:
|
||||||
|
- userptr が push されてる頻度
|
||||||
|
- 発生源(どこから来た userptr か)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚠️ 現在の対処療法の限界
|
||||||
|
|
||||||
|
### 何が隠蔽されてるのか
|
||||||
|
|
||||||
|
| 症状 | 対処方法 | 根本原因 |
|
||||||
|
|------|--------|--------|
|
||||||
|
| [TLS_SLL_NEXT_INVALID] | DROP list | freelist 破壊 |
|
||||||
|
| [UNIFIED_FREELIST_INVALID] | DROP head | freelist 破壊 |
|
||||||
|
| [NORMALIZE_USERPTR] | 自動変換 | pointer 変換 bug |
|
||||||
|
| refcount > 0 skip | defer free | lifecycle bug |
|
||||||
|
|
||||||
|
**共通点**: **メモリリーク または 長期的な破壊 の可能性**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔬 科学的接近法
|
||||||
|
|
||||||
|
### ステップ1: 問題の特性化
|
||||||
|
|
||||||
|
**Q**: 無効 next は「計算誤り」か「上書き」か?
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# ログから統計:
|
||||||
|
# - next slab_idx が「特定の値に偏ってる」?
|
||||||
|
# → 計算誤りの可能性
|
||||||
|
# - next slab_idx が「ランダム」?
|
||||||
|
# → 上書きの可能性
|
||||||
|
```
|
||||||
|
|
||||||
|
### ステップ2: 発生源の限定
|
||||||
|
|
||||||
|
**Q**: freelist が壊れるのは「どのコード経路」か?
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# prev 検証で freelist corruption の正確な位置を特定
|
||||||
|
# → その付近の code を audit
|
||||||
|
# → 原因が浮かぶ
|
||||||
|
```
|
||||||
|
|
||||||
|
### ステップ3: 根本修正
|
||||||
|
|
||||||
|
**Q**: 修正は「1行」か「10行」か?
|
||||||
|
|
||||||
|
```
|
||||||
|
対処療法: +3 層(refcount, validation, drop)
|
||||||
|
根本修正: -1 何か(freelist 計算 OR pointer 変換)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📈 現在の実装の危険性
|
||||||
|
|
||||||
|
### 1. Refcount 遅延解放
|
||||||
|
|
||||||
|
```
|
||||||
|
✅ SIGSEGV は防ぐ
|
||||||
|
⚠️ メモリ: refcount > 0 で永遠に free されない
|
||||||
|
⚠️ 結果: メモリリーク蓄積
|
||||||
|
```
|
||||||
|
|
||||||
|
**リスク**: 長時間実行で RSS が増え続ける
|
||||||
|
|
||||||
|
### 2. Freelist DROP
|
||||||
|
|
||||||
|
```
|
||||||
|
✅ 破損伝播は防ぐ
|
||||||
|
⚠️ メモリ: DROP されたブロックは回収されない
|
||||||
|
⚠️ 結果: Freelist 喪失 → 割り当て効率低下
|
||||||
|
```
|
||||||
|
|
||||||
|
**リスク**: 長期実行でメモリ枯渇
|
||||||
|
|
||||||
|
### 3. Next Validation DROP
|
||||||
|
|
||||||
|
```
|
||||||
|
✅ リスト遍走のクラッシュは防ぐ
|
||||||
|
⚠️ メモリ: リスト全体が失われる可能性
|
||||||
|
⚠️ 結果: 大量のメモリが「未割り当て」状態
|
||||||
|
```
|
||||||
|
|
||||||
|
**リスク**: メモリ使用効率が低下
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 推奨される進め方
|
||||||
|
|
||||||
|
### 今すぐやるべき(根本重視)
|
||||||
|
|
||||||
|
**Task 1A**: slab_index_for() の完全監査
|
||||||
|
- 計算ロジック正確か?
|
||||||
|
- off-by-one ないか?
|
||||||
|
- boundary check は十分?
|
||||||
|
|
||||||
|
**Task 2A**: freelist→next の被上書き監視
|
||||||
|
- prev/next 一貫性チェック追加
|
||||||
|
- 破壊を「検知」「修復」から「予防」へ
|
||||||
|
|
||||||
|
**Task 3A**: pointer 変換の audit
|
||||||
|
- user ↔ base 変換が一貫してるか
|
||||||
|
- クラス別に間違いないか
|
||||||
|
|
||||||
|
### 並行してやるべき(デバッグ)
|
||||||
|
|
||||||
|
**Metrics 収集**:
|
||||||
|
- [TLS_SLL_NEXT_INVALID] の発生頻度
|
||||||
|
- [FREELIST_INVALID] の発生頻度
|
||||||
|
- [NORMALIZE_USERPTR] の発生頻度
|
||||||
|
- → パターン認識
|
||||||
|
|
||||||
|
**Memory 監視**:
|
||||||
|
- RSS の増加率(対処療法の影響)
|
||||||
|
- refcount > 0 の SuperSlab 数
|
||||||
|
- dropped freelist の総バイト数
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📌 結論
|
||||||
|
|
||||||
|
### 現状の評価
|
||||||
|
|
||||||
|
```
|
||||||
|
✅ 安定性: 達成(SIGSEGV ゼロ)
|
||||||
|
❌ 健全性: 低下(対処療法の積み重ね)
|
||||||
|
❌ 根本原因: 未解決(症状だけ見えなくしてる)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 危険信号
|
||||||
|
|
||||||
|
```
|
||||||
|
⚠️ [TLS_SLL_NEXT_INVALID] が「多発」
|
||||||
|
→ freelist が頻繁に破壊されてる
|
||||||
|
|
||||||
|
⚠️ refcount > 0 のスラブが増殖
|
||||||
|
→ メモリが「解放待ち」で蓄積
|
||||||
|
|
||||||
|
⚠️ [NORMALIZE_USERPTR] の多数発生
|
||||||
|
→ pointer 変換の根本問題が複数ある
|
||||||
|
```
|
||||||
|
|
||||||
|
### 推奨アクション
|
||||||
|
|
||||||
|
```
|
||||||
|
現在: 「症状を隠蔽して安定性を得た」
|
||||||
|
次へ: 「根本原因を特定して健全性を回復」
|
||||||
|
|
||||||
|
Timeline:
|
||||||
|
Task 1: slab_index_for() audit (1-2h)
|
||||||
|
Task 2: freelist corruption detection (1-2h)
|
||||||
|
Task 3: pointer 変換 audit (1h)
|
||||||
|
↓
|
||||||
|
根本原因の最終特定(1h)
|
||||||
|
↓
|
||||||
|
根本修正(1-3 lines)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Assessment**: 今は「安定性優先」から「健全性重視」へシフトする時期。
|
||||||
|
対処療法の層数が増えすぎる前に、根本原因に向き合おう。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Document created: 2025-12-03*
|
||||||
|
*Analysis: Symptoms are being suppressed, not cured*
|
||||||
|
*Risk Level: MEDIUM (stability achieved, but long-term viability uncertain)*
|
||||||
Reference in New Issue
Block a user