From 423acb9483f672df5cf220e386b7d85e35b95fb8 Mon Sep 17 00:00:00 2001 From: Mark Wooding Date: Sun, 11 Sep 2016 14:29:49 +0100 Subject: [PATCH] math/mprand.[ch], rand/grand.c: Check range of arguments. * mprand: It doesn't make sense to ask for a zero-bit integer whose low bit is set; or, indeed, a four-bit integer whose fourth bit is set. So check the mask against the bit length. * mprand: On the other hand, it /does/ make sense to ask for a zero-bit integer, and the answer is simply zero. But the code used to segfault. Fix this. * mprand_range, grand_defaultrange: It doesn't make sense to ask for an integer in [0, 0), because there aren't any. Check before trying. --- math/mprand.c | 21 ++++++++++++++++++--- math/mprand.h | 5 ++++- rand/grand.c | 1 + 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/math/mprand.c b/math/mprand.c index eb779cb8..5805e6ed 100644 --- a/math/mprand.c +++ b/math/mprand.c @@ -49,17 +49,27 @@ * uniformly distributed in the interval %$[2^{b - 1}, 2^b)$%. * The result is then ORred with the given @or@ value. This * will often be 1, to make the result odd. + * + * The length @b@ may be zero; but %$\texttt{or} \ge 2^b$% is + * not permitted. */ mp *mprand(mp *d, unsigned b, grand *r, mpw or) { size_t sz = (b + 7) >> 3; arena *a = (d && (d->f & MP_BURN)) ? arena_secure : arena_global; - octet *v = x_alloc(a, sz); + octet *v; unsigned m; + assert(b >= MPW_BITS || !(or >> b)); + + /* --- Special case --- */ + + if (!b) return (MP_ZERO); + /* --- Fill buffer with random data --- */ + v = x_alloc(a, sz); r->ops->fill(r, v, sz); /* --- Force into the correct range --- * @@ -74,7 +84,11 @@ mp *mprand(mp *d, unsigned b, grand *r, mpw or) /* --- Mask, load and return --- */ d = mp_loadb(d, v, sz); - d->v[0] |= or; + if (or) { + assert(d->sz); + if (!MP_LEN(d)) d->vl = d->v + 1; + d->v[0] |= or; + } memset(v, 0, sz); x_free(a, v); return (d); @@ -91,7 +105,7 @@ mp *mprand(mp *d, unsigned b, grand *r, mpw or) * interval %$[0, l)$%. * * Use: Generates a uniformly-distributed pseudorandom number in the - * appropriate range. + * appropriate range. We must have %$l > 0$%. */ mp *mprand_range(mp *d, mp *l, grand *r, mpw or) @@ -119,6 +133,7 @@ mp *mprand_range(mp *d, mp *l, grand *r, mpw or) * As usual, the number of iterations expected is two. */ + assert(MP_POSP(l)); b = ((b - 1) & 7) + 1; m = (1 << b) - 1; do { diff --git a/math/mprand.h b/math/mprand.h index 0c193c03..a088df8a 100644 --- a/math/mprand.h +++ b/math/mprand.h @@ -58,6 +58,9 @@ * uniformly distributed in the interval %$[2^{b - 1}, 2^b)$%. * The result is then ORred with the given @or@ value. This * will often be 1, to make the result odd. + * + * The length @b@ may be zero; but %$\texttt{or} \ge 2^b$% is + * not permitted. */ extern mp *mprand(mp */*d*/, unsigned /*b*/, grand */*r*/, mpw /*or*/); @@ -73,7 +76,7 @@ extern mp *mprand(mp */*d*/, unsigned /*b*/, grand */*r*/, mpw /*or*/); * interval %$[0, l)$%. * * Use: Generates a uniformly-distributed pseudorandom number in the - * appropriate range. + * appropriate range. We must have %$l > 0$%. */ extern mp *mprand_range(mp */*d*/, mp */*l*/, grand */*r*/, mpw /*or*/); diff --git a/rand/grand.c b/rand/grand.c index e4451917..a95c89f0 100644 --- a/rand/grand.c +++ b/rand/grand.c @@ -97,6 +97,7 @@ uint32 grand_defaultrange(grand *r, uint32 l) * @byte@, but by that point it must be able to satisfy us. */ + assert(l); if (r->ops->max && r->ops->max >= l) { w = r->ops->raw; m = r->ops->max; -- 2.11.0