3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "common/c_internal.h"
21 #include "util/numeric.h"
26 #include <algorithm> // std::find
28 std::string script_get_backtrace(lua_State *L)
30 lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_BACKTRACE);
32 std::string result = luaL_checkstring(L, -1);
37 int script_exception_wrapper(lua_State *L, lua_CFunction f)
40 return f(L); // Call wrapped function and return result.
41 } catch (const char *s) { // Catch and convert exceptions.
43 } catch (std::exception &e) {
44 lua_pushstring(L, e.what());
46 return lua_error(L); // Rethrow as a Lua error.
50 * Note that we can't get tracebacks for LUA_ERRMEM or LUA_ERRERR (without
51 * hacking Lua internals). For LUA_ERRMEM, this is because memory errors will
52 * not execute the error handler, and by the time lua_pcall returns the
53 * execution stack will have already been unwound. For LUA_ERRERR, there was
54 * another error while trying to generate a backtrace from a LUA_ERRRUN. It is
55 * presumed there is an error with the internal Lua state and thus not possible
56 * to gather a coherent backtrace. Realistically, the best we can do here is
57 * print which C function performed the failing pcall.
59 void script_error(lua_State *L, int pcall_result, const char *mod, const char *fxn)
61 if (pcall_result == 0)
65 switch (pcall_result) {
73 err_type = "Double fault";
85 const char *err_descr = lua_tostring(L, -1);
87 err_descr = "<no description>";
90 porting::mt_snprintf(buf, sizeof(buf), "%s error from mod '%s' in callback %s(): ",
93 std::string err_msg(buf);
96 if (pcall_result == LUA_ERRMEM) {
97 err_msg += "\nCurrent Lua memory usage: "
98 + itos(lua_gc(L, LUA_GCCOUNT, 0) >> 10) + " MB";
101 throw LuaError(err_msg);
104 static void script_log_add_source(lua_State *L, std::string &message, int stack_depth)
108 if (lua_getstack(L, stack_depth, &ar)) {
109 FATAL_ERROR_IF(!lua_getinfo(L, "Sl", &ar), "lua_getinfo() failed");
110 message.append(" (at " + std::string(ar.short_src) + ":"
111 + std::to_string(ar.currentline) + ")");
113 message.append(" (at ?:?)");
117 bool script_log_unique(lua_State *L, std::string message, std::ostream &log_to,
120 thread_local std::vector<u64> logged_messages;
122 script_log_add_source(L, message, stack_depth);
123 u64 hash = murmur_hash_64_ua(message.data(), message.length(), 0xBADBABE);
125 if (std::find(logged_messages.begin(), logged_messages.end(), hash)
126 == logged_messages.end()) {
128 logged_messages.emplace_back(hash);
129 log_to << message << std::endl;
135 DeprecatedHandlingMode get_deprecated_handling_mode()
137 static thread_local bool configured = false;
138 static thread_local DeprecatedHandlingMode ret = DeprecatedHandlingMode::Ignore;
140 // Only read settings on first call
142 std::string value = g_settings->get("deprecated_lua_api_handling");
143 if (value == "log") {
144 ret = DeprecatedHandlingMode::Log;
145 } else if (value == "error") {
146 ret = DeprecatedHandlingMode::Error;
154 void log_deprecated(lua_State *L, std::string message, int stack_depth)
156 DeprecatedHandlingMode mode = get_deprecated_handling_mode();
157 if (mode == DeprecatedHandlingMode::Ignore)
160 script_log_add_source(L, message, stack_depth);
161 warningstream << message << std::endl;
163 if (mode == DeprecatedHandlingMode::Error)
164 script_error(L, LUA_ERRRUN, NULL, NULL);
166 infostream << script_get_backtrace(L) << std::endl;
169 void call_string_dump(lua_State *L, int idx)
171 // Retrieve string.dump from insecure env to avoid it being tampered with
172 lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP);
173 if (!lua_isnil(L, -1))
174 lua_getfield(L, -1, "string");
176 lua_getglobal(L, "string");
177 lua_getfield(L, -1, "dump");
178 lua_remove(L, -2); // remove _G
179 lua_remove(L, -2); // remove 'string' table
180 lua_pushvalue(L, idx);