Skip site navigation (1)Skip section navigation (2)
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>