diff options
author | Neil Moore <neil@s-z.org> | 2014-06-19 21:19:53 -0400 |
---|---|---|
committer | Neil Moore <neil@s-z.org> | 2014-06-19 21:24:00 -0400 |
commit | a500ab0ab47421beab86b3ad297e686f745d487c (patch) | |
tree | 5d0d750248341479e60d086b7d9141d049e224a6 /crawl-ref/source/random-var.cc | |
parent | 29500c91d564d99d7d5e191de54fffae51fd125b (diff) | |
download | crawl-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.cc | 36 |
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); |