Fix #16: Resolve double BASE→USER conversion causing header corruption

🎯 ROOT CAUSE: Internal allocation helpers were prematurely converting
BASE → USER pointers before returning to caller. The caller then applied
HAK_RET_ALLOC/tiny_region_id_write_header which performed ANOTHER BASE→USER
conversion, resulting in double offset (BASE+2) and header written at
wrong location.

📦 BOX THEORY SOLUTION: Establish clean pointer conversion boundary at
tiny_region_id_write_header, making it the single source of truth for
BASE → USER conversion.

🔧 CHANGES:
- Fix #16: Remove premature BASE→USER conversions (6 locations)
  * core/tiny_alloc_fast.inc.h (3 fixes)
  * core/hakmem_tiny_refill.inc.h (2 fixes)
  * core/hakmem_tiny_fastcache.inc.h (1 fix)

- Fix #12: Add header validation in tls_sll_pop (detect corruption)
- Fix #14: Defense-in-depth header restoration in tls_sll_splice
- Fix #15: USER pointer detection (for debugging)
- Fix #13: Bump window header restoration
- Fix #2, #6, #7, #8: Various header restoration & NULL termination

🧪 TEST RESULTS: 100% SUCCESS
- 10K-500K iterations: All passed
- 8 seeds × 100K: All passed (42,123,456,789,999,314,271,161)
- Performance: ~630K ops/s average (stable)
- Header corruption: ZERO

📋 FIXES SUMMARY:
Fix #1-8:   Initial header restoration & chain fixes (chatgpt-san)
Fix #9-10:  USER pointer auto-fix (later disabled)
Fix #12:    Validation system (caught corruption at call 14209)
Fix #13:    Bump window header writes
Fix #14:    Splice defense-in-depth
Fix #15:    USER pointer detection (debugging tool)
Fix #16:    Double conversion fix (FINAL SOLUTION) 

🎓 LESSONS LEARNED:
1. Validation catches bugs early (Fix #12 was critical)
2. Class-specific inline logging reveals patterns (Option C)
3. Box Theory provides clean architectural boundaries
4. Multiple investigation approaches (Task/chatgpt-san collaboration)

📄 DOCUMENTATION:
- P0_BUG_STATUS.md: Complete bug tracking timeline
- C2_CORRUPTION_ROOT_CAUSE_FINAL.md: Detailed root cause analysis
- FINAL_ANALYSIS_C2_CORRUPTION.md: Investigation methodology

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Task Agent <task@anthropic.com>
Co-Authored-By: ChatGPT <chatgpt@openai.com>
This commit is contained in:
Moe Charm (CI)
2025-11-12 10:33:57 +09:00
parent af589c7169
commit 84dbd97fe9
13 changed files with 1270 additions and 72 deletions

View File

@ -1775,6 +1775,9 @@ TinySlab* hak_tiny_owner_slab(void* ptr) {
static _Atomic uint64_t wrapper_call_count = 0;
uint64_t call_num = atomic_fetch_add(&wrapper_call_count, 1);
// Pointer tracking init (first call only)
PTR_TRACK_INIT();
// PRIORITY 3: Periodic canary validation (every 1000 ops)
periodic_canary_check(call_num, "hak_tiny_alloc_fast_wrapper");
@ -1800,7 +1803,17 @@ TinySlab* hak_tiny_owner_slab(void* ptr) {
}
void hak_tiny_free_fast_wrapper(void* ptr) {
static _Atomic uint64_t free_call_count = 0;
uint64_t call_num = atomic_fetch_add(&free_call_count, 1);
if (call_num > 14135 && call_num < 14145) {
fprintf(stderr, "[HAK_TINY_FREE_FAST_WRAPPER] call=%lu ptr=%p\n", call_num, ptr);
fflush(stderr);
}
tiny_free_fast(ptr);
if (call_num > 14135 && call_num < 14145) {
fprintf(stderr, "[HAK_TINY_FREE_FAST_WRAPPER] call=%lu completed\n", call_num);
fflush(stderr);
}
}
#elif defined(HAKMEM_TINY_PHASE6_ULTRA_SIMPLE)
@ -1961,3 +1974,52 @@ static void tiny_class5_stats_dump(void) {
g_tiny_hotpath_class5, tls5->cap, tls5->refill_low, tls5->spill_high, tls5->count);
fprintf(stderr, "===============================\n");
}
// ========= Tiny Guard (targeted debug; low overhead when disabled) =========
static int g_tiny_guard_enabled = -1;
static int g_tiny_guard_class = 2;
static int g_tiny_guard_limit = 8;
static __thread int g_tiny_guard_seen = 0;
static inline int tiny_guard_enabled_runtime(void) {
if (__builtin_expect(g_tiny_guard_enabled == -1, 0)) {
const char* e = getenv("HAKMEM_TINY_GUARD");
g_tiny_guard_enabled = (e && *e && *e != '0') ? 1 : 0;
const char* ec = getenv("HAKMEM_TINY_GUARD_CLASS");
if (ec && *ec) g_tiny_guard_class = atoi(ec);
const char* el = getenv("HAKMEM_TINY_GUARD_MAX");
if (el && *el) g_tiny_guard_limit = atoi(el);
if (g_tiny_guard_limit <= 0) g_tiny_guard_limit = 8;
}
return g_tiny_guard_enabled;
}
int tiny_guard_is_enabled(void) { return tiny_guard_enabled_runtime(); }
static void tiny_guard_dump_bytes(const char* tag, const uint8_t* p, size_t n) {
fprintf(stderr, "[TGUARD] %s:", tag);
for (size_t i = 0; i < n; i++) fprintf(stderr, " %02x", p[i]);
fprintf(stderr, "\n");
}
void tiny_guard_on_alloc(int cls, void* base, void* user, size_t stride) {
if (!tiny_guard_enabled_runtime() || cls != g_tiny_guard_class) return;
if (g_tiny_guard_seen++ >= g_tiny_guard_limit) return;
uint8_t* b = (uint8_t*)base;
uint8_t* u = (uint8_t*)user;
fprintf(stderr, "[TGUARD] alloc cls=%d base=%p user=%p stride=%zu hdr=%02x\n",
cls, base, user, stride, b[0]);
// 隣接ヘッダ可視化(前後)
tiny_guard_dump_bytes("around_base", b, (stride >= 8 ? 8 : stride));
tiny_guard_dump_bytes("next_header", b + stride, 4);
}
void tiny_guard_on_invalid(void* user_ptr, uint8_t hdr) {
if (!tiny_guard_enabled_runtime()) return;
if (g_tiny_guard_seen++ >= g_tiny_guard_limit) return;
uint8_t* u = (uint8_t*)user_ptr;
fprintf(stderr, "[TGUARD] invalid header at user=%p hdr=%02x prev=%02x next=%02x\n",
user_ptr, hdr, *(u - 2), *(u));
tiny_guard_dump_bytes("dump_before", u - 8, 8);
tiny_guard_dump_bytes("dump_after", u, 8);
}