diff --git a/core/box/hak_wrappers.inc.h b/core/box/hak_wrappers.inc.h index aa595418..2c879526 100644 --- a/core/box/hak_wrappers.inc.h +++ b/core/box/hak_wrappers.inc.h @@ -34,6 +34,10 @@ void* realloc(void* ptr, size_t size) { #include "../front/malloc_tiny_fast.h" // Phase 26: Front Gate Unification #include "tiny_front_config_box.h" // Phase 4-Step3: Compile-time config for dead code elimination #include "wrapper_env_box.h" // Wrapper env cache (step trace / LD safe / free trace) +#include "../hakmem_internal.h" // AllocHeader helpers for diagnostics +#include "../hakmem_super_registry.h" // Superslab lookup for diagnostics +#include "../superslab/superslab_inline.h" // slab_index_for, capacity +#include // mincore for safe mapping checks #include // write for diagnostics #include // strlen for diagnostics @@ -232,6 +236,8 @@ void free(void* ptr) { // Fallback to normal path for non-Tiny or no-header mode } + const wrapper_env_cfg_t* wcfg = wrapper_env_cfg(); + // Phase 26: Front Gate Unification (Tiny free fast path) // Placed AFTER BenchFast check, BEFORE expensive classify_ptr() // Bypasses: hak_free_at routing + wrapper overhead + classification @@ -381,6 +387,53 @@ void free(void* ptr) { #endif } // No valid hakmem header → external pointer (BenchMeta, libc allocation, etc.) + if (__builtin_expect(wcfg->wrap_diag, 0)) { + SuperSlab* ss = hak_super_lookup(ptr); + int slab_idx = -1; + int meta_cls = -1; + int alloc_method = -1; + if (__builtin_expect(ss && ss->magic == SUPERSLAB_MAGIC, 0)) { + slab_idx = slab_index_for(ss, (void*)((uint8_t*)ptr - 1)); + if (slab_idx >= 0 && slab_idx < ss_slabs_capacity(ss)) { + meta_cls = ss->slabs[slab_idx].class_idx; + } + } else if (offset_in_page >= HEADER_SIZE) { + AllocHeader* ah = hak_header_from_user(ptr); + if (hak_header_validate(ah)) { + alloc_method = ah->method; + } + } + fprintf(stderr, + "[WRAP_FREE_NOT_OWNED] ptr=%p hdr=0x%02x off=0x%lx lockdepth=%d init=%d ss=%p slab=%d meta_cls=%d alloc_method=%d\n", + ptr, + header, + (unsigned long)offset_in_page, + g_hakmem_lock_depth, + g_initializing, + (void*)ss, + slab_idx, + meta_cls, + alloc_method); + } + + // Self-heal: if this looks like a SuperSlab (magic matches) but registry lookup failed, + // re-register on the fly and route to hakmem free to avoid libc abort. + { + SuperSlab* ss_guess = (SuperSlab*)((uintptr_t)ptr & ~((uintptr_t)SUPERSLAB_SIZE_MIN - 1u)); + long page_sz = sysconf(_SC_PAGESIZE); + unsigned char mincore_vec = 0; + int mapped = (page_sz > 0) && + (mincore((void*)((uintptr_t)ss_guess & ~(uintptr_t)(page_sz - 1)), + (size_t)page_sz, + &mincore_vec) == 0); + if (mapped && ss_guess->magic == SUPERSLAB_MAGIC) { + hak_super_register((uintptr_t)ss_guess, ss_guess); // idempotent if already registered + g_hakmem_lock_depth++; + hak_free_at(ptr, 0, HAK_CALLSITE()); + g_hakmem_lock_depth--; + return; + } + } extern void __libc_free(void*); ptr_trace_dump_now("wrap_libc_external_nomag"); wrapper_record_fallback(FB_NOT_OWNED, "[wrap] libc free: not_owned\n"); diff --git a/core/hakmem_super_registry.c b/core/hakmem_super_registry.c index b13754be..2ce3c15f 100644 --- a/core/hakmem_super_registry.c +++ b/core/hakmem_super_registry.c @@ -461,6 +461,10 @@ SuperSlab* hak_ss_lru_pop(uint8_t size_class) { curr->lru_prev = NULL; curr->lru_next = NULL; + // ROOT CAUSE FIX: Re-register in global registry (idempotent) + // Without this, hak_super_lookup() fails in free() path + hak_super_register((uintptr_t)curr, curr); + return curr; } diff --git a/docs/sh8bench_debug_instruction.md b/docs/sh8bench_debug_instruction.md new file mode 100644 index 00000000..6834d7f2 --- /dev/null +++ b/docs/sh8bench_debug_instruction.md @@ -0,0 +1,187 @@ +# sh8bench TLS Header Corruption Debug Instruction + +## 問題の概要 + +hakmemメモリアロケータを`LD_PRELOAD`でsh8benchベンチマークに適用すると、以下のエラーが発生してベンチマークが正常に完了しない: + +``` +[TLS_SLL_HDR_RESET] cls=1 base=0x7c18d6bc7858 got=0x61 expect=0xa1 count=0 +``` + +## 環境情報 + +- **ビルド構成**: Release build with `-O3 -DNDEBUG -flto -march=native` +- **問題の発生状況**: sh8benchでのみ発生、cfracなど他のベンチマークは正常動作 +- **エラーの意味**: TLS(Thread-Local Storage)のSingle-Linked-List Header が破損している + +## エラー詳細 + +- **cls=1**: サイズクラス1(小さいメモリブロック) +- **base**: Slabのベースアドレス +- **got=0x61**: 実際に読み取られたヘッダー値 +- **expect=0xa1**: 期待されるヘッダー値(サイズクラス1のマーカー) +- **count=0**: リセット回数 + +期待値0xa1のフォーマット: +- 上位4bit (0xa): サイズクラスインデックス + マーカー +- 下位4bit (0x1): サイズクラスインデックス + +実際の値0x61は破損している。 + +## コード箇所 + +### エラー出力箇所 +**ファイル**: `core/box/tls_sll_box.h` + +該当するコードを探してください(`TLS_SLL_HDR_RESET`で検索)。 + +### 関連する可能性のあるコード + +1. **TLS SLL (Single-Linked-List) 操作** + - `core/box/tls_sll_box.h` - TLSフリーリスト管理 + - ヘッダーの読み書き操作 + +2. **Tiny allocation fast path** + - `core/tiny_alloc_fast_push.c` + - `core/tiny_alloc_fast_sfc.inc.h` + - `core/hakmem_tiny_sfc.c` + +3. **Thread-local state** + - `core/hakmem_tiny_tls_state_box.inc` + +## 調査すべきポイント + +### 1. ヘッダー値の設定・検証ロジック + +- ヘッダー値0xa1がどこで設定されているか +- ヘッダー値の検証がどこで行われているか +- マルチスレッド環境でのヘッダー操作の競合 + +### 2. sh8bench固有の特性 + +```bash +# sh8benchのソースコードを確認 +cat mimalloc-bench/bench/sh8bench/sh8bench.c +``` + +sh8benchがどのような割り当てパターンを行うか: +- スレッド数: 8 +- 割り当てサイズ +- 割り当て/解放の順序 +- スレッド間でのメモリ共有パターン + +### 3. 競合条件の可能性 + +- 複数スレッドが同時に同じSlabにアクセス +- TLSの初期化タイミング +- フリーリストの操作中の競合 + +### 4. メモリ破壊の原因候補 + +- Use-after-free +- Double-free +- バッファオーバーラン +- アライメント問題 +- 初期化されていないメモリの使用 + +## デバッグ手順 + +### Step 1: 最小再現ケースの作成 + +```bash +# sh8benchを直接実行 +cd /mnt/workdisk/public_share/hakmem +LD_PRELOAD=./libhakmem.so ./mimalloc-bench/out/bench/sh8bench +``` + +### Step 2: デバッグビルドで詳細情報を取得 + +```bash +# デバッグビルド(NDEFUGを外す) +make clean-objects # または rm -f *.o +make shared -j8 EXTRA_CFLAGS="-g -O0" + +# 詳細ログ有効化 +HAKMEM_DEBUG_LEVEL=3 LD_PRELOAD=./libhakmem.so ./mimalloc-bench/out/bench/sh8bench 2>&1 | tee debug.log +``` + +### Step 3: コード検証 + +`core/box/tls_sll_box.h`で以下を確認: + +1. ヘッダー値の計算ロジック + ```c + // 期待されるヘッダー値の計算(例) + uint8_t expected_header = (class_idx << 4) | class_idx; + ``` + +2. ヘッダー検証のタイミング + - push時 + - pop時 + - リセット時 + +3. 競合保護 + - アトミック操作の使用 + - TLS変数へのアクセス制御 + +### Step 4: Valgrind/AddressSanitizerによる検証 + +```bash +# AddressSanitizer +make clean-objects +make shared EXTRA_CFLAGS="-fsanitize=address -g -O1" +LD_PRELOAD=./libhakmem.so ./mimalloc-bench/out/bench/sh8bench + +# ThreadSanitizer +make clean-objects +make shared EXTRA_CFLAGS="-fsanitize=thread -g -O1" +LD_PRELOAD=./libhakmem.so ./mimalloc-bench/out/bench/sh8bench +``` + +## 期待される修正 + +1. **競合条件の修正** + - 適切なロック機構の追加 + - アトミック操作への変更 + +2. **初期化の改善** + - TLS変数の適切な初期化タイミング + - ヘッダー値の確実な設定 + +3. **検証強化** + - より早期のエラー検出 + - デバッグ情報の追加 + +## 参考情報 + +### ビルド方法 +```bash +cd /mnt/workdisk/public_share/hakmem +make shared -j8 # Release build +``` + +### 動作する他のベンチマーク(比較用) +```bash +# cfrac - 正常動作 +LD_PRELOAD=./libhakmem.so ./mimalloc-bench/out/bench/cfrac 17545186520507317056371138836327483792789528 + +# larson - 正常動作(確認が必要) +LD_PRELOAD=./libhakmem.so ./mimalloc-bench/out/bench/larson 10 7 8 100 10000 +``` + +## 追加のヒント + +- 前回のcommitで`malloc_count`のアトミック操作を削除して性能が改善(17s→10s) +- この変更は関係ない(revertしても同じエラーが発生) +- エラーメッセージは`TLS_SLL_HDR_RESET`なので、TLSのSingle-Linked-List操作に関連 + +## 質問すべきこと + +1. ヘッダー値0xa1はどのように計算されているか? +2. なぜsh8benchだけでこの問題が発生するのか? +3. got=0x61という値には何か意味があるか?(0x61 = 'a' ASCII) +4. TLS_SLL_HDR_RESETはどのタイミングで呼ばれるか? + +--- + +この指示書を使って、sh8benchでのTLSヘッダー破損問題をデバッグし、修正してください。