Files
hakmem/docs/ANALYSIS_SYMPTOM_PROLIFERATION.md
Moe Charm (CI) 9dbe008f13 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>
2025-12-04 03:09:28 +09:00

9.0 KiB
Raw Blame History

📊 警告: 対処療法が増殖している (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] 多数

解釈:

  • userptroffset +1 したもの)が TLS SLL に push されてる
  • base pointer として expected なのに user pointer が来てる
  • 型変換の誤り が多発

🎯 根本原因の仮説(修正版)

仮説A: Freelist 自体が破壊されてる

// どこかで freelist の next を誤って上書き?
tls_slab->freelist->next = GARBAGE;

証拠:

  • [UNIFIED_FREELIST_INVALID] が多発
  • スラブ境界を越えたポインタ
  • unified_cache_refill で検出

対処療法との関係:

  • validation で DROP → 安定
  • 但し原因は未解決 → 対症療法

仮説B: Pointer 変換の一貫性崩壊

// 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 計算の誤り

// slab_idx 計算で off-by-one?
int idx = slab_index_for(ss, ptr);  // 誤計算 → 0x45c?

証拠:

  • next が slab_idx=0x45c明らかに範囲外
  • 同一 SuperSlab 内だが「計算が狂ってる」

仮説D: SuperSlab 再利用時のゴミ残し

// 古い SuperSlab を解放
ss_free(ss_old);

// 新しい ss で同じアドレスが再割当
ss_new = ss_alloc();  // ss_old と同じアドレス
// → 古い freelist が残ってる?

📋 次の調査(根本を目指す)

Task 1: 無効 next の発生源特定 優先度最高

実行内容:

# [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 破壊の瞬間検出 優先度最高

実行内容:

// 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 混入源の絞込

実行内容:

// クラス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 は「計算誤り」か「上書き」か?

# ログから統計:
# - next slab_idx が「特定の値に偏ってる」?
#   → 計算誤りの可能性
# - next slab_idx が「ランダム」?
#   → 上書きの可能性

ステップ2: 発生源の限定

Q: freelist が壊れるのは「どのコード経路」か?

# 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)