Date: Sat, 6 Sep 2003 03:30:21 +0900 (JST) From: Hiroki Sato <hrs@FreeBSD.org> To: FreeBSD-gnats-submit@FreeBSD.org Subject: bin/56502: initstate() causes memory corruption on LP64 platforms Message-ID: <200309051830.h85IULXJ075842@alph.allbsd.org> Resent-Message-ID: <200309051840.h85Ie0Lg025003@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 56502 >Category: bin >Synopsis: initstate() causes memory corruption on LP64 platforms >Confidential: no >Severity: critical >Priority: medium >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Fri Sep 05 11:40:00 PDT 2003 >Closed-Date: >Last-Modified: >Originator: Hiroki Sato >Release: FreeBSD 4.8-STABLE i386 >Organization: Tokyo University of Science >Environment: System: FreeBSD alph.allbsd.org 4.8-STABLE FreeBSD 4.8-STABLE #7: Tue May 20 00:05:43 JST 2003 hrs@alph.allbsd.org:/home/obj/home/src/sys/ALPH i386 >Description: I noticed that initstate() caused memory corruption on FreeBSD/sparc64. I guess this is because lib/libc/stdlib/random.c assumes "long" is 32-bit long. >How-To-Repeat: #include <sys/time.h> #include <stdio.h> static int *a; static char b[256]; static int *c; int main(void) { struct timeval tv; gettimeofday(&tv, NULL); printf("before: %p\n", c); initstate((unsigned long)tv.tv_usec, b, sizeof(b)); printf("after: %p\n", c); return(0); } >Fix: Index: stdlib/random.c =================================================================== RCS file: /home/ncvs/src/lib/libc/stdlib/random.c,v retrieving revision 1.23 diff -d -u -I\$FreeBSD:.*\$ -I\$NetBSD:.*\$ -I\$OpenBSD:.*\$ -I\$Id:.*\$ -I\$hrs:.*\$ -r1.23 random.c --- stdlib/random.c 10 Aug 2003 17:49:55 -0000 1.23 +++ stdlib/random.c 1 Sep 2003 02:11:49 -0000 @@ -61,10 +61,10 @@ * congruential generator. If the amount of state information is less than * 32 bytes, a simple linear congruential R.N.G. is used. * - * Internally, the state information is treated as an array of longs; the + * Internally, the state information is treated as an array of ints; the * zeroeth element of the array is the type of R.N.G. being used (small * integer); the remainder of the array is the state information for the - * R.N.G. Thus, 32 bytes of state information will give 7 longs worth of + * R.N.G. Thus, 32 bytes of state information will give 7 ints worth of * state information, which will allow a degree seven polynomial. (Note: * the zeroeth word of state information also has some other information * stored in it -- see setstate() for details). @@ -148,8 +148,8 @@ #define NSHUFF 50 /* to drop some "seed -> 1st value" linearity */ #endif /* !USE_WEAK_SEEDING */ -static long degrees[MAX_TYPES] = { DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 }; -static long seps [MAX_TYPES] = { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 }; +static const int degrees[MAX_TYPES] = { DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 }; +static const int seps [MAX_TYPES] = { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 }; /* * Initially, everything is set up as if from: @@ -165,7 +165,7 @@ * MAX_TYPES * (rptr - state) + TYPE_3 == TYPE_3. */ -static long randtbl[DEG_3 + 1] = { +static uint32_t randtbl[DEG_3 + 1] = { TYPE_3, #ifdef USE_WEAK_SEEDING /* Historic implementation compatibility */ @@ -200,8 +200,8 @@ * in the initialization of randtbl) because the state table pointer is set * to point to randtbl[1] (as explained below). */ -static long *fptr = &randtbl[SEP_3 + 1]; -static long *rptr = &randtbl[1]; +static uint32_t *fptr = &randtbl[SEP_3 + 1]; +static uint32_t *rptr = &randtbl[1]; /* * The following things are the pointer to the state information table, the @@ -213,11 +213,11 @@ * this is more efficient than indexing every time to find the address of * the last element to see if the front and rear pointers have wrapped. */ -static long *state = &randtbl[1]; -static long rand_type = TYPE_3; -static long rand_deg = DEG_3; -static long rand_sep = SEP_3; -static long *end_ptr = &randtbl[DEG_3 + 1]; +static uint32_t *state = &randtbl[1]; +static int rand_type = TYPE_3; +static int rand_deg = DEG_3; +static int rand_sep = SEP_3; +static uint32_t *end_ptr = &randtbl[DEG_3 + 1]; static inline long good_rand(long); @@ -270,14 +270,14 @@ srandom(x) unsigned long x; { - long i, lim; + int i, lim; - state[0] = x; + state[0] = (uint32_t)x; if (rand_type == TYPE_0) lim = NSHUFF; else { for (i = 1; i < rand_deg; i++) - state[i] = good_rand(state[i - 1]); + state[i] = (uint32_t)good_rand(state[i - 1]); fptr = &state[rand_sep]; rptr = &state[0]; lim = 10 * rand_deg; @@ -350,7 +350,7 @@ * * Returns a pointer to the old state. * - * Note: The Sparc platform requires that arg_state begin on a long + * Note: The Sparc platform requires that arg_state begin on an int * word boundary; otherwise a bus error will occur. Even so, lint will * complain about mis-alignment, but you should disregard these messages. */ @@ -361,12 +361,12 @@ long n; /* # bytes of state info */ { char *ostate = (char *)(&state[-1]); - long *long_arg_state = (long *) arg_state; + uint32_t *int_arg_state = (uint32_t *)(void *)arg_state; if (rand_type == TYPE_0) state[-1] = rand_type; else - state[-1] = MAX_TYPES * (rptr - state) + rand_type; + state[-1] = MAX_TYPES * (uint32_t)(rptr - state) + rand_type; if (n < BREAK_0) { (void)fprintf(stderr, "random: not enough state (%ld bytes); ignored.\n", n); @@ -393,13 +393,13 @@ rand_deg = DEG_4; rand_sep = SEP_4; } - state = (long *) (long_arg_state + 1); /* first location */ + state = (uint32_t *) (int_arg_state + 1); /* first location */ end_ptr = &state[rand_deg]; /* must set end_ptr before srandom */ - srandom(seed); + srandom((uint32_t)seed); if (rand_type == TYPE_0) - long_arg_state[0] = rand_type; + int_arg_state[0] = rand_type; else - long_arg_state[0] = MAX_TYPES * (rptr - state) + rand_type; + int_arg_state[0] = MAX_TYPES * (uint32_t)(rptr - state) + rand_type; return(ostate); } @@ -426,15 +426,15 @@ setstate(arg_state) char *arg_state; /* pointer to state array */ { - long *new_state = (long *) arg_state; - long type = new_state[0] % MAX_TYPES; - long rear = new_state[0] / MAX_TYPES; + uint32_t *new_state = (uint32_t *)(void *)arg_state; + uint32_t type = new_state[0] % MAX_TYPES; + uint32_t rear = new_state[0] / MAX_TYPES; char *ostate = (char *)(&state[-1]); if (rand_type == TYPE_0) state[-1] = rand_type; else - state[-1] = MAX_TYPES * (rptr - state) + rand_type; + state[-1] = MAX_TYPES * (uint32_t)(rptr - state) + rand_type; switch(type) { case TYPE_0: case TYPE_1: @@ -449,7 +449,7 @@ (void)fprintf(stderr, "random: state info corrupted; not changed.\n"); } - state = (long *) (new_state + 1); + state = (uint32_t *) (new_state + 1); if (rand_type != TYPE_0) { rptr = &state[rear]; fptr = &state[(rear + rand_sep) % rand_deg]; @@ -478,8 +478,8 @@ long random() { - long i; - long *f, *r; + uint32_t i; + uint32_t *f, *r; if (rand_type == TYPE_0) { i = state[0]; @@ -490,7 +490,8 @@ */ f = fptr; r = rptr; *f += *r; - i = (*f >> 1) & 0x7fffffff; /* chucking least random bit */ + /* chucking least random bit */ + i = (*f >> 1) & 0x7fffffff; if (++f >= end_ptr) { f = state; ++r; @@ -501,5 +502,5 @@ fptr = f; rptr = r; } - return(i); + return((long)i); } >Release-Note: >Audit-Trail: >Unformatted:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200309051830.h85IULXJ075842>