From c8b391c1585c5a3c1d40d8708f08afb4ed5fd3ac Mon Sep 17 00:00:00 2001 From: Shauren Date: Sun, 22 Feb 2026 20:14:22 +0100 Subject: [PATCH] Core/MMaps: Fix possible access of freed memory in DynamicTileBuilder --- .../game/Maps/DynamicMMapTileBuilder.cpp | 34 +++++++++++++------ 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/src/server/game/Maps/DynamicMMapTileBuilder.cpp b/src/server/game/Maps/DynamicMMapTileBuilder.cpp index 2cee7c833f..7471c56c03 100644 --- a/src/server/game/Maps/DynamicMMapTileBuilder.cpp +++ b/src/server/game/Maps/DynamicMMapTileBuilder.cpp @@ -274,7 +274,20 @@ void DynamicTileBuilder::Update(Milliseconds diff) std::weak_ptr DynamicTileBuilder::BuildTile(uint32 terrainMapId, uint32 tileX, uint32 tileY) { - std::vector> gameObjectModelReferences; // hold strong refs to models + struct GameObjectModelWorkData + { + explicit GameObjectModelWorkData(std::shared_ptr worldModel, G3D::Vector3 const& position, float scale, + G3D::Quat const& rotation, GameObjectModel const* gameObject) : WorldModel(std::move(worldModel)), Position(position), + Rotation(rotation), Scale(scale), GameObject(gameObject) { } + + std::shared_ptr WorldModel; + G3D::Vector3 Position; + G3D::Quat Rotation; + float Scale; + GameObjectModel const* GameObject; + }; + + std::vector modelSpawns; for (GameObjectModel const* gameObjectModel : m_map->GetGameObjectModelsInGrid(tileX, tileY)) { if (!gameObjectModel->IsIncludedInNavMesh()) @@ -284,13 +297,14 @@ std::weak_ptr DynamicTileBuilder::BuildTile if (!worldModel) continue; - gameObjectModelReferences.emplace_back(worldModel, gameObjectModel); + modelSpawns.emplace_back(std::move(worldModel), gameObjectModel->GetPosition(), + gameObjectModel->GetScale(), gameObjectModel->GetRotation(), gameObjectModel); } - TileCacheKey cacheKey{ .TerrainMapId = terrainMapId, .X = tileX, .Y = tileY, .CachedHash = 0, .Objects = std::vector(gameObjectModelReferences.size()) }; - for (std::size_t i = 0; i < gameObjectModelReferences.size(); ++i) + TileCacheKey cacheKey{ .TerrainMapId = terrainMapId, .X = tileX, .Y = tileY, .CachedHash = 0, .Objects = std::vector(modelSpawns.size()) }; + for (std::size_t i = 0; i < modelSpawns.size(); ++i) { - GameObjectModel const* gameObjectModel = gameObjectModelReferences[i].get(); + GameObjectModel const* gameObjectModel = modelSpawns[i].GameObject; TileCacheKeyObject& object = cacheKey.Objects[i]; object.DisplayId = gameObjectModel->GetDisplayId(); object.Scale = int16(gameObjectModel->GetScale() * 1024.0f); @@ -314,7 +328,7 @@ std::weak_ptr DynamicTileBuilder::BuildTile return itr->second.Data; itr->second.Data = std::make_shared(); - tileCache->StartTask([result = itr->second.Data, hash = cacheKey.CachedHash, selfRef = weak_from_this(), terrainMapId, tileX, tileY, gameObjectModelReferences = std::move(gameObjectModelReferences)]() mutable + tileCache->StartTask([result = itr->second.Data, hash = cacheKey.CachedHash, selfRef = weak_from_this(), terrainMapId, tileX, tileY, modelSpawns = std::move(modelSpawns)]() mutable { auto isReadyGuard = Trinity::make_unique_ptr_with_deleter(result.get()); @@ -338,15 +352,15 @@ std::weak_ptr DynamicTileBuilder::BuildTile // get model data self->m_terrainBuilder.loadVMap(terrainMapId, tileX, tileY, meshData, vmapManager.get()); - for (std::shared_ptr const& gameObjectModel : gameObjectModelReferences) + for (GameObjectModelWorkData const& model : modelSpawns) { - G3D::Vector3 position = gameObjectModel->GetPosition(); + G3D::Vector3 position = model.Position; position.x = -position.x; position.y = -position.y; - G3D::Matrix3 invRotation = (G3D::Quat(0, 0, 1, 0) * gameObjectModel->GetRotation()).toRotationMatrix().inverse(); + G3D::Matrix3 invRotation = (G3D::Quat(0, 0, 1, 0) * model.Rotation).toRotationMatrix().inverse(); - self->m_terrainBuilder.loadVMapModel(gameObjectModel->GetWorldModel().get(), position, invRotation, gameObjectModel->GetScale(), + self->m_terrainBuilder.loadVMapModel(model.WorldModel.get(), position, invRotation, model.Scale, meshData, vmapManager.get()); }