summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNat Goodspeed <nat@lindenlab.com>2024-04-18 16:34:32 -0400
committerNat Goodspeed <nat@lindenlab.com>2024-04-18 16:34:32 -0400
commitfa821576c010eca2cacb0fab25dd240de4062b31 (patch)
treea3f13f5e989531c73cf38c8b0e84cdb92ed87e57
parentc05bf5acd487e78e414e3d679f6ec5dbfaa4169d (diff)
Move {set,check}_interrupts_counter() to lluau namespace.
Use in LuaState::expr() so we can catch a runaway in-memory Lua chunk as well as a script read from a file.
-rw-r--r--indra/llcommon/lua_function.cpp44
-rw-r--r--indra/llcommon/lua_function.h3
-rw-r--r--indra/newview/llluamanager.cpp43
3 files changed, 49 insertions, 41 deletions
diff --git a/indra/llcommon/lua_function.cpp b/indra/llcommon/lua_function.cpp
index 332a08a444..08bc65e0c5 100644
--- a/indra/llcommon/lua_function.cpp
+++ b/indra/llcommon/lua_function.cpp
@@ -31,6 +31,9 @@
#include "lualistener.h"
#include "stringize.h"
+const S32 INTERRUPTS_MAX_LIMIT = 20000;
+const S32 INTERRUPTS_SUSPEND_LIMIT = 100;
+
#define lua_register(L, n, f) (lua_pushcfunction(L, (f), n), lua_setglobal(L, (n)))
#define lua_rawlen lua_objlen
@@ -77,6 +80,35 @@ fsyspath lluau::source_path(lua_State* L)
return ar.source;
}
+void lluau::set_interrupts_counter(lua_State *L, S32 counter)
+{
+ luaL_checkstack(L, 2, nullptr);
+ lua_pushstring(L, "_INTERRUPTS");
+ lua_pushinteger(L, counter);
+ lua_rawset(L, LUA_REGISTRYINDEX);
+}
+
+void lluau::check_interrupts_counter(lua_State* L)
+{
+ luaL_checkstack(L, 1, nullptr);
+ lua_pushstring(L, "_INTERRUPTS");
+ lua_rawget(L, LUA_REGISTRYINDEX);
+ S32 counter = lua_tointeger(L, -1);
+ lua_pop(L, 1);
+
+ lluau::set_interrupts_counter(L, ++counter);
+ if (counter > INTERRUPTS_MAX_LIMIT)
+ {
+ lluau::error(L, "Possible infinite loop, terminated.");
+ }
+ else if (counter % INTERRUPTS_SUSPEND_LIMIT == 0)
+ {
+ LL_DEBUGS("Lua") << LLCoros::getName() << " suspending at " << counter << " interrupts"
+ << LL_ENDL;
+ llcoro::suspend();
+ }
+}
+
/*****************************************************************************
* Lua <=> C++ conversions
*****************************************************************************/
@@ -485,6 +517,18 @@ bool LuaState::checkLua(const std::string& desc, int r)
std::pair<int, LLSD> LuaState::expr(const std::string& desc, const std::string& text)
{
+ lluau::set_interrupts_counter(mState, 0);
+
+ lua_callbacks(mState)->interrupt = [](lua_State *L, int gc)
+ {
+ // skip if we're interrupting only for garbage collection
+ if (gc >= 0)
+ return;
+
+ LLCoros::checkStop();
+ lluau::check_interrupts_counter(L);
+ };
+
if (! checkLua(desc, lluau::dostring(mState, desc, text)))
{
LL_WARNS("Lua") << desc << " error: " << mError << LL_ENDL;
diff --git a/indra/llcommon/lua_function.h b/indra/llcommon/lua_function.h
index ec1e6cdb10..e7013f92c6 100644
--- a/indra/llcommon/lua_function.h
+++ b/indra/llcommon/lua_function.h
@@ -52,6 +52,9 @@ namespace lluau
int loadstring(lua_State* L, const std::string& desc, const std::string& text);
fsyspath source_path(lua_State* L);
+
+ void set_interrupts_counter(lua_State *L, S32 counter);
+ void check_interrupts_counter(lua_State* L);
} // namespace lluau
std::string lua_tostdstring(lua_State* L, int index);
diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp
index e2950648a6..97779a12ad 100644
--- a/indra/newview/llluamanager.cpp
+++ b/indra/newview/llluamanager.cpp
@@ -50,22 +50,12 @@
std::map<std::string, std::string> LLLUAmanager::sScriptNames;
-const S32 INTERRUPTS_MAX_LIMIT = 20000;
-const S32 INTERRUPTS_SUSPEND_LIMIT = 100;
-
-void set_interrupts_counter(lua_State *L, S32 counter)
-{
- lua_pushstring(L, "_INTERRUPTS");
- lua_pushinteger(L, counter);
- lua_rawset(L, LUA_REGISTRYINDEX);
-}
-
lua_function(sleep, "sleep(seconds): pause the running coroutine")
{
F32 seconds = lua_tonumber(L, -1);
lua_pop(L, 1);
llcoro::suspendUntilTimeout(seconds);
- set_interrupts_counter(L, 0);
+ lluau::set_interrupts_counter(L, 0);
return 0;
};
@@ -167,7 +157,7 @@ lua_function(get_event_next,
const auto& [pump, data]{ listener->getNext() };
lua_pushstdstring(L, pump);
lua_pushllsd(L, data);
- set_interrupts_counter(L, 0);
+ lluau::set_interrupts_counter(L, 0);
return 2;
}
@@ -188,24 +178,6 @@ std::pair<int, LLSD> LLLUAmanager::waitScriptFile(const std::string& filename)
return startScriptFile(filename).get();
}
-void check_interrupts_counter(lua_State* L)
-{
- lua_pushstring(L, "_INTERRUPTS");
- lua_rawget(L, LUA_REGISTRYINDEX);
- S32 counter = lua_tointeger(L, -1);
- lua_pop(L, 1);
-
- set_interrupts_counter(L, ++counter);
- if (counter > INTERRUPTS_MAX_LIMIT)
- {
- lluau::error(L, "Possible infinite loop, terminated.");
- }
- else if (counter % INTERRUPTS_SUSPEND_LIMIT == 0)
- {
- llcoro::suspend();
- }
-}
-
void LLLUAmanager::runScriptFile(const std::string &filename, script_result_fn result_cb, script_finished_fn finished_cb)
{
// A script_result_fn will be called when LuaState::expr() completes.
@@ -220,17 +192,6 @@ void LLLUAmanager::runScriptFile(const std::string &filename, script_result_fn r
// A script_finished_fn is used to initialize the LuaState.
// It will be called when the LuaState is destroyed.
LuaState L(finished_cb);
- set_interrupts_counter(L, 0);
-
- lua_callbacks(L)->interrupt = [](lua_State *L, int gc)
- {
- // skip if we're interrupting only for garbage collection
- if (gc >= 0)
- return;
-
- LLCoros::checkStop();
- check_interrupts_counter(L);
- };
std::string text{std::istreambuf_iterator<char>(in_file), {}};
auto [count, result] = L.expr(filename, text);
if (result_cb)