* stdlib/random_r.c (__random_r): Rewrite last patch to fix buffer
	overwriting bugs.
This commit is contained in:
Ulrich Drepper 1998-05-22 22:49:57 +00:00
parent 195d0dd4aa
commit 6958e78dd1
2 changed files with 110 additions and 168 deletions

View File

@ -1,5 +1,8 @@
1998-05-22 Ulrich Drepper <drepper@cygnus.com> 1998-05-22 Ulrich Drepper <drepper@cygnus.com>
* stdlib/random_r.c (__random_r): Rewrite last patch to fix buffer
overwriting bugs.
* libio/strops.c (_IO_str_underflow): Read newly available * libio/strops.c (_IO_str_underflow): Read newly available
character from buffer as unsigned. character from buffer as unsigned.

View File

@ -107,17 +107,18 @@
struct random_poly_info struct random_poly_info
{ {
char seps[MAX_TYPES - 1]; int seps[MAX_TYPES];
char degrees[MAX_TYPES - 1]; int degrees[MAX_TYPES];
}; };
static const struct random_poly_info random_poly_info = static const struct random_poly_info random_poly_info =
{ {
{ SEP_1, SEP_2, SEP_3, SEP_4 }, { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 },
{ DEG_1, DEG_2, DEG_3, DEG_4 }, { DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 }
}; };
/* Initialize the random number generator based on the given seed. If the /* Initialize the random number generator based on the given seed. If the
type is the trivial no-state-information type, just remember the seed. type is the trivial no-state-information type, just remember the seed.
@ -134,68 +135,55 @@ __srandom_r (seed, buf)
{ {
int type; int type;
int32_t *state; int32_t *state;
long int i;
long int word;
int32_t *dst;
int kc;
if (buf == NULL) if (buf == NULL)
goto fail; goto fail;
type = buf->rand_type; type = buf->rand_type;
if ((unsigned)type >= MAX_TYPES) if ((unsigned int) type >= MAX_TYPES)
goto fail; goto fail;
/* We must make sure the seed is not 0. Take arbitrarily 1 in this case. */
state = buf->state; state = buf->state;
/* We must make sure the seed is not 0. Take arbitrarily 1 in this case. */
if (seed == 0) if (seed == 0)
seed = 1; seed = 1;
state[0] = seed; state[0] = seed;
if (type == TYPE_0) if (type == TYPE_0)
goto done; goto done;
dst = state;
word = seed;
kc = buf->rand_deg;
for (i = 1; i < kc; ++i)
{ {
int degree; /* This does:
long int word; state[i] = (16807 * state[i - 1]) % 2147483647;
int jc; but avoids overflowing 31 bits. */
int32_t *dst; long int hi = word / 127773;
int kc; long int lo = word % 127773;
int separation; word = 16807 * lo - 2836 * hi;
if (word < 0)
degree = buf->rand_deg; word += 2147483647;
jc = degree - 1; *++dst = word;
dst = state;
word = seed;
while (--jc >= 0)
{
long int hi;
long int lo;
/* This does:
state[i] = (16807 * state[i - 1]) % 2147483647;
but avoids overflowing 31 bits. */
++dst;
hi = word / 127773;
lo = word % 127773;
word = 16807 * lo - 2836 * hi;
if (word < 0)
word += 2147483647;
*dst = word;
}
state = buf->state;
degree = buf->rand_deg;
separation = buf->rand_sep;
buf->fptr = &state[separation];
buf->rptr = &state[0];
kc = 10 * degree;
while (--kc >= 0)
{
int32_t discard;
(void) __random_r (buf, &discard);
}
} }
goto done;
fail: buf->fptr = &state[buf->rand_sep];
return -1; buf->rptr = &state[0];
kc *= 10;
while (--kc >= 0)
{
int32_t discard;
(void) __random_r (buf, &discard);
}
done: done:
return 0; return 0;
fail:
return -1;
} }
weak_alias (__srandom_r, srandom_r) weak_alias (__srandom_r, srandom_r)
@ -222,8 +210,6 @@ __initstate_r (seed, arg_state, n, buf)
int degree; int degree;
int separation; int separation;
int32_t *state; int32_t *state;
int mess;
const struct random_poly_info *rpi;
if (buf == NULL) if (buf == NULL)
goto fail; goto fail;
@ -233,35 +219,33 @@ __initstate_r (seed, arg_state, n, buf)
else if (n < BREAK_1) else if (n < BREAK_1)
{ {
if (n < BREAK_0) if (n < BREAK_0)
goto fail; {
__set_errno (EINVAL);
goto fail;
}
type = TYPE_0; type = TYPE_0;
} }
else else
type = n < BREAK_2 ? TYPE_1 : TYPE_2; type = n < BREAK_2 ? TYPE_1 : TYPE_2;
degree = random_poly_info.degrees[type];
separation = random_poly_info.seps[type];
buf->rand_type = type;
buf->rand_sep = separation;
buf->rand_deg = degree;
state = &((int32_t *) arg_state)[1]; /* First location. */ state = &((int32_t *) arg_state)[1]; /* First location. */
buf->state = state;
mess = TYPE_0;
if (type == TYPE_0)
goto skip_to_here;
rpi = &random_poly_info;
degree = rpi->degrees[type - 1];
separation = rpi->seps[type - 1];
/* Must set END_PTR before srandom. */ /* Must set END_PTR before srandom. */
buf->end_ptr = &state[degree]; buf->end_ptr = &state[degree];
buf->rand_deg = degree; buf->state = state;
buf->rand_sep = separation;
mess = (buf->rptr - state) * MAX_TYPES + type;
skip_to_here:
state[-1] = mess;
__srandom_r (seed, buf); __srandom_r (seed, buf);
state[-1] = TYPE_0;
if (type != TYPE_0)
state[-1] = (buf->rptr - state) * MAX_TYPES + type;
return 0; return 0;
fail: fail:
@ -283,59 +267,41 @@ __setstate_r (arg_state, buf)
void *arg_state; void *arg_state;
struct random_data *buf; struct random_data *buf;
{ {
int32_t *new_state; int32_t *new_state = (int32_t *) arg_state;
int type; int type = new_state[0] % MAX_TYPES;
int rear; int old_type;
int32_t *old_state; int32_t *old_state;
int32_t *ns1;
int degree; int degree;
int separation; int separation;
int mess;
int old_type;
int new_mess;
int *old_rptr;
const struct random_poly_info *rpi;
if (buf == NULL) if (buf == NULL || type < TYPE_0 || type >= TYPE_4)
return -1; goto fail;
old_type = buf->rand_type; old_type = buf->rand_type;
old_state = buf->state; old_state = buf->state;
old_rptr = buf->rptr; if (old_type == TYPE_0)
mess = old_type; old_state[-1] = TYPE_0;
if (old_type != TYPE_0) else
mess += (old_rptr - old_state) * MAX_TYPES; old_state[-1] = (MAX_TYPES * (buf->rptr - old_state)) + old_type;
old_state[-1] = mess;
new_state = (int32_t *) arg_state; buf->rand_deg = degree = random_poly_info.degrees[type];
new_mess = new_state[0]; buf->rand_sep = separation = random_poly_info.seps[type];
type = new_mess % MAX_TYPES; buf->rand_type = type;
rear = new_mess / MAX_TYPES;
rpi = &random_poly_info;
degree = rpi->degrees[type - 1];
separation = rpi->seps[type - 1];
if (rear >= degree)
goto fail;
ns1 = &new_state[1];
if (type != TYPE_0) if (type != TYPE_0)
{ {
int t; int rear = new_state[0] / MAX_TYPES;
buf->rptr = &new_state[rear];
t = rear + separation; buf->fptr = &new_state[(rear + separation) % degree];
if (t >= degree)
t -= degree;
buf->rptr = &ns1[rear];
buf->fptr = &ns1[t];
buf->rand_deg = degree;
buf->rand_sep = separation;
buf->end_ptr = &ns1[degree];
} }
buf->state = &new_state[1];
/* Set end_ptr too. */
buf->end_ptr = &new_state[degree];
return 0; return 0;
fail: fail:
__set_errno (EINVAL);
return -1; return -1;
} }
@ -348,85 +314,58 @@ weak_alias (__setstate_r, setstate_r)
the one at the front pointer. Then both pointers are advanced to the next the one at the front pointer. Then both pointers are advanced to the next
location cyclically in the table. The value returned is the sum generated, location cyclically in the table. The value returned is the sum generated,
reduced to 31 bits by throwing away the "least random" low bit. reduced to 31 bits by throwing away the "least random" low bit.
Returns a 31-bit random number. */ Note: The code takes advantage of the fact that both the front and
rear pointers can't wrap on the same call by not testing the rear
pointer if the front one has wrapped. Returns a 31-bit random number. */
int int
__random_r (buf, result) __random_r (buf, result)
struct random_data *buf; struct random_data *buf;
int32_t *result; int32_t *result;
{ {
int32_t *res_ptr; int32_t *state;
int rand_type;
res_ptr = result; if (buf == NULL || result == NULL)
rand_type = buf->rand_type;
if (buf == NULL || res_ptr == NULL)
goto fail; goto fail;
if (rand_type == TYPE_0) state = buf->state;
goto old_style;
{ if (buf->rand_type == TYPE_0)
int32_t *fp0; {
int32_t *rp0; int32_t val = state[0];
int32_t sum; val = ((state[0] * 1103515245) + 12345) & 0x7fffffff;
int32_t fval; state[0] = val;
int32_t rval; *result = val;
int32_t rez; }
int32_t *fp1; else
int32_t *rp1; {
int32_t *end; int32_t *fptr = buf->fptr;
int32_t *begin; int32_t *rptr = buf->rptr;
int32_t *end_ptr = buf->end_ptr;
int32_t val;
/* 0 */ val = *fptr += *rptr;
fp0 = buf->fptr; /* Chucking least random bit. */
rp0 = buf->rptr; *result = (val >> 1) & 0x7fffffff;
++fptr;
/* 1 */ if (fptr >= end_ptr)
fval = *fp0; {
rval = *rp0; fptr = state;
fp1 = fp0 + 1; ++rptr;
}
/* 2 */ else
sum = fval + rval; {
rp1 = rp0 + 1; ++rptr;
if (rptr >= end_ptr)
/* 3 */ rptr = state;
rez = (sum >> 1) & 0x7FFFFFFF; }
*fp0 = sum; buf->fptr = fptr;
end = buf->end_ptr; buf->rptr = rptr;
}
/* 4 */ return 0;
*res_ptr = rez;
begin = buf->state;
if (fp1 == end)
fp1 = begin;
if (rp1 == end)
rp1 = begin;
/* 5 */
buf->fptr = fp1;
buf->rptr = rp1;
}
goto done;
old_style:
{
int32_t *state;
int32_t rez;
state = buf->state;
rez = ((*state * 1103515245) + 12345) & 0x7FFFFFFF;
*res_ptr = rez;
*state = rez;
}
goto done;
fail: fail:
return -1; return -1;
done:
return 0;
} }
weak_alias (__random_r, random_r) weak_alias (__random_r, random_r)