summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
authorNat Goodspeed <nat@lindenlab.com>2024-03-06 09:54:02 -0500
committerNat Goodspeed <nat@lindenlab.com>2024-03-06 09:54:02 -0500
commitb4bef56b20fbeaaea60b20bd84d1569ed76cf29b (patch)
treeaa56f2e8e315b956f322e5df20409164a078d4dd /indra
parentde71c6378e60c0f0ea0c5537729f052da8513b19 (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.cpp38
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);