Failed reask source delete needed explicit download-owner detachment
Summary¶
The failed TCP reask path in CPartFile::Process() could delete a
CUpDownClient while the client was still present in download-owner
structures. That made later cleanup capable of seeing the same source again
and contributed to double-free / heap-corruption risk around client
destruction.
The observed morning dump showed heap corruption during CUpDownClient
destruction from the CPartFile::Process() failed-reask flow. The minidump
did not include pageheap allocation history, so the exact duplicate owner
cannot be proven from that dump alone. The owner-detach fix closes the concrete
lifetime gap at the failed-reask delete site.
Provenance¶
This has mixed provenance.
The fragile lifetime contract is inherited from stock/community code:
AskForDownload()returnedfalseas a liveness signal.TryToConnect()historically documented thatfalsemeant the client was deleted.CPartFile::Process()historically carried the warning that the call may delete the client and then broke out of the source loop.
However, the exact local delete cur_src in CPartFile::Process() was
introduced by eMuleBB lifetime-explicit refactoring in commit 5037876
(FIX: make TryToConnect lifetime explicit). That refactor moved deletion
responsibility from TryToConnect() into callers. The underlying raw-pointer
ownership model is inherited, but eMuleBB owns the exact failed-reask deletion
site that was hardened here.
The workspace does not currently contain a 0.73 stock tag or branch. The
newest local/upstream community comparison point observed during the trace was
0.72a-community.
eMuleAI Latest Status¶
Checked against eMuleAI upstream master at
8e34bdec2b7e4fe9e4307df9d80f691804be99ed (eMuleAIv1.4) on 2026-05-24.
eMuleAI latest still uses the inherited AskForDownload() liveness contract
and TryToConnect() can still delete through SafeDelete(). Its
CPartFile::Process() call site still has the historical
if (!cur_src->AskForDownload()) / break shape, not eMuleBB's explicit
caller-side delete cur_src.
eMuleAI also has broader SafeDelete() / runtime-reference machinery and
download-queue removal helpers. Therefore the exact eMuleBB regression shape
is not present there, but the underlying lifetime model remains closely
related and should not be treated as a clean ownership design.
Conclusion: eMuleAI latest does not carry this exact eMuleBB caller-delete bug, but it still carries a related inherited self-delete / SafeDelete lifetime model.
Resolution¶
Fixed on eMuleBB main by app commit b65b3c9
(BUG-017 detach failed reask sources before delete). The fix detaches the
failed reask source from download ownership before deleting the client at the
caller-owned failure site.
Regression coverage was added in test commit 2a95c98
(BUG-017 cover failed reask source ownership).
Validation¶
- Native Debug parity: passed, 729 passed / 0 failed / 237 skipped.
- Native Release parity: passed, 726 passed / 0 failed / 237 skipped.
- x64 Debug app build: passed.
- x64 Release app build: passed.