(svn r10212) -Fix [FS#723]: money overflow bugs in many locations.
authorrubidium
Tue, 19 Jun 2007 00:05:26 +0000
changeset 7453 67ba4a6fc014
parent 7452 f6fd23727af0
child 7454 f86ba05c4969
(svn r10212) -Fix [FS#723]: money overflow bugs in many locations.
src/command.cpp
src/economy.cpp
src/macros.h
src/misc_cmd.cpp
src/oldloader.cpp
src/stdafx.h
--- a/src/command.cpp	Mon Jun 18 23:00:55 2007 +0000
+++ b/src/command.cpp	Tue Jun 19 00:05:26 2007 +0000
@@ -594,7 +594,7 @@
 
 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(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;
 }
 
--- a/src/economy.cpp	Mon Jun 18 23:00:55 2007 +0000
+++ b/src/economy.cpp	Tue Jun 19 00:05:26 2007 +0000
@@ -660,8 +660,8 @@
 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;
--- a/src/macros.h	Mon Jun 18 23:00:55 2007 +0000
+++ b/src/macros.h	Tue Jun 19 00:05:26 2007 +0000
@@ -26,6 +26,12 @@
 	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 uint minu(uint a, uint b) { if (a <= b) return a; return b; }
--- a/src/misc_cmd.cpp	Mon Jun 18 23:00:55 2007 +0000
+++ b/src/misc_cmd.cpp	Tue Jun 19 00:05:26 2007 +0000
@@ -144,6 +144,9 @@
 			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 @@
 
 	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 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);
 
--- a/src/oldloader.cpp	Mon Jun 18 23:00:55 2007 +0000
+++ b/src/oldloader.cpp	Tue Jun 19 00:05:26 2007 +0000
@@ -541,7 +541,7 @@
 
 	/* 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;
--- a/src/stdafx.h	Mon Jun 18 23:00:55 2007 +0000
+++ b/src/stdafx.h	Tue Jun 19 00:05:26 2007 +0000
@@ -20,6 +20,7 @@
 # endif
 #else
 # define INT64_MAX 9223372036854775807LL
+# define INT64_MIN -9223372036854775808LL
 #endif
 
 #include <cstdio>