Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 15 Jan 2001 13:50:06 -0800 (PST)
From:      Tor.Egge@fast.no
To:        freebsd-bugs@FreeBSD.org
Subject:   Re: bin/15070: vfprintf/cvt/__dtoa race condition in threaded programs
Message-ID:  <200101152150.f0FLo6P19676@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help
The following reply was made to PR bin/15070; it has been noted by GNATS.

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
 


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200101152150.f0FLo6P19676>