fix(lua): segfault on error handler, new error handler system adopted

This commit is contained in:
maelstrom 2025-07-10 02:03:35 +02:00
parent 527f159ff3
commit d558f166f9
3 changed files with 37 additions and 59 deletions

View file

@ -13,6 +13,8 @@
int script_wait(lua_State*); int script_wait(lua_State*);
int script_delay(lua_State*); int script_delay(lua_State*);
int script_wrapper(lua_State*);
int script_errhandler(lua_State*);
Script::Script(): Instance(&TYPE) { Script::Script(): Instance(&TYPE) {
source = "print(\"Hello, world!\")"; source = "print(\"Hello, world!\")";
@ -52,41 +54,11 @@ void Script::Run() {
lua_pop(Lt, 1); // _G lua_pop(Lt, 1); // _G
// Load source and push onto thread stack as function ptr // Load source and push onto thread stack as upvalue for wrapper closure
// luaL_loadstring(Lt, source.c_str()); luaL_loadbuffer(Lt, source.c_str(), source.size(), this->GetFullName().c_str());
luaL_loadbuffer(Lt, source.c_str(), source.size(), scriptContext->RegisterScriptSource(shared<Script>()).c_str()); lua_pushcclosure(Lt, script_wrapper, 1);
int status = lua_resume(Lt, 0); lua_resume(Lt, 0);
if (status > LUA_YIELD) {
lua_Debug dbg;
lua_getstack(Lt, 1, &dbg);
lua_getinfo(Lt, "S", &dbg);
std::weak_ptr<Script> source = scriptContext->GetScriptFromSource(dbg.source);
std::string errorMessage = lua_tostring(Lt, -1);
if (!source.expired())
errorMessage = source.lock()->GetFullName() + errorMessage.substr(errorMessage.find(':'));
Logger::error(errorMessage);
lua_pop(Lt, 1); // Pop return value
Logger::traceStart();
int stack = 1;
while (lua_getstack(Lt, stack++, &dbg)) {
lua_getinfo(Lt, "nlSu", &dbg);
std::weak_ptr<Script> source = scriptContext->GetScriptFromSource(dbg.source);
if (source.expired()) {
Logger::trace(dbg.source, dbg.currentline);
} else {
Logger::trace(source.lock()->GetFullName(), dbg.currentline, &source);
}
}
Logger::traceEnd();
}
lua_pop(L, 1); // Pop the thread lua_pop(L, 1); // Pop the thread
} }
@ -123,3 +95,33 @@ int script_delay(lua_State* L) {
return 0; return 0;
} }
int script_wrapper(lua_State* L) {
lua_pushcfunction(L, script_errhandler);
lua_pushvalue(L, lua_upvalueindex(1));
lua_pcall(L, 0, 0, -2);
return 0;
}
int script_errhandler(lua_State* L) {
std::string errorMessage = lua_tostring(L, -1);
Logger::error(errorMessage);
// Traceback
Logger::traceStart();
lua_Debug dbg;
int stack = 1;
while (lua_getstack(L, stack++, &dbg)) {
lua_getinfo(L, "nlSu", &dbg);
if (strcmp(dbg.what, "C") == 0)
continue; // Ignore C frames
Logger::trace(dbg.source, dbg.currentline);
}
Logger::traceEnd();
return 0;
}

View file

@ -105,11 +105,7 @@ void ScriptContext::RunSleepingThreads() {
// Time args // Time args
lua_pushnumber(sleep.thread, float(tu_clock_micros() - sleep.timeYieldedWhen) / 1'000'000); lua_pushnumber(sleep.thread, float(tu_clock_micros() - sleep.timeYieldedWhen) / 1'000'000);
lua_pushnumber(sleep.thread, float(tu_clock_micros()) / 1'000'000); lua_pushnumber(sleep.thread, float(tu_clock_micros()) / 1'000'000);
int status = lua_resume(sleep.thread, 2); lua_resume(sleep.thread, 2);
if (status > LUA_YIELD) {
Logger::error(lua_tostring(sleep.thread, -1));
lua_pop(sleep.thread, 1); // Pop return value
}
// Remove thread // Remove thread
deleted = true; deleted = true;
@ -134,23 +130,6 @@ void ScriptContext::RunSleepingThreads() {
schedTime = tu_clock_micros() - startTime; schedTime = tu_clock_micros() - startTime;
} }
std::string ScriptContext::RegisterScriptSource(std::shared_ptr<Script> script) {
// If it has already been registered, reference it here
for (auto& [id, script2] : scriptSources) {
if (!script2.expired() && script2.lock() == script)
return "=f" + std::to_string(id);
}
int id = lastScriptSourceId++;
scriptSources[id] = script;
return "=f" + std::to_string(id);
}
std::weak_ptr<Script> ScriptContext::GetScriptFromSource(std::string source) {
int id = std::stoi(source.c_str() + 2);
return scriptSources[id];
}
// https://www.lua.org/source/5.1/lbaselib.c.html // https://www.lua.org/source/5.1/lbaselib.c.html
static int g_print(lua_State* L) { static int g_print(lua_State* L) {
std::string buf; std::string buf;

View file

@ -19,7 +19,6 @@ class DEF_INST_SERVICE ScriptContext : public Service {
AUTOGEN_PREAMBLE AUTOGEN_PREAMBLE
std::vector<SleepingThread> sleepingThreads; std::vector<SleepingThread> sleepingThreads;
std::map<int, std::weak_ptr<Script>> scriptSources;
int lastScriptSourceId = 0; int lastScriptSourceId = 0;
protected: protected:
void InitService() override; void InitService() override;
@ -32,8 +31,6 @@ public:
lua_State* state; lua_State* state;
void PushThreadSleep(lua_State* thread, float delay); void PushThreadSleep(lua_State* thread, float delay);
void RunSleepingThreads(); void RunSleepingThreads();
std::string RegisterScriptSource(std::shared_ptr<Script>);
std::weak_ptr<Script> GetScriptFromSource(std::string source);
static inline std::shared_ptr<Instance> Create() { return std::make_shared<ScriptContext>(); }; static inline std::shared_ptr<Instance> Create() { return std::make_shared<ScriptContext>(); };
}; };