summaryrefslogtreecommitdiff
path: root/src/tunnelbridge_cmd.cpp
diff options
context:
space:
mode:
authorJonathan G Rennison <j.g.rennison@gmail.com>2018-07-22 13:25:28 +0100
committerPatric Stout <truebrain@openttd.org>2018-07-22 21:58:05 +0200
commit6a3d411fa1a77a713fe7e21012c412740433b793 (patch)
tree7e2a17631eebd8687d97bb2592acc7fc938083ef /src/tunnelbridge_cmd.cpp
parent38443bab0bd39dc6ae1f8e51c401a1f032d38fb2 (diff)
downloadopenttd-6a3d411fa1a77a713fe7e21012c412740433b793.tar.xz
Fix: Use after free in CmdBuildTunnel (#6856)
Use after free could occur when when excavating far end removed multiple NewGRF objects
Diffstat (limited to 'src/tunnelbridge_cmd.cpp')
-rw-r--r--src/tunnelbridge_cmd.cpp16
1 files changed, 15 insertions, 1 deletions
diff --git a/src/tunnelbridge_cmd.cpp b/src/tunnelbridge_cmd.cpp
index 9ba9b26e3..5f194a319 100644
--- a/src/tunnelbridge_cmd.cpp
+++ b/src/tunnelbridge_cmd.cpp
@@ -701,8 +701,22 @@ CommandCost CmdBuildTunnel(TileIndex start_tile, DoCommandFlag flags, uint32 p1,
/* Hide the tile from the terraforming command */
TileIndex old_first_tile = coa->first_tile;
coa->first_tile = INVALID_TILE;
+
+ /* CMD_TERRAFORM_LAND may append further items to _cleared_object_areas,
+ * however it will never erase or re-order existing items.
+ * _cleared_object_areas is a value-type SmallVector, therefore appending items
+ * may result in a backing-store re-allocation, which would invalidate the coa pointer.
+ * The index of the coa pointer into the _cleared_object_areas vector remains valid,
+ * and can be used safely after the CMD_TERRAFORM_LAND operation.
+ * Deliberately clear the coa pointer to avoid leaving dangling pointers which could
+ * inadvertently be dereferenced.
+ */
+ assert(coa >= _cleared_object_areas.Begin() && coa < _cleared_object_areas.End());
+ size_t coa_index = coa - _cleared_object_areas.Begin();
+ coa = NULL;
+
ret = DoCommand(end_tile, end_tileh & start_tileh, 0, flags, CMD_TERRAFORM_LAND);
- coa->first_tile = old_first_tile;
+ _cleared_object_areas[coa_index].first_tile = old_first_tile;
if (ret.Failed()) return_cmd_error(STR_ERROR_UNABLE_TO_EXCAVATE_LAND);
cost.AddCost(ret);
}