Since v1.5.1 , Hook_ReplyConnection calls client->Disconnect() synchronously when mm_addon_connection_timeout expires.
This invalidates the client's network object, but engine2 continues using the cached pointer after the hook returns, causing an access violation at engine2.dll+0x9DD73.
Crash flow
engine2 caches client+0x58 in R14
→ calls ReplyConnection hooked by MultiAddonManager
→ Hook_ReplyConnection calls client->Disconnect()
→ Disconnect clears the network object
→ engine2 returns and reuses cached R14
→ access violation
Latest dump:
Exception: 0xC0000005 (read)
RIP: engine2.dll+0x9DD73
Instruction: call qword ptr [rax+0x2A8]
RAX: 0
Fault address: 0x2A8
[client+0x58] = 0
[R14] = 0
Relevant engine instructions:
engine2+0x9DC5F mov r14, [rdi+0x58]
engine2+0x9DC94 call engine2+0xA3C70 ; hooked ReplyConnection
engine2+0x9DD5F mov rax, [r14]
engine2+0x9DD73 call qword ptr [rax+0x2A8]
The timeout path calls Disconnect() synchronously:
|
else if (mm_addon_connection_timeout.Get() > 0 && |
|
clientInfo.connectedState == CLIENTCONN_CONNECTING && |
|
Plat_FloatTime() - clientInfo.connectionStartTime > mm_addon_connection_timeout.Get()) |
|
{ |
|
clientInfo.connectedState = CLIENTCONN_NONE; |
|
client->Disconnect(NETWORK_DISCONNECT_KICKED, "Required Workshop addon download was not accepted in time"); |
|
return; |
clientInfo.connectedState = CLIENTCONN_NONE;
client->Disconnect(
NETWORK_DISCONNECT_KICKED,
"Required Workshop addon download was not accepted in time");
return;
Before a0b2246, timeout disconnects were deferred to GameFrame. Moving the disconnect inside Hook_ReplyConnection appears to invalidate an object that the engine caller continues using after the hook returns.
Since v1.5.1 ,
Hook_ReplyConnectioncallsclient->Disconnect()synchronously whenmm_addon_connection_timeoutexpires.This invalidates the client's network object, but
engine2continues using the cached pointer after the hook returns, causing an access violation atengine2.dll+0x9DD73.Crash flow
Latest dump:
Relevant engine instructions:
The timeout path calls
Disconnect()synchronously:MultiAddonManager/src/multiaddonmanager.cpp
Lines 1251 to 1257 in a0b2246
Before
a0b2246, timeout disconnects were deferred toGameFrame. Moving the disconnect insideHook_ReplyConnectionappears to invalidate an object that the engine caller continues using after the hook returns.