diff options
author | Nat Goodspeed <nat@lindenlab.com> | 2024-03-06 09:54:02 -0500 |
---|---|---|
committer | Nat Goodspeed <nat@lindenlab.com> | 2024-03-06 09:54:02 -0500 |
commit | b4bef56b20fbeaaea60b20bd84d1569ed76cf29b (patch) | |
tree | aa56f2e8e315b956f322e5df20409164a078d4dd /indra | |
parent | de71c6378e60c0f0ea0c5537729f052da8513b19 (diff) |
Defend LuaState::expr() against lua_tollsd() errors.
This is an unusual use case in which lua_tollsd() is called by C++ code
without the Lua runtime farther up the call stack.
Diffstat (limited to 'indra')
-rw-r--r-- | indra/llcommon/lua_function.cpp | 38 |
1 files changed, 35 insertions, 3 deletions
diff --git a/indra/llcommon/lua_function.cpp b/indra/llcommon/lua_function.cpp index 78abb8ba7e..b5de5099ba 100644 --- a/indra/llcommon/lua_function.cpp +++ b/indra/llcommon/lua_function.cpp @@ -16,9 +16,11 @@ // STL headers // std headers #include <algorithm> +#include <exception> #include <iomanip> // std::quoted #include <map> #include <memory> // std::unique_ptr +#include <typeinfo> // external library headers // other Linden headers #include "hexdump.h" @@ -26,6 +28,7 @@ #include "llsd.h" #include "llsdutil.h" #include "lualistener.h" +#include "stringize.h" /***************************************************************************** * luau namespace @@ -496,16 +499,45 @@ std::pair<int, LLSD> LuaState::expr(const std::string& desc, const std::string& // aha, at least one entry on the stack! if (result.first == 1) { - result.second = lua_tollsd(mState, 1); + // Don't forget that lua_tollsd() can throw Lua errors. + try + { + result.second = lua_tollsd(mState, 1); + } + catch (const std::exception& error) + { + // lua_tollsd() is designed to be called from a lua_function(), + // that is, from a C++ function called by Lua. In case of error, + // it throws a Lua error to be caught by the Lua runtime. expr() + // is a peculiar use case in which our C++ code is calling + // lua_tollsd() after return from the Lua runtime. We must catch + // the exception thrown for a Lua error, else it will propagate + // out to the main coroutine and terminate the viewer -- but since + // we instead of the Lua runtime catch it, our lua_State retains + // its internal error status. Any subsequent lua_pcall() calls + // with this lua_State will report error regardless of whether the + // chunk runs successfully. Get a new lua_State(). + initLuaState(); + return { -1, stringize(LLError::Log::classname(error), ": ", error.what()) }; + } // pop the result we claimed lua_settop(mState, 0); return result; } // multiple entries on the stack - for (int index = 1; index <= result.first; ++index) + try + { + for (int index = 1; index <= result.first; ++index) + { + result.second.append(lua_tollsd(mState, index)); + } + } + catch (const std::exception& error) { - result.second.append(lua_tollsd(mState, index)); + // see above comments regarding lua_State's error status + initLuaState(); + return { -1, stringize(LLError::Log::classname(error), ": ", error.what()) }; } // pop everything lua_settop(mState, 0); |