X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fscript%2Fcommon%2Fc_internal.cpp;h=df82dba146ec7ddcb5d0becc7446b743e8c71e17;hb=391eec9ee78fc9dfdc476ad2a8ed7755009e4a2f;hp=14d992df006059a7a02d38f9237c48da18b1d77f;hpb=3304e1e517fb8aac008c4684e72a4b59b408414a;p=minetest.git diff --git a/src/script/common/c_internal.cpp b/src/script/common/c_internal.cpp index 14d992df0..df82dba14 100644 --- a/src/script/common/c_internal.cpp +++ b/src/script/common/c_internal.cpp @@ -18,43 +18,20 @@ with this program; if not, write to the Free Software Foundation, Inc., */ #include "common/c_internal.h" +#include "util/numeric.h" #include "debug.h" #include "log.h" +#include "porting.h" #include "settings.h" +#include // std::find std::string script_get_backtrace(lua_State *L) { - std::string s; - lua_getglobal(L, "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); - } + 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 s; -} - -int script_error_handler(lua_State *L) { - lua_getglobal(L, "debug"); - if (!lua_istable(L, -1)) { - lua_pop(L, 1); - return 1; - } - lua_getfield(L, -1, "traceback"); - if (!lua_isfunction(L, -1)) { - lua_pop(L, 2); - return 1; - } - lua_pushvalue(L, 1); - lua_pushinteger(L, 2); - lua_call(L, 2, 1); - return 1; + return result; } int script_exception_wrapper(lua_State *L, lua_CFunction f) @@ -72,7 +49,7 @@ int script_exception_wrapper(lua_State *L, lua_CFunction f) /* * 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 + * 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 @@ -110,7 +87,7 @@ void script_error(lua_State *L, int pcall_result, const char *mod, const char *f err_descr = ""; char buf[256]; - snprintf(buf, sizeof(buf), "%s error from mod '%s' in callback %s(): ", + porting::mt_snprintf(buf, sizeof(buf), "%s error from mod '%s' in callback %s(): ", err_type, mod, fxn); std::string err_msg(buf); @@ -124,74 +101,68 @@ void script_error(lua_State *L, int pcall_result, const char *mod, const char *f throw LuaError(err_msg); } -// Push the list of callbacks (a lua table). -// Then push nargs arguments. -// Then call this function, which -// - runs the callbacks -// - replaces the table and arguments with the return value, -// computed depending on mode -void script_run_callbacks_f(lua_State *L, int nargs, - RunCallbacksMode mode, const char *fxn) +static void script_log_add_source(lua_State *L, std::string &message, int stack_depth) { - FATAL_ERROR_IF(lua_gettop(L) < nargs + 1, "Not enough arguments"); - - // Insert error handler - PUSH_ERROR_HANDLER(L); - int error_handler = lua_gettop(L) - nargs - 1; - lua_insert(L, error_handler); - - // Insert run_callbacks between error handler and table - lua_getglobal(L, "core"); - lua_getfield(L, -1, "run_callbacks"); - lua_remove(L, -2); - lua_insert(L, error_handler + 1); + 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 ?:?)"); + } +} - // Insert mode after table - lua_pushnumber(L, (int) mode); - lua_insert(L, error_handler + 3); +bool script_log_unique(lua_State *L, std::string message, std::ostream &log_to, + int stack_depth) +{ + thread_local std::vector logged_messages; - // Stack now looks like this: - // ... ... + script_log_add_source(L, message, stack_depth); + u64 hash = murmur_hash_64_ua(message.data(), message.length(), 0xBADBABE); - int result = lua_pcall(L, nargs + 2, 1, error_handler); - if (result != 0) - script_error(L, result, NULL, fxn); + if (std::find(logged_messages.begin(), logged_messages.end(), hash) + == logged_messages.end()) { - lua_remove(L, error_handler); + logged_messages.emplace_back(hash); + log_to << message << std::endl; + return true; + } + return false; } -void log_deprecated(lua_State *L, const std::string &message) +DeprecatedHandlingMode get_deprecated_handling_mode() { - static bool configured = false; - static bool dolog = false; - static bool doerror = false; + static thread_local bool configured = false; + static thread_local DeprecatedHandlingMode ret = DeprecatedHandlingMode::Ignore; - // performance optimization to not have to read and compare setting for every logline + // Only read settings on first call if (!configured) { std::string value = g_settings->get("deprecated_lua_api_handling"); if (value == "log") { - dolog = true; + ret = DeprecatedHandlingMode::Log; } else if (value == "error") { - dolog = true; - doerror = true; + ret = DeprecatedHandlingMode::Error; } + configured = true; } - if (doerror) { - if (L != NULL) { - script_error(L, LUA_ERRRUN, NULL, NULL); - } else { - FATAL_ERROR("Can't do a scripterror for this deprecated message, " - "so exit completely!"); - } - } + return ret; +} - if (dolog) { - /* abusing actionstream because of lack of file-only-logged loglevel */ - actionstream << message << std::endl; - if (L != NULL) { - actionstream << script_get_backtrace(L) << std::endl; - } - } +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; }