diff options
Diffstat (limited to 'src/script/common/c_internal.cpp')
-rw-r--r-- | src/script/common/c_internal.cpp | 84 |
1 files changed, 64 insertions, 20 deletions
diff --git a/src/script/common/c_internal.cpp b/src/script/common/c_internal.cpp index f811dd5d3..2a10ce0f2 100644 --- a/src/script/common/c_internal.cpp +++ b/src/script/common/c_internal.cpp @@ -20,7 +20,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "common/c_internal.h" #include "debug.h" #include "log.h" -#include "main.h" #include "settings.h" std::string script_get_backtrace(lua_State *L) @@ -64,19 +63,65 @@ int script_exception_wrapper(lua_State *L, lua_CFunction f) return f(L); // Call wrapped function and return result. } catch (const char *s) { // Catch and convert exceptions. lua_pushstring(L, s); - } catch (std::exception& e) { + } catch (std::exception &e) { lua_pushstring(L, e.what()); - } catch (...) { - lua_pushliteral(L, "caught (...)"); } return lua_error(L); // Rethrow as a Lua error. } -void script_error(lua_State *L) +/* + * Note that we can't get tracebacks for LUA_ERRMEM or LUA_ERRERR (without + * hacking Lua internals). For LUA_ERRMEM, this is because memory errors will + * not execute the the error handler, and by the time lua_pcall returns the + * execution stack will have already been unwound. For LUA_ERRERR, there was + * another error while trying to generate a backtrace from a LUA_ERRRUN. It is + * presumed there is an error with the internal Lua state and thus not possible + * to gather a coherent backtrace. Realistically, the best we can do here is + * print which C function performed the failing pcall. + */ +void script_error(lua_State *L, int pcall_result, const char *mod, const char *fxn) { - const char *s = lua_tostring(L, -1); - std::string str(s ? s : ""); - throw LuaError(str); + if (pcall_result == 0) + return; + + const char *err_type; + switch (pcall_result) { + case LUA_ERRRUN: + err_type = "Runtime"; + break; + case LUA_ERRMEM: + err_type = "OOM"; + break; + case LUA_ERRERR: + err_type = "Double fault"; + break; + default: + err_type = "Unknown"; + } + + if (!mod) + mod = "??"; + + if (!fxn) + fxn = "??"; + + const char *err_descr = lua_tostring(L, -1); + if (!err_descr) + err_descr = "<no description>"; + + char buf[256]; + snprintf(buf, sizeof(buf), "%s error from mod '%s' in callback %s(): ", + err_type, mod, fxn); + + std::string err_msg(buf); + err_msg += err_descr; + + if (pcall_result == LUA_ERRMEM) { + err_msg += "\nCurrent Lua memory usage: " + + itos(lua_gc(L, LUA_GCCOUNT, 0) >> 10) + " MB"; + } + + throw LuaError(err_msg); } // Push the list of callbacks (a lua table). @@ -85,9 +130,10 @@ void script_error(lua_State *L) // - runs the callbacks // - replaces the table and arguments with the return value, // computed depending on mode -void script_run_callbacks(lua_State *L, int nargs, RunCallbacksMode mode) +void script_run_callbacks_f(lua_State *L, int nargs, + RunCallbacksMode mode, const char *fxn) { - assert(lua_gettop(L) >= nargs + 1); + FATAL_ERROR_IF(lua_gettop(L) < nargs + 1, "Not enough arguments"); // Insert error handler lua_pushcfunction(L, script_error_handler); @@ -107,14 +153,14 @@ void script_run_callbacks(lua_State *L, int nargs, RunCallbacksMode mode) // Stack now looks like this: // ... <error handler> <run_callbacks> <table> <mode> <arg#1> <arg#2> ... <arg#n> - if (lua_pcall(L, nargs + 2, 1, errorhandler)) { - script_error(L); - } + int result = lua_pcall(L, nargs + 2, 1, errorhandler); + if (result != 0) + script_error(L, result, NULL, fxn); lua_remove(L, -2); // Remove error handler } -void log_deprecated(lua_State *L, std::string message) +void log_deprecated(lua_State *L, const std::string &message) { static bool configured = false; static bool dolog = false; @@ -125,8 +171,7 @@ void log_deprecated(lua_State *L, std::string message) std::string value = g_settings->get("deprecated_lua_api_handling"); if (value == "log") { dolog = true; - } - if (value == "error") { + } else if (value == "error") { dolog = true; doerror = true; } @@ -134,11 +179,10 @@ void log_deprecated(lua_State *L, std::string message) if (doerror) { if (L != NULL) { - script_error(L); + script_error(L, LUA_ERRRUN, NULL, NULL); } else { - /* As of april 2014 assert is not optimized to nop in release builds - * therefore this is correct. */ - assert("Can't do a scripterror for this deprecated message, so exit completely!"); + FATAL_ERROR("Can't do a scripterror for this deprecated message, " + "so exit completely!"); } } |