From cc8f11bf43842e38f0a515b8070f4a7afe9a716d Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Mon, 18 Jan 2016 06:24:09 -0800 Subject: Don't allow non-positive modulus in rand and random. * rand.c (random): In fixnum case, allow only m >= 1. The code is restructured so that this check is done before we do some arithmetic with derived values, where the behavior can become undefined. * txr.1: Document the restriction on modulus range for rand and random. --- rand.c | 42 ++++++++++++++++++++++-------------------- txr.1 | 7 +++++++ 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/rand.c b/rand.c index 480c22df..a2215124 100644 --- a/rand.c +++ b/rand.c @@ -223,34 +223,36 @@ val random(val state, val modulus) } else if (fixnump(modulus)) { cnum m = c_num(modulus); int bits = highest_bit(m); + if (m == 1) { + return zero; + } else if (m > 1) { #if SIZEOF_PTR >= 8 - int rands_needed = (bits + 32 - 1) / 32; + int rands_needed = (bits + 32 - 1) / 32; #endif - int msb_rand_bits = bits % 32; - rand32_t msb_rand_mask = convert(rand32_t, -1) >> (32 - msb_rand_bits); - if (m <= 0) - goto invalid; - for (;;) { - cnum out = 0; + int msb_rand_bits = bits % 32; + rand32_t msb_rand_mask = convert(rand32_t, -1) >> (32 - msb_rand_bits); + for (;;) { + cnum out = 0; #if SIZEOF_PTR >= 8 - int i; + int i; - for (i = 0; i < rands_needed; i++) { - rand32_t rnd = rand32(r); - out <<= 32; - if (i == 0) - rnd &= msb_rand_mask; - out |= rnd; - } + for (i = 0; i < rands_needed; i++) { + rand32_t rnd = rand32(r); + out <<= 32; + if (i == 0) + rnd &= msb_rand_mask; + out |= rnd; + } #else - out = rand32(r) & msb_rand_mask; + out = rand32(r) & msb_rand_mask; #endif - if (out >= m) - continue; - return num(out); + if (out >= m) + continue; + return num(out); + } } } -invalid: + uw_throwf(numeric_error_s, lit("random: invalid modulus ~s"), modulus, nao); } diff --git a/txr.1 b/txr.1 index 5f8a4c3b..9568e6b1 100644 --- a/txr.1 +++ b/txr.1 @@ -34829,6 +34829,13 @@ object is the second argument and is optional. If it is omitted, the global .code *random-state* object is used. +The +.meta modulus +argument must be a positive integer. If +.meta modulus +is 1, then the function returns zero without altering the state of the +pseudo-random number generator. + .SS* Time .coNP Functions @ time and @ time-usec .synb -- cgit v1.2.3