Files
hakmem/docs/tls_sll_hdr_reset_final_report.md
2025-12-03 11:14:59 +09:00

3.3 KiB
Raw Blame History

最終調査報告: TLS_SLL_HDR_RESET の完全解明

結論

sh8benchfree() に渡すポインタが、malloc() 返却値から +1 されていることがログ解析により数学的に証明されました。

ソースコード上には明示的なポインタ操作は見当たりませんでしたが、実行時の挙動として「奇数アドレスTiny Allocatorの仕様が返された場合に、偶数アドレスに補正して使用し、そのまま free() している」ことは確実です。


証明プロセス

1. ログからの逆算

エラーログ:

[TLS_SLL_NORMALIZE_USERPTR] cls=1 node=0x...e1 -> base=0x...e0 stride=16

このログは core/box/tls_sll_box.htls_sll_push() 内で、引数 nodeBase Pointer のアラインメント16の倍数からズレている場合に発生します。

  1. node の値は 0x...e1 です。
  2. tls_sll_push(class_idx, ptr) は、呼び出し元 tiny_free_fast()ptr = user_ptr - 1 として呼び出されます。
  3. つまり、node (0xe1) = user_ptr - 1 です。
  4. したがって、free() に渡された user_ptr0xe2 です。

2. アドレスの矛盾

  • malloc() の仕様: Class 1 (16B) の場合、Header(1B) + Payload なので、Base(0xe0) + 1 = 0xe1 を返します。
  • free() の実態: 上記の計算通り、0xe2 が渡されています。
  • 差分: 0xe2 - 0xe1 = +1

この +1 のズレにより、以下の問題が連鎖的に発生しました:

  1. 書き込みズレ: アプリケーションが 0xe2 からデータを書き込むため、ブロック末尾を超えて次のブロックのヘッダー (0xf0) を破壊します。
  2. 隣接破壊検知: 破壊された隣接ブロックが pop される際、ヘッダー異常 (0xa1 であるべきがデータ値 0xd1 等になっている) を検知し、TLS_SLL_HDR_RESET が発生します。
  3. freeの成功: free(0xe2)normalize 機能により Base(0xe0) に補正されるため、free 自体はクラッシュせずに成功します(これが問題を隠蔽していました)。

3. ASan版で再現しない理由

ASanAddressSanitizerを有効にすると、各ブロックの周囲に「Redzone立ち入り禁止領域」が追加され、アラインメント要件も厳しくなります通常16/32バイトアラインメント。 その結果、malloc が偶数アドレスまたは16バイト境界を返すようになり、sh8bench が(奇数アドレス回避のための)補正を行わなくなったため、エラーが発生しなかったと考えられます。

推奨アクション

短期対策(完了)

実装済みの 「Atomic Fence + ヘッダー強制書き込み」 は、この「外部からの破壊」に対する「自己修復機能」として極めて有効に機能しています。現状のままで運用可能です。

長期対策Phase 2 リファクタリング)

hakmem の仕様として「アラインメントを保証するHeaderless化など」ことが根本解決になります。提案済みの REFACTOR_PLAN_GEMINI_ENHANCED.md に沿って、ptr の型安全化とレイアウト変更を進めることを強く推奨します。

以上