From 1da8f1a2295b628ed802a475183c25a4584c7ab3 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 18 Apr 2021 11:05:24 +0100 Subject: [PATCH] Fix signed integer overflow when initialising scheduled dispatch When date * daylength is too large for int32 --- src/schdispatch_cmd.cpp | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/schdispatch_cmd.cpp b/src/schdispatch_cmd.cpp index 7142e1c296..ffd3825c4d 100644 --- a/src/schdispatch_cmd.cpp +++ b/src/schdispatch_cmd.cpp @@ -310,9 +310,25 @@ void OrderList::RemoveScheduledDispatch(uint32 offset) void OrderList::UpdateScheduledDispatch() { bool update_windows = false; + if (this->GetScheduledDispatchStartTick() == 0) { + int64 start = _scaled_date_ticks - (_scaled_date_ticks % this->GetScheduledDispatchDuration()); + SchdispatchConvertToFullDateFract( + start, + &this->scheduled_dispatch_start_date, &this->scheduled_dispatch_start_full_date_fract); + int64 last_dispatch = -start; + if (last_dispatch < INT_MIN && _settings_game.game_time.time_in_minutes) { + /* Advance by multiples of 24 hours */ + const int64 day = 24 * 60 * _settings_game.game_time.ticks_per_minute; + this->scheduled_dispatch_last_dispatch = last_dispatch + (CeilDivT(INT_MIN - last_dispatch, day) * day); + } else { + this->scheduled_dispatch_last_dispatch = ClampToI32(last_dispatch); + } + } /* Most of the time this loop does not runs. It makes sure start date in in past */ while (this->GetScheduledDispatchStartTick() > _scaled_date_ticks) { - this->scheduled_dispatch_last_dispatch += this->GetScheduledDispatchDuration(); + OverflowSafeInt32 last_dispatch = this->scheduled_dispatch_last_dispatch; + last_dispatch += this->GetScheduledDispatchDuration(); + this->scheduled_dispatch_last_dispatch = last_dispatch; SchdispatchConvertToFullDateFract( this->GetScheduledDispatchStartTick() - this->GetScheduledDispatchDuration(), &this->scheduled_dispatch_start_date, &this->scheduled_dispatch_start_full_date_fract); @@ -320,7 +336,9 @@ void OrderList::UpdateScheduledDispatch() } /* Most of the time this loop runs once. It makes sure the start date is as close to current time as possible. */ while (this->GetScheduledDispatchStartTick() + this->GetScheduledDispatchDuration() <= _scaled_date_ticks) { - this->scheduled_dispatch_last_dispatch -= this->GetScheduledDispatchDuration(); + OverflowSafeInt32 last_dispatch = this->scheduled_dispatch_last_dispatch; + last_dispatch -= this->GetScheduledDispatchDuration(); + this->scheduled_dispatch_last_dispatch = last_dispatch; SchdispatchConvertToFullDateFract( this->GetScheduledDispatchStartTick() + this->GetScheduledDispatchDuration(), &this->scheduled_dispatch_start_date, &this->scheduled_dispatch_start_full_date_fract);