diff --git a/src/command.cpp b/src/command.cpp --- a/src/command.cpp +++ b/src/command.cpp @@ -594,7 +594,7 @@ callb_err: CommandCost CommandCost::AddCost(CommandCost ret) { - this->cost += ret.cost; + this->AddCost(ret.cost); if (this->success && !ret.success) { this->message = ret.message; this->success = false; @@ -604,13 +604,25 @@ CommandCost CommandCost::AddCost(Command CommandCost CommandCost::AddCost(Money cost) { - this->cost += cost; + /* Overflow protection */ + if (cost < 0 && (this->cost + cost) > this->cost) { + this->cost = INT64_MIN; + } else if (cost > 0 && (this->cost + cost) < this->cost) { + this->cost = INT64_MAX; + } else { + this->cost += cost; + } return *this; } CommandCost CommandCost::MultiplyCost(int factor) { - this->cost *= factor; + /* Overflow protection */ + if (factor != 0 && (INT64_MAX / myabs(factor)) < myabs(this->cost)) { + this->cost = (this->cost < 0 == factor < 0) ? INT64_MAX : INT64_MIN; + } else { + this->cost *= factor; + } return *this; } diff --git a/src/economy.cpp b/src/economy.cpp --- a/src/economy.cpp +++ b/src/economy.cpp @@ -660,8 +660,8 @@ static void PlayersGenStatistics() static void AddSingleInflation(Money *value, uint16 *frac, int32 amt) { /* Is it safe to add inflation ? */ - if ((MAX_UVALUE(Money) / 2 / amt) > (*value + *frac + 1)) { - *value = MAX_UVALUE(Money); + if ((INT64_MAX / amt) < (*value + 1)) { + *value = INT64_MAX / amt; *frac = 0; } else { int64 tmp = (int64)*value * amt + *frac; diff --git a/src/macros.h b/src/macros.h --- a/src/macros.h +++ b/src/macros.h @@ -26,6 +26,12 @@ static inline T max(T a, T b) return a >= b ? a : b; } +template +static inline T min(T a, T b) +{ + return a < b ? a : b; +} + static inline int min(int a, int b) { if (a <= b) return a; return b; } static inline uint minu(uint a, uint b) { if (a <= b) return a; return b; } diff --git a/src/misc_cmd.cpp b/src/misc_cmd.cpp --- a/src/misc_cmd.cpp +++ b/src/misc_cmd.cpp @@ -144,6 +144,9 @@ CommandCost CmdIncreaseLoan(TileIndex ti break; } + /* Overflow protection */ + if (p->player_money + p->current_loan + loan < p->player_money) return CMD_ERROR; + if (flags & DC_EXEC) { p->player_money += loan; p->current_loan += loan; @@ -166,14 +169,14 @@ CommandCost CmdDecreaseLoan(TileIndex ti if (p->current_loan == 0) return_cmd_error(STR_702D_LOAN_ALREADY_REPAYED); - int32 loan; + Money loan; switch (p2) { default: return CMD_ERROR; // Invalid method case 0: // Pay back one step loan = min(p->current_loan, (IsHumanPlayer(_current_player) || _patches.ainew_active) ? LOAN_INTERVAL : LOAN_INTERVAL_OLD_AI); break; case 1: // Pay back as much as possible - loan = max(min(p->current_loan, p->player_money), (int32)LOAN_INTERVAL); + loan = max(min(p->current_loan, p->player_money), (Money)LOAN_INTERVAL); loan -= loan % LOAN_INTERVAL; break; } @@ -304,7 +307,7 @@ CommandCost CmdMoneyCheat(TileIndex tile CommandCost CmdGiveMoney(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) { const Player *p = GetPlayer(_current_player); - CommandCost amount((Money)min(p1, 20000000LL)); + CommandCost amount(min((Money)p1, 20000000LL)); SET_EXPENSES_TYPE(EXPENSES_OTHER); diff --git a/src/oldloader.cpp b/src/oldloader.cpp --- a/src/oldloader.cpp +++ b/src/oldloader.cpp @@ -541,7 +541,7 @@ static bool LoadOldPrice(LoadgameState * /* We use a struct to store the prices, but they are ints in a row.. so just access the struct as an array of int32's */ - ((int32*)&_price)[num] = _old_price; + ((Money*)&_price)[num] = _old_price; _price_frac[num] = _old_price_frac; return true; diff --git a/src/stdafx.h b/src/stdafx.h --- a/src/stdafx.h +++ b/src/stdafx.h @@ -20,6 +20,7 @@ # endif #else # define INT64_MAX 9223372036854775807LL +# define INT64_MIN -9223372036854775808LL #endif #include