summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/random-var.cc
diff options
context:
space:
mode:
authorNeil Moore <neil@s-z.org>2014-06-19 21:19:53 -0400
committerNeil Moore <neil@s-z.org>2014-06-19 21:24:00 -0400
commita500ab0ab47421beab86b3ad297e686f745d487c (patch)
tree5d0d750248341479e60d086b7d9141d049e224a6 /crawl-ref/source/random-var.cc
parent29500c91d564d99d7d5e191de54fffae51fd125b (diff)
downloadcrawl-ref-a500ab0ab47421beab86b3ad297e686f745d487c.tar.gz
crawl-ref-a500ab0ab47421beab86b3ad297e686f745d487c.zip
Avoid a random_var crash (#8698)
If the sum of the weights of a random_var goes over INT_MAX, rescale them rather than leaving the total as a negative number.
Diffstat (limited to 'crawl-ref/source/random-var.cc')
-rw-r--r--crawl-ref/source/random-var.cc36
1 files changed, 34 insertions, 2 deletions
diff --git a/crawl-ref/source/random-var.cc b/crawl-ref/source/random-var.cc
index 1979e71e15..da2cd40ec0 100644
--- a/crawl-ref/source/random-var.cc
+++ b/crawl-ref/source/random-var.cc
@@ -50,9 +50,41 @@ void random_var::init_weights(weight_func w)
void random_var::init()
{
- total = 0;
+ int64_t sum = 0;
for (int v = start; v < end; ++v)
- total += weight(v);
+ sum += weight(v);
+
+ if (sum <= (int64_t) INT_MAX)
+ total = (int) sum;
+ else
+ {
+ // The total is too big: rescale all entries by 256.
+ ASSERT(sum <= 256 * (int64_t) INT_MAX);
+
+ total = 0;
+
+ const int length = weights.size();
+ int first_nonzero = -1;
+ int last_nonzero = -1;
+ for (int i = 0; i < length; ++i)
+ {
+ weights[i] /= 256;
+ total += weights[i];
+
+ if (first_nonzero < 0 && weights[i] > 0)
+ first_nonzero = i;
+ if (weights[i] > 0)
+ last_nonzero = i;
+ }
+ ASSERT(first_nonzero >= 0 && last_nonzero >= 0);
+
+ // Weights that rounded to zero should be dropped.
+ weights.erase(weights.begin() + last_nonzero + 1, weights.end());
+ weights.erase(weights.begin(), weights.begin() + first_nonzero);
+ start += first_nonzero;
+ end -= (length - last_nonzero - 1);
+ }
+
ASSERT(total > 0);
ASSERT(weight(start) > 0);
ASSERT(weight(end - 1) > 0);