Skip to content

Commit

Permalink
Pass a errfunc to lua_pcall to get a traceback
Browse files Browse the repository at this point in the history
  • Loading branch information
ShadowNinja committed Nov 15, 2013
1 parent 3f519eb commit 371b39a
Show file tree
Hide file tree
Showing 19 changed files with 423 additions and 323 deletions.
9 changes: 6 additions & 3 deletions src/script/common/c_content.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -871,6 +871,8 @@ void read_groups(lua_State *L, int index,
/******************************************************************************/ /******************************************************************************/
void push_items(lua_State *L, const std::vector<ItemStack> &items) 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 // Get the table insert function
lua_getglobal(L, "table"); lua_getglobal(L, "table");
lua_getfield(L, -1, "insert"); lua_getfield(L, -1, "insert");
Expand All @@ -883,11 +885,12 @@ void push_items(lua_State *L, const std::vector<ItemStack> &items)
lua_pushvalue(L, table_insert); lua_pushvalue(L, table_insert);
lua_pushvalue(L, table); lua_pushvalue(L, table);
LuaItemStack::create(L, item); LuaItemStack::create(L, item);
if(lua_pcall(L, 2, 0, 0)) if(lua_pcall(L, 2, 0, errorhandler))
script_error(L, "error: %s", lua_tostring(L, -1)); script_error(L);
} }
lua_remove(L, -2); // Remove table
lua_remove(L, -2); // Remove insert lua_remove(L, -2); // Remove insert
lua_remove(L, -2); // Remove table
lua_remove(L, -2); // Remove error handler
} }


/******************************************************************************/ /******************************************************************************/
Expand Down
56 changes: 36 additions & 20 deletions src/script/common/c_internal.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -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 script_get_backtrace(lua_State *L)
{ {
std::string s; std::string s;
lua_getfield(L, LUA_GLOBALSINDEX, "debug"); lua_getglobal(L, "debug");
if(lua_istable(L, -1)){ if(lua_istable(L, -1)){
lua_getfield(L, -1, "traceback"); lua_getfield(L, -1, "traceback");
if(lua_isfunction(L, -1)){ if(lua_isfunction(L, -1)) {
lua_call(L, 0, 1); lua_call(L, 0, 1);
if(lua_isstring(L, -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); lua_pop(L, 1);
return s; 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; throw LuaError(NULL, lua_tostring(L, -1));
va_start(argp, fmt);
char buf[10000];
vsnprintf(buf, 10000, fmt, argp);
va_end(argp);
throw LuaError(L, buf);
} }


// Push the list of callbacks (a lua table). // Push the list of callbacks (a lua table).
Expand All @@ -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 // Insert the return value into the lua stack, below the table
assert(lua_gettop(L) >= nargs + 1); assert(lua_gettop(L) >= nargs + 1);

lua_pushnil(L); 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: // 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 = errorhandler + 1;
int table = rv + 1;
int arg = table + 1; int arg = table + 1;


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


// Move return value to designated space in stack // Move return value to designated space in stack
// Or pop it // Or pop it
Expand Down
9 changes: 5 additions & 4 deletions src/script/common/c_internal.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -64,9 +64,10 @@ enum RunCallbacksMode
// are converted by lua_toboolean to true or false, respectively. // are converted by lua_toboolean to true or false, respectively.
}; };


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


#endif /* C_INTERNAL_H_ */ #endif /* C_INTERNAL_H_ */
5 changes: 2 additions & 3 deletions src/script/common/c_types.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -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) LuaError::LuaError(lua_State *L, const std::string &s)
{ {
m_s = "LuaError: "; m_s = "LuaError: " + s;
m_s += s + "\n"; if (L) m_s += '\n' + script_get_backtrace(L);
m_s += script_get_backtrace(L);
} }


struct EnumString es_ItemType[] = struct EnumString es_ItemType[] =
Expand Down
33 changes: 5 additions & 28 deletions src/script/cpp_api/s_base.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -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 ScriptApiBase
Expand Down Expand Up @@ -133,7 +116,7 @@ bool ScriptApiBase::loadScript(const std::string &scriptpath)


lua_State *L = getStack(); lua_State *L = getStack();


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


int ret = luaL_loadfile(L, scriptpath.c_str()) || lua_pcall(L, 0, 0, errorhandler); int ret = luaL_loadfile(L, scriptpath.c_str()) || lua_pcall(L, 0, 0, errorhandler);
Expand All @@ -144,7 +127,7 @@ bool ScriptApiBase::loadScript(const std::string &scriptpath)
errorstream<<std::endl; errorstream<<std::endl;
errorstream<<lua_tostring(L, -1)<<std::endl; errorstream<<lua_tostring(L, -1)<<std::endl;
errorstream<<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 error message from stack
lua_pop(L, 1); // Pop the error handler from stack lua_pop(L, 1); // Pop the error handler from stack
return false; return false;
Expand All @@ -159,19 +142,13 @@ void ScriptApiBase::realityCheck()
if(top >= 30){ if(top >= 30){
dstream<<"Stack is over 30:"<<std::endl; dstream<<"Stack is over 30:"<<std::endl;
stackDump(dstream); 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; throw LuaError(NULL, lua_tostring(m_luastack, -1));
va_start(argp, fmt);
char buf[10000];
vsnprintf(buf, 10000, fmt, argp);
va_end(argp);
//errorstream<<"SCRIPT ERROR: "<<buf;
throw LuaError(m_luastack, buf);
} }


void ScriptApiBase::stackDump(std::ostream &o) void ScriptApiBase::stackDump(std::ostream &o)
Expand Down
3 changes: 2 additions & 1 deletion src/script/cpp_api/s_base.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ extern "C" {
#include "jthread/jmutex.h" #include "jthread/jmutex.h"
#include "jthread/jmutexautolock.h" #include "jthread/jmutexautolock.h"
#include "common/c_types.h" #include "common/c_types.h"
#include "common/c_internal.h"


#define SCRIPTAPI_LOCK_DEBUG #define SCRIPTAPI_LOCK_DEBUG


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


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


Server* getServer() { return m_server; } Server* getServer() { return m_server; }
Expand Down
60 changes: 41 additions & 19 deletions src/script/cpp_api/s_entity.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -78,25 +78,29 @@ void ScriptApiEntity::luaentity_Activate(u16 id,
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER


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

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


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


// Get on_activate function // Get on_activate function
lua_pushvalue(L, object);
lua_getfield(L, -1, "on_activate"); lua_getfield(L, -1, "on_activate");
if(!lua_isnil(L, -1)){ if(!lua_isnil(L, -1)) {
luaL_checktype(L, -1, LUA_TFUNCTION); luaL_checktype(L, -1, LUA_TFUNCTION);
lua_pushvalue(L, object); // self lua_pushvalue(L, object); // self
lua_pushlstring(L, staticdata.c_str(), staticdata.size()); lua_pushlstring(L, staticdata.c_str(), staticdata.size());
lua_pushinteger(L, dtime_s); lua_pushinteger(L, dtime_s);
// Call with 3 arguments, 0 results // Call with 3 arguments, 0 results
if(lua_pcall(L, 3, 0, 0)) if(lua_pcall(L, 3, 0, errorhandler))
scriptError("error running function on_activate: %s\n", scriptError();
lua_tostring(L, -1)); } else {
lua_pop(L, 1);
} }
lua_pop(L, 2); // Pop object and error handler
} }


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


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

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


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


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


luaL_checktype(L, -1, LUA_TFUNCTION); luaL_checktype(L, -1, LUA_TFUNCTION);
lua_pushvalue(L, object); // self lua_pushvalue(L, object); // self
// Call with 1 arguments, 1 results // Call with 1 arguments, 1 results
if(lua_pcall(L, 1, 1, 0)) if(lua_pcall(L, 1, 1, errorhandler))
scriptError("error running function get_staticdata: %s\n", scriptError();
lua_tostring(L, -1)); 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); const char *s = lua_tolstring(L, -1, &len);
return std::string(s, len); return std::string(s, len);
} }
Expand Down Expand Up @@ -192,10 +199,13 @@ void ScriptApiEntity::luaentity_Step(u16 id, float dtime)
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER


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

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


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


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


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

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


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


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


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

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


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


Loading

0 comments on commit 371b39a

Please sign in to comment.