From a500ab0ab47421beab86b3ad297e686f745d487c Mon Sep 17 00:00:00 2001 From: Neil Moore Date: Thu, 19 Jun 2014 21:19:53 -0400 Subject: 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. --- crawl-ref/source/random-var.cc | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) (limited to 'crawl-ref/source/random-var.cc') 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); -- cgit v1.2.3-54-g00ecf