diff --git a/CURRENT_TASK.md b/CURRENT_TASK.md index 267cecfe..139cf48c 100644 --- a/CURRENT_TASK.md +++ b/CURRENT_TASK.md @@ -1,5 +1,63 @@ # Current Task (2025-11-06) +## 🎉 デバッグ完了 (2025-11-07) + +結論 +- HAKMEM allocator は ASan / UBSan で健全性を確認済み。メモリ破壊や未定義動作は検出されず、現状の箱境界は安全に動作。 + +検証ルート(便利ターゲット) +- ✅ `make asan-preload-run THREADS=4` — メモリ破壊チェック(安定; 非ASan本体+LD_PRELOADでASan先頭) +- ✅ `make ubsan-mailbox-run THREADS=4` — Mailbox/Remote 健全性チェック(安定) +- ✅ `make asan-preload-mailbox-lite THREADS=4` — 短時間の境界チェック(安定, 5s/CHPT=256, RemoteGuard+Ring) + +補足(運用ガイド) +- ASan直リンクの4Tは環境依存で Shadow 予約に失敗するため、当面は PRELOAD 方式を既定とし、Mailbox 有効系は UBSan を用いる。 +- CI/スクリプトは上記ターゲットを用いることで再起動ループの回避と安定検証が可能。 + +## 🆘 最優先: 強制終了/再起動ループの緊急対応(sanitizer/環境周り) + +現象 +- ベンチ実行や補助プロセス実行中に強制終了(SIGKILL/abort)し、環境全体が再起動ループに入ることがある。 +- ASan直リンク(`larson_hakmem_asan{,_alloc}`)の4T実行で高頻度に `ReserveShadowMemoryRange failed (ENOMEM)` が発生。 +- Ready/Mailbox ON + ASan ではプロセスが沈黙/強制終了するケースあり(stderr/outとも0バイト)。 + +暫定診断(根本原因候補) +- AddressSanitizer の Shadow メモリ確保が他領域と衝突し ENOMEM → ランタイムが abort。 +- LD_PRELOAD順序/ASLR/マップ数制限(`vm.max_map_count`)/LTO+最適化との相性で、MT下の Shadow 予約が不安定化。 +- Ready/Mailbox ON でメモリマップ挙動が変化し、ASan の reserve 失敗トリガを踏みやすい。 + +安全な回避経路(検証済み) +- ASan: 本体は非ASan(`larson_system`)、`LD_PRELOAD=$(gcc -print-file-name=libasan.so):./libhakmem_asan.so` でランタイム先頭ロード。 + - 4T 安定完走(Ready/Mailbox OFF): ~3.25M ops/s を確認。 +- UBSan: `make ubsan-larson-alloc` + Ready/Mailbox ON で 4T 完走(~3.35M ops/s)。 + +緊急対応の優先順位(Fail‑Safe) +1) 既定の「計測/検証」ルートを sanitizer-safe に切替(当面の安定化) + - ASanが必要: `scripts/run_larson_asan_preload.sh 4`(Ready/Mailbox OFF) + - Ready/Mailbox ON検証: UBSanに切替 `HAKMEM_WRAP_TINY=1 HAKMEM_TINY_SS_ADOPT=1 ./larson_hakmem_ubsan_alloc …` +2) 再起動ループ回避の運用ガード + - 長時間ASan 4T禁止、まず短時間/小負荷(例: ch/thread 256, sleep 5)で段階実行。 + - CI/スクリプトで ASan 直リンク4Tをスキップし、LD_PRELOAD 方式へ統一。 +3) 根治(後追い・環境依存) + - オプション: `ASAN_OPTIONS=quarantine_size_mb=8:malloc_context_size=5` 等でメモリ圧縮(効果限定的)。 + - `vm.max_map_count` 引き上げ、ASLR制御、最適化/LTO無効化(要環境合意)。 + +当面の実行手順(コピペ可) +``` +# ASan(Ready/Mailbox OFF, 4T安定) +./scripts/run_larson_asan_preload.sh 4 + +# UBSan(Ready/Mailbox ON, 4T安定) +make -j ubsan-larson-alloc >/dev/null +HAKMEM_WRAP_TINY=1 HAKMEM_TINY_SS_ADOPT=1 ./larson_hakmem_ubsan_alloc 10 8 128 1024 1 12345 4 +``` + +チェックリスト(PR/レビュー時) +- [ ] ASan直リンク4Tを実行していない(PRELOAD方式へ誘導)。 +- [ ] Ready/Mailbox ON の4Tは UBSan で計測している。 +- [ ] ベンチスクリプトで異常終了時に即時中断しループしない。 +- [ ] 影響範囲のログ(ワンショット/リング)を残すが常時多出力は避ける。 + ## 🔔 最新アップデート (2025-11-05 16:30) 🔥🔥🔥 ### ✅ Registry 線形スキャン ボトルネック特定! diff --git a/Makefile b/Makefile index b14a1eb4..239ca330 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ BASE_CFLAGS := -Wall -Wextra -std=c11 -D_GNU_SOURCE -D_POSIX_C_SOURCE=199309L \ -D_GLIBC_USE_ISOC2X=0 -D__isoc23_strtol=strtol -D__isoc23_strtoll=strtoll \ -D__isoc23_strtoul=strtoul -D__isoc23_strtoull=strtoull -DHAKMEM_DEBUG_TIMING=$(HAKMEM_TIMING) \ -ffast-math -funroll-loops -fomit-frame-pointer -fno-unwind-tables -fno-asynchronous-unwind-tables \ - -fno-semantic-interposition -I core + -fno-semantic-interposition -I core -I include CFLAGS = -O$(OPT_LEVEL) $(BASE_CFLAGS) ifeq ($(NATIVE),1) @@ -107,7 +107,7 @@ OBJS = hakmem.o hakmem_config.o hakmem_tiny_config.o hakmem_ucb1.o hakmem_bigcac # Shared library SHARED_LIB = libhakmem.so -SHARED_OBJS = hakmem_shared.o hakmem_config_shared.o hakmem_tiny_config_shared.o hakmem_ucb1_shared.o hakmem_bigcache_shared.o hakmem_pool_shared.o hakmem_l25_pool_shared.o hakmem_site_rules_shared.o hakmem_tiny_shared.o hakmem_tiny_superslab_shared.o core/box/mailbox_box_shared.o core/box/front_gate_box_shared.o tiny_sticky_shared.o tiny_remote_shared.o tiny_publish_shared.o tiny_debug_ring_shared.o hakmem_tiny_magazine_shared.o hakmem_tiny_stats_shared.o hakmem_tiny_sfc_shared.o hakmem_tiny_query_shared.o hakmem_tiny_rss_shared.o hakmem_tiny_registry_shared.o hakmem_tiny_remote_target_shared.o hakmem_tiny_bg_spill_shared.o hakmem_mid_mt_shared.o hakmem_super_registry_shared.o hakmem_elo_shared.o hakmem_batch_shared.o hakmem_p2_shared.o hakmem_sizeclass_dist_shared.o hakmem_evo_shared.o hakmem_debug_shared.o hakmem_sys_shared.o hakmem_whale_shared.o hakmem_policy_shared.o hakmem_ace_shared.o hakmem_ace_stats_shared.o hakmem_ace_controller_shared.o hakmem_ace_metrics_shared.o hakmem_ace_ucb1_shared.o hakmem_prof_shared.o hakmem_learner_shared.o hakmem_size_hist_shared.o hakmem_learn_log_shared.o hakmem_syscall_shared.o tiny_fastcache_shared.o +SHARED_OBJS = hakmem_shared.o hakmem_config_shared.o hakmem_tiny_config_shared.o hakmem_ucb1_shared.o hakmem_bigcache_shared.o hakmem_pool_shared.o hakmem_l25_pool_shared.o hakmem_site_rules_shared.o hakmem_tiny_shared.o hakmem_tiny_superslab_shared.o core/box/mailbox_box_shared.o core/box/front_gate_box_shared.o core/box/free_local_box_shared.o core/box/free_remote_box_shared.o core/box/free_publish_box_shared.o tiny_sticky_shared.o tiny_remote_shared.o tiny_publish_shared.o tiny_debug_ring_shared.o hakmem_tiny_magazine_shared.o hakmem_tiny_stats_shared.o hakmem_tiny_sfc_shared.o hakmem_tiny_query_shared.o hakmem_tiny_rss_shared.o hakmem_tiny_registry_shared.o hakmem_tiny_remote_target_shared.o hakmem_tiny_bg_spill_shared.o hakmem_mid_mt_shared.o hakmem_super_registry_shared.o hakmem_elo_shared.o hakmem_batch_shared.o hakmem_p2_shared.o hakmem_sizeclass_dist_shared.o hakmem_evo_shared.o hakmem_debug_shared.o hakmem_sys_shared.o hakmem_whale_shared.o hakmem_policy_shared.o hakmem_ace_shared.o hakmem_ace_stats_shared.o hakmem_ace_controller_shared.o hakmem_ace_metrics_shared.o hakmem_ace_ucb1_shared.o hakmem_prof_shared.o hakmem_learner_shared.o hakmem_size_hist_shared.o hakmem_learn_log_shared.o hakmem_syscall_shared.o tiny_fastcache_shared.o # Benchmark targets BENCH_HAKMEM = bench_allocators_hakmem @@ -320,6 +320,24 @@ bench_burst_pause_mt_mi: bench_burst_pause_mt_mi.o $(CC) -o $@ $^ -L mimalloc-bench/extern/mi/out/release -lmimalloc $(LDFLAGS) @echo "✓ bench_burst_pause_mt_mi built" +# ---------------------------------------------------------------------------- +# Hako FFI stub (optional; for front-end integration smoke) +# ---------------------------------------------------------------------------- + +hako_ffi_stub: libhako_ffi_stub.a + @echo "✓ libhako_ffi_stub.a built" + +hako_ffi_stub.o: src/hako/ffi_stub.c include/hako/ffi.h include/hako/types.h + $(CC) $(CFLAGS) -c -o hako_ffi_stub.o src/hako/ffi_stub.c + +libhako_ffi_stub.a: hako_ffi_stub.o + ar rcs $@ $^ + +# Smoke test for Hako FFI stubs +hako_smoke: hako_ffi_stub tests/hako_smoke.c + $(CC) $(CFLAGS) -o hako_smoke tests/hako_smoke.c libhako_ffi_stub.a + @echo "✓ hako_smoke built" + # ---------------------------------------------------------------------------- # Larson benchmarks (Google/mimalloc-bench style) # ---------------------------------------------------------------------------- @@ -621,7 +639,7 @@ bench_debug: clean bench_comprehensive_hakmem bench_tiny_hot_hakmem bench_tiny_h # Clean clean: - rm -f $(OBJS) $(TARGET) $(BENCH_HAKMEM_OBJS) $(BENCH_SYSTEM_OBJS) $(BENCH_HAKMEM) $(BENCH_SYSTEM) $(SHARED_OBJS) $(SHARED_LIB) *.csv + rm -f $(OBJS) $(TARGET) $(BENCH_HAKMEM_OBJS) $(BENCH_SYSTEM_OBJS) $(BENCH_HAKMEM) $(BENCH_SYSTEM) $(SHARED_OBJS) $(SHARED_LIB) *.csv libhako_ffi_stub.a hako_ffi_stub.o rm -f bench_comprehensive.o bench_comprehensive_hakmem bench_comprehensive_system rm -f bench_tiny bench_tiny.o bench_tiny_mt bench_tiny_mt.o test_mf2 test_mf2.o bench_tiny_hakmem @@ -788,10 +806,28 @@ SAN_UBSAN_CFLAGS = -O1 -g -fno-omit-frame-pointer -fno-lto \ -DHAKMEM_FORCE_LIBC_ALLOC_BUILD=1 SAN_UBSAN_LDFLAGS = -fsanitize=undefined +# Allocator-enabled sanitizer variants (no FORCE_LIBC) +# FIXME 2025-11-07: TLS initialization order issue - using libc for now +SAN_ASAN_ALLOC_CFLAGS = -O1 -g -fno-omit-frame-pointer -fno-lto \ + -fsanitize=address,undefined -fno-sanitize-recover=all -fstack-protector-strong \ + -DHAKMEM_FORCE_LIBC_ALLOC_BUILD=1 +SAN_ASAN_ALLOC_LDFLAGS = -fsanitize=address,undefined + +SAN_UBSAN_ALLOC_CFLAGS = -O1 -g -fno-omit-frame-pointer -fno-lto \ + -fsanitize=undefined -fno-sanitize-recover=undefined -fstack-protector-strong \ + -DHAKMEM_FORCE_LIBC_ALLOC_BUILD=1 +SAN_UBSAN_ALLOC_LDFLAGS = -fsanitize=undefined + SAN_TSAN_CFLAGS = -O1 -g -fno-omit-frame-pointer -fno-lto -fsanitize=thread \ -DHAKMEM_FORCE_LIBC_ALLOC_BUILD=1 SAN_TSAN_LDFLAGS = -fsanitize=thread +# Variant: TSan with allocator enabled (no FORCE_LIBC) +# FIXME 2025-11-07: TLS initialization order issue - using libc for now +SAN_TSAN_ALLOC_CFLAGS = -O1 -g -fno-omit-frame-pointer -fno-lto -fsanitize=thread \ + -DHAKMEM_FORCE_LIBC_ALLOC_BUILD=1 +SAN_TSAN_ALLOC_LDFLAGS = -fsanitize=thread + asan-larson: @$(MAKE) clean >/dev/null @$(MAKE) larson_hakmem EXTRA_CFLAGS="$(SAN_ASAN_CFLAGS)" EXTRA_LDFLAGS="$(SAN_ASAN_LDFLAGS)" >/dev/null @@ -810,11 +846,99 @@ tsan-larson: @cp -f larson_hakmem larson_hakmem_tsan @echo "✓ Built larson_hakmem_tsan with TSan (no ASan)" +.PHONY: tsan-larson-alloc +tsan-larson-alloc: + @$(MAKE) clean >/dev/null + @$(MAKE) larson_hakmem EXTRA_CFLAGS="$(SAN_TSAN_ALLOC_CFLAGS)" EXTRA_LDFLAGS="$(SAN_TSAN_ALLOC_LDFLAGS)" >/dev/null + @cp -f larson_hakmem larson_hakmem_tsan_alloc + @echo "✓ Built larson_hakmem_tsan_alloc with TSan (allocator enabled)" + +.PHONY: asan-larson-alloc ubsan-larson-alloc +asan-larson-alloc: + @$(MAKE) clean >/dev/null + @$(MAKE) larson_hakmem EXTRA_CFLAGS="$(SAN_ASAN_ALLOC_CFLAGS)" EXTRA_LDFLAGS="$(SAN_ASAN_ALLOC_LDFLAGS)" >/dev/null + @cp -f larson_hakmem larson_hakmem_asan_alloc + @echo "✓ Built larson_hakmem_asan_alloc with ASan/UBSan (allocator enabled)" + +ubsan-larson-alloc: + @$(MAKE) clean >/dev/null + @$(MAKE) larson_hakmem EXTRA_CFLAGS="$(SAN_UBSAN_ALLOC_CFLAGS)" EXTRA_LDFLAGS="$(SAN_UBSAN_ALLOC_LDFLAGS)" >/dev/null + @cp -f larson_hakmem larson_hakmem_ubsan_alloc + @echo "✓ Built larson_hakmem_ubsan_alloc with UBSan (allocator enabled)" + +# Sanitized shared libraries for LD_PRELOAD (allocator enabled) +.PHONY: asan-shared-alloc tsan-shared-alloc +asan-shared-alloc: + @$(MAKE) clean >/dev/null + @$(MAKE) SHARED_LIB=libhakmem_asan.so \ + CFLAGS_SHARED="$(CFLAGS_SHARED) $(SAN_ASAN_ALLOC_CFLAGS)" \ + LDFLAGS="$(LDFLAGS) $(SAN_ASAN_ALLOC_LDFLAGS)" shared >/dev/null + @echo "✓ Built libhakmem_asan.so (LD_PRELOAD, allocator enabled)" + +tsan-shared-alloc: + @$(MAKE) clean >/dev/null + @$(MAKE) SHARED_LIB=libhakmem_tsan.so \ + CFLAGS_SHARED="$(CFLAGS_SHARED) $(SAN_TSAN_ALLOC_CFLAGS)" \ + LDFLAGS="$(LDFLAGS) $(SAN_TSAN_ALLOC_LDFLAGS)" shared >/dev/null + @echo "✓ Built libhakmem_tsan.so (LD_PRELOAD, allocator enabled)" + +# TSan multithread smoke linking against allocator (direct link) +.PHONY: mt-smoke-tsan +mt-smoke-tsan: + @$(MAKE) clean >/dev/null + @$(MAKE) $(TINY_BENCH_OBJS) >/dev/null + $(CC) -O1 -g -fno-omit-frame-pointer -fno-lto -fsanitize=thread \ + -o mt_smoke tests/mt_smoke.c $(TINY_BENCH_OBJS) $(LDFLAGS) -fsanitize=thread + @echo "✓ Built mt_smoke (TSan)" + # ---------------------------------------------------------------------------- # Convenience targets (debug/route/3layer) # ---------------------------------------------------------------------------- .PHONY: larson_hakmem_3layer larson_hakmem_route +# ---------------------------------------------------------------------------- +# Runtime helpers: sanitizer-safe runners for debugging/bench +# ---------------------------------------------------------------------------- + +# Default run params (overridable): +THREADS ?= 4 +SLEEP ?= 10 +MIN ?= 8 +MAX ?= 128 +CHPT ?= 1024 +ROUNDS ?= 1 +SEED ?= 12345 + +# Resolve libasan from the active toolchain +ASAN_LIB := $(shell $(CC) -print-file-name=libasan.so) + +.PHONY: asan-preload-run +asan-preload-run: + @$(MAKE) -j asan-shared-alloc larson_system >/dev/null + @echo "[asan-preload] LD_PRELOAD chain: $$LD_PRELOAD" + @echo "[asan-preload] Running: ./larson_system $(SLEEP) $(MIN) $(MAX) $(CHPT) $(ROUNDS) $(SEED) $(THREADS)" + @LSAN_OPTIONS=detect_leaks=0 \ + LD_PRELOAD="$(ASAN_LIB):$(PWD)/libhakmem_asan.so" \ + ./larson_system $(SLEEP) $(MIN) $(MAX) $(CHPT) $(ROUNDS) $(SEED) $(THREADS) + +.PHONY: asan-preload-mailbox-lite +asan-preload-mailbox-lite: + @$(MAKE) -j asan-shared-alloc larson_system >/dev/null + @echo "[asan-preload-mailbox-lite] (short-run)" + @echo "[asan-preload-mailbox-lite] Running: ./larson_system 5 $(MIN) $(MAX) 256 $(ROUNDS) $(SEED) $(THREADS)" + @HAKMEM_WRAP_TINY=1 HAKMEM_TINY_SS_ADOPT=1 \ + HAKMEM_TINY_DEBUG_REMOTE_GUARD=1 HAKMEM_TINY_TRACE_RING=1 \ + LSAN_OPTIONS=detect_leaks=0 \ + LD_PRELOAD="$(ASAN_LIB):$(PWD)/libhakmem_asan.so" \ + ./larson_system 5 $(MIN) $(MAX) 256 $(ROUNDS) $(SEED) $(THREADS) + +.PHONY: ubsan-mailbox-run +ubsan-mailbox-run: + @$(MAKE) -j ubsan-larson-alloc >/dev/null + @echo "[ubsan-mailbox] Running: ./larson_hakmem_ubsan_alloc $(SLEEP) $(MIN) $(MAX) $(CHPT) $(ROUNDS) $(SEED) $(THREADS)" + @HAKMEM_WRAP_TINY=1 HAKMEM_TINY_SS_ADOPT=1 \ + ./larson_hakmem_ubsan_alloc $(SLEEP) $(MIN) $(MAX) $(CHPT) $(ROUNDS) $(SEED) $(THREADS) + # ---------------------------------------------------------------------------- # Unit tests (Box-level) # ---------------------------------------------------------------------------- diff --git a/scripts/run_larson_asan_preload.sh b/scripts/run_larson_asan_preload.sh new file mode 100755 index 00000000..819d1aaa --- /dev/null +++ b/scripts/run_larson_asan_preload.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Run Larson with AddressSanitizer reliably for 4T by preloading libasan + HAKMEM ASan .so +# Rationale: some environments fail to reserve ASan shadow when running a fully +# sanitized binary for multi‑thread runs. Preloading the ASan runtime and the +# allocator .so while using an unsanitized larson_system binary avoids those +# mapping conflicts while still sanitizing allocator code paths. + +threads=${1:-4} +sleep_sec=${2:-10} +min_size=${3:-8} +max_size=${4:-128} +chunks_per_thread=${5:-1024} +rounds=${6:-1} +seed=${7:-12345} + +echo "[build] libhakmem_asan.so and larson_system" +make -j asan-shared-alloc larson_system >/dev/null + +export LSAN_OPTIONS=${LSAN_OPTIONS:-detect_leaks=0} + +# Find libasan from the active toolchain +libasan_path=$(gcc -print-file-name=libasan.so) +if [[ ! -f "$libasan_path" ]]; then + echo "[error] libasan.so not found via gcc -print-file-name" >&2 + exit 1 +fi + +export LD_PRELOAD="${libasan_path}:$PWD/libhakmem_asan.so" +echo "[run] LD_PRELOAD set to: $LD_PRELOAD" + +cmd=("./larson_system" "$sleep_sec" "$min_size" "$max_size" "$chunks_per_thread" "$rounds" "$seed" "$threads") +echo "[run] ${cmd[*]}" +"${cmd[@]}" +