summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/newview/llfloaterluadebug.cpp6
-rw-r--r--indra/newview/llluamanager.cpp35
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);