From 8e80f97bbcec362b255d326aa06e508ea4219ba9 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Wed, 6 May 2026 10:06:20 -0700 Subject: [PATCH] fix(wot): cap doodadNames/wmoNames at 65536 + guard non-string entries Both name lists used n.get which throws on non-string entries (would abort the entire WOT load). Real zones use ~5k names max; cap at 65536 (uint16 nameId range upper bound) so the cap is generous but bounded. Guard with is_string so a single bad entry just gets skipped instead of failing the file. --- src/pipeline/wowee_terrain_loader.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/pipeline/wowee_terrain_loader.cpp b/src/pipeline/wowee_terrain_loader.cpp index 20f17b25..a2f603cc 100644 --- a/src/pipeline/wowee_terrain_loader.cpp +++ b/src/pipeline/wowee_terrain_loader.cpp @@ -173,10 +173,15 @@ bool WoweeTerrainLoader::loadMetadata(const std::string& wotPath, ADTTerrain& te } } - // Parse doodad placements + // Parse doodad placements. n.get throws on non-string + // entries — guard with is_string and cap the list at 65536 (uint32 + // nameId range is far larger but real zones top out around ~5k). if (j.contains("doodadNames") && j["doodadNames"].is_array()) { - for (const auto& n : j["doodadNames"]) - terrain.doodadNames.push_back(n.get()); + constexpr size_t kMaxNames = 65536; + for (const auto& n : j["doodadNames"]) { + if (terrain.doodadNames.size() >= kMaxNames) break; + if (n.is_string()) terrain.doodadNames.push_back(n.get()); + } } // Helper used by both doodad and WMO loaders below. auto san3 = [](float& a, float& b, float& c) { @@ -208,10 +213,13 @@ bool WoweeTerrainLoader::loadMetadata(const std::string& wotPath, ADTTerrain& te } } - // Parse WMO placements + // Parse WMO placements (same guards as doodadNames above). if (j.contains("wmoNames") && j["wmoNames"].is_array()) { - for (const auto& n : j["wmoNames"]) - terrain.wmoNames.push_back(n.get()); + constexpr size_t kMaxWmoNames = 65536; + for (const auto& n : j["wmoNames"]) { + if (terrain.wmoNames.size() >= kMaxWmoNames) break; + if (n.is_string()) terrain.wmoNames.push_back(n.get()); + } } if (j.contains("wmos") && j["wmos"].is_array()) { for (const auto& jw : j["wmos"]) {