From 888249e0c1520e606373f3e509bcbd7da7f47b9b Mon Sep 17 00:00:00 2001 From: deraadt <> Date: Sun, 29 Oct 2006 18:45:56 +0000 Subject: [PATCH] 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() --- src/lib/libc/stdlib/ecvt.c | 14 +++-- src/lib/libc/stdlib/gcvt.c | 5 +- src/lib/libc/stdlib/strtod.c | 106 +++++++++++++++++++++++++---------- 3 files changed, 89 insertions(+), 36 deletions(-) diff --git a/src/lib/libc/stdlib/ecvt.c b/src/lib/libc/stdlib/ecvt.c index eb0e4289..719370a8 100644 --- a/src/lib/libc/stdlib/ecvt.c +++ b/src/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 @@ -25,13 +25,14 @@ #include 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/src/lib/libc/stdlib/gcvt.c b/src/lib/libc/stdlib/gcvt.c index bc6295c0..c24157e4 100644 --- a/src/lib/libc/stdlib/gcvt.c +++ b/src/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 @@ -26,6 +26,7 @@ #include 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/src/lib/libc/stdlib/strtod.c b/src/lib/libc/stdlib/strtod.c index a8a52e02..253bc4dd 100644 --- a/src/lib/libc/stdlib/strtod.c +++ b/src/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) {