From 59c72c95b5fdd756d4b0134fad32f7a3f4daa2aa Mon Sep 17 00:00:00 2001 From: skal Date: Tue, 3 Feb 2026 08:42:12 +0100 Subject: fix(assets): Resolve static initialization order fiasco Replaces the global array with which wraps a local static array. This ensures the asset table is initialized on first use, preventing crashes when other globals (like shader strings) try to access assets during dynamic initialization. --- src/util/asset_manager.cc | 16 ++++++---------- tools/asset_packer.cc | 20 ++++++++++++++------ 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/util/asset_manager.cc b/src/util/asset_manager.cc index 65b3200..d9ecfe1 100644 --- a/src/util/asset_manager.cc +++ b/src/util/asset_manager.cc @@ -24,14 +24,6 @@ static const std::map kAssetManagerProcGenFuncMap = { {"make_periodic", procedural::make_periodic}, }; -// These are defined in the generated assets_data.cc -#if defined(USE_TEST_ASSETS) -extern const AssetRecord g_assets[]; -extern const size_t g_assets_count; -#else -extern const AssetRecord g_assets[]; -extern const size_t g_assets_count; -#endif // Array-based cache for assets. // Initialized to all zeros (nullptr data, 0 size, false is_procedural) // The size is derived from the generated ASSET_LAST_ID enum value. @@ -59,15 +51,19 @@ const uint8_t* GetAsset(AssetId asset_id, size_t* out_size) { return g_asset_cache[index].data; } + const AssetRecord* assets = GetAssetRecordTable(); + size_t count = GetAssetCount(); + // Not in cache, retrieve from static data (packed in binary) or generate // procedurally - if (index >= g_assets_count) { + if (index >= count) { if (out_size) *out_size = 0; return nullptr; // Invalid asset_id or asset not in static packed data. } - AssetRecord source_record = g_assets[index]; + AssetRecord source_record = assets[index]; + AssetRecord cached_record = source_record; if (source_record.is_procedural) { diff --git a/tools/asset_packer.cc b/tools/asset_packer.cc index d86e29b..2de57d0 100644 --- a/tools/asset_packer.cc +++ b/tools/asset_packer.cc @@ -86,7 +86,7 @@ int main(int argc, char* argv[]) { assets_data_cc_file, "// This file is auto-generated by asset_packer.cc. Do not edit.\n\n"); fprintf(assets_data_cc_file, "#include \"util/asset_manager.h\"\n"); - fprintf(assets_data_cc_file, "#include \"%s\"\n\n", + fprintf(assets_data_cc_file, "#include \"%s\"\n", generated_header_name.c_str()); // Forward declare procedural functions for AssetRecord initialization @@ -196,6 +196,10 @@ int main(int argc, char* argv[]) { fprintf(assets_h_file, "#include \"util/asset_manager.h\"\n"); // Include here AFTER enum // definition + fprintf(assets_h_file, "\n// Accessors to avoid static initialization order issues\n"); + fprintf(assets_h_file, "const struct AssetRecord* GetAssetRecordTable();\n"); + fprintf(assets_h_file, "size_t GetAssetCount();\n"); + std::fclose(assets_h_file); for (const auto& info : asset_build_infos) { @@ -238,7 +242,8 @@ int main(int argc, char* argv[]) { } } - fprintf(assets_data_cc_file, "extern const AssetRecord g_assets[] = {\n"); + fprintf(assets_data_cc_file, "const AssetRecord* GetAssetRecordTable() {\n"); + fprintf(assets_data_cc_file, " static const AssetRecord assets[] = {\n"); for (const auto& info : asset_build_infos) { fprintf(assets_data_cc_file, " { "); if (info.is_procedural) { @@ -251,10 +256,13 @@ int main(int argc, char* argv[]) { } fprintf(assets_data_cc_file, " },\n"); } - fprintf(assets_data_cc_file, "};\n"); - fprintf(assets_data_cc_file, - "extern const size_t g_assets_count = sizeof(g_assets) / " - "sizeof(g_assets[0]);\n"); + fprintf(assets_data_cc_file, " };\n"); + fprintf(assets_data_cc_file, " return assets;\n"); + fprintf(assets_data_cc_file, "}\n\n"); + + fprintf(assets_data_cc_file, "size_t GetAssetCount() {\n"); + fprintf(assets_data_cc_file, " return %zu;\n", asset_build_infos.size()); + fprintf(assets_data_cc_file, "}\n\n"); std::fclose(assets_data_cc_file); -- cgit v1.2.3