mirror of https://github.com/OpenTTD/OpenTTD
(svn r10212) -Fix [FS#723]: money overflow bugs in many locations.
parent
23af871615
commit
16ce2192e4
|
@ -594,7 +594,7 @@ callb_err:
|
||||||
|
|
||||||
CommandCost CommandCost::AddCost(CommandCost ret)
|
CommandCost CommandCost::AddCost(CommandCost ret)
|
||||||
{
|
{
|
||||||
this->cost += ret.cost;
|
this->AddCost(ret.cost);
|
||||||
if (this->success && !ret.success) {
|
if (this->success && !ret.success) {
|
||||||
this->message = ret.message;
|
this->message = ret.message;
|
||||||
this->success = false;
|
this->success = false;
|
||||||
|
@ -604,13 +604,25 @@ CommandCost CommandCost::AddCost(CommandCost ret)
|
||||||
|
|
||||||
CommandCost CommandCost::AddCost(Money cost)
|
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;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
CommandCost CommandCost::MultiplyCost(int factor)
|
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;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -660,8 +660,8 @@ static void PlayersGenStatistics()
|
||||||
static void AddSingleInflation(Money *value, uint16 *frac, int32 amt)
|
static void AddSingleInflation(Money *value, uint16 *frac, int32 amt)
|
||||||
{
|
{
|
||||||
/* Is it safe to add inflation ? */
|
/* Is it safe to add inflation ? */
|
||||||
if ((MAX_UVALUE(Money) / 2 / amt) > (*value + *frac + 1)) {
|
if ((INT64_MAX / amt) < (*value + 1)) {
|
||||||
*value = MAX_UVALUE(Money);
|
*value = INT64_MAX / amt;
|
||||||
*frac = 0;
|
*frac = 0;
|
||||||
} else {
|
} else {
|
||||||
int64 tmp = (int64)*value * amt + *frac;
|
int64 tmp = (int64)*value * amt + *frac;
|
||||||
|
|
|
@ -26,6 +26,12 @@ static inline T max(T a, T b)
|
||||||
return a >= b ? a : b;
|
return a >= b ? a : b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
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 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; }
|
static inline uint minu(uint a, uint b) { if (a <= b) return a; return b; }
|
||||||
|
|
|
@ -144,6 +144,9 @@ CommandCost CmdIncreaseLoan(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Overflow protection */
|
||||||
|
if (p->player_money + p->current_loan + loan < p->player_money) return CMD_ERROR;
|
||||||
|
|
||||||
if (flags & DC_EXEC) {
|
if (flags & DC_EXEC) {
|
||||||
p->player_money += loan;
|
p->player_money += loan;
|
||||||
p->current_loan += loan;
|
p->current_loan += loan;
|
||||||
|
@ -166,14 +169,14 @@ CommandCost CmdDecreaseLoan(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
|
||||||
|
|
||||||
if (p->current_loan == 0) return_cmd_error(STR_702D_LOAN_ALREADY_REPAYED);
|
if (p->current_loan == 0) return_cmd_error(STR_702D_LOAN_ALREADY_REPAYED);
|
||||||
|
|
||||||
int32 loan;
|
Money loan;
|
||||||
switch (p2) {
|
switch (p2) {
|
||||||
default: return CMD_ERROR; // Invalid method
|
default: return CMD_ERROR; // Invalid method
|
||||||
case 0: // Pay back one step
|
case 0: // Pay back one step
|
||||||
loan = min(p->current_loan, (IsHumanPlayer(_current_player) || _patches.ainew_active) ? LOAN_INTERVAL : LOAN_INTERVAL_OLD_AI);
|
loan = min(p->current_loan, (IsHumanPlayer(_current_player) || _patches.ainew_active) ? LOAN_INTERVAL : LOAN_INTERVAL_OLD_AI);
|
||||||
break;
|
break;
|
||||||
case 1: // Pay back as much as possible
|
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;
|
loan -= loan % LOAN_INTERVAL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -304,7 +307,7 @@ CommandCost CmdMoneyCheat(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
|
||||||
CommandCost CmdGiveMoney(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
|
CommandCost CmdGiveMoney(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
|
||||||
{
|
{
|
||||||
const Player *p = GetPlayer(_current_player);
|
const Player *p = GetPlayer(_current_player);
|
||||||
CommandCost amount((Money)min(p1, 20000000LL));
|
CommandCost amount(min((Money)p1, 20000000LL));
|
||||||
|
|
||||||
SET_EXPENSES_TYPE(EXPENSES_OTHER);
|
SET_EXPENSES_TYPE(EXPENSES_OTHER);
|
||||||
|
|
||||||
|
|
|
@ -541,7 +541,7 @@ static bool LoadOldPrice(LoadgameState *ls, int num)
|
||||||
|
|
||||||
/* We use a struct to store the prices, but they are ints in a row..
|
/* 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 */
|
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;
|
_price_frac[num] = _old_price_frac;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
# endif
|
# endif
|
||||||
#else
|
#else
|
||||||
# define INT64_MAX 9223372036854775807LL
|
# define INT64_MAX 9223372036854775807LL
|
||||||
|
# define INT64_MIN -9223372036854775808LL
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
Loading…
Reference in New Issue