diff options
author | Nat Goodspeed <nat@lindenlab.com> | 2024-04-18 16:34:32 -0400 |
---|---|---|
committer | Nat Goodspeed <nat@lindenlab.com> | 2024-04-18 16:34:32 -0400 |
commit | fa821576c010eca2cacb0fab25dd240de4062b31 (patch) | |
tree | a3f13f5e989531c73cf38c8b0e84cdb92ed87e57 | |
parent | c05bf5acd487e78e414e3d679f6ec5dbfaa4169d (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.cpp | 44 | ||||
-rw-r--r-- | indra/llcommon/lua_function.h | 3 | ||||
-rw-r--r-- | indra/newview/llluamanager.cpp | 43 |
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) |