handlesys: Output allocation timestamp during panic (#1110)

* Track Handle creation time

* Move ConVar operations outside of loop

* We support bee's here

* Catch windows awfulness

* Prevent Character Truncation

* Add timestamp info to memory leak dump

* Remove last line and adjust new leak dump output

* KyleS fixes

* Fixed width output

* Create invalid parameter failure redirection helper

* Fix rebase regression

* Update sm_invalidparamhandler.h

* Update HandleSys.cpp

* Update HandleSys.cpp

* Update HandleSys.cpp

Co-authored-by: Kyle Sanderson <[email protected]>
This commit is contained in:
Headline
2020-07-09 18:21:45 -07:00
committed by GitHub
co-authored by Kyle Sanderson
parent a065773b6d
commit 2653a450fc
6 changed files with 174 additions and 79 deletions
+68 -6
View File
@@ -30,6 +30,7 @@
*/
#include "HandleSys.h"
#include <time.h>
#include <assert.h>
#include <string.h>
#include "common_logic.h"
@@ -38,10 +39,18 @@
#include "PluginSys.h"
#include <am-string.h>
#include <bridge/include/ILogger.h>
#include <bridge/include/CoreProvider.h>
#include <ISourceMod.h>
#include "sm_platform.h"
#ifdef PLATFORM_WINDOWS
#include "sm_invalidparamhandler.h"
#endif
HandleSystem g_HandleSys;
QHandle *ignore_handle;
extern ConVar *g_datetime_format;
inline HandleType_t TypeParent(HandleType_t type)
{
@@ -430,7 +439,7 @@ Handle_t HandleSystem::CreateHandleInt(HandleType_t type,
pHandle->object = object;
pHandle->clone = 0;
pHandle->timestamp = g_pSM->GetAdjustedTime();
return handle;
}
@@ -1014,6 +1023,8 @@ bool HandleSystem::TryAndFreeSomeHandles()
unsigned int * pCount = new unsigned int[HANDLESYS_TYPEARRAY_SIZE+1];
memset(pCount, 0, ((HANDLESYS_TYPEARRAY_SIZE + 1) * sizeof(unsigned int)));
const QHandle *oldest = nullptr;
const QHandle *newest = nullptr;
for (unsigned int i = 1; i <= m_HandleTail; ++i)
{
const QHandle &Handle = m_Handles[i];
@@ -1030,6 +1041,15 @@ bool HandleSystem::TryAndFreeSomeHandles()
highest_index = ((Handle.type) + 1);
}
if (!oldest || oldest->timestamp > Handle.timestamp)
{
oldest = &Handle;
}
if (!newest || newest->timestamp < Handle.timestamp)
{
newest = &Handle;
}
if (Handle.clone != 0)
{
continue;
@@ -1057,7 +1077,33 @@ bool HandleSystem::TryAndFreeSomeHandles()
HANDLE_LOG_VERY_BAD("Type\t%-20.20s|\tCount\t%u", pTypeName, pCount[i]);
}
const char *fmt = bridge->GetCvarString(g_datetime_format);
char oldstamp[256], newstamp[256]; // 256 should be more than enough
// scope for InvalidParameterHandler
{
#ifdef PLATFORM_WINDOWS
InvalidParameterHandler p;
#endif
size_t written = strftime(oldstamp, sizeof(oldstamp), fmt, localtime(&oldest->timestamp));
if (!written)
{
ke::SafeStrcpy(oldstamp, sizeof(oldstamp), "INVALID");
}
written = strftime(newstamp, sizeof(newstamp), fmt, localtime(&newest->timestamp));
if (!written)
{
ke::SafeStrcpy(newstamp, sizeof(newstamp), "INVALID");
}
}
HANDLE_LOG_VERY_BAD("--------------------------------------------------------------------------");
HANDLE_LOG_VERY_BAD("Oldest Living Handle: %s created at %s", m_Types[oldest->type].name->c_str(), oldstamp);
HANDLE_LOG_VERY_BAD("Newest Living Handle: %s created at %s", m_Types[newest->type].name->c_str(), newstamp);
HANDLE_LOG_VERY_BAD("-- Approximately %d bytes of memory are in use by (%u) Handles.\n", total_size, total);
delete [] pCount;
@@ -1081,8 +1127,10 @@ static void rep(const HandleReporter &fn, const char *fmt, ...)
void HandleSystem::Dump(const HandleReporter &fn)
{
unsigned int total_size = 0;
rep(fn, "%-10.10s\t%-20.20s\t%-20.20s\t%-10.10s", "Handle", "Owner", "Type", "Memory");
rep(fn, "--------------------------------------------------------------------------");
rep(fn, "%-10.10s\t%-20.20s\t%-20.20s\t%-10.10s\t%-30.30s", "Handle", "Owner", "Type", "Memory", "Time Created");
rep(fn, "---------------------------------------------------------------------------------------------");
const char *fmt = bridge->GetCvarString(g_datetime_format);
for (unsigned int i = 1; i <= m_HandleTail; i++)
{
if (m_Handles[i].set != HandleSet_Used)
@@ -1150,19 +1198,33 @@ void HandleSystem::Dump(const HandleReporter &fn)
bresult = pType->dispatch->GetHandleApproxSize(m_Handles[i].type, m_Handles[i].object, &size);
}
char date[256]; // 256 should be more than enough
size_t written = 0;
// scope for InvalidParameterHandler
{
#ifdef PLATFORM_WINDOWS
InvalidParameterHandler p;
#endif
written = strftime(date, sizeof(date), fmt, localtime(&m_Handles[i].timestamp));
}
if (!written)
{
ke::SafeStrcpy(date, sizeof(date), "INVALID");
}
if (pType->dispatch->GetDispatchVersion() < HANDLESYS_MEMUSAGE_MIN_VERSION
|| !bresult)
{
rep(fn, "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\t%-30.30s", index, owner, type, "-1", date);
}
else
{
char buffer[32];
ke::SafeSprintf(buffer, sizeof(buffer), "%d", size);
rep(fn, "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\t%-30.30s", index, owner, type, buffer, date);
total_size += size;
}
}
rep(fn, "-- Approximately %d bytes of memory are in use by Handles.\n", total_size);
}
+1
View File
@@ -90,6 +90,7 @@ struct QHandle
bool access_special; /* Whether or not access rules are special or type-derived */
bool is_destroying; /* Whether or not the handle is being destroyed */
HandleAccess sec; /* Security rules */
time_t timestamp; /* Creation timestamp */
/* The following variables are unrelated to the Handle array, and used
* as an inlined chain of information */
unsigned int freeID; /* ID of a free handle in the free handle chain */
+14 -25
View File
@@ -45,6 +45,7 @@
#if defined PLATFORM_WINDOWS
#include <windows.h>
#include "sm_invalidparamhandler.h"
#elif defined PLATFORM_POSIX
#include <limits.h>
#include <unistd.h>
@@ -65,7 +66,7 @@ HandleType_t g_FrameIter;
IForward *g_OnLogAction = NULL;
static ConVar *sm_datetime_format = NULL;
ConVar *g_datetime_format = NULL;
class CoreNativeHelpers :
public SMGlobalClass,
@@ -91,7 +92,7 @@ public:
Param_Cell,
Param_String);
sm_datetime_format = bridge->FindConVar("sm_datetime_format");
g_datetime_format = bridge->FindConVar("sm_datetime_format");
}
void OnHandleDestroy(HandleType_t type, void *object)
{
@@ -173,19 +174,6 @@ static cell_t GetTime(IPluginContext *pContext, const cell_t *params)
return static_cast<cell_t>(t);
}
#if defined SUBPLATFORM_SECURECRT
void _ignore_invalid_parameter(
const wchar_t * expression,
const wchar_t * function,
const wchar_t * file,
unsigned int line,
uintptr_t pReserved
)
{
/* Wow we don't care, thanks Microsoft. */
}
#endif
static cell_t FormatTime(IPluginContext *pContext, const cell_t *params)
{
char *format, *buffer;
@@ -194,19 +182,20 @@ static cell_t FormatTime(IPluginContext *pContext, const cell_t *params)
if (format == NULL)
{
format = const_cast<char *>(bridge->GetCvarString(sm_datetime_format));
format = const_cast<char *>(bridge->GetCvarString(g_datetime_format));
}
#if defined SUBPLATFORM_SECURECRT
_invalid_parameter_handler handler = _set_invalid_parameter_handler(_ignore_invalid_parameter);
#endif
time_t t = (params[4] == -1) ? g_pSM->GetAdjustedTime() : (time_t)params[4];
size_t written = strftime(buffer, params[2], format, localtime(&t));
#if defined SUBPLATFORM_SECURECRT
_set_invalid_parameter_handler(handler);
time_t t;
size_t written = 0;
// scope for InvalidParameterHandler
{
#ifdef PLATFORM_WINDOWS
InvalidParameterHandler p;
#endif
t = (params[4] == -1) ? g_pSM->GetAdjustedTime() : (time_t)params[4];
written = strftime(buffer, params[2], format, localtime(&t));
}
if (params[2] && format[0] != '\0' && !written)
{