diff --git a/core/sm_srvcmds.cpp b/core/sm_srvcmds.cpp index 77cf815d..81bd00b6 100644 --- a/core/sm_srvcmds.cpp +++ b/core/sm_srvcmds.cpp @@ -15,6 +15,7 @@ #include "sm_srvcmds.h" #include "sm_version.h" #include "sm_stringutil.h" +#include "HandleSys.h" RootConsoleMenu g_RootMenu; @@ -254,3 +255,24 @@ CON_COMMAND(sm, "SourceMod Menu") { g_RootMenu.GotRootCmd(); } + +CON_COMMAND(sm_dump_handles, "Dumps Handle usage to a file for finding Handle leaks") +{ + if (engine->Cmd_Argc() < 2) + { + g_RootMenu.ConsolePrint("Usage: sm_dump_handles "); + return; + } + + const char *arg = engine->Cmd_Argv(1); + FILE *fp = fopen(arg, "wt"); + if (!fp) + { + g_RootMenu.ConsolePrint("Could not find file \"%s\"", arg); + return; + } + + g_HandleSys.Dump(fp); + + fclose(fp); +} diff --git a/core/systems/HandleSys.cpp b/core/systems/HandleSys.cpp index d6a7e934..07d7e766 100644 --- a/core/systems/HandleSys.cpp +++ b/core/systems/HandleSys.cpp @@ -15,6 +15,7 @@ #include "HandleSys.h" #include "ShareSys.h" #include "PluginSys.h" +#include "ExtensionSys.h" #include #include @@ -899,3 +900,52 @@ bool HandleSystem::InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHa return true; } + +void HandleSystem::Dump(FILE *fp) +{ + fprintf(fp, "%-10.10s\t%-20.20s\t%-20.20s\n", "Handle", "Owner", "Type"); + fprintf(fp, "---------------------------------------------\n"); + for (unsigned int i=1; i<=m_HandleTail; i++) + { + if (m_Handles[i].set == HandleSet_Freed + || m_Handles[i].set == HandleSet_Identity) + { + continue; + } + /* Get the index */ + unsigned int index = (m_Handles[i].serial << 16) | i; + /* Determine the owner */ + const char *owner = "UNKNOWN"; + if (m_Handles[i].owner) + { + IdentityToken_t *pOwner = m_Handles[i].owner; + if (pOwner == g_pCoreIdent) + { + owner = "CORE"; + } else if (pOwner == g_PluginSys.GetIdentity()) { + owner = "PLUGINSYS"; + } else { + CExtension *ext = g_Extensions.GetExtensionFromIdent(pOwner); + if (ext) + { + owner = ext->GetFilename(); + } else { + CPlugin *pPlugin = g_PluginSys.GetPluginFromIdentity(pOwner); + if (pPlugin) + { + owner = pPlugin->GetFilename(); + } + } + } + } else { + owner = "NONE"; + } + const char *type = "ANON"; + QHandleType *pType = &m_Types[m_Handles[i].type]; + if (pType->nameIdx != -1) + { + type = m_strtab->GetString(pType->nameIdx); + } + fprintf(fp, "0x%08x\t%-20.20s\t%-20.20s\n", index, owner, type); + } +} diff --git a/core/systems/HandleSys.h b/core/systems/HandleSys.h index 1837f5cb..d64501ae 100644 --- a/core/systems/HandleSys.h +++ b/core/systems/HandleSys.h @@ -16,6 +16,7 @@ #define _INCLUDE_SOURCEMOD_HANDLESYSTEM_H_ #include +#include #include "sm_globals.h" #include "sm_trie.h" #include "sourcemod.h" @@ -136,6 +137,8 @@ public: //IHandleSystem const HandleSecurity *pSec, const HandleAccess *pAccess, HandleError *err); + + void Dump(FILE *fp); protected: /** * Decodes a handle with sanity and security checking. diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index d268c474..50137b66 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -1961,3 +1961,13 @@ void CPluginManager::AddFunctionsToForward(const char *name, IChangeableForward } } } + +CPlugin *CPluginManager::GetPluginFromIdentity(IdentityToken_t *pToken) +{ + if (pToken->type != g_PluginIdent) + { + return NULL; + } + + return (CPlugin *)(pToken->ptr); +} diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index ba0a2b5f..b5f325bf 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -362,6 +362,8 @@ public: */ void AddFunctionsToForward(const char *name, IChangeableForward *pForward); + CPlugin *GetPluginFromIdentity(IdentityToken_t *pToken); + private: LoadRes _LoadPlugin(CPlugin **pPlugin, const char *path, bool debug, PluginType type, char error[], size_t maxlength); @@ -398,6 +400,7 @@ protected: * Caching internal objects */ void ReleaseIterator(CPluginIterator *iter); +public: inline IdentityToken_t *GetIdentity() { return m_MyIdent;