Fix #18140 & #18143: Invalid read in Staff

The tile element should be determined the same way as is done when checking if the footpath is blocked by a vehicle.

Also added some extra safety checks and made the code a bit more efficient / reusable. For example: when the staff member is not a mechanic, the tile element doesn't have to determined.
This commit is contained in:
Rik Smeets 2022-09-30 20:00:59 +02:00 committed by GitHub
parent d352ca3d01
commit efa7a23773
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 35 additions and 18 deletions

View File

@ -864,10 +864,17 @@ bool Staff::DoMiscPathFinding()
bool Staff::IsMechanicHeadingToFixRideBlockingPath()
{
auto trackElement = map_get_track_element_at(CoordsXYZ{ GetDestination(), NextLoc.z });
if (!IsMechanic())
return false;
auto tileCoords = TileCoordsXYZ(CoordsXYZ{ GetDestination(), NextLoc.z });
auto trackElement = MapGetFirstTileElementWithBaseHeightBetween<TrackElement>(
{ tileCoords, tileCoords.z + PATH_HEIGHT_STEP });
if (trackElement == nullptr)
return false;
auto ride = get_ride(trackElement->GetRideIndex());
return AssignedStaffType == StaffType::Mechanic && ride->id == CurrentRide
&& ride->breakdown_reason == BREAKDOWN_SAFETY_CUT_OUT;
return ride->id == CurrentRide && ride->breakdown_reason == BREAKDOWN_SAFETY_CUT_OUT;
}
/**

View File

@ -42,7 +42,7 @@
// This string specifies which version of network stream current build uses.
// It is used for making sure only compatible builds get connected, even within
// single OpenRCT2 version.
#define NETWORK_STREAM_VERSION "21"
#define NETWORK_STREAM_VERSION "22"
#define NETWORK_STREAM_ID OPENRCT2_VERSION "-" NETWORK_STREAM_VERSION
static Peep* _pickup_peep = nullptr;

View File

@ -2023,7 +2023,7 @@ void footpath_update_path_wide_flags(const CoordsXY& footpathPos)
bool footpath_is_blocked_by_vehicle(const TileCoordsXYZ& position)
{
auto pathElement = MapGetFirstPathElementWithBaseHeightBetween({ position, position.z + PATH_HEIGHT_STEP });
auto pathElement = MapGetFirstTileElementWithBaseHeightBetween<PathElement>({ position, position.z + PATH_HEIGHT_STEP });
return pathElement != nullptr && pathElement->IsBlockedByVehicle();
}

View File

@ -371,6 +371,22 @@ TileElement* map_get_nth_element_at(const CoordsXY& coords, int32_t n)
return nullptr;
}
TileElement* MapGetFirstTileElementWithBaseHeightBetween(const TileCoordsXYRangedZ& loc, TileElementType type)
{
TileElement* tileElement = map_get_first_element_at(loc.ToCoordsXY());
if (tileElement == nullptr)
return nullptr;
do
{
if (tileElement->GetType() != type)
continue;
if (tileElement->base_height >= loc.baseZ && tileElement->base_height <= loc.clearanceZ)
return tileElement;
} while (!(tileElement++)->IsLastForTile());
return nullptr;
}
void map_set_tile_element(const TileCoordsXY& tilePos, TileElement* elements)
{
if (!map_is_location_valid(tilePos.ToCoordsXY()))
@ -401,18 +417,6 @@ PathElement* map_get_path_element_at(const TileCoordsXYZ& loc)
return nullptr;
}
PathElement* MapGetFirstPathElementWithBaseHeightBetween(const TileCoordsXYRangedZ& loc)
{
for (auto* element : TileElementsView<PathElement>(loc.ToCoordsXY()))
{
if (element->IsGhost())
continue;
if (element->base_height >= loc.baseZ && element->base_height <= loc.clearanceZ)
return element;
}
return nullptr;
}
BannerElement* map_get_banner_element_at(const CoordsXYZ& bannerPos, uint8_t position)
{
const auto bannerTilePos = TileCoordsXYZ{ bannerPos };

View File

@ -164,12 +164,12 @@ void map_strip_ghost_flag_from_elements();
TileElement* map_get_first_element_at(const CoordsXY& tilePos);
TileElement* map_get_first_element_at(const TileCoordsXY& tilePos);
TileElement* map_get_nth_element_at(const CoordsXY& coords, int32_t n);
TileElement* MapGetFirstTileElementWithBaseHeightBetween(const TileCoordsXYRangedZ& loc, TileElementType type);
void map_set_tile_element(const TileCoordsXY& tilePos, TileElement* elements);
int32_t map_height_from_slope(const CoordsXY& coords, int32_t slopeDirection, bool isSloped);
BannerElement* map_get_banner_element_at(const CoordsXYZ& bannerPos, uint8_t direction);
SurfaceElement* map_get_surface_element_at(const CoordsXY& coords);
PathElement* map_get_path_element_at(const TileCoordsXYZ& loc);
PathElement* MapGetFirstPathElementWithBaseHeightBetween(const TileCoordsXYRangedZ& loc);
WallElement* map_get_wall_element_at(const CoordsXYZD& wallCoords);
WallElement* map_get_wall_element_at(const CoordsXYRangedZ& coords);
SmallSceneryElement* map_get_small_scenery_element_at(const CoordsXYZ& sceneryCoords, int32_t type, uint8_t quadrant);
@ -198,6 +198,12 @@ void map_invalidate_selection_rect();
bool MapCheckCapacityAndReorganise(const CoordsXY& loc, size_t numElements = 1);
TileElement* tile_element_insert(const CoordsXYZ& loc, int32_t occupiedQuadrants, TileElementType type);
template<typename T = TileElement> T* MapGetFirstTileElementWithBaseHeightBetween(const TileCoordsXYRangedZ& loc)
{
auto* element = MapGetFirstTileElementWithBaseHeightBetween(loc, T::ElementType);
return element != nullptr ? element->template as<T>() : nullptr;
}
template<typename T> T* TileElementInsert(const CoordsXYZ& loc, int32_t occupiedQuadrants)
{
auto* element = tile_element_insert(loc, occupiedQuadrants, T::ElementType);