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 *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";
+ }
+
+ const char *err_descr = lua_tostring(L, -1);
+ if (!err_descr)
+ err_descr = "<no description>";
+
+ std::string err_msg(err_type);
+ if (fxn) {
+ err_msg += " error in ";
+ err_msg += fxn;
+ err_msg += "(): ";
+ } else {
+ err_msg += " error: ";
+ }
+ err_msg += err_descr;
+
+ throw LuaError(err_msg);
}
// Push the list of callbacks (a lua table).
// - 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)
{
FATAL_ERROR_IF(lua_gettop(L) < nargs + 1, "Not enough arguments");
// 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);
- }
+ script_error(L, lua_pcall(L, nargs + 2, 1, errorhandler), 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;
if (doerror) {
if (L != NULL) {
- script_error(L);
+ script_error(L, LUA_ERRRUN, NULL);
} else {
- FATAL_ERROR("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!");
}
}
#include "common/c_types.h"
+#define PCALL_RESL(L, RES) do { \
+ int result_ = (RES); \
+ if (result_ != 0) { \
+ script_error((L), result_, __FUNCTION__); \
+ } \
+} while (0)
+
+#define script_run_callbacks(L, nargs, mode) \
+ script_run_callbacks_f((L), (nargs), (mode), __FUNCTION__)
+
// What script_run_callbacks does with the return values of callbacks.
// Regardless of the mode, if only one callback is defined,
// its return value is the total return value.
std::string script_get_backtrace(lua_State *L);
int script_error_handler(lua_State *L);
int script_exception_wrapper(lua_State *L, lua_CFunction f);
-void script_error(lua_State *L);
-void script_run_callbacks(lua_State *L, int nargs, RunCallbacksMode mode);
-void log_deprecated(lua_State *L, std::string message);
+void script_error(lua_State *L, int pcall_result, const char *fxn);
+void script_run_callbacks_f(lua_State *L, int nargs,
+ RunCallbacksMode mode, const char *fxn);
+void log_deprecated(lua_State *L, const std::string &message);
#endif /* C_INTERNAL_H_ */
lua_pushlstring(L, jobDone.serializedResult.data(),
jobDone.serializedResult.size());
- if (lua_pcall(L, 2, 0, errorhandler)) {
- script_error(L);
- }
+ PCALL_RESL(L, lua_pcall(L, 2, 0, errorhandler));
}
resultQueueMutex.Unlock();
lua_pop(L, 1); // Pop core
toProcess.serializedParams.data(),
toProcess.serializedParams.size());
- if (lua_pcall(L, 2, 1, m_errorhandler)) {
- scriptError();
+ int result = lua_pcall(L, 2, 1, m_errorhandler);
+ if (result) {
+ PCALL_RES(result);
toProcess.serializedResult = "";
} else {
// Fetch result
}
}
-void ScriptApiBase::scriptError()
+void ScriptApiBase::scriptError(int result, const char *fxn)
{
- throw LuaError(lua_tostring(m_luastack, -1));
+ script_error(getStack(), result, fxn);
}
void ScriptApiBase::stackDump(std::ostream &o)
// use that name to bypass security!
#define BUILTIN_MOD_NAME "*builtin*"
+#define PCALL_RES(RES) do { \
+ int result_ = (RES); \
+ if (result_ != 0) { \
+ scriptError(result_, __FUNCTION__); \
+ } \
+} while (0)
class Server;
class Environment;
{ return m_luastack; }
void realityCheck();
- void scriptError();
+ void scriptError(int result, const char *fxn);
void stackDump(std::ostream &o);
void setServer(Server* server) { m_server = server; }
lua_pushlstring(L, staticdata.c_str(), staticdata.size());
lua_pushinteger(L, dtime_s);
// Call with 3 arguments, 0 results
- if (lua_pcall(L, 3, 0, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 3, 0, m_errorhandler));
} else {
lua_pop(L, 1);
}
luaL_checktype(L, -1, LUA_TFUNCTION);
lua_pushvalue(L, object); // self
// Call with 1 arguments, 1 results
- if (lua_pcall(L, 1, 1, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 1, 1, m_errorhandler));
lua_remove(L, object); // Remove object
size_t len = 0;
lua_pushvalue(L, object); // self
lua_pushnumber(L, dtime); // dtime
// Call with 2 arguments, 0 results
- if (lua_pcall(L, 2, 0, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 2, 0, m_errorhandler));
lua_pop(L, 1); // Pop object
}
push_tool_capabilities(L, *toolcap);
push_v3f(L, dir);
// Call with 5 arguments, 0 results
- if (lua_pcall(L, 5, 0, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 5, 0, m_errorhandler));
lua_pop(L, 1); // Pop object
}
lua_pushvalue(L, object); // self
objectrefGetOrCreate(L, clicker); // Clicker reference
// Call with 2 arguments, 0 results
- if (lua_pcall(L, 2, 0, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 2, 0, m_errorhandler));
lua_pop(L, 1); // Pop object
}
lua_pushinteger(L, to_index + 1); // to_index
lua_pushinteger(L, count); // count
objectrefGetOrCreate(L, player); // player
- if (lua_pcall(L, 7, 1, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 7, 1, m_errorhandler));
if(!lua_isnumber(L, -1))
throw LuaError("allow_move should return a number. name=" + name);
int ret = luaL_checkinteger(L, -1);
lua_pushinteger(L, index + 1); // index
LuaItemStack::create(L, stack); // stack
objectrefGetOrCreate(L, player); // player
- if (lua_pcall(L, 5, 1, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 5, 1, m_errorhandler));
if (!lua_isnumber(L, -1))
throw LuaError("allow_put should return a number. name=" + name);
int ret = luaL_checkinteger(L, -1);
lua_pushinteger(L, index + 1); // index
LuaItemStack::create(L, stack); // stack
objectrefGetOrCreate(L, player); // player
- if (lua_pcall(L, 5, 1, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 5, 1, m_errorhandler));
if (!lua_isnumber(L, -1))
throw LuaError("allow_take should return a number. name=" + name);
int ret = luaL_checkinteger(L, -1);
lua_pushinteger(L, to_index + 1); // to_index
lua_pushinteger(L, count); // count
objectrefGetOrCreate(L, player); // player
- if (lua_pcall(L, 7, 0, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 7, 0, m_errorhandler));
}
// Report put items
lua_pushinteger(L, index + 1); // index
LuaItemStack::create(L, stack); // stack
objectrefGetOrCreate(L, player); // player
- if (lua_pcall(L, 5, 0, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 5, 0, m_errorhandler));
}
// Report taken items
lua_pushinteger(L, index + 1); // index
LuaItemStack::create(L, stack); // stack
objectrefGetOrCreate(L, player); // player
- if (lua_pcall(L, 5, 0, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 5, 0, m_errorhandler));
}
// Retrieves core.detached_inventories[name][callbackname]
LuaItemStack::create(L, item);
objectrefGetOrCreate(L, dropper);
pushFloatPos(L, pos);
- if (lua_pcall(L, 3, 1, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 3, 1, m_errorhandler));
if (!lua_isnil(L, -1)) {
try {
item = read_item(L,-1, getServer());
LuaItemStack::create(L, item);
objectrefGetOrCreate(L, placer);
pushPointedThing(pointed);
- if (lua_pcall(L, 3, 1, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 3, 1, m_errorhandler));
if (!lua_isnil(L, -1)) {
try {
item = read_item(L,-1, getServer());
LuaItemStack::create(L, item);
objectrefGetOrCreate(L, user);
pushPointedThing(pointed);
- if (lua_pcall(L, 3, 1, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 3, 1, m_errorhandler));
if(!lua_isnil(L, -1)) {
try {
item = read_item(L,-1, getServer());
lua_getfield(L, -1, "on_craft");
LuaItemStack::create(L, item);
objectrefGetOrCreate(L, user);
-
+
// Push inventory list
std::vector<ItemStack> items;
for (u32 i = 0; i < old_craft_grid->getSize(); i++) {
push_items(L, items);
InvRef::create(L, craft_inv);
- if (lua_pcall(L, 4, 1, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 4, 1, m_errorhandler));
if (!lua_isnil(L, -1)) {
try {
item = read_item(L,-1, getServer());
push_items(L, items);
InvRef::create(L, craft_inv);
- if (lua_pcall(L, 4, 1, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 4, 1, m_errorhandler));
if (!lua_isnil(L, -1)) {
try {
item = read_item(L,-1, getServer());
// Call it
lua_pushstring(L, text.c_str());
- if (lua_pcall(L, 1, 0, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 1, 0, m_errorhandler));
}
void ScriptApiMainMenu::handleMainMenuButtons(const StringMap &fields)
}
// Call it
- if (lua_pcall(L, 1, 0, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 1, 0, m_errorhandler));
}
pushnode(L, node, ndef);
objectrefGetOrCreate(L, puncher);
pushPointedThing(pointed);
- if (lua_pcall(L, 4, 0, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 4, 0, m_errorhandler));
return true;
}
push_v3s16(L, p);
pushnode(L, node, ndef);
objectrefGetOrCreate(L, digger);
- if (lua_pcall(L, 3, 0, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 3, 0, m_errorhandler));
return true;
}
// Call function
push_v3s16(L, p);
- if (lua_pcall(L, 1, 0, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 1, 0, m_errorhandler));
}
void ScriptApiNode::node_on_destruct(v3s16 p, MapNode node)
// Call function
push_v3s16(L, p);
- if (lua_pcall(L, 1, 0, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 1, 0, m_errorhandler));
}
void ScriptApiNode::node_after_destruct(v3s16 p, MapNode node)
// Call function
push_v3s16(L, p);
pushnode(L, node, ndef);
- if (lua_pcall(L, 2, 0, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 2, 0, m_errorhandler));
}
bool ScriptApiNode::node_on_timer(v3s16 p, MapNode node, f32 dtime)
// Call function
push_v3s16(L, p);
lua_pushnumber(L,dtime);
- if (lua_pcall(L, 2, 1, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 2, 1, m_errorhandler));
return (bool) lua_isboolean(L, -1) && (bool) lua_toboolean(L, -1) == true;
}
lua_settable(L, -3);
}
objectrefGetOrCreate(L, sender); // player
- if (lua_pcall(L, 4, 0, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 4, 0, m_errorhandler));
}
void ScriptApiNode::node_falling_update(v3s16 p)
lua_getglobal(L, "nodeupdate");
push_v3s16(L, p);
- if (lua_pcall(L, 1, 0, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 1, 0, m_errorhandler));
}
void ScriptApiNode::node_falling_update_single(v3s16 p)
lua_getglobal(L, "nodeupdate_single");
push_v3s16(L, p);
- if (lua_pcall(L, 1, 0, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 1, 0, m_errorhandler));
}
-
lua_pushinteger(L, to_index + 1); // to_index
lua_pushinteger(L, count); // count
objectrefGetOrCreate(L, player); // player
- if (lua_pcall(L, 7, 1, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 7, 1, m_errorhandler));
if (!lua_isnumber(L, -1))
throw LuaError("allow_metadata_inventory_move should"
" return a number, guilty node: " + nodename);
lua_pushinteger(L, index + 1); // index
LuaItemStack::create(L, stack); // stack
objectrefGetOrCreate(L, player); // player
- if (lua_pcall(L, 5, 1, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 5, 1, m_errorhandler));
if(!lua_isnumber(L, -1))
throw LuaError("allow_metadata_inventory_put should"
" return a number, guilty node: " + nodename);
lua_pushinteger(L, index + 1); // index
LuaItemStack::create(L, stack); // stack
objectrefGetOrCreate(L, player); // player
- if (lua_pcall(L, 5, 1, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 5, 1, m_errorhandler));
if (!lua_isnumber(L, -1))
throw LuaError("allow_metadata_inventory_take should"
" return a number, guilty node: " + nodename);
lua_pushinteger(L, to_index + 1); // to_index
lua_pushinteger(L, count); // count
objectrefGetOrCreate(L, player); // player
- if (lua_pcall(L, 7, 0, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 7, 0, m_errorhandler));
}
// Report put items
lua_pushinteger(L, index + 1); // index
LuaItemStack::create(L, stack); // stack
objectrefGetOrCreate(L, player); // player
- if (lua_pcall(L, 5, 0, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 5, 0, m_errorhandler));
}
// Report taken items
lua_pushinteger(L, index + 1); // index
LuaItemStack::create(L, stack); // stack
objectrefGetOrCreate(L, player); // player
- if (lua_pcall(L, 5, 0, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 5, 0, m_errorhandler));
}
-ScriptApiNodemeta::ScriptApiNodemeta() {
+ScriptApiNodemeta::ScriptApiNodemeta()
+{
}
-ScriptApiNodemeta::~ScriptApiNodemeta() {
+ScriptApiNodemeta::~ScriptApiNodemeta()
+{
}
objectrefGetOrCreate(L, player);
lua_pushnumber(L, hp_change);
- if (lua_pcall(L, 2, 1, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 2, 1, m_errorhandler));
hp_change = lua_tointeger(L, -1);
lua_pop(L, -1);
return hp_change;
if (lua_type(L, -1) != LUA_TFUNCTION)
throw LuaError("Authentication handler missing get_auth");
lua_pushstring(L, playername.c_str());
- if (lua_pcall(L, 1, 1, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 1, 1, m_errorhandler));
lua_remove(L, -2); // Remove auth handler
// nil = login not allowed
throw LuaError("Authentication handler missing create_auth");
lua_pushstring(L, playername.c_str());
lua_pushstring(L, password.c_str());
- if (lua_pcall(L, 2, 0, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 2, 0, m_errorhandler));
}
bool ScriptApiServer::setPassword(const std::string &playername,
throw LuaError("Authentication handler missing set_password");
lua_pushstring(L, playername.c_str());
lua_pushstring(L, password.c_str());
- if (lua_pcall(L, 2, 1, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 2, 1, m_errorhandler));
return lua_toboolean(L, -1);
}
pushnode(L, n, env->getGameDef()->ndef());
lua_pushnumber(L, active_object_count);
lua_pushnumber(L, active_object_count_wider);
- if(lua_pcall(L, 4, 0, errorhandler))
- script_error(L);
+
+ PCALL_RESL(L, lua_pcall(L, 4, 0, errorhandler));
+
lua_pop(L, 1); // Pop error handler
}
return 0;
lua_pushvalue(L, 1);
lua_pushstring(L, item.getItemString().c_str());
- if(lua_pcall(L, 2, 1, errorhandler))
- script_error(L);
+
+ PCALL_RESL(L, lua_pcall(L, 2, 1, errorhandler));
+
lua_remove(L, errorhandler); // Remove error handler
return 1;
}
LuaSettings::Register(L);
}
-void log_deprecated(std::string message)
+void log_deprecated(const std::string &message)
{
- log_deprecated(NULL,message);
+ log_deprecated(NULL, message);
}
void InitializeModApi(lua_State *L, int top);
};
-void log_deprecated(std::string message);
+void log_deprecated(const std::string &message);
#endif /* SCRIPTING_GAME_H_ */