Initial commit — leak-hunt project complete

Five bugs identified and patched in retail Asheron's Call client:
- v3b: palette refcount over-increment (3-byte NOP at two sites)
- v5: RenderSurface PurgeResource no-op stub (vtable slot 2 thunk)
- v11: two dangling-pointer crash guards (NULL-check + reorder)
- v14: CEnvCell::Destroy ClipPlaneList leak (18-byte JMP to cleanup thunk)
- v22: unpacker stale-pointer SEH guard (whole-function __try/__except)

All five ship in leakfix.dll (117 KB, SHA d282f23c…) which is loaded
by acclient.exe at process start via PE import table patching by
tools/install_leakfix.py.

Controlled 15-client fleet soak: unpatched control died at 26h with
palette exhaustion; all 14 patched clients survived past that point
and reached ≥5-day uptime.

Residual ~15 MB/h growth traced to d3d9.dll's internal slab allocator
(260KB surface backing buffers retained after Release). See REPORT.md
§10 for the full investigation; conclusion is that it's unfixable from
outside d3d9.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
acbot 2026-05-23 21:05:17 +02:00
commit 57b5e43d0e
199 changed files with 1648333 additions and 0 deletions

48
templates/trace.cdb Normal file
View file

@ -0,0 +1,48 @@
$$ cdb scripting template — attach to acclient.exe, set non-blocking
$$ breakpoints on suspected allocator functions, count hits, auto-detach.
$$
$$ Usage:
$$ cdb.exe -pn acclient.exe -cf <this-file> -logo <output.log>
$$
$$ Or attach by PID:
$$ cdb.exe -p <pid> -cf <this-file> -logo <output.log>
$$
$$ Tips:
$$ - `gc` = "go conditional" — continue without breaking the debuggee
$$ - `qd` = "quit detached" — leaves the debuggee running, exits cdb
$$ - Counter $t0..$t19 are persistent across breakpoint hits
$$ - Don't put `;` inside breakpoint action strings without escaping —
$$ cdb's command parser splits on `;` even inside actions.
.logopen /t leak-trace.log
$$ Symbol path — local PDB only, no symbol server.
.sympath C:\leak-hunt\pdb
.symopt+ 0x40
.reload /f acclient.exe
$$ Verify the symbol we care about resolves (replace as needed)
$$ x acclient!CChatManager::AddLine
$$ ============================================================
$$ Counters
$$ ============================================================
r $t0 = 0 $$ alloc-site hits
r $t1 = 0 $$ free-site hits
r $t2 = 0 $$ unmatched (leak candidate) hits
$$ ============================================================
$$ Breakpoint pattern: increment counter, log every Nth, auto-detach at M
$$ ============================================================
$$ Replace <ALLOC_FN> and <FREE_FN> with the suspected function names.
bp acclient!<ALLOC_FN> "r $t0 = @$t0 + 1; .if (@$t0 % 1000 == 0) { .printf \"alloc hits: %d\\n\", @$t0 }; .if (@$t0 >= 100000) { .printf \"AUTO-DETACH at %d\\n\", @$t0; qd } .else { gc }"
bp acclient!<FREE_FN> "r $t1 = @$t1 + 1; .if (@$t1 % 1000 == 0) { .printf \"free hits: %d\\n\", @$t1 }; gc"
$$ Optional: dump `this` struct on first hit
$$ bp acclient!<ALLOC_FN> "r $t0 = @$t0 + 1; .if (@$t0 == 1) { dt acclient!<ClassName> @ecx }; gc"
g
.logclose