]> git.lizzy.rs Git - minetest.git/commitdiff
Use a Lua error handler that calls tostring (#11913)
authorJude Melton-Houghton <jwmhjwmh@gmail.com>
Thu, 15 Dec 2022 12:37:49 +0000 (07:37 -0500)
committerGitHub <noreply@github.com>
Thu, 15 Dec 2022 12:37:49 +0000 (07:37 -0500)
builtin/init.lua
doc/lua_api.txt
src/script/common/c_internal.cpp
src/script/common/c_internal.h
src/script/cpp_api/s_base.cpp

index 96e7a937c0963f8e1ea36318d34a654d1cf34655..e03c2c6deb379aaa3b200d5e440811f520bce621 100644 (file)
@@ -6,6 +6,9 @@
 --
 
 -- Initialize some very basic things
+function core.error_handler(err, level)
+       return debug.traceback(tostring(err), level)
+end
 do
        local function concat_args(...)
                local n, t = select("#", ...), {...}
index e017df88069064a3360939abdc28afddc505c052..ba6ff75f3d5d88ef1bd24cb9f20c2abc8e005e7c 100644 (file)
@@ -9956,3 +9956,17 @@ Bit Library
 Functions: bit.tobit, bit.tohex, bit.bnot, bit.band, bit.bor, bit.bxor, bit.lshift, bit.rshift, bit.arshift, bit.rol, bit.ror, bit.bswap
 
 See http://bitop.luajit.org/ for advanced information.
+
+Error Handling
+--------------
+
+When an error occurs that is not caught, Minetest calls the function
+`minetest.error_handler` with the error object as its first argument. The second
+argument is the stack level where the error occurred. The return value is the
+error string that should be shown. By default this is a backtrace from
+`debug.traceback`. If the error object is not a string, it is first converted
+with `tostring` before being displayed. This means that you can use tables as
+error objects so long as you give them `__tostring` metamethods.
+
+You can override `minetest.error_handler`. You should call the previous handler
+with the correct stack level in your implementation.
index ddd2d184c5b320186846e7647326871f4dc9799b..79063141d3e86ebb0f0944161bed04f655c0a297 100644 (file)
@@ -27,10 +27,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 std::string script_get_backtrace(lua_State *L)
 {
-       lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_BACKTRACE);
+       lua_getglobal(L, "debug");
+       lua_getfield(L, -1, "traceback");
        lua_call(L, 0, 1);
        std::string result = luaL_checkstring(L, -1);
-       lua_pop(L, 1);
+       lua_pop(L, 2);
        return result;
 }
 
@@ -46,6 +47,25 @@ int script_exception_wrapper(lua_State *L, lua_CFunction f)
        return lua_error(L);  // Rethrow as a Lua error.
 }
 
+int script_error_handler(lua_State *L)
+{
+       lua_getglobal(L, "core");
+       lua_getfield(L, -1, "error_handler");
+       if (!lua_isnil(L, -1)) {
+               lua_pushvalue(L, 1);
+       } else {
+               // No Lua error handler available. Call debug.traceback(tostring(#1), level).
+               lua_getglobal(L, "debug");
+               lua_getfield(L, -1, "traceback");
+               lua_getglobal(L, "tostring");
+               lua_pushvalue(L, 1);
+               lua_call(L, 1, 1);
+       }
+       lua_pushinteger(L, 2); // Stack level
+       lua_call(L, 2, 1);
+       return 1;
+}
+
 /*
  * 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
index 5cbcbb7db227fb0c0812217242f39ef42a5311d8..c8bce099cb9acf0cef48c31cef3a2f26ec9bba8c 100644 (file)
@@ -54,7 +54,7 @@ enum {
        CUSTOM_RIDX_SCRIPTAPI,
        CUSTOM_RIDX_GLOBALS_BACKUP,
        CUSTOM_RIDX_CURRENT_MOD_NAME,
-       CUSTOM_RIDX_BACKTRACE,
+       CUSTOM_RIDX_ERROR_HANDLER,
        CUSTOM_RIDX_HTTP_API_LUA,
        CUSTOM_RIDX_METATABLE_MAP,
 
@@ -78,7 +78,7 @@ enum {
 
 // Pushes the error handler onto the stack and returns its index
 #define PUSH_ERROR_HANDLER(L) \
-       (lua_rawgeti((L), LUA_REGISTRYINDEX, CUSTOM_RIDX_BACKTRACE), lua_gettop((L)))
+       (lua_rawgeti((L), LUA_REGISTRYINDEX, CUSTOM_RIDX_ERROR_HANDLER), lua_gettop((L)))
 
 #define PCALL_RESL(L, RES) {                            \
        int result_ = (RES);                                \
@@ -121,6 +121,8 @@ enum RunCallbacksMode
 std::string script_get_backtrace(lua_State *L);
 // Wrapper for CFunction calls that converts C++ exceptions to Lua errors
 int script_exception_wrapper(lua_State *L, lua_CFunction f);
+// Acts as the error handler for lua_pcall
+int script_error_handler(lua_State *L);
 // Takes an error from lua_pcall and throws it as a LuaError
 void script_error(lua_State *L, int pcall_result, const char *mod, const char *fxn);
 
index e8d973de15fa3e056c30f70c4e823b1399177e40..b91f5961367173bcabda55034174ce02e44ab255 100644 (file)
@@ -103,11 +103,8 @@ ScriptApiBase::ScriptApiBase(ScriptingType type):
 #endif
        lua_rawseti(m_luastack, LUA_REGISTRYINDEX, CUSTOM_RIDX_SCRIPTAPI);
 
-       // Add and save an error handler
-       lua_getglobal(m_luastack, "debug");
-       lua_getfield(m_luastack, -1, "traceback");
-       lua_rawseti(m_luastack, LUA_REGISTRYINDEX, CUSTOM_RIDX_BACKTRACE);
-       lua_pop(m_luastack, 1); // pop debug
+       lua_pushcfunction(m_luastack, script_error_handler);
+       lua_rawseti(m_luastack, LUA_REGISTRYINDEX, CUSTOM_RIDX_ERROR_HANDLER);
 
        // Add a C++ wrapper function to catch exceptions thrown in Lua -> C++ calls
 #if USE_LUAJIT