From d93ead21a255a62c38001766d61df898b36ab17c Mon Sep 17 00:00:00 2001
From: tegge <tegge@FreeBSD.org>
Date: Thu, 8 Feb 2001 20:22:28 +0000
Subject: Protect freelists managed by Balloc/Bfree with a spinlock. Change
 __dtoa to not free the string it allocated the previous time it was called. 
 The caller now frees the string after usage if appropiate.

PR:		15070
---
 lib/libc/stdio/vfprintf.c       | 23 ++++++++++++++++++-----
 lib/libc/stdlib/netbsd_strtod.c | 40 ++++++++++++++++++++++------------------
 lib/libc/stdlib/strtod.c        | 40 +++++++++++++++++++++++-----------------
 3 files changed, 63 insertions(+), 40 deletions(-)

diff --git a/lib/libc/stdio/vfprintf.c b/lib/libc/stdio/vfprintf.c
index fff9aa8..afb10b0 100644
--- a/lib/libc/stdio/vfprintf.c
+++ b/lib/libc/stdio/vfprintf.c
@@ -267,7 +267,7 @@ vfprintf(FILE *fp, const char *fmt0, va_list ap)
 #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 */
@@ -313,6 +313,7 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap)
 	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 */
@@ -421,6 +422,9 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap)
         }
         
 
+#ifdef FLOATING_POINT
+	dtoaresult = NULL;
+#endif
 	/* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
 	if (cantwrite(fp))
 		return (EOF);
@@ -606,8 +610,12 @@ fp_begin:		if (prec == -1)
 				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';
@@ -863,6 +871,10 @@ number:			if ((dprec = prec) >= 0)
 done:
 	FLUSH();
 error:
+#ifdef FLOATING_POINT
+	if (dtoaresult != NULL)
+		free(dtoaresult);
+#endif
 	if (__sferror(fp))
 		ret = EOF;
         if ((argtable != NULL) && (argtable != statargtable))
@@ -1194,11 +1206,11 @@ __grow_type_table (int nextarg, unsigned char **typetable, int *tablesize)
 
 #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;
@@ -1220,7 +1232,8 @@ cvt(double value, int ndigits, int flags, char *sign, int *decpt,
 		*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;
diff --git a/lib/libc/stdlib/netbsd_strtod.c b/lib/libc/stdlib/netbsd_strtod.c
index a402b68..ea0dbcd 100644
--- a/lib/libc/stdlib/netbsd_strtod.c
+++ b/lib/libc/stdlib/netbsd_strtod.c
@@ -142,7 +142,7 @@ __RCSID("$NetBSD: strtod.c,v 1.26 1998/02/03 18:44:21 perry Exp $");
 #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
@@ -384,6 +384,16 @@ Bigint {
 
  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
@@ -395,10 +405,13 @@ Balloc
 	int x;
 	Bigint *rv;
 
+	THREAD_LOCK();
 	if ((rv = freelist[k]) != NULL) {
 		freelist[k] = rv->next;
+		THREAD_UNLOCK();
 		}
 	else {
+		THREAD_UNLOCK();
 		x = 1 << k;
 		rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(Long));
 		rv->k = k;
@@ -417,8 +430,10 @@ Bfree
 #endif
 {
 	if (v) {
+		THREAD_LOCK();
 		v->next = freelist[v->k];
 		freelist[v->k] = v;
+		THREAD_UNLOCK();
 		}
 	}
 
@@ -1900,10 +1915,11 @@ quorem
  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 +1969,6 @@ __dtoa
 	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 +2130,8 @@ __dtoa
 			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) {
 
diff --git a/lib/libc/stdlib/strtod.c b/lib/libc/stdlib/strtod.c
index 27fb499..e70a965 100644
--- a/lib/libc/stdlib/strtod.c
+++ b/lib/libc/stdlib/strtod.c
@@ -29,6 +29,8 @@
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
+ *
+ * $FreeBSD$
  */
 
 #if defined(LIBC_SCCS) && !defined(lint)
@@ -371,6 +373,16 @@ Bigint {
 
  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 +394,12 @@ Balloc
 	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 +418,10 @@ Bfree
 #endif
 {
 	if (v) {
+		THREAD_LOCK();
 		v->next = freelist[v->k];
 		freelist[v->k] = v;
+		THREAD_UNLOCK();
 	}
 }
 
@@ -1839,10 +1856,11 @@ quorem
 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 +1908,6 @@ __dtoa
 	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 +2066,8 @@ __dtoa
 			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) {
 
-- 
cgit v1.1