summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>2006-10-29 18:45:57 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>2006-10-29 18:45:57 +0000
commit55076a7e5f3140f7be84e40e22c34d7039a6743f (patch)
treeb6961d83a44c0c8393363e2771bd62e5a7bab070
parent720edb472d516d92f44623a2f02ecf0e5d7d84c6 (diff)
make __dtoa & strtod() thread-safe useing the same method as newer gdtoa
codebase. tested mostly by ckuethe and myself. __dtoa() use now requires a call to __freedtoa()
-rw-r--r--lib/libc/stdio/vfprintf.c15
-rw-r--r--lib/libc/stdlib/ecvt.c14
-rw-r--r--lib/libc/stdlib/gcvt.c5
-rw-r--r--lib/libc/stdlib/strtod.c106
4 files changed, 100 insertions, 40 deletions
diff --git a/lib/libc/stdio/vfprintf.c b/lib/libc/stdio/vfprintf.c
index 24ca20a3ccc..e4173e3e4e9 100644
--- a/lib/libc/stdio/vfprintf.c
+++ b/lib/libc/stdio/vfprintf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vfprintf.c,v 1.38 2006/04/29 23:00:23 tedu Exp $ */
+/* $OpenBSD: vfprintf.c,v 1.39 2006/10/29 18:45:55 deraadt Exp $ */
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
@@ -117,6 +117,8 @@ __sbprintf(FILE *fp, const char *fmt, va_list ap)
#define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */
#define DEFPREC 6
+extern char *__dtoa(double, int, int, int *, int *, char **);
+extern void __freedtoa(char *);
static char *cvt(double, int, int, char *, int *, int, int *);
static int exponent(char *, int, int);
@@ -174,6 +176,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 = NULL;
#endif
uintmax_t _umax; /* integer arguments %[diouxX] */
@@ -497,7 +500,9 @@ reswitch: switch (ch) {
}
flags |= FPT;
- cp = cvt(_double, prec, flags, &softsign,
+ if (dtoaresult)
+ __freedtoa(dtoaresult);
+ dtoaresult = cp = cvt(_double, prec, flags, &softsign,
&expt, ch, &ndig);
if (ch == 'g' || ch == 'G') {
if (expt <= -4 || expt > prec)
@@ -782,6 +787,10 @@ number: if ((dprec = prec) >= 0)
done:
FLUSH();
error:
+#ifdef FLOATING_POINT
+ if (dtoaresult)
+ __freedtoa(dtoaresult);
+#endif
if (argtable != NULL && argtable != statargtable) {
munmap(argtable, argtablesiz);
argtable = NULL;
@@ -1173,8 +1182,6 @@ __grow_type_table(unsigned char **typetable, int *tablesize)
#ifdef FLOATING_POINT
-extern char *__dtoa(double, int, int, int *, int *, char **);
-
static char *
cvt(double value, int ndigits, int flags, char *sign, int *decpt, int ch,
int *length)
diff --git a/lib/libc/stdlib/ecvt.c b/lib/libc/stdlib/ecvt.c
index eb0e4289966..719370a8f37 100644
--- a/lib/libc/stdlib/ecvt.c
+++ b/lib/libc/stdlib/ecvt.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ecvt.c,v 1.5 2006/01/10 16:18:37 millert Exp $ */
+/* $OpenBSD: ecvt.c,v 1.6 2006/10/29 18:45:56 deraadt Exp $ */
/*
* Copyright (c) 2002, 2006 Todd C. Miller <Todd.Miller@courtesan.com>
@@ -25,13 +25,14 @@
#include <string.h>
extern char *__dtoa(double, int, int, int *, int *, char **);
+extern void __freedtoa(char *);
static char *__cvt(double, int, int *, int *, int, int);
static char *
__cvt(double value, int ndigit, int *decpt, int *sign, int fmode, int pad)
{
static char *s;
- char *p, *rve;
+ char *p, *rve, c;
size_t siz;
if (ndigit == 0) {
@@ -64,15 +65,20 @@ __cvt(double value, int ndigit, int *decpt, int *sign, int fmode, int pad)
if (*decpt == 9999) {
/* Infinity or Nan, convert to inf or nan like printf */
*decpt = 0;
- return(*p == 'I' ? "inf" : "nan");
+ c = *p;
+ __freedtoa(p);
+ return(c == 'I' ? "inf" : "nan");
}
/* Make a local copy and adjust rve to be in terms of s */
if (pad && fmode)
siz += *decpt;
- if ((s = (char *)malloc(siz)) == NULL)
+ if ((s = (char *)malloc(siz)) == NULL) {
+ __freedtoa(p);
return(NULL);
+ }
(void) strlcpy(s, p, siz);
rve = s + (rve - p);
+ __freedtoa(p);
}
/* Add trailing zeros */
diff --git a/lib/libc/stdlib/gcvt.c b/lib/libc/stdlib/gcvt.c
index bc6295c03de..c24157e465a 100644
--- a/lib/libc/stdlib/gcvt.c
+++ b/lib/libc/stdlib/gcvt.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: gcvt.c,v 1.9 2006/01/10 16:18:37 millert Exp $ */
+/* $OpenBSD: gcvt.c,v 1.10 2006/10/29 18:45:56 deraadt Exp $ */
/*
* Copyright (c) 2002, 2003, 2006 Todd C. Miller <Todd.Miller@courtesan.com>
@@ -26,6 +26,7 @@
#include <string.h>
extern char *__dtoa(double, int, int, int *, int *, char **);
+extern void __freedtoa(char *);
char *
gcvt(double value, int ndigit, char *buf)
@@ -48,6 +49,7 @@ gcvt(double value, int ndigit, char *buf)
*/
snprintf(buf, ndigit + 1, "%s%s", sign ? "-" : "",
*digits == 'I' ? "inf" : "nan");
+ __freedtoa(digits);
return (buf);
}
@@ -104,5 +106,6 @@ gcvt(double value, int ndigit, char *buf)
}
*dst = '\0';
}
+ __freedtoa(digits);
return (buf);
}
diff --git a/lib/libc/stdlib/strtod.c b/lib/libc/stdlib/strtod.c
index a8a52e02c58..253bc4ddc0b 100644
--- a/lib/libc/stdlib/strtod.c
+++ b/lib/libc/stdlib/strtod.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: strtod.c,v 1.28 2006/10/13 03:50:14 deraadt Exp $ */
+/* $OpenBSD: strtod.c,v 1.29 2006/10/29 18:45:56 deraadt Exp $ */
/****************************************************************
*
* The author of this software is David M. Gay.
@@ -125,6 +125,11 @@
#define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);}
#endif
+#include "thread_private.h"
+
+_THREAD_PRIVATE_KEY(dtoa);
+_THREAD_PRIVATE_KEY(pow5mult);
+
#ifdef __cplusplus
#include "malloc.h"
#include "memory.h"
@@ -365,21 +370,35 @@ Bigint {
static Bigint *freelist[Kmax+1];
+#define PRIVATE_MEM 2304
+#define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double))
+ static double private_mem[PRIVATE_mem], *pmem_next = private_mem;
+
static Bigint *
Balloc(int k)
{
int x;
+ unsigned int len;
Bigint *rv;
+ _THREAD_PRIVATE_MUTEX_LOCK(dtoa);
if ((rv = freelist[k])) {
freelist[k] = rv->next;
}
else {
x = 1 << k;
- rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(Long));
+ len = (sizeof(Bigint) + (x-1)*sizeof(Long) + sizeof(double) - 1)
+ /sizeof(double);
+ if (pmem_next - private_mem + len <= PRIVATE_mem) {
+ rv = (Bigint *)pmem_next;
+ pmem_next += len;
+ }
+ else
+ rv = (Bigint *)MALLOC(len *sizeof(double));
rv->k = k;
rv->maxwds = x;
}
+ _THREAD_PRIVATE_MUTEX_UNLOCK(dtoa);
rv->sign = rv->wds = 0;
return rv;
}
@@ -388,14 +407,55 @@ Balloc(int k)
Bfree(Bigint *v)
{
if (v) {
+ _THREAD_PRIVATE_MUTEX_LOCK(dtoa);
v->next = freelist[v->k];
freelist[v->k] = v;
+ _THREAD_PRIVATE_MUTEX_UNLOCK(dtoa);
}
}
#define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \
y->wds*sizeof(Long) + 2*sizeof(int))
+/* return value is only used as a simple string, so mis-aligned parts
+ * inside the Bigint are not at risk on strict align architectures
+ */
+ static char *
+rv_alloc(int i)
+{
+ int j, k, *r;
+
+ j = sizeof(ULong);
+ for(k = 0;
+ sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= i;
+ j <<= 1)
+ k++;
+ r = (int*)Balloc(k);
+ *r = k;
+ return (char *)(r+1);
+ }
+
+ static char *
+nrv_alloc(char *s, char **rve, int n)
+{
+ char *rv, *t;
+
+ t = rv = rv_alloc(n);
+ while((*t = *s++) !=0)
+ t++;
+ if (rve)
+ *rve = t;
+ return rv;
+ }
+
+ void
+__freedtoa(char *s)
+{
+ Bigint *b = (Bigint *)((int *)s - 1);
+ b->maxwds = 1 << (b->k = *(int*)b);
+ Bfree(b);
+ }
+
static Bigint *
multadd(Bigint *b, int m, int a) /* multiply by m and add a */
{
@@ -651,8 +711,10 @@ pow5mult(Bigint *b, int k)
return b;
if (!(p5 = p5s)) {
/* first time */
+ _THREAD_PRIVATE_MUTEX_LOCK(pow5mult);
p5 = p5s = i2b(625);
p5->next = 0;
+ _THREAD_PRIVATE_MUTEX_UNLOCK(pow5mult);
}
for(;;) {
if (k & 1) {
@@ -663,8 +725,12 @@ pow5mult(Bigint *b, int k)
if (!(k >>= 1))
break;
if (!(p51 = p5->next)) {
- p51 = p5->next = mult(p5,p5);
- p51->next = 0;
+ _THREAD_PRIVATE_MUTEX_LOCK(pow5mult);
+ if (!(p51 = p5->next)) {
+ p51 = p5->next = mult(p5,p5);
+ p51->next = 0;
+ }
+ _THREAD_PRIVATE_MUTEX_UNLOCK(pow5mult);
}
p5 = p51;
}
@@ -1848,17 +1914,9 @@ __dtoa(double _d, int mode, int ndigits, int *decpt, int *sign, char **rve)
Bigint *b, *b1, *delta, *mlo, *mhi, *S;
double ds;
char *s, *s0;
- static Bigint *result;
- static int result_k;
_double d, d2, eps;
value(d) = _d;
- 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 */
@@ -1877,18 +1935,11 @@ __dtoa(double _d, int mode, int ndigits, int *decpt, int *sign, char **rve)
{
/* Infinity or NaN */
*decpt = 9999;
- s =
#ifdef IEEE_Arith
- !word1(d) && !(word0(d) & 0xfffff) ? ndigits < 8 ? "Inf" : "Infinity" :
+ if (!word1(d) && !(word0(d) & 0xfffff))
+ return nrv_alloc("Infinity", rve, 8);
#endif
- "NaN";
- if (rve)
- *rve =
-#ifdef IEEE_Arith
- s[3] ? s + 8 :
-#endif
- s + 3;
- return s;
+ return nrv_alloc("NaN", rve, 3);
}
#endif
#ifdef IBM
@@ -1896,10 +1947,7 @@ __dtoa(double _d, int mode, int ndigits, int *decpt, int *sign, char **rve)
#endif
if (!value(d)) {
*decpt = 1;
- s = "0";
- if (rve)
- *rve = s + 1;
- return s;
+ return nrv_alloc("0", rve, 1);
}
b = d2b(value(d), &be, &bbits);
@@ -2021,11 +2069,7 @@ __dtoa(double _d, int mode, int ndigits, int *decpt, int *sign, char **rve)
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;
+ s = s0 = rv_alloc(i);
if (ilim >= 0 && ilim <= Quick_max && try_quick) {