From 5502c74229be911ec29c4156b905f347bcb45f36 Mon Sep 17 00:00:00 2001 From: SaltySnail Date: Sun, 14 Jul 2024 00:22:48 +0200 Subject: [PATCH 1/6] add stacktrace to the server lua engine (WIP) --- src/TLuaEngine.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index a48c848..84c1e64 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -498,6 +498,7 @@ sol::table TLuaEngine::StateThreadData::Lua_TriggerGlobalEvent(const std::string Result->Error = false; Result->Result = LuaResult; } else { + beammp_debug("Some call failed 2"); Result->Error = true; Result->ErrorMessage = "Function result in TriggerGlobalEvent was invalid"; } @@ -786,6 +787,12 @@ sol::table TLuaEngine::StateThreadData::Lua_JsonDecode(const std::string& str) { return table; } +static std::string traceback(lua_State *L) { + auto globals = sol::state_view(L).globals(); + auto test = globals.get("debug").get("traceback"); + return test(); +} + TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, TLuaStateId StateId, TLuaEngine& Engine) : mName(Name) , mStateId(StateId) @@ -796,6 +803,7 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, TLuaStateI return; } luaL_openlibs(mState); + // lua_pushcfunction(mState, (lua_CFunction)(traceback)); sol::state_view StateView(mState); lua_atpanic(mState, LuaAPI::PanicHandler); // StateView.globals()["package"].get() @@ -1090,6 +1098,8 @@ void TLuaEngine::StateThreadData::operator()() { S.second->Error = false; S.second->Result = std::move(Res); } else { + beammp_debug("Some call failed"); + traceback(StateView.lua_state()); S.second->Error = true; sol::error Err = Res; S.second->ErrorMessage = Err.what(); @@ -1113,7 +1123,7 @@ void TLuaEngine::StateThreadData::operator()() { // TODO: Use TheQueuedFunction.EventName for errors, warnings, etc Result->StateId = mStateId; sol::state_view StateView(mState); - auto Fn = StateView[FnName]; + sol::protected_function Fn = StateView[FnName]; if (Fn.valid() && Fn.get_type() == sol::type::function) { std::vector LuaArgs; for (const auto& Arg : Args) { @@ -1149,17 +1159,21 @@ void TLuaEngine::StateThreadData::operator()() { break; } } + Fn.set_error_handler([](const std::string& error, sol::this_state state) -> std::string { return traceback(state.lua_state()); }); auto Res = Fn(sol::as_args(LuaArgs)); if (Res.valid()) { Result->Error = false; Result->Result = std::move(Res); } else { + beammp_debug("Some call failed 3"); Result->Error = true; sol::error Err = Res; Result->ErrorMessage = Err.what(); + // beammp_lua_error(traceback(StateView.lua_state())); } Result->MarkAsReady(); } else { + beammp_debug("Some call failed 4"); Result->Error = true; Result->ErrorMessage = BeamMPFnNotFoundError; // special error kind that we can ignore later Result->MarkAsReady(); From 4fad047bf46b0dce823c0ba574399fdf3fa181bf Mon Sep 17 00:00:00 2001 From: SaltySnail Date: Sun, 14 Jul 2024 01:00:57 +0200 Subject: [PATCH 2/6] Add working stacktrace --- src/TLuaEngine.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 84c1e64..ecb75ae 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -1099,7 +1099,7 @@ void TLuaEngine::StateThreadData::operator()() { S.second->Result = std::move(Res); } else { beammp_debug("Some call failed"); - traceback(StateView.lua_state()); + // traceback(StateView.lua_state()); S.second->Error = true; sol::error Err = Res; S.second->ErrorMessage = Err.what(); @@ -1123,7 +1123,12 @@ void TLuaEngine::StateThreadData::operator()() { // TODO: Use TheQueuedFunction.EventName for errors, warnings, etc Result->StateId = mStateId; sol::state_view StateView(mState); - sol::protected_function Fn = StateView[FnName]; + StateView.script(R"( + function beammp_internal_error_handler(message) + return "Error: " .. message .. ", Stacktrace: " .. debug.traceback() + end + )"); + sol::protected_function Fn(StateView[FnName], StateView["beammp_internal_error_handler"]); if (Fn.valid() && Fn.get_type() == sol::type::function) { std::vector LuaArgs; for (const auto& Arg : Args) { @@ -1159,7 +1164,8 @@ void TLuaEngine::StateThreadData::operator()() { break; } } - Fn.set_error_handler([](const std::string& error, sol::this_state state) -> std::string { return traceback(state.lua_state()); }); + // StateView.set_panic( sol::c_call ); + // Fn.set_error_handler([](const std::string& error, sol::this_state state) -> std::string { return traceback(state.lua_state()); }); auto Res = Fn(sol::as_args(LuaArgs)); if (Res.valid()) { Result->Error = false; From 6f4c3f0ceb6da62915bbe17fef983e0eb6326d86 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sun, 14 Jul 2024 01:43:01 +0200 Subject: [PATCH 3/6] add traceback to lua errors by way of shitty lua hacks --- src/TLuaEngine.cpp | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index ecb75ae..924db0f 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -30,7 +30,9 @@ #include #include #include +#include #include +#include #include #include @@ -787,12 +789,6 @@ sol::table TLuaEngine::StateThreadData::Lua_JsonDecode(const std::string& str) { return table; } -static std::string traceback(lua_State *L) { - auto globals = sol::state_view(L).globals(); - auto test = globals.get("debug").get("traceback"); - return test(); -} - TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, TLuaStateId StateId, TLuaEngine& Engine) : mName(Name) , mStateId(StateId) @@ -1123,13 +1119,8 @@ void TLuaEngine::StateThreadData::operator()() { // TODO: Use TheQueuedFunction.EventName for errors, warnings, etc Result->StateId = mStateId; sol::state_view StateView(mState); - StateView.script(R"( - function beammp_internal_error_handler(message) - return "Error: " .. message .. ", Stacktrace: " .. debug.traceback() - end - )"); - sol::protected_function Fn(StateView[FnName], StateView["beammp_internal_error_handler"]); - if (Fn.valid() && Fn.get_type() == sol::type::function) { + auto RawFn = StateView[FnName]; + if (RawFn.valid() && RawFn.get_type() == sol::type::function) { std::vector LuaArgs; for (const auto& Arg : Args) { if (Arg.valueless_by_exception()) { @@ -1164,8 +1155,19 @@ void TLuaEngine::StateThreadData::operator()() { break; } } - // StateView.set_panic( sol::c_call ); - // Fn.set_error_handler([](const std::string& error, sol::this_state state) -> std::string { return traceback(state.lua_state()); }); + StateView["INTERNAL_ERROR_HANDLER"] = [](lua_State* L) { + auto Error = sol::stack::get>(L); + std::string ErrorString = ""; + if (Error.has_value()) { + ErrorString = Error.value(); + } + auto DebugTracebackFn = sol::state_view(L).globals() + .get("debug") + .get("traceback"); + std::string Traceback = DebugTracebackFn(ErrorString, 2); // refusing to elaborate. questions? rtfm. + return sol::stack::push(L, Traceback); + }; + sol::protected_function Fn(RawFn, StateView["INTERNAL_ERROR_HANDLER"]); auto Res = Fn(sol::as_args(LuaArgs)); if (Res.valid()) { Result->Error = false; @@ -1175,7 +1177,6 @@ void TLuaEngine::StateThreadData::operator()() { Result->Error = true; sol::error Err = Res; Result->ErrorMessage = Err.what(); - // beammp_lua_error(traceback(StateView.lua_state())); } Result->MarkAsReady(); } else { From 9db3619cd8ce38759cc8448fe16bd112401682b8 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sun, 14 Jul 2024 01:50:31 +0200 Subject: [PATCH 4/6] cleanup and add comments to traceback feature --- src/TLuaEngine.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 924db0f..5676a38 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -1161,10 +1161,9 @@ void TLuaEngine::StateThreadData::operator()() { if (Error.has_value()) { ErrorString = Error.value(); } - auto DebugTracebackFn = sol::state_view(L).globals() - .get("debug") - .get("traceback"); - std::string Traceback = DebugTracebackFn(ErrorString, 2); // refusing to elaborate. questions? rtfm. + auto DebugTracebackFn = sol::state_view(L).globals().get("debug").get("traceback"); + // 2 = start collecting the trace one above the current function (1=current function) + std::string Traceback = DebugTracebackFn(ErrorString, 2); return sol::stack::push(L, Traceback); }; sol::protected_function Fn(RawFn, StateView["INTERNAL_ERROR_HANDLER"]); From 012ce08b9197c4072f15203e320dddf742d8b151 Mon Sep 17 00:00:00 2001 From: SaltySnail Date: Sun, 14 Jul 2024 03:18:59 +0200 Subject: [PATCH 5/6] Add proper lua server stacktraces --- include/TLuaEngine.h | 4 +++- src/TLuaEngine.cpp | 41 ++++++++++++++++++++++------------------- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index 3d74483..658d753 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -192,7 +192,9 @@ public: for (const auto& Event : mLuaEvents.at(EventName)) { for (const auto& Function : Event.second) { if (Event.first != IgnoreId) { - Results.push_back(EnqueueFunctionCall(Event.first, Function, Arguments)); + auto Result = EnqueueFunctionCall(Event.first, Function, Arguments); + Results.push_back(Result); + AddResultToCheck(Result); } } } diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 5676a38..195ca47 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -38,6 +38,8 @@ TLuaEngine* LuaAPI::MP::Engine; +static sol::protected_function addTraceback(sol::state_view StateView, sol::protected_function RawFn); + TLuaEngine::TLuaEngine() : mResourceServerPath(fs::path(Application::Settings.getAsString(Settings::Key::General_ResourceFolder)) / "Server") { Application::SetSubsystemStatus("LuaEngine", Application::Status::Starting); @@ -493,6 +495,7 @@ sol::table TLuaEngine::StateThreadData::Lua_TriggerGlobalEvent(const std::string sol::variadic_results LocalArgs = JsonStringToArray(Str); for (const auto& Handler : MyHandlers) { auto Fn = mStateView[Handler]; + Fn = addTraceback(mStateView, Fn); if (Fn.valid()) { auto LuaResult = Fn(LocalArgs); auto Result = std::make_shared(); @@ -500,9 +503,10 @@ sol::table TLuaEngine::StateThreadData::Lua_TriggerGlobalEvent(const std::string Result->Error = false; Result->Result = LuaResult; } else { - beammp_debug("Some call failed 2"); Result->Error = true; - Result->ErrorMessage = "Function result in TriggerGlobalEvent was invalid"; + sol::error Err = LuaResult; + Result->ErrorMessage = Err.what(); + beammp_errorf("An error occured while executing local event handler \"{}\" for event \"{}\": {}", Handler, EventName, Result->ErrorMessage); } Result->MarkAsReady(); Return.push_back(Result); @@ -799,7 +803,6 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, TLuaStateI return; } luaL_openlibs(mState); - // lua_pushcfunction(mState, (lua_CFunction)(traceback)); sol::state_view StateView(mState); lua_atpanic(mState, LuaAPI::PanicHandler); // StateView.globals()["package"].get() @@ -1053,6 +1056,21 @@ void TLuaEngine::StateThreadData::RegisterEvent(const std::string& EventName, co mEngine->RegisterEvent(EventName, mStateId, FunctionName); } +static sol::protected_function addTraceback(sol::state_view StateView, sol::protected_function RawFn) { + StateView["INTERNAL_ERROR_HANDLER"] = [](lua_State *L) { + auto Error = sol::stack::get>(L); + std::string ErrorString = ""; + if (Error.has_value()) { + ErrorString = Error.value(); + } + auto DebugTracebackFn = sol::state_view(L).globals().get("debug").get("traceback"); + // 2 = start collecting the trace one above the current function (1=current function) + std::string Traceback = DebugTracebackFn(ErrorString, 2); + return sol::stack::push(L, Traceback); + }; + return sol::protected_function(RawFn, StateView["INTERNAL_ERROR_HANDLER"]); +} + void TLuaEngine::StateThreadData::operator()() { RegisterThread("Lua:" + mStateId); while (!Application::IsShuttingDown()) { @@ -1094,8 +1112,6 @@ void TLuaEngine::StateThreadData::operator()() { S.second->Error = false; S.second->Result = std::move(Res); } else { - beammp_debug("Some call failed"); - // traceback(StateView.lua_state()); S.second->Error = true; sol::error Err = Res; S.second->ErrorMessage = Err.what(); @@ -1155,31 +1171,18 @@ void TLuaEngine::StateThreadData::operator()() { break; } } - StateView["INTERNAL_ERROR_HANDLER"] = [](lua_State* L) { - auto Error = sol::stack::get>(L); - std::string ErrorString = ""; - if (Error.has_value()) { - ErrorString = Error.value(); - } - auto DebugTracebackFn = sol::state_view(L).globals().get("debug").get("traceback"); - // 2 = start collecting the trace one above the current function (1=current function) - std::string Traceback = DebugTracebackFn(ErrorString, 2); - return sol::stack::push(L, Traceback); - }; - sol::protected_function Fn(RawFn, StateView["INTERNAL_ERROR_HANDLER"]); + auto Fn = addTraceback(StateView, RawFn); auto Res = Fn(sol::as_args(LuaArgs)); if (Res.valid()) { Result->Error = false; Result->Result = std::move(Res); } else { - beammp_debug("Some call failed 3"); Result->Error = true; sol::error Err = Res; Result->ErrorMessage = Err.what(); } Result->MarkAsReady(); } else { - beammp_debug("Some call failed 4"); Result->Error = true; Result->ErrorMessage = BeamMPFnNotFoundError; // special error kind that we can ignore later Result->MarkAsReady(); From 4a062e5aa049df90148995314b751e18fe1be546 Mon Sep 17 00:00:00 2001 From: SaltySnail <51403141+SaltySnail@users.noreply.github.com> Date: Wed, 17 Jul 2024 19:00:21 +0200 Subject: [PATCH 6/6] Fix not following naming convention Co-authored-by: Lion --- src/TLuaEngine.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 195ca47..d423c69 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -38,7 +38,7 @@ TLuaEngine* LuaAPI::MP::Engine; -static sol::protected_function addTraceback(sol::state_view StateView, sol::protected_function RawFn); +static sol::protected_function AddTraceback(sol::state_view StateView, sol::protected_function RawFn); TLuaEngine::TLuaEngine() : mResourceServerPath(fs::path(Application::Settings.getAsString(Settings::Key::General_ResourceFolder)) / "Server") { @@ -495,7 +495,7 @@ sol::table TLuaEngine::StateThreadData::Lua_TriggerGlobalEvent(const std::string sol::variadic_results LocalArgs = JsonStringToArray(Str); for (const auto& Handler : MyHandlers) { auto Fn = mStateView[Handler]; - Fn = addTraceback(mStateView, Fn); + Fn = AddTraceback(mStateView, Fn); if (Fn.valid()) { auto LuaResult = Fn(LocalArgs); auto Result = std::make_shared(); @@ -1056,7 +1056,7 @@ void TLuaEngine::StateThreadData::RegisterEvent(const std::string& EventName, co mEngine->RegisterEvent(EventName, mStateId, FunctionName); } -static sol::protected_function addTraceback(sol::state_view StateView, sol::protected_function RawFn) { +static sol::protected_function AddTraceback(sol::state_view StateView, sol::protected_function RawFn) { StateView["INTERNAL_ERROR_HANDLER"] = [](lua_State *L) { auto Error = sol::stack::get>(L); std::string ErrorString = ""; @@ -1171,7 +1171,7 @@ void TLuaEngine::StateThreadData::operator()() { break; } } - auto Fn = addTraceback(StateView, RawFn); + auto Fn = AddTraceback(StateView, RawFn); auto Res = Fn(sol::as_args(LuaArgs)); if (Res.valid()) { Result->Error = false;