diff --git a/docs/ANALYSIS_SYMPTOM_PROLIFERATION.md b/docs/ANALYSIS_SYMPTOM_PROLIFERATION.md new file mode 100644 index 00000000..a8d8e822 --- /dev/null +++ b/docs/ANALYSIS_SYMPTOM_PROLIFERATION.md @@ -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)*