From c76b0753486133a691ff9461d2290a01ae0915ce Mon Sep 17 00:00:00 2001 From: Richard Jenkins Date: Sat, 20 Jan 2018 21:51:26 +0000 Subject: [PATCH] Fix #7052: Infinite loops occur in track circuit iteration --- src/openrct2/ride/Ride.cpp | 58 ++++++++++++++++++++++++++++++------- src/openrct2/ride/Track.cpp | 8 +++++ src/openrct2/ride/Track.h | 1 + 3 files changed, 57 insertions(+), 10 deletions(-) diff --git a/src/openrct2/ride/Ride.cpp b/src/openrct2/ride/Ride.cpp index a0556eb159..11f6f9ba7e 100644 --- a/src/openrct2/ride/Ride.cpp +++ b/src/openrct2/ride/Ride.cpp @@ -818,7 +818,7 @@ sint32 ride_find_track_gap(rct_xy_element *input, rct_xy_element *output) if (w != nullptr && _rideConstructionState != RIDE_CONSTRUCTION_STATE_0 && _currentRideIndex == rideIndex) ride_construction_invalidate_current_track(); - bool counter = true; + bool moveSlowIt = true; track_circuit_iterator_begin(&it, *input); slowIt = it; while (track_circuit_iterator_next(&it)) { @@ -827,13 +827,12 @@ sint32 ride_find_track_gap(rct_xy_element *input, rct_xy_element *output) return 1; } //#2081: prevent an infinite loop - counter = !counter; - if (counter) { + moveSlowIt = !moveSlowIt; + if (moveSlowIt) + { track_circuit_iterator_next(&slowIt); - if (slowIt.currentZ == it.currentZ && - slowIt.currentDirection == it.currentDirection && - slowIt.current.x == it.current.x && - slowIt.current.y == it.current.y) { + if (track_circuit_iterators_match(&it, &slowIt)) + { *output = it.current; return 1; } @@ -4172,14 +4171,28 @@ static bool ride_check_track_contains_inversions(rct_xy_element *input, rct_xy_e ride_construction_invalidate_current_track(); } - track_circuit_iterator it; + bool moveSlowIt = true; + track_circuit_iterator it, slowIt; track_circuit_iterator_begin(&it, *input); + slowIt = it; + while (track_circuit_iterator_next(&it)) { sint32 trackType = track_element_get_type(it.current.element); if (TrackFlags[trackType] & TRACK_ELEM_FLAG_INVERSION_TO_NORMAL) { *output = it.current; return true; } + + // Prevents infinite loops + moveSlowIt = !moveSlowIt; + if (moveSlowIt) + { + track_circuit_iterator_next(&slowIt); + if (track_circuit_iterators_match(&it, &slowIt)) + { + return false; + } + } } return false; } @@ -4203,14 +4216,28 @@ static bool ride_check_track_contains_banked(rct_xy_element *input, rct_xy_eleme ride_construction_invalidate_current_track(); } - track_circuit_iterator it; + bool moveSlowIt = true; + track_circuit_iterator it, slowIt; track_circuit_iterator_begin(&it, *input); + slowIt = it; + while (track_circuit_iterator_next(&it)) { sint32 trackType = track_element_get_type(output->element); if (TrackFlags[trackType] & TRACK_ELEM_FLAG_BANKED) { *output = it.current; return true; } + + // Prevents infinite loops + moveSlowIt = !moveSlowIt; + if (moveSlowIt) + { + track_circuit_iterator_next(&slowIt); + if (track_circuit_iterators_match(&it, &slowIt)) + { + return false; + } + } } return false; } @@ -6991,7 +7018,7 @@ static sint32 ride_get_track_length(Ride * ride) { rct_window * w; rct_tile_element * tileElement = nullptr; - track_circuit_iterator it; + track_circuit_iterator it, slowIt; sint32 x = 0, y = 0, z, trackType, rideIndex, result; bool foundTrack = false; @@ -7033,12 +7060,23 @@ static sint32 ride_get_track_length(Ride * ride) ride_construction_invalidate_current_track(); } + bool moveSlowIt = true; result = 0; track_circuit_iterator_begin(&it, {x, y, tileElement}); + slowIt = it; while (track_circuit_iterator_next(&it)) { trackType = track_element_get_type(it.current.element); result += TrackPieceLengths[trackType]; + + if (moveSlowIt) + { + track_circuit_iterator_next(&slowIt); + if (track_circuit_iterators_match(&it, &slowIt)) + { + return 0; + } + } } return result; } diff --git a/src/openrct2/ride/Track.cpp b/src/openrct2/ride/Track.cpp index 9de798f60c..08ee5a9c79 100644 --- a/src/openrct2/ride/Track.cpp +++ b/src/openrct2/ride/Track.cpp @@ -2402,6 +2402,14 @@ bool track_circuit_iterator_next(track_circuit_iterator * it) } } +bool track_circuit_iterators_match(const track_circuit_iterator * firstIt, const track_circuit_iterator * secondIt) +{ + return (firstIt->currentZ == secondIt->currentZ && + firstIt->currentDirection == secondIt->currentDirection && + firstIt->current.x == secondIt->current.x && + firstIt->current.y == secondIt->current.y); +} + void track_get_back(rct_xy_element * input, rct_xy_element * output) { rct_xy_element lastTrack; diff --git a/src/openrct2/ride/Track.h b/src/openrct2/ride/Track.h index 5df17d8a1f..14dbc1d6a3 100644 --- a/src/openrct2/ride/Track.h +++ b/src/openrct2/ride/Track.h @@ -537,6 +537,7 @@ const rct_track_coordinates * get_track_coord_from_ride(Ride * ride, sint32 trac void track_circuit_iterator_begin(track_circuit_iterator * it, rct_xy_element first); bool track_circuit_iterator_previous(track_circuit_iterator * it); bool track_circuit_iterator_next(track_circuit_iterator * it); +bool track_circuit_iterators_match(const track_circuit_iterator * firstIt, const track_circuit_iterator * secondIt); void track_get_back(rct_xy_element * input, rct_xy_element * output); void track_get_front(rct_xy_element * input, rct_xy_element * output);