Bug 15070

Summary: vfprintf/cvt/__dtoa race condition in threaded programs
Product: Base System Reporter: Tor Egge <tegge>
Component: binAssignee: tegge
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: 4.0-CURRENT   
Hardware: Any   
OS: Any   

Description Tor Egge 1999-11-24 05:10:01 UTC
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
Comment 1 Tor Egge 2001-01-15 02:35:04 UTC
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();
 	}
 }
Comment 2 peter 2001-01-15 03:26:04 UTC
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
Comment 3 Tor Egge 2001-01-15 03:51:54 UTC
> 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
Comment 4 Tor Egge 2001-01-15 21:48:55 UTC
> 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
Comment 5 Tor Egge 2001-01-16 02:11:04 UTC
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
Comment 6 Tor Egge 2001-02-14 21:02:36 UTC
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) {
Comment 7 eischen 2001-02-15 03:26:00 UTC
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
Comment 8 Mike Barcroft freebsd_committer freebsd_triage 2001-07-21 04:17:28 UTC
Responsible Changed
From-To: freebsd-bugs->tegge


Tor Egge is a committer.  He seems to have a good idea what needs 
to be fixed.
Comment 9 tegge freebsd_committer freebsd_triage 2001-11-15 18:23:34 UTC
State Changed
From-To: open->closed

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