diff --git a/bridge/include/BridgeAPI.h b/bridge/include/BridgeAPI.h index b8057ac9..702a0b4e 100644 --- a/bridge/include/BridgeAPI.h +++ b/bridge/include/BridgeAPI.h @@ -35,7 +35,7 @@ namespace SourceMod { // Add 1 to the RHS of this expression to bump the intercom file // This is to prevent mismatching core/logic binaries -static const uint32_t SM_LOGIC_MAGIC = 0x0F47C0DE - 52; +static const uint32_t SM_LOGIC_MAGIC = 0x0F47C0DE - 53; } // namespace SourceMod diff --git a/bridge/include/LogicProvider.h b/bridge/include/LogicProvider.h index e7574058..4817379c 100644 --- a/bridge/include/LogicProvider.h +++ b/bridge/include/LogicProvider.h @@ -68,7 +68,6 @@ struct sm_logic_t IDebugListener *debugger; void (*GenerateError)(IPluginContext *, cell_t, int, const char *, ...); void (*AddNatives)(sp_nativeinfo_t *natives); - void (*DumpHandles)(void (*dumpfn)(const char *fmt, ...)); void (*RegisterProfiler)(IProfilingTool *tool); void (*OnRootCommand)(const ICommandArgs *args); IDataPack * (*CreateDataPack)(); diff --git a/core/logic/HandleSys.cpp b/core/logic/HandleSys.cpp index afa37850..10c9791c 100644 --- a/core/logic/HandleSys.cpp +++ b/core/logic/HandleSys.cpp @@ -1066,11 +1066,23 @@ bool HandleSystem::TryAndFreeSomeHandles() return scripts->UnloadPlugin(highest_owner); } -void HandleSystem::Dump(HANDLE_REPORTER rep) +static void rep(const HandleReporter &fn, const char *fmt, ...) +{ + va_list ap; + char buffer[1024]; + + va_start(ap, fmt); + ke::SafeVsprintf(buffer, sizeof(buffer), fmt, ap); + va_end(ap); + + fn(buffer); +} + +void HandleSystem::Dump(const HandleReporter &fn) { unsigned int total_size = 0; - rep("%-10.10s\t%-20.20s\t%-20.20s\t%-10.10s", "Handle", "Owner", "Type", "Memory"); - rep("--------------------------------------------------------------------------"); + rep(fn, "%-10.10s\t%-20.20s\t%-20.20s\t%-10.10s", "Handle", "Owner", "Type", "Memory"); + rep(fn, "--------------------------------------------------------------------------"); for (unsigned int i = 1; i <= m_HandleTail; i++) { if (m_Handles[i].set != HandleSet_Used) @@ -1141,16 +1153,16 @@ void HandleSystem::Dump(HANDLE_REPORTER rep) if (pType->dispatch->GetDispatchVersion() < HANDLESYS_MEMUSAGE_MIN_VERSION || !bresult) { - rep("0x%08x\t%-20.20s\t%-20.20s\t%-10.10s", index, owner, type, "-1"); + rep(fn, "0x%08x\t%-20.20s\t%-20.20s\t%-10.10s", index, owner, type, "-1"); } else { char buffer[32]; ke::SafeSprintf(buffer, sizeof(buffer), "%d", size); - rep("0x%08x\t%-20.20s\t%-20.20s\t%-10.10s", index, owner, type, buffer); + rep(fn, "0x%08x\t%-20.20s\t%-20.20s\t%-10.10s", index, owner, type, buffer); total_size += size; } } - rep("-- Approximately %d bytes of memory are in use by Handles.\n", total_size); + rep(fn, "-- Approximately %d bytes of memory are in use by Handles.\n", total_size); } diff --git a/core/logic/HandleSys.h b/core/logic/HandleSys.h index 670f5602..a549c251 100644 --- a/core/logic/HandleSys.h +++ b/core/logic/HandleSys.h @@ -35,7 +35,8 @@ #include #include #include -#include +#include +#include #include "common_logic.h" #define HANDLESYS_MAX_HANDLES (1<<15) @@ -111,7 +112,7 @@ struct QHandleType } }; -typedef void (HANDLE_REPORTER)(const char *str, ...); +typedef ke::Lambda HandleReporter; class HandleSystem : public IHandleSys @@ -163,7 +164,7 @@ public: //IHandleSystem const HandleAccess *pAccess, HandleError *err); - void Dump(HANDLE_REPORTER rep); + void Dump(const HandleReporter &reporter); /* Bypasses security checks. */ Handle_t FastCloneHandle(Handle_t hndl); diff --git a/core/logic/RootConsoleMenu.cpp b/core/logic/RootConsoleMenu.cpp index b6cacc7c..265c8494 100644 --- a/core/logic/RootConsoleMenu.cpp +++ b/core/logic/RootConsoleMenu.cpp @@ -27,10 +27,15 @@ #include "RootConsoleMenu.h" #include #include +#include #include +#include "HandleSys.h" RootConsoleMenu g_RootMenu; +// Some top-level commands that are just thrown in here. +static bool sm_dump_handles(int client, const ICommandArgs *args); + RootConsoleMenu::RootConsoleMenu() { } @@ -49,6 +54,9 @@ void RootConsoleMenu::OnSourceModStartup(bool late) { AddRootConsoleCommand3("version", "Display version information", this); AddRootConsoleCommand3("credits", "Display credits listing", this); + + bridge->DefineCommand("sm_dump_handles", "Dumps Handle usage to a file for finding Handle leaks", + sm_dump_handles); } void RootConsoleMenu::OnSourceModAllInitialized() @@ -232,3 +240,45 @@ void RootConsoleMenu::OnRootConsoleCommand(const char *cmdname, const ICommandAr ConsolePrint(" http://www.sourcemod.net/"); } } + +static bool sm_dump_handles(int client, const ICommandArgs *args) +{ + if (args->ArgC() < 2) { + bridge->ConsolePrint("Usage: sm_dump_handles or for game logs"); + return true; + } + + if (strcmp(args->Arg(1), "log") == 0) { + auto write_handles_to_game = [] (const char *str) -> void + { + char buffer[1024]; + size_t len = ke::SafeSprintf(buffer, sizeof(buffer)-2, "%s", str); + + buffer[len] = '\n'; + buffer[len+1] = '\0'; + + bridge->LogToGame(buffer); + }; + g_HandleSys.Dump(write_handles_to_game); + return true; + } + + FILE *fp = nullptr; + auto write_handles_to_log = [&fp] (const char *str) -> void + { + fprintf(fp, "%s\n", str); + }; + + char filename[PLATFORM_MAX_PATH]; + const char *arg = args->Arg(1); + g_pSM->BuildPath(Path_Game, filename, sizeof(filename), "%s", arg); + + fp = fopen(filename, "wt"); + if (!fp) { + bridge->ConsolePrint("Failed to open \"%s\" for writing", filename); + return true; + } + + g_HandleSys.Dump(write_handles_to_log); + fclose(fp); +} diff --git a/core/logic/common_logic.cpp b/core/logic/common_logic.cpp index 675dd49e..d45c1ee7 100644 --- a/core/logic/common_logic.cpp +++ b/core/logic/common_logic.cpp @@ -109,11 +109,6 @@ static void AddNatives(sp_nativeinfo_t *natives) g_CoreNatives.AddNatives(natives); } -static void DumpHandles(void (*dumpfn)(const char *fmt, ...)) -{ - g_HandleSys.Dump(dumpfn); -} - static void RegisterProfiler(IProfilingTool *tool) { g_ProfileToolManager.RegisterTool(tool); @@ -154,7 +149,6 @@ static sm_logic_t logic = &g_DbgReporter, GenerateError, AddNatives, - DumpHandles, RegisterProfiler, OnRootCommand, CDataPack::New, diff --git a/core/sm_srvcmds.cpp b/core/sm_srvcmds.cpp index 59c23223..28662c9e 100644 --- a/core/sm_srvcmds.cpp +++ b/core/sm_srvcmds.cpp @@ -70,67 +70,3 @@ CON_COMMAND(sm, "SourceMod Menu") logicore.OnRootCommand(&cargs); } - -FILE *g_pHndlLog = NULL; - -void write_handles_to_log(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vfprintf(g_pHndlLog, fmt, ap); - fprintf(g_pHndlLog, "\n"); - va_end(ap); -} - -void write_handles_to_game(const char *fmt, ...) -{ - size_t len; - va_list ap; - char buffer[1024]; - - va_start(ap, fmt); - len = ke::SafeSprintf(buffer, sizeof(buffer)-2, fmt, ap); - va_end(ap); - - buffer[len] = '\n'; - buffer[len+1] = '\0'; - - engine->LogPrint(buffer); -} - -CON_COMMAND(sm_dump_handles, "Dumps Handle usage to a file for finding Handle leaks") -{ -#if SOURCE_ENGINE <= SE_DARKMESSIAH - CCommand args; -#endif - if (args.ArgC() < 2) - { - UTIL_ConsolePrint("Usage: sm_dump_handles or for game logs"); - return; - } - - if (strcmp(args.Arg(1), "log") != 0) - { - char filename[PLATFORM_MAX_PATH]; - const char *arg = args.Arg(1); - g_SourceMod.BuildPath(Path_Game, filename, sizeof(filename), "%s", arg); - - FILE *fp = fopen(filename, "wt"); - if (!fp) - { - UTIL_ConsolePrint("Failed to open \"%s\" for writing", filename); - return; - } - - g_pHndlLog = fp; - logicore.DumpHandles(write_handles_to_log); - g_pHndlLog = NULL; - - fclose(fp); - } - else - { - logicore.DumpHandles(write_handles_to_game); - } -} diff --git a/public/amtl b/public/amtl index c4c2aa3e..298217cb 160000 --- a/public/amtl +++ b/public/amtl @@ -1 +1 @@ -Subproject commit c4c2aa3e97157407c3832b40fed43ba9cd24a2c1 +Subproject commit 298217cbbfac16851bb58574bc6744f58b260b15