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
This commit is contained in:
parent
290f90a3a3
commit
da0a160371
@ -75,12 +75,51 @@ void DebugReport::GenerateError(IPluginContext *ctx, cell_t func_idx, int err, c
|
|||||||
sp_public_t *function;
|
sp_public_t *function;
|
||||||
if (ctx->GetPublicByIndex(func_idx, &function) == SP_ERROR_NONE)
|
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)
|
void DebugReport::OnContextExecuteError(IPluginContext *ctx, IContextTrace *error)
|
||||||
{
|
{
|
||||||
const char *lastname;
|
const char *lastname;
|
||||||
|
@ -44,6 +44,7 @@ public: // SMGlobalClass
|
|||||||
public: // IDebugListener
|
public: // IDebugListener
|
||||||
void OnContextExecuteError(IPluginContext *ctx, IContextTrace *error);
|
void OnContextExecuteError(IPluginContext *ctx, IContextTrace *error);
|
||||||
void GenerateError(IPluginContext *ctx, cell_t func_idx, int err, const char *message, ...);
|
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:
|
private:
|
||||||
int _GetPluginIndex(IPluginContext *ctx);
|
int _GetPluginIndex(IPluginContext *ctx);
|
||||||
};
|
};
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
#include "ForwardSys.h"
|
#include "ForwardSys.h"
|
||||||
#include "PluginSys.h"
|
#include "PluginSys.h"
|
||||||
#include "ShareSys.h"
|
#include "ShareSys.h"
|
||||||
|
#include "DebugReporter.h"
|
||||||
|
|
||||||
CForwardManager g_Forwards;
|
CForwardManager g_Forwards;
|
||||||
|
|
||||||
@ -308,6 +309,7 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter)
|
|||||||
|
|
||||||
for (unsigned int i=0; i<num_params; i++)
|
for (unsigned int i=0; i<num_params; i++)
|
||||||
{
|
{
|
||||||
|
int err = SP_ERROR_PARAM;
|
||||||
param = &temp_info[i];
|
param = &temp_info[i];
|
||||||
if (i >= m_numparams || m_types[i] == Param_Any)
|
if (i >= m_numparams || m_types[i] == Param_Any)
|
||||||
{
|
{
|
||||||
@ -322,31 +324,37 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter)
|
|||||||
*/
|
*/
|
||||||
if (type == Param_String)
|
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) {
|
} else if (type == Param_Float || type == Param_Cell) {
|
||||||
func->PushCellByRef(¶m->val);
|
err = func->PushCellByRef(¶m->val);
|
||||||
} else {
|
} 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);
|
assert(type == Param_Array || type == Param_FloatByRef || type == Param_CellByRef);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* If we're not byref or not vararg, our job is a bit easier. */
|
/* If we're not byref or not vararg, our job is a bit easier. */
|
||||||
assert(type == Param_Cell || type == Param_Float);
|
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. */
|
/* Call the function and deal with the return value. */
|
||||||
if ((err=func->Execute(&cur_result)) != SP_ERROR_NONE)
|
if ((err=func->Execute(&cur_result)) != SP_ERROR_NONE)
|
||||||
{
|
{
|
||||||
bool handled = false;
|
|
||||||
if (filter)
|
if (filter)
|
||||||
{
|
{
|
||||||
handled = filter->OnErrorReport(this, func, err);
|
filter->OnErrorReport(this, func, err);
|
||||||
}
|
|
||||||
if (!handled)
|
|
||||||
{
|
|
||||||
/* :TODO: invoke global error reporting here */
|
|
||||||
}
|
}
|
||||||
failed++;
|
failed++;
|
||||||
} else {
|
} else {
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
|
|
||||||
#ifdef SOURCEMOD_BUILD
|
#ifdef SOURCEMOD_BUILD
|
||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
|
#include "DebugReporter.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using namespace SourcePawn;
|
using namespace SourcePawn;
|
||||||
@ -149,7 +150,7 @@ void BaseContext::RefreshFunctionCache()
|
|||||||
{
|
{
|
||||||
continue;
|
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()
|
IPluginDebugInfo *BaseContext::GetDebugInfo()
|
||||||
{
|
{
|
||||||
|
if (!IsDebugging())
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -243,7 +248,13 @@ int BaseContext::Execute(uint32_t code_addr, cell_t *result)
|
|||||||
uint32_t pushcount = ctx->pushcount;
|
uint32_t pushcount = ctx->pushcount;
|
||||||
int err;
|
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;
|
ctx->pushcount = 0;
|
||||||
|
|
||||||
cell_t save_sp = ctx->sp;
|
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);
|
g_SourcePawn.PopTracer(err, m_CustomMsg ? m_MsgCache : NULL);
|
||||||
|
|
||||||
#if 1//defined _DEBUG
|
#if defined SOURCEMOD_BUILD
|
||||||
//:TODO: debug code for leak detection, remove before the release?
|
|
||||||
if (err == SP_ERROR_NONE)
|
if (err == SP_ERROR_NONE)
|
||||||
{
|
{
|
||||||
if ((ctx->sp - (cell_t)(pushcount * sizeof(cell_t))) != save_sp)
|
if ((ctx->sp - (cell_t)(pushcount * sizeof(cell_t))) != save_sp)
|
||||||
{
|
{
|
||||||
const char *name;
|
g_DbgReporter.GenerateCodeError(this,
|
||||||
ctx->context->GetDebugInfo()->LookupFunction(code_addr, &name);
|
code_addr,
|
||||||
g_Logger.LogError("Stack leak detected: sp:%d should be %d on function %s", ctx->sp, save_sp, name);
|
SP_ERROR_STACKLEAK,
|
||||||
|
"Stack leak detected: sp:%d should be %d!",
|
||||||
|
ctx->sp,
|
||||||
|
save_sp);
|
||||||
}
|
}
|
||||||
if (ctx->hp != save_hp)
|
if (ctx->hp != save_hp)
|
||||||
{
|
{
|
||||||
const char *name;
|
g_DbgReporter.GenerateCodeError(this,
|
||||||
ctx->context->GetDebugInfo()->LookupFunction(code_addr, &name);
|
code_addr,
|
||||||
g_Logger.LogError("Heap leak detected: hp:%d should be %d on function %s", ctx->hp, save_hp, name);
|
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
|
#endif
|
||||||
|
|
||||||
if (err != SP_ERROR_NONE)
|
if (err != SP_ERROR_NONE)
|
||||||
{
|
{
|
||||||
ctx->sp = save_sp;
|
ctx->sp = save_sp;
|
||||||
@ -958,10 +973,10 @@ IPluginFunction *BaseContext::GetFunctionById(funcid_t func_id)
|
|||||||
pFunc = m_pub_funcs[func_id];
|
pFunc = m_pub_funcs[func_id];
|
||||||
if (!pFunc)
|
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];
|
pFunc = m_pub_funcs[func_id];
|
||||||
} else if (pFunc->IsInvalidated()) {
|
} 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 {
|
} else {
|
||||||
/* :TODO: currently not used */
|
/* :TODO: currently not used */
|
||||||
@ -1001,7 +1016,7 @@ IPluginFunction *BaseContext::GetFunctionByName(const char *public_name)
|
|||||||
GetPublicByIndex(index, &pub);
|
GetPublicByIndex(index, &pub);
|
||||||
if (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];
|
pFunc = m_pub_funcs[index];
|
||||||
} else if (pFunc->IsInvalidated()) {
|
} else if (pFunc->IsInvalidated()) {
|
||||||
@ -1009,7 +1024,7 @@ IPluginFunction *BaseContext::GetFunctionByName(const char *public_name)
|
|||||||
GetPublicByIndex(index, &pub);
|
GetPublicByIndex(index, &pub);
|
||||||
if (pub)
|
if (pub)
|
||||||
{
|
{
|
||||||
pFunc->Set(pub->code_offs, this);
|
pFunc->Set(pub->code_offs, this, pub->funcid);
|
||||||
} else {
|
} else {
|
||||||
pFunc = NULL;
|
pFunc = NULL;
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
* FUNCTION CALLING *
|
* 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_codeaddr = code_addr;
|
||||||
m_pContext = plugin;
|
m_pContext = plugin;
|
||||||
@ -45,6 +45,7 @@ void CFunction::Set(uint32_t code_addr, IPluginContext *plugin)
|
|||||||
m_errorstate = SP_ERROR_NONE;
|
m_errorstate = SP_ERROR_NONE;
|
||||||
m_Invalid = false;
|
m_Invalid = false;
|
||||||
m_pCtx = plugin ? plugin->GetContext() : NULL;
|
m_pCtx = plugin ? plugin->GetContext() : NULL;
|
||||||
|
m_FnId = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CFunction::IsRunnable()
|
bool CFunction::IsRunnable()
|
||||||
@ -72,9 +73,9 @@ IPluginContext *CFunction::GetParentContext()
|
|||||||
return m_pContext;
|
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_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;
|
m_Invalid = false;
|
||||||
if (plugin)
|
if (plugin)
|
||||||
@ -313,3 +314,8 @@ int CFunction::Execute(cell_t *result)
|
|||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
funcid_t CFunction::GetFunctionID()
|
||||||
|
{
|
||||||
|
return m_FnId;
|
||||||
|
}
|
||||||
|
@ -55,7 +55,7 @@ class CFunction : public IPluginFunction
|
|||||||
{
|
{
|
||||||
friend class SourcePawnEngine;
|
friend class SourcePawnEngine;
|
||||||
public:
|
public:
|
||||||
CFunction(uint32_t code_addr, IPluginContext *pContext);
|
CFunction(uint32_t code_addr, IPluginContext *pContext, funcid_t fnid);
|
||||||
public:
|
public:
|
||||||
virtual int PushCell(cell_t cell);
|
virtual int PushCell(cell_t cell);
|
||||||
virtual int PushCellByRef(cell_t *cell, int flags);
|
virtual int PushCellByRef(cell_t *cell, int flags);
|
||||||
@ -77,8 +77,9 @@ public:
|
|||||||
m_Invalid = true;
|
m_Invalid = true;
|
||||||
}
|
}
|
||||||
bool IsRunnable();
|
bool IsRunnable();
|
||||||
|
funcid_t GetFunctionID();
|
||||||
public:
|
public:
|
||||||
void Set(uint32_t code_addr, IPluginContext *plugin);
|
void Set(uint32_t code_addr, IPluginContext *plugin, funcid_t fnid);
|
||||||
private:
|
private:
|
||||||
int _PushString(const char *string, int sz_flags, int cp_flags, size_t len);
|
int _PushString(const char *string, int sz_flags, int cp_flags, size_t len);
|
||||||
inline int SetError(int err)
|
inline int SetError(int err)
|
||||||
@ -96,6 +97,7 @@ private:
|
|||||||
int m_errorstate;
|
int m_errorstate;
|
||||||
CFunction *m_pNext;
|
CFunction *m_pNext;
|
||||||
bool m_Invalid;
|
bool m_Invalid;
|
||||||
|
funcid_t m_FnId;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //_INCLUDE_SOURCEMOD_BASEFUNCTION_H_
|
#endif //_INCLUDE_SOURCEMOD_BASEFUNCTION_H_
|
||||||
|
Loading…
Reference in New Issue
Block a user