From a92efe581f3b6a37f3217684a7174efb50bb6ef9 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 12 Feb 2026 01:35:57 +0300 Subject: [PATCH 1/3] fix: assets access attempts in headless mode leading to segfaults --- src/engine/Engine.cpp | 2 +- src/logic/scripting/lua/libs/libassets.cpp | 12 ++++++++++++ src/logic/scripting/lua/libs/libgui.cpp | 3 +++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index 0f34cb031..60973437c 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -420,7 +420,7 @@ EngineSettings& Engine::getSettings() { } Assets* Engine::getAssets() { - return assets->getStorage(); + return assets ? assets->getStorage() : nullptr; } AssetsLoader& Engine::acquireBackgroundLoader() { diff --git a/src/logic/scripting/lua/libs/libassets.cpp b/src/logic/scripting/lua/libs/libassets.cpp index 0921f1b9c..27d376542 100644 --- a/src/logic/scripting/lua/libs/libassets.cpp +++ b/src/logic/scripting/lua/libs/libassets.cpp @@ -26,6 +26,9 @@ static void load_texture( } static int l_request_texture(lua::State* L) { + if (engine->isHeadless()) { + throw std::runtime_error("not available in headless mode"); + } std::string filename = lua::require_string(L, 1); std::string alias = lua::require_string(L, 2); auto& loader = engine->acquireBackgroundLoader(); @@ -34,6 +37,9 @@ static int l_request_texture(lua::State* L) { } static int l_load_texture(lua::State* L) { + if (engine->isHeadless()) { + throw std::runtime_error("not available in headless mode"); + } if (lua::isstring(L, 3) && lua::require_lstring(L, 3) != "png") { throw std::runtime_error("unsupportd image format"); } @@ -61,6 +67,9 @@ static int l_load_texture(lua::State* L) { } static int l_parse_model(lua::State* L) { + if (engine->isHeadless()) { + throw std::runtime_error("not available in headless mode"); + } auto format = lua::require_lstring(L, 1); auto string = lua::require_lstring(L, 2); auto name = lua::require_string(L, 3); @@ -79,6 +88,9 @@ static int l_parse_model(lua::State* L) { } static int l_to_canvas(lua::State* L) { + if (engine->isHeadless()) { + throw std::runtime_error("not available in headless mode"); + } auto& assets = *engine->getAssets(); auto alias = lua::require_lstring(L, 1); diff --git a/src/logic/scripting/lua/libs/libgui.cpp b/src/logic/scripting/lua/libs/libgui.cpp index fe4cabada..0ec5e6475 100644 --- a/src/logic/scripting/lua/libs/libgui.cpp +++ b/src/logic/scripting/lua/libs/libgui.cpp @@ -32,6 +32,9 @@ using namespace scripting; static DocumentNode get_document_node_impl( lua::State*, const std::string& name, const std::string& nodeName, bool throwable=true ) { + if (engine->isHeadless()) { + throw std::runtime_error("not available in headless mode"); + } auto doc = engine->getAssets()->get(name); if (doc == nullptr) { if (throwable) { From 8750c5b5b9421bfb164f5ab8350b49538eb832c9 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 12 Feb 2026 01:44:25 +0300 Subject: [PATCH 2/3] cleanup --- src/devtools/stdin_cmd_reader.cpp | 2 +- src/engine/Engine.cpp | 10 ++++++++ src/engine/Engine.hpp | 1 + src/logic/scripting/lua/libs/libassets.cpp | 29 +++++++++------------- 4 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/devtools/stdin_cmd_reader.cpp b/src/devtools/stdin_cmd_reader.cpp index fccbb7f57..8e4a48c22 100644 --- a/src/devtools/stdin_cmd_reader.cpp +++ b/src/devtools/stdin_cmd_reader.cpp @@ -8,7 +8,7 @@ #include #include -static debug::Logger logger("stdin-reader"); +static debug::Logger logger("stdin-cmd"); static std::thread reader_thread; diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index 60973437c..17e9e9f80 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -423,7 +423,17 @@ Assets* Engine::getAssets() { return assets ? assets->getStorage() : nullptr; } +Assets& Engine::requireAssets() { + if (isHeadless()) { + throw std::runtime_error("assets are not available in headless mode"); + } + return *assets->getStorage(); +} + AssetsLoader& Engine::acquireBackgroundLoader() { + if (isHeadless()) { + throw std::runtime_error("assets are not available in headless mode"); + } return assets->acquireBackgroundLoader(); } diff --git a/src/engine/Engine.hpp b/src/engine/Engine.hpp index 4f4e68280..4f726b700 100644 --- a/src/engine/Engine.hpp +++ b/src/engine/Engine.hpp @@ -110,6 +110,7 @@ public: /// @brief Get active assets storage instance Assets* getAssets(); + Assets& requireAssets(); AssetsLoader& acquireBackgroundLoader(); diff --git a/src/logic/scripting/lua/libs/libassets.cpp b/src/logic/scripting/lua/libs/libassets.cpp index 27d376542..82135ad86 100644 --- a/src/logic/scripting/lua/libs/libassets.cpp +++ b/src/logic/scripting/lua/libs/libassets.cpp @@ -15,10 +15,10 @@ using namespace scripting; static void load_texture( - const ubyte* bytes, size_t size, const std::string& destname + Assets& assets, const ubyte* bytes, size_t size, const std::string& destname ) { try { - engine->getAssets()->store(png::load_texture(bytes, size), destname); + assets.store(png::load_texture(bytes, size), destname); } catch (const std::runtime_error& err) { debug::Logger logger("lua.assetslib"); logger.error() << err.what(); @@ -26,9 +26,6 @@ static void load_texture( } static int l_request_texture(lua::State* L) { - if (engine->isHeadless()) { - throw std::runtime_error("not available in headless mode"); - } std::string filename = lua::require_string(L, 1); std::string alias = lua::require_string(L, 2); auto& loader = engine->acquireBackgroundLoader(); @@ -37,9 +34,8 @@ static int l_request_texture(lua::State* L) { } static int l_load_texture(lua::State* L) { - if (engine->isHeadless()) { - throw std::runtime_error("not available in headless mode"); - } + auto& assets = engine->requireAssets(); + if (lua::isstring(L, 3) && lua::require_lstring(L, 3) != "png") { throw std::runtime_error("unsupportd image format"); } @@ -53,10 +49,13 @@ static int l_load_texture(lua::State* L) { lua::pop(L); } lua::pop(L); - load_texture(buffer.data(), buffer.size(), lua::require_string(L, 2)); + load_texture( + assets, buffer.data(), buffer.size(), lua::require_string(L, 2) + ); } else { auto string = lua::bytearray_as_string(L, 1); load_texture( + assets, reinterpret_cast(string.data()), string.size(), lua::require_string(L, 2) @@ -67,16 +66,15 @@ static int l_load_texture(lua::State* L) { } static int l_parse_model(lua::State* L) { - if (engine->isHeadless()) { - throw std::runtime_error("not available in headless mode"); - } + auto& assets = engine->requireAssets(); + auto format = lua::require_lstring(L, 1); auto string = lua::require_lstring(L, 2); auto name = lua::require_string(L, 3); if (format == "xml" || format == "vcm") { auto vcmModel = vcm::parse(name, string, format == "xml"); - engine->getAssets()->store( + assets.store( std::make_unique(std::move(vcmModel.squash())), name ); } else { @@ -88,10 +86,7 @@ static int l_parse_model(lua::State* L) { } static int l_to_canvas(lua::State* L) { - if (engine->isHeadless()) { - throw std::runtime_error("not available in headless mode"); - } - auto& assets = *engine->getAssets(); + auto& assets = engine->requireAssets(); auto alias = lua::require_lstring(L, 1); size_t sep = alias.rfind(':'); From 428127f620dc2b2dc4002a46b34005d76cfb00bb Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 12 Feb 2026 01:58:00 +0300 Subject: [PATCH 3/3] another cleanup --- src/logic/scripting/lua/libs/libgui.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/logic/scripting/lua/libs/libgui.cpp b/src/logic/scripting/lua/libs/libgui.cpp index 0ec5e6475..514f3f98d 100644 --- a/src/logic/scripting/lua/libs/libgui.cpp +++ b/src/logic/scripting/lua/libs/libgui.cpp @@ -32,10 +32,7 @@ using namespace scripting; static DocumentNode get_document_node_impl( lua::State*, const std::string& name, const std::string& nodeName, bool throwable=true ) { - if (engine->isHeadless()) { - throw std::runtime_error("not available in headless mode"); - } - auto doc = engine->getAssets()->get(name); + auto doc = engine->requireAssets().get(name); if (doc == nullptr) { if (throwable) { throw std::runtime_error("document '" + name + "' not found"); @@ -1029,7 +1026,7 @@ static int l_gui_str(lua::State* L) { static int l_gui_reindex(lua::State* L) { auto name = lua::require_string(L, 1); - auto doc = engine->getAssets()->get(name); + auto doc = engine->requireAssets().get(name); if (doc == nullptr) { throw std::runtime_error( "document '" + std::string(name) + "' not found" @@ -1127,7 +1124,7 @@ static int l_gui_load_document(lua::State* L) { engine->getGUI(), std::move(env), alias, filename, filename.string() ); auto document = documentPtr.get(); - engine->getAssets()->store(std::move(documentPtr), alias); + engine->requireAssets().store(std::move(documentPtr), alias); // namespace extension if (lua::istable(L, 4)) {