diff options
-rw-r--r-- | indra/newview/llfloaterluadebug.cpp | 6 | ||||
-rw-r--r-- | indra/newview/llluamanager.cpp | 35 |
2 files changed, 39 insertions, 2 deletions
diff --git a/indra/newview/llfloaterluadebug.cpp b/indra/newview/llfloaterluadebug.cpp index f247528231..6fd11dd1c7 100644 --- a/indra/newview/llfloaterluadebug.cpp +++ b/indra/newview/llfloaterluadebug.cpp @@ -123,8 +123,10 @@ void LLFloaterLUADebug::completion(int count, const LLSD& result) if (count < 0) { // error: show error message - mResultOutput->insertText("*** "); - mResultOutput->pasteTextWithLinebreaks(result.asString()); + LLStyle::Params params; + params.readonly_color = LLUIColorTable::instance().getColor("LtRed"); + mResultOutput->appendText(result.asString(), false, params); + mResultOutput->endOfDoc(); return; } if (count == 1) diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index 853ed5a634..dfa27ebc37 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -51,11 +51,22 @@ std::map<std::string, std::string> LLLUAmanager::sScriptNames; std::set<std::string> LLLUAmanager::sTerminationList; +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); return 0; }; @@ -98,6 +109,8 @@ std::string lua_print_msg(lua_State* L, const std::string_view& level) std::string msg{ out.str() }; // put message out there for any interested party (*koff* LLFloaterLUADebug *koff*) LLEventPumps::instance().obtain("lua output").post(stringize(level, ": ", msg)); + + llcoro::suspend(); return msg; } @@ -155,6 +168,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); return 2; } @@ -175,6 +189,25 @@ 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); + + counter++; + if (counter > INTERRUPTS_MAX_LIMIT) + { + lluau::error(L, "Possible infinite loop, terminated."); + } + else if (counter % INTERRUPTS_SUSPEND_LIMIT == 0) + { + llcoro::suspend(); + } + set_interrupts_counter(L, counter); +} + 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. @@ -189,6 +222,7 @@ 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) { @@ -202,6 +236,7 @@ void LLLUAmanager::runScriptFile(const std::string &filename, script_result_fn r sTerminationList.erase(it); lluau::error(L, "Script was terminated"); } + check_interrupts_counter(L); }; std::string text{std::istreambuf_iterator<char>(in_file), {}}; auto [count, result] = L.expr(filename, text); |