Catch runtime errors
crashdetect can report runtime errors to a public function - hook this function and use it to throw exceptions.
One of the problems with doing this is the outer public function will return 0 before OnRuntimeError, which makes it impossible to gracefully handle runtime errors in callbacks such as OnPlayerUpdate and OnPlayerCommandText.
Old code for this:
forward OnRuntimeError(code);
public OnRuntimeError(code) {
if (s_UncaughtException) {
return;
}
static const sc_messages[28][54] = {
/* AMX_ERR_NONE */ "None",
/* AMX_ERR_EXIT */ "Forced exit",
/* AMX_ERR_ASSERT */ "Assertion failed",
/* AMX_ERR_STACKERR */ "Stack/heap collision (insufficient stack size)",
/* AMX_ERR_BOUNDS */ "Array index out of bounds",
/* AMX_ERR_MEMACCESS */ "Invalid memory access",
/* AMX_ERR_INVINSTR */ "Invalid instruction",
/* AMX_ERR_STACKLOW */ "Stack underflow",
/* AMX_ERR_HEAPLOW */ "Heap underflow",
/* AMX_ERR_CALLBACK */ "No (valid) native function callback",
/* AMX_ERR_NATIVE */ "Native function failed",
/* AMX_ERR_DIVIDE */ "Divide by zero",
/* AMX_ERR_SLEEP */ "sleep mode",
/* 13 */ "reserved",
/* 14 */ "reserved",
/* 15 */ "reserved",
/* AMX_ERR_MEMORY */ "Out of memory",
/* AMX_ERR_FORMAT */ "Invalid/unsupported P-code file format",
/* AMX_ERR_VERSION */ "File is for a newer version of the AMX",
/* AMX_ERR_NOTFOUND */ "File or function is not found",
/* AMX_ERR_INDEX */ "Invalid index parameter (bad entry point)",
/* AMX_ERR_DEBUG */ "Debugger cannot run",
/* AMX_ERR_INIT */ "AMX not initialized (or doubly initialized)",
/* AMX_ERR_USERDATA */ "Unable to set user data field (table full)",
/* AMX_ERR_INIT_JIT */ "Cannot initialize the JIT",
/* AMX_ERR_PARAMS */ "Parameter error",
/* AMX_ERR_DOMAIN */ "Domain error, expression result does not fit in range",
/* AMX_ERR_GENERAL */ "General error (unknown or unspecific error)"
};
static msg[128];
if (0 <= code < sizeof(sc_messages)) {
format(msg, sizeof(msg), "runtime error %d: %s", code, sc_messages[code]);
} else {
format(msg, sizeof(msg), "runtime error %d", code);
}
if (funcidx(!"Exceptions_OnRuntimeError") != -1) {
CallLocalFunction(!"Exceptions_OnRuntimeError", !"i", code);
}
ThrowError(msg);
}
#if defined _ALS_OnRuntimeError
#undef OnRuntimeError
#else
#define _ALS_OnRuntimeError
#endif
#define OnRuntimeError Exceptions_OnRuntimeError
@Zeex do you think it would be possible to avoid when a runtime error happens?
For example: if you catch AMX_ERR_BOUNDS in OnPlayerCommandText, can you prevent SERVER: Unknown command?
Should be possible now with this: https://github.com/Zeex/samp-plugin-crashdetect/commit/bbea212ce8c11e9b66d7c5b964040ec23c844adf
Now basically whatever you return in OnRuntimeError is returned to the server like if you return from the public itself. You can make a table of "default" return values for all SA-MP callbacks and return them in case of an error.
Nice!