Skip to content

DHooks might crash on plugin reload #1688

Description

@Adrianilloo

Help us help you

  • I have checked that my issue doesn't exist yet.
  • I can always reproduce the issue with the provided description below.

Environment

  • Operating System version: Ubuntu 20.04.3 LTS
  • Game/AppID (with version if applicable): Half-Life 2: Deathmatch / 320
  • Current SourceMod version: 1.11
  • Current SourceMod snapshot: 6842
  • Current Metamod: Source snapshot: 1.11.0-dev+1145

Description

DHooks2 showcases a possible DHooksCallback::plugin_callback NULL pointer de-reference crash sequence when plugins that use it (properly setting hook at OnPluginStart and having double-checked gamedata) get reloaded. Concretely I repeatedly recompile one of them and have it reloaded by restarting map (doing both steps once each new map session), rather than via sm plugins reload (which I didn't test yet). The crash has enough chance to happen each map reload.

Reference plugin.

Recompiled DHooks info

I recompiled DHooks with some debug logging stataments (targetting error logs, for my own convenience) showing relevant related data (callback addresses, offsets, etc.), manually preventing the crash as well, and resulting logs are attached below. Here are the exact testing changes:

+++ b/extensions/dhooks/dynhooks_sourcepawn.cpp
@@ -472,6 +472,8 @@ ReturnAction_t HandleDetour(HookType_t hookType, CHook* pDetour)
 
 CDynamicHooksSourcePawn::CDynamicHooksSourcePawn(HookSetup *setup, CHook *pDetour, IPluginFunction *pCallback, bool post)
 {
+       g_pSM->LogError(myself, "CDynamicHooksSourcePawn called for this = %p with pCallback = %p (plugin callback)",
+               this, pCallback);
        this->params = setup->params;

+++ b/extensions/dhooks/listeners.cpp
@@ -75,6 +75,9 @@ void DHooksEntityListener::CleanupListeners(IPluginContext *pContext)
                IPluginFunction *cb = manager->callback->plugin_callback;
                if (pContext == NULL || (cb && pContext == cb->GetParentRuntime()->GetDefaultContext()))
                {
+                       g_pSM->LogError(myself, "DHooksEntityListener::CleanupListeners cleaning DHooksCallback at %p"
+                               " (plugin_callback = %p; offset = %i)", manager->callback, manager->callback->plugin_callback,
+                               manager->callback->offset);
                        manager->callback->plugin_callback = nullptr;

+++ b/extensions/dhooks/vhook.cpp
@@ -148,7 +148,8 @@ DHooksManager::DHooksManager(HookSetup *setup, void *iface, IPluginFunction *rem
        this->callback->post = post;
        this->callback->hookType = setup->hookType;
        this->callback->params = setup->params;

+       g_pSM->LogError(myself, "DHooksManager constructor of instance %p called! (callback = %p; plugincb = %p; offset = %i)",
+               this, this->callback, plugincb, setup->offset);

@@ -411,6 +412,12 @@ void *Callback(DHooksCallback *dg, void **argStack)
 
        if(dg->thisType == ThisPointer_CBaseEntity || dg->thisType == ThisPointer_Address)
        {
+               if (dg->plugin_callback == NULL)
+               {
+                       g_pSM->LogError(myself, "dg->plugin_callback was NULL!!! (dg = %p; offset = %i)", dg, dg->offset);
+                       return NULL;
+               }
+
                dg->plugin_callback->PushCell(GetThisPtr(g_SHPtr->GetIfacePtr(), dg->thisType));
        }
        if(dg->returnType != ReturnType_Void)

Important: notice how the logs show several map reloads and after one happens, the dg->plugin_callback was NULL!!! log arises, and its dg object has been cleared early at DHooksEntityListener::CleanupListeners.

It seems to me that the calling stack that triggers this is the following:

DHooksManager::DHooksManager -> MakeHandler(ReturnType type) -> GenerateThunk(ReturnType type) -> Callback(DHooksCallback *dg, void **argStack)

Captura

Notice that at DHooksManager, the plugin_callback is only assigned after the MakeHandler call.

Logs

errors_20220107.log
crash_j6efozxcjard.zip

Metadata

Metadata

Assignees

Labels

Buggeneral bugs; can be anythingdhooks

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions