From 163aebf8ca95e4e5317318cf6e8ad14d53e0fde5 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Thu, 14 May 2015 19:46:18 +0200 Subject: Fixed cPluginManager:ForEachCommand() and ForEachConsoleCommand() The functions would leak one value on the Lua stack for each enumerated command. Fixes #2017. --- src/Bindings/ManualBindings.cpp | 147 +++++++++++++++------------------------- 1 file changed, 54 insertions(+), 93 deletions(-) (limited to 'src/Bindings') diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index 324ca9b89..ff904d74a 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -747,39 +747,38 @@ static int tolua_cPluginManager_AddHook(lua_State * tolua_S) static int tolua_cPluginManager_ForEachCommand(lua_State * tolua_S) { - int NumArgs = lua_gettop(tolua_S) - 1; /* This includes 'self' */ - if (NumArgs != 1) - { - LOGWARN("Error in function call 'ForEachCommand': Requires 1 argument, got %i", NumArgs); - return 0; - } - - cPluginManager * self = (cPluginManager *)tolua_tousertype(tolua_S, 1, nullptr); - if (self == nullptr) - { - LOGWARN("Error in function call 'ForEachCommand': Not called on an object instance"); - return 0; - } + /* + Function signature: + cPluginManager:Get():ForEachCommand(a_CallbackFn) -> bool + */ - if (!lua_isfunction(tolua_S, 2)) + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamUserType(1, "cPluginManager") || + !L.CheckParamFunction(2) || + !L.CheckParamEnd(3) + ) { - LOGWARN("Error in function call 'ForEachCommand': Expected a function for parameter #1"); return 0; } - int FuncRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); - if (FuncRef == LUA_REFNIL) + // Get the params: + cLuaState::cRef FnRef; + L.GetStackValues(2, FnRef); + if (!FnRef.IsValid()) { LOGWARN("Error in function call 'ForEachCommand': Could not get function reference of parameter #1"); return 0; } + // Callback for enumerating all commands: class cLuaCallback : public cPluginManager::cCommandEnumCallback { public: - cLuaCallback(lua_State * a_LuaState, int a_FuncRef): - LuaState(a_LuaState), - FuncRef(a_FuncRef) + cLuaCallback(cLuaState & a_LuaState, cLuaState::cRef & a_FnRef): + m_LuaState(a_LuaState), + m_FnRef(a_FnRef) { } @@ -787,35 +786,16 @@ static int tolua_cPluginManager_ForEachCommand(lua_State * tolua_S) virtual bool Command(const AString & a_Command, const cPlugin * a_Plugin, const AString & a_Permission, const AString & a_HelpString) override { UNUSED(a_Plugin); - - lua_rawgeti(LuaState, LUA_REGISTRYINDEX, FuncRef); /* Push function reference */ - tolua_pushcppstring(LuaState, a_Command); - tolua_pushcppstring(LuaState, a_Permission); - tolua_pushcppstring(LuaState, a_HelpString); - - int s = lua_pcall(LuaState, 3, 1, 0); - if (cLuaState::ReportErrors(LuaState, s)) - { - return true; /* Abort enumeration */ - } - - if (lua_isboolean(LuaState, -1)) - { - return (tolua_toboolean(LuaState, -1, 0) > 0); - } - return false; /* Continue enumeration */ + bool ret = false; + m_LuaState.Call(m_FnRef, a_Command, a_Permission, a_HelpString, cLuaState::Return, ret); + return ret; } - lua_State * LuaState; - int FuncRef; - } Callback(tolua_S, FuncRef); + cLuaState & m_LuaState; + cLuaState::cRef & m_FnRef; + } Callback(L, FnRef); - bool bRetVal = self->ForEachCommand(Callback); - - /* Unreference the values again, so the LUA_REGISTRYINDEX can make place for other references */ - luaL_unref(tolua_S, LUA_REGISTRYINDEX, FuncRef); - - /* Push return value on stack */ - tolua_pushboolean(tolua_S, bRetVal); + // Execute and push the returned value: + L.Push(cPluginManager::Get()->ForEachCommand(Callback)); return 1; } @@ -825,39 +805,38 @@ static int tolua_cPluginManager_ForEachCommand(lua_State * tolua_S) static int tolua_cPluginManager_ForEachConsoleCommand(lua_State * tolua_S) { - int NumArgs = lua_gettop(tolua_S) - 1; /* This includes 'self' */ - if (NumArgs != 1) - { - LOGWARN("Error in function call 'ForEachConsoleCommand': Requires 1 argument, got %i", NumArgs); - return 0; - } - - cPluginManager * self = (cPluginManager *)tolua_tousertype(tolua_S, 1, nullptr); - if (self == nullptr) - { - LOGWARN("Error in function call 'ForEachConsoleCommand': Not called on an object instance"); - return 0; - } + /* + Function signature: + cPluginManager:Get():ForEachConsoleCommand(a_CallbackFn) -> bool + */ - if (!lua_isfunction(tolua_S, 2)) + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamUserType(1, "cPluginManager") || + !L.CheckParamFunction(2) || + !L.CheckParamEnd(3) + ) { - LOGWARN("Error in function call 'ForEachConsoleCommand': Expected a function for parameter #1"); return 0; } - int FuncRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); - if (FuncRef == LUA_REFNIL) + // Get the params: + cLuaState::cRef FnRef; + L.GetStackValues(2, FnRef); + if (!FnRef.IsValid()) { LOGWARN("Error in function call 'ForEachConsoleCommand': Could not get function reference of parameter #1"); return 0; } + // Callback for enumerating all commands: class cLuaCallback : public cPluginManager::cCommandEnumCallback { public: - cLuaCallback(lua_State * a_LuaState, int a_FuncRef): - LuaState(a_LuaState), - FuncRef(a_FuncRef) + cLuaCallback(cLuaState & a_LuaState, cLuaState::cRef & a_FnRef): + m_LuaState(a_LuaState), + m_FnRef(a_FnRef) { } @@ -866,34 +845,16 @@ static int tolua_cPluginManager_ForEachConsoleCommand(lua_State * tolua_S) { UNUSED(a_Plugin); UNUSED(a_Permission); - - lua_rawgeti(LuaState, LUA_REGISTRYINDEX, FuncRef); /* Push function reference */ - tolua_pushcppstring(LuaState, a_Command); - tolua_pushcppstring(LuaState, a_HelpString); - - int s = lua_pcall(LuaState, 2, 1, 0); - if (cLuaState::ReportErrors(LuaState, s)) - { - return true; /* Abort enumeration */ - } - - if (lua_isboolean(LuaState, -1)) - { - return (tolua_toboolean(LuaState, -1, 0) > 0); - } - return false; /* Continue enumeration */ + bool ret = false; + m_LuaState.Call(m_FnRef, a_Command, a_HelpString, cLuaState::Return, ret); + return ret; } - lua_State * LuaState; - int FuncRef; - } Callback(tolua_S, FuncRef); - - bool bRetVal = self->ForEachConsoleCommand(Callback); - - /* Unreference the values again, so the LUA_REGISTRYINDEX can make place for other references */ - luaL_unref(tolua_S, LUA_REGISTRYINDEX, FuncRef); + cLuaState & m_LuaState; + cLuaState::cRef & m_FnRef; + } Callback(L, FnRef); - /* Push return value on stack */ - tolua_pushboolean(tolua_S, bRetVal); + // Execute and push the returned value: + L.Push(cPluginManager::Get()->ForEachConsoleCommand(Callback)); return 1; } -- cgit v1.2.3 From 1240c76cb472931253e2ce502356c0428f974c5a Mon Sep 17 00:00:00 2001 From: Mattes D Date: Sat, 16 May 2015 16:19:18 +0200 Subject: Lua: Break into ZBS debugger on API errors. --- src/Bindings/LuaState.cpp | 26 ++++++++++++++++++++++++++ src/Bindings/LuaState.h | 3 +++ 2 files changed, 29 insertions(+) (limited to 'src/Bindings') diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp index ccf812417..08c7e19d7 100644 --- a/src/Bindings/LuaState.cpp +++ b/src/Bindings/LuaState.cpp @@ -927,6 +927,9 @@ bool cLuaState::CheckParamTable(int a_StartParam, int a_EndParam) VERIFY(lua_getstack(m_LuaState, 0, &entry)); VERIFY(lua_getinfo (m_LuaState, "n", &entry)); AString ErrMsg = Printf("#ferror in function '%s'.", (entry.name != nullptr) ? entry.name : "?"); + + BreakIntoDebugger(m_LuaState); + tolua_error(m_LuaState, ErrMsg.c_str(), &tolua_err); return false; } // for i - Param @@ -1366,6 +1369,7 @@ int cLuaState::ReportFnCallErrors(lua_State * a_LuaState) { LOGWARNING("LUA: %s", lua_tostring(a_LuaState, -1)); LogStackTrace(a_LuaState, 1); + BreakIntoDebugger(a_LuaState); return 1; // We left the error message on the stack as the return value } @@ -1373,6 +1377,28 @@ int cLuaState::ReportFnCallErrors(lua_State * a_LuaState) +int cLuaState::BreakIntoDebugger(lua_State * a_LuaState) +{ + // Call the BreakIntoDebugger function, if available: + lua_getglobal(a_LuaState, "BreakIntoDebugger"); + if (!lua_isfunction(a_LuaState, -1)) + { + LOGD("LUA: BreakIntoDebugger() not found / not a function"); + lua_pop(a_LuaState, 1); + return 1; + } + lua_insert(a_LuaState, -2); // Copy the string that has been passed to us + LOGD("Calling BreakIntoDebugger()..."); + lua_call(a_LuaState, 1, 0); + LOGD("Returned from BreakIntoDebugger()."); + + return 0; +} + + + + + //////////////////////////////////////////////////////////////////////////////// // cLuaState::cRef: diff --git a/src/Bindings/LuaState.h b/src/Bindings/LuaState.h index b38401fd8..5b4ec3ae4 100644 --- a/src/Bindings/LuaState.h +++ b/src/Bindings/LuaState.h @@ -389,6 +389,9 @@ protected: /** Used as the error reporting function for function calls */ static int ReportFnCallErrors(lua_State * a_LuaState); + + /** Tries to break into the MobDebug debugger, if it is installed. */ + static int BreakIntoDebugger(lua_State * a_LuaState); } ; -- cgit v1.2.3