From tegge@crash.fast.no Tue Nov 23 21:07:17 1999
Return-Path: <tegge@crash.fast.no>
Received: from midten.fast.no (midten.fast.no [195.139.251.11])
	by hub.freebsd.org (Postfix) with ESMTP id 2910F1550A
	for <FreeBSD-gnats-submit@freebsd.org>; Tue, 23 Nov 1999 21:07:09 -0800 (PST)
	(envelope-from tegge@crash.fast.no)
Received: from crash.fast.no (crash.fast.no [195.139.251.13])
	by midten.fast.no (8.9.3/8.9.3) with ESMTP id GAA69810
	for <FreeBSD-gnats-submit@freebsd.org>; Wed, 24 Nov 1999 06:06:53 +0100 (CET)
Received: (from tegge@localhost)
	by crash.fast.no (8.9.3/8.8.8) id GAA05938;
	Wed, 24 Nov 1999 06:06:53 +0100 (CET)
	(envelope-from tegge@crash.fast.no)
Message-Id: <199911240506.GAA05938@crash.fast.no>
Date: Wed, 24 Nov 1999 06:06:53 +0100 (CET)
From: Tor Egge <tegge@crash.fast.no>
Reply-To: tegge@crash.fast.no
To: FreeBSD-gnats-submit@freebsd.org
Subject: vfprintf/cvt/__dtoa race condition in threaded programs
X-Send-Pr-Version: 3.2

>Number:         15070
>Category:       bin
>Synopsis:       vfprintf/cvt/__dtoa race condition in threaded programs
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    tegge
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Nov 23 21:10:01 PST 1999
>Closed-Date:    Thu Nov 15 18:23:34 2001
>Last-Modified:  Thu Nov 15 18:28:35 PST 2001
>Originator:     Tor Egge
>Release:        FreeBSD 4.0-CURRENT i386
>Organization:
Fast Search & Transfer ASA
>Environment:

FreeBSD crash.fast.no 4.0-CURRENT FreeBSD 4.0-CURRENT #0: Sat Oct 16 04:21:25 CEST 1999     root@local-crash.fast.no:/usr/src/sys/compile/CRASH  i386

>Description:

Printing floating point numbers in a threaded program might result in a
segmentation fault or bus error.

crash:~$ gdb ./threadbug4
GNU gdb 4.18
Copyright 1998 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-unknown-freebsd"...
(gdb) run
Starting program: /home/tegge/./threadbug4 
Time is  2.664
Time is  5.544

Program received signal SIGSEGV, Segmentation fault.
0x80528c8 in bcopy ()
(gdb) where
#0  0x80528c8 in bcopy ()
#1  0x4 in ?? ()
#2  0x8054473 in __dtoa ()
#3  0x80521d8 in vfprintf ()
#4  0x80508f2 in vfprintf ()
#5  0x804f9d1 in sprintf ()
#6  0x804819a in crashme (data=0x0) at threadbug4.c:27
#7  0x80487b0 in _thread_start ()
#8  0x0 in ?? ()
(gdb)

>How-To-Repeat:

Compile and run the enclosed threaded program.

-------------------------------------------
#include <sys/types.h>
#include <sys/errno.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <signal.h>
#include <pthread.h>
#include <sys/time.h>
#include <time.h>


void *crashme(void *data)
{
  char buf[200];
  int i, j;
  double div;
  while (1) {
    i = random();
    j = random();
    if (j == 0)
      j = 1;
    div = (double) i / (double) j;
    sprintf(buf, "%6.5f", div);
    sprintf(buf, "%2.4f", div);
    sprintf(buf, "%3.6f", div);
    sprintf(buf, "%8.2f", div);
    sprintf(buf, "%10.2f", div);
  }
}

void 
reportloop(void)
{
  struct timeval stime, now, delta;
  double fdelta;

  gettimeofday(&stime, NULL);
  while (1) {
    sleep(1);
    gettimeofday(&now, NULL);
    timersub(&now, &stime, &delta);
    fdelta = delta.tv_sec + ((double) delta.tv_usec) / 1000000.0;
    printf("Time is %6.3f\n", fdelta);
    fflush(stdout);
  }
}

int
main(int argc,char **argv)
{
  int i;
  pthread_t curthread;
  srandom(time(NULL));

  for (i = 0; i < 10; i++) {
    pthread_create(&curthread, NULL, crashme, (void *) NULL);
  }
  reportloop();
  exit(0);
}
--------------------------
crash:~$ cc -static -O -g -pthread -o threadbug4 threadbug4.c

>Fix:

>Release-Note:
>Audit-Trail:

From: Tor.Egge@fast.no
To: freebsd-gnats-submit@FreeBSD.ORG
Cc:  
Subject: Re: bin/15070: vfprintf/cvt/__dtoa race condition in threaded programs
Date: Mon, 15 Jan 2001 03:35:04 +0100

 One workaround for the race is to serialize vfprintf() calls that use
 floating point conversion specifications.
 
 
 Index: stdio/vfprintf.c
 ===================================================================
 RCS file: /home/ncvs/src/lib/libc/stdio/vfprintf.c,v
 retrieving revision 1.23
 diff -u -r1.23 vfprintf.c
 --- stdio/vfprintf.c	2001/01/06 20:48:00	1.23
 +++ stdio/vfprintf.c	2001/01/06 23:15:45
 @@ -261,6 +261,17 @@
  #include <math.h>
  #include "floatio.h"
  
 +/* 
 + * Serialize calls to cvt and __dtoa() and the usage of the result
 + * in threaded programs.
 + */
 +
 +#include "libc_private.h"
 +#include "spinlock.h"
 +static spinlock_t thread_lock	= _SPINLOCK_INITIALIZER;
 +#define THREAD_LOCK()		if (__isthreaded) _SPINLOCK(&thread_lock);
 +#define THREAD_UNLOCK()		if (__isthreaded) _SPINUNLOCK(&thread_lock);
 +
  #define	BUF		(MAXEXP+MAXFRACT+1)	/* + decimal point */
  #define	DEFPREC		6
  
 @@ -271,6 +282,9 @@
  
  #define	BUF		68
  
 +#define THREAD_LOCK()
 +#define THREAD_UNLOCK()
 +
  #endif /* FLOATING_POINT */
  
  #define STATIC_ARG_TBL_SIZE 8           /* Size of static argument table. */
 @@ -303,6 +317,7 @@
  	int width;		/* width from format (%8d), or 0 */
  	int prec;		/* precision from format (%.3d), or -1 */
  	char sign;		/* sign prefix (' ', '+', '-', or \0) */
 +	int didlock;		/* have obtained thread lock */
  #ifdef FLOATING_POINT
  	char softsign;		/* temporary negative sign for floats */
  	double _double;		/* double precision arguments %[eEfgG] */
 @@ -418,6 +433,7 @@
          }
          
  
 +	didlock = 0;
  	FLOCKFILE(fp);
  	/* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
  	if (cantwrite(fp)) {
 @@ -608,6 +624,8 @@
  				break;
  			}
  			flags |= FPT;
 +			THREAD_LOCK();
 +			didlock = 1;
  			cp = cvt(_double, prec, flags, &softsign,
  				&expt, ch, &ndig);
  			if (ch == 'g' || ch == 'G') {
 @@ -849,6 +867,10 @@
  					PRINT(cp, 1);
  				PRINT(expstr, expsize);
  			}
 +			if (didlock != 0) {
 +			  THREAD_UNLOCK();
 +			  didlock = 0;
 +			}
  		}
  #else
  		PRINT(cp, size);
 @@ -865,6 +887,10 @@
  done:
  	FLUSH();
  error:
 +	if (didlock != 0) {
 +	  THREAD_UNLOCK();
 +	  didlock = 0;
 +	}
  	if (__sferror(fp))
  		ret = EOF;
  	FUNLOCKFILE(fp);
 Index: stdlib/strtod.c
 ===================================================================
 RCS file: /home/ncvs/src/lib/libc/stdlib/strtod.c,v
 retrieving revision 1.3
 diff -u -r1.3 strtod.c
 --- stdlib/strtod.c	1996/07/12 18:55:22	1.3
 +++ stdlib/strtod.c	2000/06/15 03:48:29
 @@ -371,6 +371,16 @@
  
   static Bigint *freelist[Kmax+1];
  
 +  /*
 +   * Make Balloc/Bfree thread-safe in libc for use with
 +   * kernel threads.
 +   */
 +#include "libc_private.h"
 +#include "spinlock.h"
 +static spinlock_t thread_lock	= _SPINLOCK_INITIALIZER;
 +#define THREAD_LOCK()		if (__isthreaded) _SPINLOCK(&thread_lock);
 +#define THREAD_UNLOCK()		if (__isthreaded) _SPINUNLOCK(&thread_lock);
 +
   static Bigint *
  Balloc
  #ifdef KR_headers
 @@ -382,9 +392,12 @@
  	int x;
  	Bigint *rv;
  
 +	THREAD_LOCK();
  	if ( (rv = freelist[k]) ) {
  		freelist[k] = rv->next;
 +		THREAD_UNLOCK();
  	} else {
 +		THREAD_UNLOCK();
  		x = 1 << k;
  		rv = (Bigint *)malloc(sizeof(Bigint) + (x-1)*sizeof(long));
  		rv->k = k;
 @@ -403,8 +416,10 @@
  #endif
  {
  	if (v) {
 +		THREAD_LOCK();
  		v->next = freelist[v->k];
  		freelist[v->k] = v;
 +		THREAD_UNLOCK();
  	}
  }
  
 

From: Peter Wemm <peter@netplex.com.au>
To: Tor.Egge@fast.no
Cc: freebsd-gnats-submit@FreeBSD.ORG
Subject: Re: bin/15070: vfprintf/cvt/__dtoa race condition in threaded programs 
Date: Sun, 14 Jan 2001 19:26:04 -0800

 Tor.Egge@fast.no wrote:
 
 >  One workaround for the race is to serialize vfprintf() calls that use
 >  floating point conversion specifications.
 
 Umm.. I wonder if this is the cause of the 'FreeBSD libc sprintf bug'
 that the MySQL folks see and mention on their web site?  They use libc_r
 and see problems with sprintf...
 
 Cheers,
 -Peter
 --
 Peter Wemm - peter@FreeBSD.org; peter@yahoo-inc.com; peter@netplex.com.au
 "All of this is for nothing if we don't go to the stars" - JMS/B5
 
 

From: Tor.Egge@fast.no
To: peter@netplex.com.au
Cc: freebsd-gnats-submit@FreeBSD.ORG
Subject: Re: bin/15070: vfprintf/cvt/__dtoa race condition in threaded programs 
Date: Mon, 15 Jan 2001 04:51:54 +0100

 > Umm.. I wonder if this is the cause of the 'FreeBSD libc sprintf bug'
 > that the MySQL folks see and mention on their web site?  They use libc_r
 > and see problems with sprintf...
 
 Yes.
 
 The stack trace shown by gdb on the mysql mailing list is very similar
 to that generated by the sample program in this PR.
 
 - Tor Egge
 

From: Tor.Egge@fast.no
To: wollman@khavrinen.lcs.mit.edu
Cc: freebsd-gnats-submit@FreeBSD.ORG
Subject: Re: bin/15070: vfprintf/cvt/__dtoa race condition in threaded programs
Date: Mon, 15 Jan 2001 22:48:55 +0100

 > Since the interface is purely internal, it would be better to simply
 > *fix* it....
 
 Like this ?
 
 
 Index: lib/libc/stdlib/strtod.c
 ===================================================================
 RCS file: /home/ncvs/src/lib/libc/stdlib/strtod.c,v
 retrieving revision 1.3
 diff -u -r1.3 strtod.c
 --- lib/libc/stdlib/strtod.c	1996/07/12 18:55:22	1.3
 +++ lib/libc/stdlib/strtod.c	2001/01/15 21:06:01
 @@ -371,6 +371,16 @@
  
   static Bigint *freelist[Kmax+1];
  
 +  /*
 +   * Make Balloc/Bfree thread-safe in libc for use with
 +   * kernel threads.
 +   */
 +#include "libc_private.h"
 +#include "spinlock.h"
 +static spinlock_t thread_lock	= _SPINLOCK_INITIALIZER;
 +#define THREAD_LOCK()		if (__isthreaded) _SPINLOCK(&thread_lock);
 +#define THREAD_UNLOCK()		if (__isthreaded) _SPINUNLOCK(&thread_lock);
 +
   static Bigint *
  Balloc
  #ifdef KR_headers
 @@ -382,9 +392,12 @@
  	int x;
  	Bigint *rv;
  
 +	THREAD_LOCK();
  	if ( (rv = freelist[k]) ) {
  		freelist[k] = rv->next;
 +		THREAD_UNLOCK();
  	} else {
 +		THREAD_UNLOCK();
  		x = 1 << k;
  		rv = (Bigint *)malloc(sizeof(Bigint) + (x-1)*sizeof(long));
  		rv->k = k;
 @@ -403,8 +416,10 @@
  #endif
  {
  	if (v) {
 +		THREAD_LOCK();
  		v->next = freelist[v->k];
  		freelist[v->k] = v;
 +		THREAD_UNLOCK();
  	}
  }
  
 @@ -1839,10 +1854,11 @@
  char *
  __dtoa
  #ifdef KR_headers
 -	(d, mode, ndigits, decpt, sign, rve)
 -	double d; int mode, ndigits, *decpt, *sign; char **rve;
 +	(d, mode, ndigits, decpt, sign, rve, resultp)
 +	double d; int mode, ndigits, *decpt, *sign; char **rve, **resultp;
  #else
 -	(double d, int mode, int ndigits, int *decpt, int *sign, char **rve)
 +	(double d, int mode, int ndigits, int *decpt, int *sign, char **rve,
 +	 char **resultp)
  #endif
  {
   /*	Arguments ndigits, decpt, sign are similar to those
 @@ -1890,15 +1906,6 @@
  	Bigint *b, *b1, *delta, *mlo, *mhi, *S;
  	double d2, ds, eps;
  	char *s, *s0;
 -	static Bigint *result;
 -	static int result_k;
 -
 -	if (result) {
 -		result->k = result_k;
 -		result->maxwds = 1 << result_k;
 -		Bfree(result);
 -		result = 0;
 -	}
  
  	if (word0(d) & Sign_bit) {
  		/* set sign for everything, including 0's and NaNs */
 @@ -2057,11 +2064,8 @@
  			if (i <= 0)
  				i = 1;
  	}
 -	j = sizeof(unsigned long);
 -	for (result_k = 0; sizeof(Bigint) - sizeof(unsigned long) + j < i;
 -		j <<= 1) result_k++;
 -	result = Balloc(result_k);
 -	s = s0 = (char *)result;
 +	*resultp = (char *) malloc(i);
 +	s = s0 = *resultp;
  
  	if (ilim >= 0 && ilim <= Quick_max && try_quick) {
  
 Index: lib/libc/stdio/vfprintf.c
 ===================================================================
 RCS file: /home/ncvs/src/lib/libc/stdio/vfprintf.c,v
 retrieving revision 1.23
 diff -u -r1.23 vfprintf.c
 --- lib/libc/stdio/vfprintf.c	2001/01/06 20:48:00	1.23
 +++ lib/libc/stdio/vfprintf.c	2001/01/15 21:43:09
 @@ -264,7 +264,7 @@
  #define	BUF		(MAXEXP+MAXFRACT+1)	/* + decimal point */
  #define	DEFPREC		6
  
 -static char *cvt __P((double, int, int, char *, int *, int, int *));
 +static char *cvt __P((double, int, int, char *, int *, int, int *, char **));
  static int exponent __P((char *, int, int));
  
  #else /* no FLOATING_POINT */
 @@ -310,6 +310,7 @@
  	int expsize;		/* character count for expstr */
  	int ndig;		/* actual number of digits returned by cvt */
  	char expstr[7];		/* buffer for exponent string */
 +	char *dtoaresult;	/* buffer allocated by dtoa */
  #endif
  	u_long	ulval;		/* integer arguments %[diouxX] */
  	u_quad_t uqval;		/* %q integers */
 @@ -418,6 +419,9 @@
          }
          
  
 +#ifdef FLOATING_POINT
 +	dtoaresult = NULL;
 +#endif
  	FLOCKFILE(fp);
  	/* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
  	if (cantwrite(fp)) {
 @@ -608,8 +612,12 @@
  				break;
  			}
  			flags |= FPT;
 +			if (dtoaresult != NULL) {
 +				free(dtoaresult);
 +				dtoaresult = NULL;
 +			}
  			cp = cvt(_double, prec, flags, &softsign,
 -				&expt, ch, &ndig);
 +				&expt, ch, &ndig, &dtoaresult);
  			if (ch == 'g' || ch == 'G') {
  				if (expt <= -4 || expt > prec)
  					ch = (ch == 'g') ? 'e' : 'E';
 @@ -865,6 +873,10 @@
  done:
  	FLUSH();
  error:
 +#ifdef FLOATING_POINT
 +	if (dtoaresult != NULL)
 +		free(dtoaresult);
 +#endif
  	if (__sferror(fp))
  		ret = EOF;
  	FUNLOCKFILE(fp);
 @@ -1203,13 +1215,14 @@
  
  #ifdef FLOATING_POINT
  
 -extern char *__dtoa __P((double, int, int, int *, int *, char **));
 +extern char *__dtoa __P((double, int, int, int *, int *, char **, char **));
  
  static char *
 -cvt(value, ndigits, flags, sign, decpt, ch, length)
 +cvt(value, ndigits, flags, sign, decpt, ch, length, dtoaresultp)
  	double value;
  	int ndigits, flags, *decpt, ch, *length;
  	char *sign;
 +	char **dtoaresultp;
  {
  	int mode, dsgn;
  	char *digits, *bp, *rve;
 @@ -1231,7 +1244,8 @@
  		*sign = '-';
  	} else
  		*sign = '\000';
 -	digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve);
 +	digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve,
 +			dtoaresultp);
  	if ((ch != 'g' && ch != 'G') || flags & ALT) {
  		/* print trailing zeros */
  		bp = digits + ndigits;
 
 
 - Tor Egge
 

From: Tor.Egge@fast.no
To: wollman@khavrinen.lcs.mit.edu
Cc: freebsd-gnats-submit@FreeBSD.ORG
Subject: Re: bin/15070: vfprintf/cvt/__dtoa race condition in threaded programs
Date: Tue, 16 Jan 2001 03:11:04 +0100

 This uncovered another old __dtoa() bug.
 
 	*resultp = (char *) malloc(i);
 
 in the patch must be changed to
 
 	*resultp = (char *) malloc(i + 1);
 
 in order to avoid writing beyond the end of the allocated memory.
 Otherwise the sample program
 
 
 	#include <sys/types.h>
 	#include <stdio.h>
 	
 	
 	int
 	main(int argc,char **argv)
 	{
 	  (void) malloc(4);
 	  printf("%.23e\n", 2.4);
 	
 	  return 0;
 	}
 
 linked with Electric Fence crashes on the i386 platform.
 
 - Tor Egge
 

From: Tor.Egge@fast.no
To: Daniel Eischen <deischen@FreeBSD.org>, jdp@polstra.com
Cc: freebsd-gnats-submit@FreeBSD.org, Mike Smith <msmith@FreeBSD.org>
Subject: Re: bin/15070: vfprintf/cvt/__dtoa race condition in threaded programs
Date: Wed, 14 Feb 2001 22:02:36 +0100

 An updated patch that doesn't use spinlocks is enclosed.
 
 - Tor Egge
 
 
 Index: lib/libc/stdio/vfprintf.c
 ===================================================================
 RCS file: /home/ncvs/src/lib/libc/stdio/vfprintf.c,v
 retrieving revision 1.27
 diff -u -r1.27 vfprintf.c
 --- lib/libc/stdio/vfprintf.c	2001/02/10 06:25:33	1.27
 +++ lib/libc/stdio/vfprintf.c	2001/02/10 22:29:23
 @@ -268,7 +268,7 @@
  #define	BUF		(MAXEXP+MAXFRACT+1)	/* + decimal point */
  #define	DEFPREC		6
  
 -static char *cvt __P((double, int, int, char *, int *, int, int *));
 +static char *cvt __P((double, int, int, char *, int *, int, int *, char **));
  static int exponent __P((char *, int, int));
  
  #else /* no FLOATING_POINT */
 @@ -315,6 +315,7 @@
  	int expsize;		/* character count for expstr */
  	int ndig;		/* actual number of digits returned by cvt */
  	char expstr[7];		/* buffer for exponent string */
 +	char *dtoaresult;	/* buffer allocated by dtoa */
  #endif
  	u_long	ulval;		/* integer arguments %[diouxX] */
  	u_quad_t uqval;		/* %q integers */
 @@ -423,6 +424,9 @@
          }
          
  
 +#ifdef FLOATING_POINT
 +	dtoaresult = NULL;
 +#endif
  	/* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
  	if (cantwrite(fp))
  		return (EOF);
 @@ -608,8 +612,12 @@
  				break;
  			}
  			flags |= FPT;
 +			if (dtoaresult != NULL) {
 +				free(dtoaresult);
 +				dtoaresult = NULL;
 +			}
  			cp = cvt(_double, prec, flags, &softsign,
 -				&expt, ch, &ndig);
 +				&expt, ch, &ndig, &dtoaresult);
  			if (ch == 'g' || ch == 'G') {
  				if (expt <= -4 || expt > prec)
  					ch = (ch == 'g') ? 'e' : 'E';
 @@ -864,6 +872,10 @@
  done:
  	FLUSH();
  error:
 +#ifdef FLOATING_POINT
 +	if (dtoaresult != NULL)
 +		free(dtoaresult);
 +#endif
  	if (__sferror(fp))
  		ret = EOF;
          if ((argtable != NULL) && (argtable != statargtable))
 @@ -1195,11 +1207,11 @@
  
  #ifdef FLOATING_POINT
  
 -extern char *__dtoa __P((double, int, int, int *, int *, char **));
 +extern char *__dtoa __P((double, int, int, int *, int *, char **, char **));
  
  static char *
  cvt(double value, int ndigits, int flags, char *sign, int *decpt,
 -    int ch, int *length)
 +    int ch, int *length, char **dtoaresultp)
  {
  	int mode, dsgn;
  	char *digits, *bp, *rve;
 @@ -1221,7 +1233,8 @@
  		*sign = '-';
  	} else
  		*sign = '\000';
 -	digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve);
 +	digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve,
 +			dtoaresultp);
  	if ((ch != 'g' && ch != 'G') || flags & ALT) {
  		/* print trailing zeros */
  		bp = digits + ndigits;
 Index: lib/libc/stdlib/netbsd_strtod.c
 ===================================================================
 RCS file: /home/ncvs/src/lib/libc/stdlib/netbsd_strtod.c,v
 retrieving revision 1.4
 diff -u -r1.4 netbsd_strtod.c
 --- lib/libc/stdlib/netbsd_strtod.c	2001/02/09 20:31:47	1.4
 +++ lib/libc/stdlib/netbsd_strtod.c	2001/02/14 20:53:26
 @@ -142,7 +142,7 @@
  #include "memory.h"
  #endif
  #endif
 -char *__dtoa __P((double, int, int, int *, int *, char **));
 +char *__dtoa __P((double, int, int, int *, int *, char **, char **));
  
  #ifdef MALLOC
  #ifdef KR_headers
 @@ -382,8 +382,6 @@
  
   typedef struct Bigint Bigint;
  
 - static Bigint *freelist[Kmax+1];
 -
   static Bigint *
  Balloc
  #ifdef KR_headers
 @@ -395,15 +393,10 @@
  	int x;
  	Bigint *rv;
  
 -	if ((rv = freelist[k]) != NULL) {
 -		freelist[k] = rv->next;
 -		}
 -	else {
 -		x = 1 << k;
 -		rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(Long));
 -		rv->k = k;
 -		rv->maxwds = x;
 -		}
 +	x = 1 << k;
 +	rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(Long));
 +	rv->k = k;
 +	rv->maxwds = x;
  	rv->sign = rv->wds = 0;
  	return rv;
  	}
 @@ -416,10 +409,7 @@
  	(Bigint *v)
  #endif
  {
 -	if (v) {
 -		v->next = freelist[v->k];
 -		freelist[v->k] = v;
 -		}
 +	free(v);
  	}
  
  #define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \
 @@ -1900,10 +1890,11 @@
   char *
  __dtoa
  #ifdef KR_headers
 -	(d, mode, ndigits, decpt, sign, rve)
 -	double d; int mode, ndigits, *decpt, *sign; char **rve;
 +	(d, mode, ndigits, decpt, sign, rve, resultp)
 +	double d; int mode, ndigits, *decpt, *sign; char **rve, **resultp;
  #else
 -	(double d, int mode, int ndigits, int *decpt, int *sign, char **rve)
 +	(double d, int mode, int ndigits, int *decpt, int *sign, char **rve,
 +	 char **resultp)
  #endif
  {
   /*	Arguments ndigits, decpt, sign are similar to those
 @@ -1953,15 +1944,6 @@
  	Bigint *mlo = NULL; /* pacify gcc */
  	double d2, ds, eps;
  	char *s, *s0;
 -	static Bigint *result;
 -	static int result_k;
 -
 -	if (result) {
 -		result->k = result_k;
 -		result->maxwds = 1 << result_k;
 -		Bfree(result);
 -		result = 0;
 -		}
  
  	if (word0(d) & Sign_bit) {
  		/* set sign for everything, including 0's and NaNs */
 @@ -2123,11 +2105,8 @@
  			if (i <= 0)
  				i = 1;
  		}
 -	j = sizeof(ULong);
 -	for(result_k = 0; sizeof(Bigint) - sizeof(ULong) + j <= i;
 -		j <<= 1) result_k++;
 -	result = Balloc(result_k);
 -	s = s0 = (char *)result;
 +	*resultp = (char *) malloc(i + 1);
 +	s = s0 = *resultp;
  
  	if (ilim >= 0 && ilim <= Quick_max && try_quick) {
  
 Index: lib/libc/stdlib/strtod.c
 ===================================================================
 RCS file: /home/ncvs/src/lib/libc/stdlib/strtod.c,v
 retrieving revision 1.6
 diff -u -r1.6 strtod.c
 --- lib/libc/stdlib/strtod.c	2001/02/10 05:05:09	1.6
 +++ lib/libc/stdlib/strtod.c	2001/02/14 20:53:26
 @@ -372,8 +372,6 @@
  
   typedef struct Bigint Bigint;
  
 - static Bigint *freelist[Kmax+1];
 -
   static Bigint *
  Balloc
  #ifdef KR_headers
 @@ -385,14 +383,10 @@
  	int x;
  	Bigint *rv;
  
 -	if ( (rv = freelist[k]) ) {
 -		freelist[k] = rv->next;
 -	} else {
 -		x = 1 << k;
 -		rv = (Bigint *)malloc(sizeof(Bigint) + (x-1)*sizeof(long));
 -		rv->k = k;
 -		rv->maxwds = x;
 -	}
 +	x = 1 << k;
 +	rv = (Bigint *)malloc(sizeof(Bigint) + (x-1)*sizeof(long));
 +	rv->k = k;
 +	rv->maxwds = x;
  	rv->sign = rv->wds = 0;
  	return rv;
  }
 @@ -405,10 +399,7 @@
  	(Bigint *v)
  #endif
  {
 -	if (v) {
 -		v->next = freelist[v->k];
 -		freelist[v->k] = v;
 -	}
 +	free(v);
  }
  
  #define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \
 @@ -1844,10 +1835,11 @@
  char *
  __dtoa
  #ifdef KR_headers
 -	(d, mode, ndigits, decpt, sign, rve)
 -	double d; int mode, ndigits, *decpt, *sign; char **rve;
 +	(d, mode, ndigits, decpt, sign, rve, resultp)
 +	double d; int mode, ndigits, *decpt, *sign; char **rve, **resultp;
  #else
 -	(double d, int mode, int ndigits, int *decpt, int *sign, char **rve)
 +	(double d, int mode, int ndigits, int *decpt, int *sign, char **rve,
 +	 char **resultp)
  #endif
  {
   /*	Arguments ndigits, decpt, sign are similar to those
 @@ -1895,15 +1887,6 @@
  	Bigint *b, *b1, *delta, *mlo, *mhi, *S;
  	double d2, ds, eps;
  	char *s, *s0;
 -	static Bigint *result;
 -	static int result_k;
 -
 -	if (result) {
 -		result->k = result_k;
 -		result->maxwds = 1 << result_k;
 -		Bfree(result);
 -		result = 0;
 -	}
  
  	if (word0(d) & Sign_bit) {
  		/* set sign for everything, including 0's and NaNs */
 @@ -2062,11 +2045,8 @@
  			if (i <= 0)
  				i = 1;
  	}
 -	j = sizeof(unsigned long);
 -	for (result_k = 0; sizeof(Bigint) - sizeof(unsigned long) + j < i;
 -		j <<= 1) result_k++;
 -	result = Balloc(result_k);
 -	s = s0 = (char *)result;
 +	*resultp = (char *) malloc(i + 1);
 +	s = s0 = *resultp;
  
  	if (ilim >= 0 && ilim <= Quick_max && try_quick) {
  
 

From: Daniel Eischen <eischen@vigrid.com>
To: Tor.Egge@fast.no
Cc: freebsd-gnats-submit@FreeBSD.org
Subject: Re: bin/15070: vfprintf/cvt/__dtoa race condition in threaded programs
Date: Wed, 14 Feb 2001 22:26:00 -0500 (EST)

 On Wed, 14 Feb 2001 Tor.Egge@fast.no wrote:
 > 
 > An updated patch that doesn't use spinlocks is enclosed.
 
 Looks OK to me.
 
 I was toying with the idea of adding unthreaded versions of 
 _pthread_key_{create,delete}, _pthread_{get,set}specific to
 libc -- these would actually work for the single threaded
 case instead of being stub functions.
 
 -- 
 Dan Eischen
 
Responsible-Changed-From-To: freebsd-bugs->tegge 
Responsible-Changed-By: mike 
Responsible-Changed-When: Fri Jul 20 20:17:28 PDT 2001 
Responsible-Changed-Why:  

Tor Egge is a committer.  He seems to have a good idea what needs 
to be fixed. 

http://www.FreeBSD.org/cgi/query-pr.cgi?pr=15070

State-Changed-From-To: open->closed
State-Changed-By: tegge
State-Changed-When: Thu Nov 15 18:23:34 2001
State-Changed-Why:
Fixed in
  lib/libc/stdio/vfprintf.c       1.28 and 1.22.2.2
  lib/libc/stdlib/strtod.c        1.7 and 1.3.8.1
  lib/libc/stdlib/netbsd_strtod.c 1.6 and 1.2.2.2
>Unformatted:
