Description
I am not sure this was my side or sdk side, but can confirm to be reproduced on BebopSpikeSpiegel/NoMoreAltF4@d97ed8a
Disabling the plugin via the SDK overlay menu at runtime causes an access violation crash. The crash occurs immediately after the DLL is unloaded — the game tries to execute code at an address that was inside the now-freed plugin DLL.
Claude wrote the rest —
Steps to Reproduce
- Create a plugin that registers detours in
OnEngineInitialized():
void MyPlugin::OnEngineInitialized() {
Hooks::ZAchievementManagerSimple_OnEventReceived->AddDetour(this, &MyPlugin::OnEventReceived);
Hooks::ZAchievementManagerSimple_OnEventSent->AddDetour(this, &MyPlugin::OnEventSent);
Hooks::Http_WinHttpCallback->AddDetour(this, &MyPlugin::Http_WinHttpCallback);
Hooks::ZHttpResultDynamicObject_OnBufferReady->AddDetour(this, &MyPlugin::OnBufferReady);
}
- Load the plugin, enter a mission (so hooks are actively being called)
- Open the SDK overlay menu (
~ key) and uncheck the plugin to disable it
- Game crashes immediately
Crash Log
'HITMAN3.exe' (Win32): Unloaded 'D:\SteamLibrary\steamapps\common\HITMAN 3\Retail\mods\NoMoreAltF4.dll'
Exception thrown at 0x00007FF9D179BDB0 in HITMAN3.exe: 0xC0000005: Access violation executing location 0x00007FF9D179BDB0.
This is followed by hundreds of std::filesystem::filesystem_error exceptions, eventually leading to a stack overflow and process termination.
Analysis
The crash address (0x00007FF9D179BDB0) was inside the plugin DLL's code space before it was unloaded. After the DLL is freed from memory, something (likely the detour framework or a hooked game thread) still tries to jump to that address.
I initially tried calling RemoveDetoursWithContext(this) in the destructor, but this didn't help — the DLL is unloaded immediately after the destructor returns, and other threads may already have resolved function pointers into the DLL.
Looking at the sample mods (NoPause, AdvancedRating, FreeCam), none of them call RemoveDetoursWithContext in their destructors — they rely on the SDK framework to handle detour cleanup on plugin unload. This suggests the framework should be handling this automatically but isn't doing so safely when hooks are actively being called on other threads.
Expected Behavior
Disabling a plugin at runtime should safely remove all detours before unloading the DLL, ensuring no thread can jump into freed code.
Environment
- ZHMModSDK: v4.0.0-rc.3
- Game: HITMAN World of Assassination (latest Steam version)
- OS: Windows 11 Pro
- Hooks used:
ZAchievementManagerSimple_OnEventReceived, ZAchievementManagerSimple_OnEventSent, Http_WinHttpCallback, ZHttpResultDynamicObject_OnBufferReady
Note
The v4.0.0-rc.3 release notes mention "Fixed game crash on editor unload" — this may be a similar issue affecting regular plugin unloads as well.
Description
I am not sure this was my side or sdk side, but can confirm to be reproduced on BebopSpikeSpiegel/NoMoreAltF4@d97ed8a
Disabling the plugin via the SDK overlay menu at runtime causes an access violation crash. The crash occurs immediately after the DLL is unloaded — the game tries to execute code at an address that was inside the now-freed plugin DLL.
Claude wrote the rest —
Steps to Reproduce
OnEngineInitialized():~key) and uncheck the plugin to disable itCrash Log
This is followed by hundreds of
std::filesystem::filesystem_errorexceptions, eventually leading to a stack overflow and process termination.Analysis
The crash address (
0x00007FF9D179BDB0) was inside the plugin DLL's code space before it was unloaded. After the DLL is freed from memory, something (likely the detour framework or a hooked game thread) still tries to jump to that address.I initially tried calling
RemoveDetoursWithContext(this)in the destructor, but this didn't help — the DLL is unloaded immediately after the destructor returns, and other threads may already have resolved function pointers into the DLL.Looking at the sample mods (NoPause, AdvancedRating, FreeCam), none of them call
RemoveDetoursWithContextin their destructors — they rely on the SDK framework to handle detour cleanup on plugin unload. This suggests the framework should be handling this automatically but isn't doing so safely when hooks are actively being called on other threads.Expected Behavior
Disabling a plugin at runtime should safely remove all detours before unloading the DLL, ensuring no thread can jump into freed code.
Environment
ZAchievementManagerSimple_OnEventReceived,ZAchievementManagerSimple_OnEventSent,Http_WinHttpCallback,ZHttpResultDynamicObject_OnBufferReadyNote
The v4.0.0-rc.3 release notes mention "Fixed game crash on editor unload" — this may be a similar issue affecting regular plugin unloads as well.