X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fscript%2Fcommon%2Fc_internal.cpp;h=df82dba146ec7ddcb5d0becc7446b743e8c71e17;hb=391eec9ee78fc9dfdc476ad2a8ed7755009e4a2f;hp=42e9fb3e1e66a02943fd67f3cc4b670148478b45;hpb=ab433775777c4f5055bcf4d2a1cffc506c4f9961;p=minetest.git diff --git a/src/script/common/c_internal.cpp b/src/script/common/c_internal.cpp index 42e9fb3e1..df82dba14 100644 --- a/src/script/common/c_internal.cpp +++ b/src/script/common/c_internal.cpp @@ -18,48 +18,151 @@ with this program; if not, write to the Free Software Foundation, Inc., */ #include "common/c_internal.h" -#include "server.h" -#include "cpp_api/scriptapi.h" +#include "util/numeric.h" +#include "debug.h" +#include "log.h" +#include "porting.h" +#include "settings.h" +#include // std::find -ScriptApi* get_scriptapi(lua_State *L) +std::string script_get_backtrace(lua_State *L) { - // Get server from registry - lua_getfield(L, LUA_REGISTRYINDEX, "scriptapi"); - ScriptApi* sapi_ptr = (ScriptApi*) lua_touserdata(L, -1); + lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_BACKTRACE); + lua_call(L, 0, 1); + std::string result = luaL_checkstring(L, -1); lua_pop(L, 1); - return sapi_ptr; + return result; } -std::string script_get_backtrace(lua_State *L) +int script_exception_wrapper(lua_State *L, lua_CFunction f) { - std::string s; - lua_getfield(L, LUA_GLOBALSINDEX, "debug"); - if(lua_istable(L, -1)){ - lua_getfield(L, -1, "traceback"); - if(lua_isfunction(L, -1)){ - lua_call(L, 0, 1); - if(lua_isstring(L, -1)){ - s += lua_tostring(L, -1); - } - lua_pop(L, 1); - } - else{ - lua_pop(L, 1); - } + try { + 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) { + lua_pushstring(L, e.what()); } - lua_pop(L, 1); - return s; + return lua_error(L); // Rethrow as a Lua error. } -void script_error(lua_State* L,const char *fmt, ...) +/* + * 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 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) { - va_list argp; - va_start(argp, fmt); - char buf[10000]; - vsnprintf(buf, 10000, fmt, argp); - va_end(argp); - //errorstream<<"SCRIPT ERROR: "<> 10) + " MB"; + } + + throw LuaError(err_msg); } +static void script_log_add_source(lua_State *L, std::string &message, int stack_depth) +{ + lua_Debug ar; + + if (lua_getstack(L, stack_depth, &ar)) { + FATAL_ERROR_IF(!lua_getinfo(L, "Sl", &ar), "lua_getinfo() failed"); + message.append(" (at " + std::string(ar.short_src) + ":" + + std::to_string(ar.currentline) + ")"); + } else { + message.append(" (at ?:?)"); + } +} + +bool script_log_unique(lua_State *L, std::string message, std::ostream &log_to, + int stack_depth) +{ + thread_local std::vector logged_messages; + + script_log_add_source(L, message, stack_depth); + u64 hash = murmur_hash_64_ua(message.data(), message.length(), 0xBADBABE); + + if (std::find(logged_messages.begin(), logged_messages.end(), hash) + == logged_messages.end()) { + + logged_messages.emplace_back(hash); + log_to << message << std::endl; + return true; + } + return false; +} + +DeprecatedHandlingMode get_deprecated_handling_mode() +{ + static thread_local bool configured = false; + static thread_local DeprecatedHandlingMode ret = DeprecatedHandlingMode::Ignore; + + // Only read settings on first call + if (!configured) { + std::string value = g_settings->get("deprecated_lua_api_handling"); + if (value == "log") { + ret = DeprecatedHandlingMode::Log; + } else if (value == "error") { + ret = DeprecatedHandlingMode::Error; + } + configured = true; + } + + return ret; +} + +void log_deprecated(lua_State *L, std::string message, int stack_depth) +{ + DeprecatedHandlingMode mode = get_deprecated_handling_mode(); + if (mode == DeprecatedHandlingMode::Ignore) + return; + + script_log_add_source(L, message, stack_depth); + warningstream << message << std::endl; + + if (mode == DeprecatedHandlingMode::Error) + script_error(L, LUA_ERRRUN, NULL, NULL); + else + infostream << script_get_backtrace(L) << std::endl; +}