Skip to content
Permalink
Browse files

Pass a errfunc to lua_pcall to get a traceback

  • Loading branch information
ShadowNinja committed Nov 15, 2013
1 parent 3f519eb commit 371b39a09a0bf248d674fae718f5ff369e895b66
@@ -871,6 +871,8 @@ void read_groups(lua_State *L, int index,
/******************************************************************************/
void push_items(lua_State *L, const std::vector<ItemStack> &items)
{
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
// Get the table insert function
lua_getglobal(L, "table");
lua_getfield(L, -1, "insert");
@@ -883,11 +885,12 @@ void push_items(lua_State *L, const std::vector<ItemStack> &items)
lua_pushvalue(L, table_insert);
lua_pushvalue(L, table);
LuaItemStack::create(L, item);
if(lua_pcall(L, 2, 0, 0))
script_error(L, "error: %s", lua_tostring(L, -1));
if(lua_pcall(L, 2, 0, errorhandler))
script_error(L);
}
lua_remove(L, -2); // Remove table
lua_remove(L, -2); // Remove insert
lua_remove(L, -2); // Remove table
lua_remove(L, -2); // Remove error handler
}

/******************************************************************************/
@@ -23,32 +23,41 @@ with this program; if not, write to the Free Software Foundation, Inc.,
std::string script_get_backtrace(lua_State *L)
{
std::string s;
lua_getfield(L, LUA_GLOBALSINDEX, "debug");
lua_getglobal(L, "debug");
if(lua_istable(L, -1)){
lua_getfield(L, -1, "traceback");
if(lua_isfunction(L, -1)){
if(lua_isfunction(L, -1)) {
lua_call(L, 0, 1);
if(lua_isstring(L, -1)){
s += lua_tostring(L, -1);
s = lua_tostring(L, -1);
}
lua_pop(L, 1);
}
else{
lua_pop(L, 1);
}
lua_pop(L, 1);
}
lua_pop(L, 1);
return s;
}

void script_error(lua_State *L, const char *fmt, ...)
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;
}

void script_error(lua_State *L)
{
va_list argp;
va_start(argp, fmt);
char buf[10000];
vsnprintf(buf, 10000, fmt, argp);
va_end(argp);
throw LuaError(L, buf);
throw LuaError(NULL, lua_tostring(L, -1));
}

// Push the list of callbacks (a lua table).
@@ -61,13 +70,20 @@ void script_run_callbacks(lua_State *L, int nargs, RunCallbacksMode mode)
{
// Insert the return value into the lua stack, below the table
assert(lua_gettop(L) >= nargs + 1);

lua_pushnil(L);
lua_insert(L, -(nargs + 1) - 1);
int rv = lua_gettop(L) - nargs - 1;
lua_insert(L, rv);

// Insert error handler after return value
lua_pushcfunction(L, script_error_handler);
int errorhandler = rv + 1;
lua_insert(L, errorhandler);

// Stack now looks like this:
// ... <return value = nil> <table> <arg#1> <arg#2> ... <arg#n>
// ... <return value = nil> <error handler> <table> <arg#1> <arg#2> ... <arg#n>

int rv = lua_gettop(L) - nargs - 1;
int table = rv + 1;
int table = errorhandler + 1;
int arg = table + 1;

luaL_checktype(L, table, LUA_TTABLE);
@@ -81,8 +97,8 @@ void script_run_callbacks(lua_State *L, int nargs, RunCallbacksMode mode)
// Call function
for(int i = 0; i < nargs; i++)
lua_pushvalue(L, arg+i);
if(lua_pcall(L, nargs, 1, 0))
script_error(L, "error: %s", lua_tostring(L, -1));
if(lua_pcall(L, nargs, 1, errorhandler))
script_error(L);

// Move return value to designated space in stack
// Or pop it
@@ -64,9 +64,10 @@ enum RunCallbacksMode
// are converted by lua_toboolean to true or false, respectively.
};

std::string script_get_backtrace (lua_State *L);
void script_error (lua_State *L, const char *fmt, ...);
void script_run_callbacks (lua_State *L, int nargs,
RunCallbacksMode mode);
std::string script_get_backtrace(lua_State *L);
int script_error_handler(lua_State *L);
void script_error(lua_State *L);
void script_run_callbacks(lua_State *L, int nargs,
RunCallbacksMode mode);

#endif /* C_INTERNAL_H_ */
@@ -25,9 +25,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,

LuaError::LuaError(lua_State *L, const std::string &s)
{
m_s = "LuaError: ";
m_s += s + "\n";
m_s += script_get_backtrace(L);
m_s = "LuaError: " + s;
if (L) m_s += '\n' + script_get_backtrace(L);
}

struct EnumString es_ItemType[] =
@@ -55,23 +55,6 @@ class ModNameStorer
}
};

static int loadScript_ErrorHandler(lua_State *L) {
lua_getfield(L, LUA_GLOBALSINDEX, "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;
}


/*
ScriptApiBase
@@ -133,7 +116,7 @@ bool ScriptApiBase::loadScript(const std::string &scriptpath)

lua_State *L = getStack();

lua_pushcfunction(L, loadScript_ErrorHandler);
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);

int ret = luaL_loadfile(L, scriptpath.c_str()) || lua_pcall(L, 0, 0, errorhandler);
@@ -144,7 +127,7 @@ bool ScriptApiBase::loadScript(const std::string &scriptpath)
errorstream<<std::endl;
errorstream<<lua_tostring(L, -1)<<std::endl;
errorstream<<std::endl;
errorstream<<"=======END OF ERROR FROM LUA ========"<<std::endl;
errorstream<<"======= END OF ERROR FROM LUA ========"<<std::endl;
lua_pop(L, 1); // Pop error message from stack
lua_pop(L, 1); // Pop the error handler from stack
return false;
@@ -159,19 +142,13 @@ void ScriptApiBase::realityCheck()
if(top >= 30){
dstream<<"Stack is over 30:"<<std::endl;
stackDump(dstream);
scriptError("Stack is over 30 (reality check)");
throw LuaError(m_luastack, "Stack is over 30 (reality check)");
}
}

void ScriptApiBase::scriptError(const char *fmt, ...)
void ScriptApiBase::scriptError()
{
va_list argp;
va_start(argp, fmt);
char buf[10000];
vsnprintf(buf, 10000, fmt, argp);
va_end(argp);
//errorstream<<"SCRIPT ERROR: "<<buf;
throw LuaError(m_luastack, buf);
throw LuaError(NULL, lua_tostring(m_luastack, -1));
}

void ScriptApiBase::stackDump(std::ostream &o)
@@ -31,6 +31,7 @@ extern "C" {
#include "jthread/jmutex.h"
#include "jthread/jmutexautolock.h"
#include "common/c_types.h"
#include "common/c_internal.h"

#define SCRIPTAPI_LOCK_DEBUG

@@ -65,7 +66,7 @@ class ScriptApiBase {
{ return m_luastack; }

void realityCheck();
void scriptError(const char *fmt, ...);
void scriptError();
void stackDump(std::ostream &o);

Server* getServer() { return m_server; }
@@ -78,25 +78,29 @@ void ScriptApiEntity::luaentity_Activate(u16 id,
{
SCRIPTAPI_PRECHECKHEADER

lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);

verbosestream<<"scriptapi_luaentity_activate: id="<<id<<std::endl;

// Get minetest.luaentities[id]
luaentity_get(L,id);
luaentity_get(L, id);
int object = lua_gettop(L);

// Get on_activate function
lua_pushvalue(L, object);
lua_getfield(L, -1, "on_activate");
if(!lua_isnil(L, -1)){
if(!lua_isnil(L, -1)) {
luaL_checktype(L, -1, LUA_TFUNCTION);
lua_pushvalue(L, object); // self
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, 0))
scriptError("error running function on_activate: %s\n",
lua_tostring(L, -1));
if(lua_pcall(L, 3, 0, errorhandler))
scriptError();
} else {
lua_pop(L, 1);
}
lua_pop(L, 2); // Pop object and error handler
}

void ScriptApiEntity::luaentity_Remove(u16 id)
@@ -123,26 +127,29 @@ std::string ScriptApiEntity::luaentity_GetStaticdata(u16 id)
{
SCRIPTAPI_PRECHECKHEADER

lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);

//infostream<<"scriptapi_luaentity_get_staticdata: id="<<id<<std::endl;

// Get minetest.luaentities[id]
luaentity_get(L,id);
luaentity_get(L, id);
int object = lua_gettop(L);

// Get get_staticdata function
lua_pushvalue(L, object);
lua_getfield(L, -1, "get_staticdata");
if(lua_isnil(L, -1))
return "";

luaL_checktype(L, -1, LUA_TFUNCTION);
lua_pushvalue(L, object); // self
// Call with 1 arguments, 1 results
if(lua_pcall(L, 1, 1, 0))
scriptError("error running function get_staticdata: %s\n",
lua_tostring(L, -1));
if(lua_pcall(L, 1, 1, errorhandler))
scriptError();
lua_remove(L, object); // Remove object
lua_remove(L, errorhandler); // Remove error handler

size_t len=0;
size_t len = 0;
const char *s = lua_tolstring(L, -1, &len);
return std::string(s, len);
}
@@ -192,10 +199,13 @@ void ScriptApiEntity::luaentity_Step(u16 id, float dtime)
{
SCRIPTAPI_PRECHECKHEADER

lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);

//infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;

// Get minetest.luaentities[id]
luaentity_get(L,id);
luaentity_get(L, id);
int object = lua_gettop(L);
// State: object is at top of stack
// Get step function
@@ -206,8 +216,10 @@ void ScriptApiEntity::luaentity_Step(u16 id, float dtime)
lua_pushvalue(L, object); // self
lua_pushnumber(L, dtime); // dtime
// Call with 2 arguments, 0 results
if(lua_pcall(L, 2, 0, 0))
scriptError("error running function 'on_step': %s\n", lua_tostring(L, -1));
if(lua_pcall(L, 2, 0, errorhandler))
scriptError();
lua_remove(L, object); // Remove object
lua_remove(L, errorhandler); // Remove error handler
}

// Calls entity:on_punch(ObjectRef puncher, time_from_last_punch,
@@ -218,6 +230,9 @@ void ScriptApiEntity::luaentity_Punch(u16 id,
{
SCRIPTAPI_PRECHECKHEADER

lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);

//infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;

// Get minetest.luaentities[id]
@@ -235,8 +250,10 @@ void ScriptApiEntity::luaentity_Punch(u16 id,
push_tool_capabilities(L, *toolcap);
push_v3f(L, dir);
// Call with 5 arguments, 0 results
if(lua_pcall(L, 5, 0, 0))
scriptError("error running function 'on_punch': %s\n", lua_tostring(L, -1));
if(lua_pcall(L, 5, 0, errorhandler))
scriptError();
lua_remove(L, object); // Remove object
lua_remove(L, errorhandler); // Remove error handler
}

// Calls entity:on_rightclick(ObjectRef clicker)
@@ -245,6 +262,9 @@ void ScriptApiEntity::luaentity_Rightclick(u16 id,
{
SCRIPTAPI_PRECHECKHEADER

lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);

//infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;

// Get minetest.luaentities[id]
@@ -259,7 +279,9 @@ void ScriptApiEntity::luaentity_Rightclick(u16 id,
lua_pushvalue(L, object); // self
objectrefGetOrCreate(clicker); // Clicker reference
// Call with 2 arguments, 0 results
if(lua_pcall(L, 2, 0, 0))
scriptError("error running function 'on_rightclick': %s\n", lua_tostring(L, -1));
if(lua_pcall(L, 2, 0, errorhandler))
scriptError();
lua_remove(L, object); // Remove object
lua_remove(L, errorhandler); // Remove error handler
}

0 comments on commit 371b39a

Please sign in to comment.