diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 2006-10-29 18:45:57 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 2006-10-29 18:45:57 +0000 |
commit | 55076a7e5f3140f7be84e40e22c34d7039a6743f (patch) | |
tree | b6961d83a44c0c8393363e2771bd62e5a7bab070 | |
parent | 720edb472d516d92f44623a2f02ecf0e5d7d84c6 (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.c | 15 | ||||
-rw-r--r-- | lib/libc/stdlib/ecvt.c | 14 | ||||
-rw-r--r-- | lib/libc/stdlib/gcvt.c | 5 | ||||
-rw-r--r-- | lib/libc/stdlib/strtod.c | 106 |
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) { |