diff options
author | rubidium <rubidium@openttd.org> | 2014-07-22 19:46:10 +0000 |
---|---|---|
committer | rubidium <rubidium@openttd.org> | 2014-07-22 19:46:10 +0000 |
commit | f3d085e33c00d53ba8b16b45c5aec888bfb7b50c (patch) | |
tree | ca283f910ef0d043dafdada881b8ae6074130c0b | |
parent | a96a57e1619ff2cfc3f40508fca8418807669c7b (diff) | |
download | openttd-f3d085e33c00d53ba8b16b45c5aec888bfb7b50c.tar.xz |
(svn r26702) -Fix [FS#6067]: integer overflows in acceleration code causing either too low acceleration or too large acceleration
-rw-r--r-- | src/ground_vehicle.cpp | 33 | ||||
-rw-r--r-- | src/ground_vehicle.hpp | 4 |
2 files changed, 27 insertions, 10 deletions
diff --git a/src/ground_vehicle.cpp b/src/ground_vehicle.cpp index f3134608a..fcdab77b0 100644 --- a/src/ground_vehicle.cpp +++ b/src/ground_vehicle.cpp @@ -108,15 +108,30 @@ int GroundVehicle<T, Type>::GetAcceleration() const { /* Templated class used for function calls for performance reasons. */ const T *v = T::From(this); - int32 speed = v->GetCurrentSpeed(); // [km/h-ish] + /* Speed is used squared later on, so U16 * U16, and then multiplied by other values. */ + int64 speed = v->GetCurrentSpeed(); // [km/h-ish] /* Weight is stored in tonnes. */ int32 mass = this->gcache.cached_weight; - /* Power is stored in HP, we need it in watts. */ - int32 power = this->gcache.cached_power * 746; - - int32 resistance = 0; + /* Power is stored in HP, we need it in watts. + * Each vehicle can have U16 power, 128 vehicles, HP -> watt + * and km/h to m/s conversion below result in a maxium of + * about 1.1E11, way more than 4.3E9 of int32. */ + int64 power = this->gcache.cached_power * 746ll; + + /* This is constructed from: + * - axle resistance: U16 power * 10 for 128 vehicles. + * * 8.3E7 + * - rolling friction: U16 power * 144 for 128 vehicles. + * * 1.2E9 + * - slope resistance: U16 weight * 100 * 10 (steepness) for 128 vehicles. + * * 8.4E9 + * - air drag: 28 * (U8 drag + 3 * U8 drag * 128 vehicles / 20) * U16 speed * U16 speed + * * 6.2E14 before dividing by 1000 + * Sum is 6.3E11, more than 4.3E9 of int32, so int64 is needed. + */ + int64 resistance = 0; bool maglev = v->GetAccelerationType() == 2; @@ -136,7 +151,9 @@ int GroundVehicle<T, Type>::GetAcceleration() const AccelStatus mode = v->GetAccelerationStatus(); const int max_te = this->gcache.cached_max_te; // [N] - int force; + /* Constructued from power, with need to multiply by 18 and assuming + * low speed, it needs to be a 64 bit integer too. */ + int64 force; if (speed > 0) { if (!maglev) { /* Conversion factor from km/h to m/s is 5/18 to get [N] in the end. */ @@ -160,10 +177,10 @@ int GroundVehicle<T, Type>::GetAcceleration() const * down hill will never slow down enough, and a vehicle that came up * a hill will never speed up enough to (eventually) get back to the * same (maximum) speed. */ - int accel = (force - resistance) / (mass * 4); + int accel = ClampToI32((force - resistance) / (mass * 4)); return force < resistance ? min(-1, accel) : max(1, accel); } else { - return min(-force - resistance, -10000) / mass; + return ClampToI32(min(-force - resistance, -10000) / mass); } } diff --git a/src/ground_vehicle.hpp b/src/ground_vehicle.hpp index 80a88b705..c38c6c4b7 100644 --- a/src/ground_vehicle.hpp +++ b/src/ground_vehicle.hpp @@ -113,9 +113,9 @@ struct GroundVehicle : public SpecializedVehicle<T, Type> { * Calculates the total slope resistance for this vehicle. * @return Slope resistance. */ - inline int32 GetSlopeResistance() const + inline int64 GetSlopeResistance() const { - int32 incl = 0; + int64 incl = 0; for (const T *u = T::From(this); u != NULL; u = u->Next()) { if (HasBit(u->gv_flags, GVF_GOINGUP_BIT)) { |