Skip to content

Commit

Permalink
Hacky fix to ware_t good amount overflow when viewing a stop informat…
Browse files Browse the repository at this point in the history
…ion window set to list in "via (amount)" order.

If a single via destination had more than 8,388,607 units heading to it an arithmetic overflow would occur causing total unit count to be reported incorrectly. This fix prevents packet mergers once logical amount limits are reached hence keeping counting correct at the cost of duplicate listings.

git-svn-id: svn://tron.homeunix.org/simutrans/simutrans/trunk@8677 8aca7d54-2c30-db11-9de9-000461428c89
  • Loading branch information
DrSuperGood committed Feb 6, 2019
1 parent 4b317f5 commit 67d340e
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 10 deletions.
29 changes: 21 additions & 8 deletions freight_list_sorter.cc
Expand Up @@ -88,13 +88,21 @@ bool freight_list_sorter_t::compare_ware(ware_t const& w1, ware_t const& w2)



void freight_list_sorter_t::add_ware_heading( cbuffer_t &buf, uint32 sum, uint32 max, const ware_t *ware, const char *what_doing )
void freight_list_sorter_t::add_ware_heading( cbuffer_t &buf, uint64 sum, uint32 max, const ware_t *ware, const char *what_doing )
{
uint32 const max_display = ~0;

// not the first line?
if( buf.len() > 0 ) {
buf.append("\n");
}
buf.printf("%u", sum);

if (sum > max_display) {
buf.printf(">%u", max_display);
} else {
buf.printf("%u", (uint32)sum);
}

if( max != 0 ) {
// convois
buf.printf("/%u", max);
Expand Down Expand Up @@ -122,23 +130,28 @@ void freight_list_sorter_t::sort_freight(vector_tpl<ware_t> const& warray, cbuff
continue;
}
wlist[pos] = ware;
ware_t & current_good = wlist[pos];
// for the sorting via the number for the next stop we unify entries
if( sort_mode == by_via_sum ) {
// only add it, if there is not another thing waiting with the same via but another destination
for( int i=0; i<pos; i++ ) {
ware_t& wi = wlist[i];
if( wi.get_index()==ware.get_index() && wi.get_zwischenziel()==ware.get_zwischenziel() ) {
if( wi.get_index()==ware.get_index() && wi.get_zwischenziel()==ware.get_zwischenziel() && !wi.is_goods_amount_maxed() ) {
if( wi.get_zwischenziel().is_bound() ) {
if( ( wi.get_ziel()==wi.get_zwischenziel() )==( ware.get_ziel()==ware.get_zwischenziel() ) ) {
wi.menge += ware.menge;
--pos;
current_good.menge = wi.add_goods(ware.menge);
if (current_good.menge == 0) {
--pos;
}
break;
}
}
else {
if( wi.get_ziel() == ware.get_ziel() ) {
wi.menge += ware.menge;
--pos;
current_good.menge = wi.add_goods(ware.menge);
if (current_good.menge == 0) {
--pos;
}
break;
}
}
Expand Down Expand Up @@ -174,7 +187,7 @@ void freight_list_sorter_t::sort_freight(vector_tpl<ware_t> const& warray, cbuff

ware_t const& ware = wlist[j];
if( last_goods_index!=ware.get_index() && last_ware_catg!=ware.get_catg() ) {
sint32 sum = 0;
uint64 sum = 0;
last_goods_index = ware.get_index();
last_ware_catg = (ware.get_catg()!=0) ? ware.get_catg() : -1;
for( int i=j; i<pos; i++ ) {
Expand Down
2 changes: 1 addition & 1 deletion freight_list_sorter.h
Expand Up @@ -26,7 +26,7 @@ class freight_list_sorter_t

static bool compare_ware(ware_t const& w1, ware_t const& w2);

static void add_ware_heading( cbuffer_t &buf, uint32 sum, uint32 max, const ware_t *ware, const char *what_doing );
static void add_ware_heading( cbuffer_t &buf, uint64 sum, uint32 max, const ware_t *ware, const char *what_doing );
};


Expand Down
1 change: 1 addition & 0 deletions simutrans/history.txt
@@ -1,3 +1,4 @@
FIX: The stop information window in "via (amount)" order will no longer count incorrectly when more than 8,388,607 units are headed to a single destination
FIX: SDL2 build running on Windows 10 in fullscreen mode now minimizes and maximizes responsively
CHG: gui overhaul: automatic placement and size calculation of elements
ADD: use animated water graphics on shores
Expand Down
17 changes: 16 additions & 1 deletion simware.cc
Expand Up @@ -25,7 +25,7 @@

const goods_desc_t *ware_t::index_to_desc[256];


uint32 const ware_t::MAXIMUM_GOOD_AMOUNT = (1 << 23) - 1;

ware_t::ware_t() : ziel(), zwischenziel(), zielpos(-1, -1)
{
Expand Down Expand Up @@ -185,3 +185,18 @@ sint64 ware_t::calc_revenue(const goods_desc_t* desc, waytype_t wt, sint32 speed
// take the larger of both
return desc->get_value() * (grundwert128 > grundwert_bonus ? grundwert128 : grundwert_bonus);
}

uint32 ware_t::add_goods(uint32 const number) {
goods_amount_limit_t const sum = menge + number;
if (sum > MAXIMUM_GOOD_AMOUNT) {
menge = MAXIMUM_GOOD_AMOUNT;
return sum - MAXIMUM_GOOD_AMOUNT;
}

menge = sum;
return 0;
}

bool ware_t::is_goods_amount_maxed() {
return (goods_amount_limit_t)menge == MAXIMUM_GOOD_AMOUNT;
}
20 changes: 20 additions & 0 deletions simware.h
Expand Up @@ -19,6 +19,12 @@ class ware_t
static const goods_desc_t *index_to_desc[256];

public:
// Type used to specify goods limit, including handling potential overflow from addition.
typedef uint32 goods_amount_limit_t;

// Maximum number of goods per ware package. Limited by the bit field used.
static goods_amount_limit_t const MAXIMUM_GOOD_AMOUNT;

/// type of good, used as index into goods-types array
uint32 index: 8;

Expand Down Expand Up @@ -121,6 +127,20 @@ class ware_t
* @param speedkmh actual achieved speed in km/h
*/
static sint64 calc_revenue(const goods_desc_t* desc, waytype_t wt, sint32 speedkmh);

/**
* Adds the number of goods to this goods packet.
* Number of goods must be less than or equal to MAXIMUM_GOOD_AMOUNT.
* @param number The number of goods to add to this packet.
* @return Any excess goods that could not be added, eg due to logical limits.
*/
uint32 add_goods(uint32 const number);

/**
* Checks if the goods amount is maxed.
* @return If goods amount is maxed out so no more goods can be added.
*/
bool is_goods_amount_maxed();
};

#endif

0 comments on commit 67d340e

Please sign in to comment.