From da0a160371aa199b4bf966aee290347c575a181a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 15 Aug 2007 20:18:15 +0000 Subject: [PATCH] SourceMod will now spit out errors for scripts that become corrupt and would otherwise be crashing Core. if you get these errors contact the dev team. --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%401345 --- core/DebugReporter.cpp | 41 +++++++++++++++++++++++++++++- core/DebugReporter.h | 1 + core/systems/ForwardSys.cpp | 28 +++++++++++++-------- core/vm/sp_vm_basecontext.cpp | 47 +++++++++++++++++++++++------------ core/vm/sp_vm_function.cpp | 12 ++++++--- core/vm/sp_vm_function.h | 6 +++-- 6 files changed, 103 insertions(+), 32 deletions(-) diff --git a/core/DebugReporter.cpp b/core/DebugReporter.cpp index 2d93fdb9..42b448ab 100644 --- a/core/DebugReporter.cpp +++ b/core/DebugReporter.cpp @@ -75,12 +75,51 @@ void DebugReport::GenerateError(IPluginContext *ctx, cell_t func_idx, int err, c sp_public_t *function; if (ctx->GetPublicByIndex(func_idx, &function) == SP_ERROR_NONE) { - g_Logger.LogError("[SM] Unable to call function \"%s\" due to above errors.", function->name); + g_Logger.LogError("[SM] Unable to call function \"%s\" due to above error(s).", function->name); } } } } +void DebugReport::GenerateCodeError(IPluginContext *pContext, uint32_t code_addr, int err, const char *message, ...) +{ + va_list ap; + char buffer[512]; + + va_start(ap, message); + UTIL_FormatArgs(buffer, sizeof(buffer), message, ap); + va_end(ap); + + const char *plname = g_PluginSys.FindPluginByContext(pContext->GetContext())->GetFilename(); + const char *error = GetSourcePawnErrorMessage(err); + + if (error) + { + g_Logger.LogError("[SM] Plugin \"%s\" encountered error %d: %s", plname, err, error); + } else { + g_Logger.LogError("[SM] Plugin \"%s\" encountered unknown error %d", plname, err); + } + + g_Logger.LogError("[SM] %s", buffer); + + IPluginDebugInfo *pDebug; + if ((pDebug = pContext->GetDebugInfo()) == NULL) + { + g_Logger.LogError("[SM] Debug mode is not enabled for \"%s\"", plname); + g_Logger.LogError("[SM] To enable debug mode, edit plugin_settings.cfg, or type: sm plugins debug %d on", + _GetPluginIndex(pContext)); + return; + } + + const char *name; + if (pDebug->LookupFunction(code_addr, &name) == SP_ERROR_NONE) + { + g_Logger.LogError("[SM] Unable to call function \"%s\" due to above error(s).", name); + } else { + g_Logger.LogError("[SM] Unable to call function (name unknown, address \"%x\").", code_addr); + } +} + void DebugReport::OnContextExecuteError(IPluginContext *ctx, IContextTrace *error) { const char *lastname; diff --git a/core/DebugReporter.h b/core/DebugReporter.h index eb5ac50c..acac6571 100644 --- a/core/DebugReporter.h +++ b/core/DebugReporter.h @@ -44,6 +44,7 @@ public: // SMGlobalClass public: // IDebugListener void OnContextExecuteError(IPluginContext *ctx, IContextTrace *error); void GenerateError(IPluginContext *ctx, cell_t func_idx, int err, const char *message, ...); + void GenerateCodeError(IPluginContext *ctx, uint32_t code_addr, int err, const char *message, ...); private: int _GetPluginIndex(IPluginContext *ctx); }; diff --git a/core/systems/ForwardSys.cpp b/core/systems/ForwardSys.cpp index ad0615ca..cf42fa79 100644 --- a/core/systems/ForwardSys.cpp +++ b/core/systems/ForwardSys.cpp @@ -35,6 +35,7 @@ #include "ForwardSys.h" #include "PluginSys.h" #include "ShareSys.h" +#include "DebugReporter.h" CForwardManager g_Forwards; @@ -308,6 +309,7 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter) for (unsigned int i=0; i= m_numparams || m_types[i] == Param_Any) { @@ -322,31 +324,37 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter) */ if (type == Param_String) { - func->PushStringEx((char *)param->byref.orig_addr, param->byref.cells, param->byref.sz_flags, param->byref.flags); + err = func->PushStringEx((char *)param->byref.orig_addr, param->byref.cells, param->byref.sz_flags, param->byref.flags); } else if (type == Param_Float || type == Param_Cell) { - func->PushCellByRef(¶m->val); + err = func->PushCellByRef(¶m->val); } else { - func->PushArray(param->byref.orig_addr, param->byref.cells, param->byref.flags); + err = func->PushArray(param->byref.orig_addr, param->byref.cells, param->byref.flags); assert(type == Param_Array || type == Param_FloatByRef || type == Param_CellByRef); } } else { /* If we're not byref or not vararg, our job is a bit easier. */ assert(type == Param_Cell || type == Param_Float); - func->PushCell(param->val); + err = func->PushCell(param->val); + } + if (err != SP_ERROR_NONE) + { + if (!filter || !filter->OnErrorReport(this, func, err)) + { + g_DbgReporter.GenerateError(func->GetParentContext(), + func->GetFunctionID(), + err, + "Failed to push parameter while executing forward"); + } + continue; } } /* Call the function and deal with the return value. */ if ((err=func->Execute(&cur_result)) != SP_ERROR_NONE) { - bool handled = false; if (filter) { - handled = filter->OnErrorReport(this, func, err); - } - if (!handled) - { - /* :TODO: invoke global error reporting here */ + filter->OnErrorReport(this, func, err); } failed++; } else { diff --git a/core/vm/sp_vm_basecontext.cpp b/core/vm/sp_vm_basecontext.cpp index 9bb3ab65..d88cad03 100644 --- a/core/vm/sp_vm_basecontext.cpp +++ b/core/vm/sp_vm_basecontext.cpp @@ -39,6 +39,7 @@ #ifdef SOURCEMOD_BUILD #include "Logger.h" +#include "DebugReporter.h" #endif using namespace SourcePawn; @@ -149,7 +150,7 @@ void BaseContext::RefreshFunctionCache() { continue; } - m_pub_funcs[i]->Set(pub->code_offs, this); + m_pub_funcs[i]->Set(pub->code_offs, this, pub->funcid); } } @@ -221,6 +222,10 @@ int BaseContext::SetDebugBreak(SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn) IPluginDebugInfo *BaseContext::GetDebugInfo() { + if (!IsDebugging()) + { + return NULL; + } return this; } @@ -243,7 +248,13 @@ int BaseContext::Execute(uint32_t code_addr, cell_t *result) uint32_t pushcount = ctx->pushcount; int err; - PushCell(pushcount++); + if ((err = PushCell(pushcount++)) != SP_ERROR_NONE) + { +#if defined SOURCEMOD_BUILD + g_DbgReporter.GenerateCodeError(this, code_addr, err, "Stack error; cannot complete execution!"); +#endif + return SP_ERROR_NOT_RUNNABLE; + } ctx->pushcount = 0; cell_t save_sp = ctx->sp; @@ -271,26 +282,30 @@ int BaseContext::Execute(uint32_t code_addr, cell_t *result) */ g_SourcePawn.PopTracer(err, m_CustomMsg ? m_MsgCache : NULL); -#if 1//defined _DEBUG - //:TODO: debug code for leak detection, remove before the release? +#if defined SOURCEMOD_BUILD if (err == SP_ERROR_NONE) { if ((ctx->sp - (cell_t)(pushcount * sizeof(cell_t))) != save_sp) { - const char *name; - ctx->context->GetDebugInfo()->LookupFunction(code_addr, &name); - g_Logger.LogError("Stack leak detected: sp:%d should be %d on function %s", ctx->sp, save_sp, name); + g_DbgReporter.GenerateCodeError(this, + code_addr, + SP_ERROR_STACKLEAK, + "Stack leak detected: sp:%d should be %d!", + ctx->sp, + save_sp); } if (ctx->hp != save_hp) { - const char *name; - ctx->context->GetDebugInfo()->LookupFunction(code_addr, &name); - g_Logger.LogError("Heap leak detected: hp:%d should be %d on function %s", ctx->hp, save_hp, name); + g_DbgReporter.GenerateCodeError(this, + code_addr, + SP_ERROR_HEAPLEAK, + "Heap leak detected: sp:%d should be %d!", + ctx->hp, + save_hp); } - //assert(ctx->sp - pushcount * sizeof(cell_t) == save_sp); - //assert(ctx->hp == save_hp); } #endif + if (err != SP_ERROR_NONE) { ctx->sp = save_sp; @@ -958,10 +973,10 @@ IPluginFunction *BaseContext::GetFunctionById(funcid_t func_id) pFunc = m_pub_funcs[func_id]; if (!pFunc) { - m_pub_funcs[func_id] = new CFunction(ctx->publics[func_id].code_offs, this); + m_pub_funcs[func_id] = new CFunction(ctx->publics[func_id].code_offs, this, ctx->publics[func_id].funcid); pFunc = m_pub_funcs[func_id]; } else if (pFunc->IsInvalidated()) { - pFunc->Set(ctx->publics[func_id].code_offs, this); + pFunc->Set(ctx->publics[func_id].code_offs, this, ctx->publics[func_id].funcid); } } else { /* :TODO: currently not used */ @@ -1001,7 +1016,7 @@ IPluginFunction *BaseContext::GetFunctionByName(const char *public_name) GetPublicByIndex(index, &pub); if (pub) { - m_pub_funcs[index] = new CFunction(pub->code_offs, this); + m_pub_funcs[index] = new CFunction(pub->code_offs, this, pub->funcid); } pFunc = m_pub_funcs[index]; } else if (pFunc->IsInvalidated()) { @@ -1009,7 +1024,7 @@ IPluginFunction *BaseContext::GetFunctionByName(const char *public_name) GetPublicByIndex(index, &pub); if (pub) { - pFunc->Set(pub->code_offs, this); + pFunc->Set(pub->code_offs, this, pub->funcid); } else { pFunc = NULL; } diff --git a/core/vm/sp_vm_function.cpp b/core/vm/sp_vm_function.cpp index b87eaf7f..bb0b1b08 100644 --- a/core/vm/sp_vm_function.cpp +++ b/core/vm/sp_vm_function.cpp @@ -37,7 +37,7 @@ * FUNCTION CALLING * ********************/ -void CFunction::Set(uint32_t code_addr, IPluginContext *plugin) +void CFunction::Set(uint32_t code_addr, IPluginContext *plugin, funcid_t id) { m_codeaddr = code_addr; m_pContext = plugin; @@ -45,6 +45,7 @@ void CFunction::Set(uint32_t code_addr, IPluginContext *plugin) m_errorstate = SP_ERROR_NONE; m_Invalid = false; m_pCtx = plugin ? plugin->GetContext() : NULL; + m_FnId = id; } bool CFunction::IsRunnable() @@ -72,9 +73,9 @@ IPluginContext *CFunction::GetParentContext() return m_pContext; } -CFunction::CFunction(uint32_t code_addr, IPluginContext *plugin) : +CFunction::CFunction(uint32_t code_addr, IPluginContext *plugin, funcid_t id) : m_codeaddr(code_addr), m_pContext(plugin), m_curparam(0), - m_errorstate(SP_ERROR_NONE) + m_errorstate(SP_ERROR_NONE), m_FnId(id) { m_Invalid = false; if (plugin) @@ -313,3 +314,8 @@ int CFunction::Execute(cell_t *result) return err; } + +funcid_t CFunction::GetFunctionID() +{ + return m_FnId; +} diff --git a/core/vm/sp_vm_function.h b/core/vm/sp_vm_function.h index 1dcf3acb..f1bf210b 100644 --- a/core/vm/sp_vm_function.h +++ b/core/vm/sp_vm_function.h @@ -55,7 +55,7 @@ class CFunction : public IPluginFunction { friend class SourcePawnEngine; public: - CFunction(uint32_t code_addr, IPluginContext *pContext); + CFunction(uint32_t code_addr, IPluginContext *pContext, funcid_t fnid); public: virtual int PushCell(cell_t cell); virtual int PushCellByRef(cell_t *cell, int flags); @@ -77,8 +77,9 @@ public: m_Invalid = true; } bool IsRunnable(); + funcid_t GetFunctionID(); public: - void Set(uint32_t code_addr, IPluginContext *plugin); + void Set(uint32_t code_addr, IPluginContext *plugin, funcid_t fnid); private: int _PushString(const char *string, int sz_flags, int cp_flags, size_t len); inline int SetError(int err) @@ -96,6 +97,7 @@ private: int m_errorstate; CFunction *m_pNext; bool m_Invalid; + funcid_t m_FnId; }; #endif //_INCLUDE_SOURCEMOD_BASEFUNCTION_H_