diff options
author | deraadt <> | 2006-10-29 18:45:56 +0000 |
---|---|---|
committer | deraadt <> | 2006-10-29 18:45:56 +0000 |
commit | aede99584cb0d715ac3f7c41068bc88f09d2a61b (patch) | |
tree | e411f8b9691e52e1f9798a36d7cf41201ee8300d | |
parent | 182ec138408d8727b97aa8a6b7faef3a1c05037b (diff) | |
download | openbsd-aede99584cb0d715ac3f7c41068bc88f09d2a61b.tar.gz openbsd-aede99584cb0d715ac3f7c41068bc88f09d2a61b.tar.bz2 openbsd-aede99584cb0d715ac3f7c41068bc88f09d2a61b.zip |
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-- | src/lib/libc/stdlib/ecvt.c | 14 | ||||
-rw-r--r-- | src/lib/libc/stdlib/gcvt.c | 5 | ||||
-rw-r--r-- | 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 eb0e428996..719370a8f3 100644 --- a/src/lib/libc/stdlib/ecvt.c +++ b/src/lib/libc/stdlib/ecvt.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ecvt.c,v 1.5 2006/01/10 16:18:37 millert Exp $ */ | 1 | /* $OpenBSD: ecvt.c,v 1.6 2006/10/29 18:45:56 deraadt Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2002, 2006 Todd C. Miller <Todd.Miller@courtesan.com> | 4 | * Copyright (c) 2002, 2006 Todd C. Miller <Todd.Miller@courtesan.com> |
@@ -25,13 +25,14 @@ | |||
25 | #include <string.h> | 25 | #include <string.h> |
26 | 26 | ||
27 | extern char *__dtoa(double, int, int, int *, int *, char **); | 27 | extern char *__dtoa(double, int, int, int *, int *, char **); |
28 | extern void __freedtoa(char *); | ||
28 | static char *__cvt(double, int, int *, int *, int, int); | 29 | static char *__cvt(double, int, int *, int *, int, int); |
29 | 30 | ||
30 | static char * | 31 | static char * |
31 | __cvt(double value, int ndigit, int *decpt, int *sign, int fmode, int pad) | 32 | __cvt(double value, int ndigit, int *decpt, int *sign, int fmode, int pad) |
32 | { | 33 | { |
33 | static char *s; | 34 | static char *s; |
34 | char *p, *rve; | 35 | char *p, *rve, c; |
35 | size_t siz; | 36 | size_t siz; |
36 | 37 | ||
37 | if (ndigit == 0) { | 38 | if (ndigit == 0) { |
@@ -64,15 +65,20 @@ __cvt(double value, int ndigit, int *decpt, int *sign, int fmode, int pad) | |||
64 | if (*decpt == 9999) { | 65 | if (*decpt == 9999) { |
65 | /* Infinity or Nan, convert to inf or nan like printf */ | 66 | /* Infinity or Nan, convert to inf or nan like printf */ |
66 | *decpt = 0; | 67 | *decpt = 0; |
67 | return(*p == 'I' ? "inf" : "nan"); | 68 | c = *p; |
69 | __freedtoa(p); | ||
70 | return(c == 'I' ? "inf" : "nan"); | ||
68 | } | 71 | } |
69 | /* Make a local copy and adjust rve to be in terms of s */ | 72 | /* Make a local copy and adjust rve to be in terms of s */ |
70 | if (pad && fmode) | 73 | if (pad && fmode) |
71 | siz += *decpt; | 74 | siz += *decpt; |
72 | if ((s = (char *)malloc(siz)) == NULL) | 75 | if ((s = (char *)malloc(siz)) == NULL) { |
76 | __freedtoa(p); | ||
73 | return(NULL); | 77 | return(NULL); |
78 | } | ||
74 | (void) strlcpy(s, p, siz); | 79 | (void) strlcpy(s, p, siz); |
75 | rve = s + (rve - p); | 80 | rve = s + (rve - p); |
81 | __freedtoa(p); | ||
76 | } | 82 | } |
77 | 83 | ||
78 | /* Add trailing zeros */ | 84 | /* Add trailing zeros */ |
diff --git a/src/lib/libc/stdlib/gcvt.c b/src/lib/libc/stdlib/gcvt.c index bc6295c03d..c24157e465 100644 --- a/src/lib/libc/stdlib/gcvt.c +++ b/src/lib/libc/stdlib/gcvt.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: gcvt.c,v 1.9 2006/01/10 16:18:37 millert Exp $ */ | 1 | /* $OpenBSD: gcvt.c,v 1.10 2006/10/29 18:45:56 deraadt Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2002, 2003, 2006 Todd C. Miller <Todd.Miller@courtesan.com> | 4 | * Copyright (c) 2002, 2003, 2006 Todd C. Miller <Todd.Miller@courtesan.com> |
@@ -26,6 +26,7 @@ | |||
26 | #include <string.h> | 26 | #include <string.h> |
27 | 27 | ||
28 | extern char *__dtoa(double, int, int, int *, int *, char **); | 28 | extern char *__dtoa(double, int, int, int *, int *, char **); |
29 | extern void __freedtoa(char *); | ||
29 | 30 | ||
30 | char * | 31 | char * |
31 | gcvt(double value, int ndigit, char *buf) | 32 | gcvt(double value, int ndigit, char *buf) |
@@ -48,6 +49,7 @@ gcvt(double value, int ndigit, char *buf) | |||
48 | */ | 49 | */ |
49 | snprintf(buf, ndigit + 1, "%s%s", sign ? "-" : "", | 50 | snprintf(buf, ndigit + 1, "%s%s", sign ? "-" : "", |
50 | *digits == 'I' ? "inf" : "nan"); | 51 | *digits == 'I' ? "inf" : "nan"); |
52 | __freedtoa(digits); | ||
51 | return (buf); | 53 | return (buf); |
52 | } | 54 | } |
53 | 55 | ||
@@ -104,5 +106,6 @@ gcvt(double value, int ndigit, char *buf) | |||
104 | } | 106 | } |
105 | *dst = '\0'; | 107 | *dst = '\0'; |
106 | } | 108 | } |
109 | __freedtoa(digits); | ||
107 | return (buf); | 110 | return (buf); |
108 | } | 111 | } |
diff --git a/src/lib/libc/stdlib/strtod.c b/src/lib/libc/stdlib/strtod.c index a8a52e02c5..253bc4ddc0 100644 --- a/src/lib/libc/stdlib/strtod.c +++ b/src/lib/libc/stdlib/strtod.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: strtod.c,v 1.28 2006/10/13 03:50:14 deraadt Exp $ */ | 1 | /* $OpenBSD: strtod.c,v 1.29 2006/10/29 18:45:56 deraadt Exp $ */ |
2 | /**************************************************************** | 2 | /**************************************************************** |
3 | * | 3 | * |
4 | * The author of this software is David M. Gay. | 4 | * The author of this software is David M. Gay. |
@@ -125,6 +125,11 @@ | |||
125 | #define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);} | 125 | #define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);} |
126 | #endif | 126 | #endif |
127 | 127 | ||
128 | #include "thread_private.h" | ||
129 | |||
130 | _THREAD_PRIVATE_KEY(dtoa); | ||
131 | _THREAD_PRIVATE_KEY(pow5mult); | ||
132 | |||
128 | #ifdef __cplusplus | 133 | #ifdef __cplusplus |
129 | #include "malloc.h" | 134 | #include "malloc.h" |
130 | #include "memory.h" | 135 | #include "memory.h" |
@@ -365,21 +370,35 @@ Bigint { | |||
365 | 370 | ||
366 | static Bigint *freelist[Kmax+1]; | 371 | static Bigint *freelist[Kmax+1]; |
367 | 372 | ||
373 | #define PRIVATE_MEM 2304 | ||
374 | #define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double)) | ||
375 | static double private_mem[PRIVATE_mem], *pmem_next = private_mem; | ||
376 | |||
368 | static Bigint * | 377 | static Bigint * |
369 | Balloc(int k) | 378 | Balloc(int k) |
370 | { | 379 | { |
371 | int x; | 380 | int x; |
381 | unsigned int len; | ||
372 | Bigint *rv; | 382 | Bigint *rv; |
373 | 383 | ||
384 | _THREAD_PRIVATE_MUTEX_LOCK(dtoa); | ||
374 | if ((rv = freelist[k])) { | 385 | if ((rv = freelist[k])) { |
375 | freelist[k] = rv->next; | 386 | freelist[k] = rv->next; |
376 | } | 387 | } |
377 | else { | 388 | else { |
378 | x = 1 << k; | 389 | x = 1 << k; |
379 | rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(Long)); | 390 | len = (sizeof(Bigint) + (x-1)*sizeof(Long) + sizeof(double) - 1) |
391 | /sizeof(double); | ||
392 | if (pmem_next - private_mem + len <= PRIVATE_mem) { | ||
393 | rv = (Bigint *)pmem_next; | ||
394 | pmem_next += len; | ||
395 | } | ||
396 | else | ||
397 | rv = (Bigint *)MALLOC(len *sizeof(double)); | ||
380 | rv->k = k; | 398 | rv->k = k; |
381 | rv->maxwds = x; | 399 | rv->maxwds = x; |
382 | } | 400 | } |
401 | _THREAD_PRIVATE_MUTEX_UNLOCK(dtoa); | ||
383 | rv->sign = rv->wds = 0; | 402 | rv->sign = rv->wds = 0; |
384 | return rv; | 403 | return rv; |
385 | } | 404 | } |
@@ -388,14 +407,55 @@ Balloc(int k) | |||
388 | Bfree(Bigint *v) | 407 | Bfree(Bigint *v) |
389 | { | 408 | { |
390 | if (v) { | 409 | if (v) { |
410 | _THREAD_PRIVATE_MUTEX_LOCK(dtoa); | ||
391 | v->next = freelist[v->k]; | 411 | v->next = freelist[v->k]; |
392 | freelist[v->k] = v; | 412 | freelist[v->k] = v; |
413 | _THREAD_PRIVATE_MUTEX_UNLOCK(dtoa); | ||
393 | } | 414 | } |
394 | } | 415 | } |
395 | 416 | ||
396 | #define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \ | 417 | #define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \ |
397 | y->wds*sizeof(Long) + 2*sizeof(int)) | 418 | y->wds*sizeof(Long) + 2*sizeof(int)) |
398 | 419 | ||
420 | /* return value is only used as a simple string, so mis-aligned parts | ||
421 | * inside the Bigint are not at risk on strict align architectures | ||
422 | */ | ||
423 | static char * | ||
424 | rv_alloc(int i) | ||
425 | { | ||
426 | int j, k, *r; | ||
427 | |||
428 | j = sizeof(ULong); | ||
429 | for(k = 0; | ||
430 | sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= i; | ||
431 | j <<= 1) | ||
432 | k++; | ||
433 | r = (int*)Balloc(k); | ||
434 | *r = k; | ||
435 | return (char *)(r+1); | ||
436 | } | ||
437 | |||
438 | static char * | ||
439 | nrv_alloc(char *s, char **rve, int n) | ||
440 | { | ||
441 | char *rv, *t; | ||
442 | |||
443 | t = rv = rv_alloc(n); | ||
444 | while((*t = *s++) !=0) | ||
445 | t++; | ||
446 | if (rve) | ||
447 | *rve = t; | ||
448 | return rv; | ||
449 | } | ||
450 | |||
451 | void | ||
452 | __freedtoa(char *s) | ||
453 | { | ||
454 | Bigint *b = (Bigint *)((int *)s - 1); | ||
455 | b->maxwds = 1 << (b->k = *(int*)b); | ||
456 | Bfree(b); | ||
457 | } | ||
458 | |||
399 | static Bigint * | 459 | static Bigint * |
400 | multadd(Bigint *b, int m, int a) /* multiply by m and add a */ | 460 | multadd(Bigint *b, int m, int a) /* multiply by m and add a */ |
401 | { | 461 | { |
@@ -651,8 +711,10 @@ pow5mult(Bigint *b, int k) | |||
651 | return b; | 711 | return b; |
652 | if (!(p5 = p5s)) { | 712 | if (!(p5 = p5s)) { |
653 | /* first time */ | 713 | /* first time */ |
714 | _THREAD_PRIVATE_MUTEX_LOCK(pow5mult); | ||
654 | p5 = p5s = i2b(625); | 715 | p5 = p5s = i2b(625); |
655 | p5->next = 0; | 716 | p5->next = 0; |
717 | _THREAD_PRIVATE_MUTEX_UNLOCK(pow5mult); | ||
656 | } | 718 | } |
657 | for(;;) { | 719 | for(;;) { |
658 | if (k & 1) { | 720 | if (k & 1) { |
@@ -663,8 +725,12 @@ pow5mult(Bigint *b, int k) | |||
663 | if (!(k >>= 1)) | 725 | if (!(k >>= 1)) |
664 | break; | 726 | break; |
665 | if (!(p51 = p5->next)) { | 727 | if (!(p51 = p5->next)) { |
666 | p51 = p5->next = mult(p5,p5); | 728 | _THREAD_PRIVATE_MUTEX_LOCK(pow5mult); |
667 | p51->next = 0; | 729 | if (!(p51 = p5->next)) { |
730 | p51 = p5->next = mult(p5,p5); | ||
731 | p51->next = 0; | ||
732 | } | ||
733 | _THREAD_PRIVATE_MUTEX_UNLOCK(pow5mult); | ||
668 | } | 734 | } |
669 | p5 = p51; | 735 | p5 = p51; |
670 | } | 736 | } |
@@ -1848,17 +1914,9 @@ __dtoa(double _d, int mode, int ndigits, int *decpt, int *sign, char **rve) | |||
1848 | Bigint *b, *b1, *delta, *mlo, *mhi, *S; | 1914 | Bigint *b, *b1, *delta, *mlo, *mhi, *S; |
1849 | double ds; | 1915 | double ds; |
1850 | char *s, *s0; | 1916 | char *s, *s0; |
1851 | static Bigint *result; | ||
1852 | static int result_k; | ||
1853 | _double d, d2, eps; | 1917 | _double d, d2, eps; |
1854 | 1918 | ||
1855 | value(d) = _d; | 1919 | value(d) = _d; |
1856 | if (result) { | ||
1857 | result->k = result_k; | ||
1858 | result->maxwds = 1 << result_k; | ||
1859 | Bfree(result); | ||
1860 | result = 0; | ||
1861 | } | ||
1862 | 1920 | ||
1863 | if (word0(d) & Sign_bit) { | 1921 | if (word0(d) & Sign_bit) { |
1864 | /* set sign for everything, including 0's and NaNs */ | 1922 | /* 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) | |||
1877 | { | 1935 | { |
1878 | /* Infinity or NaN */ | 1936 | /* Infinity or NaN */ |
1879 | *decpt = 9999; | 1937 | *decpt = 9999; |
1880 | s = | ||
1881 | #ifdef IEEE_Arith | 1938 | #ifdef IEEE_Arith |
1882 | !word1(d) && !(word0(d) & 0xfffff) ? ndigits < 8 ? "Inf" : "Infinity" : | 1939 | if (!word1(d) && !(word0(d) & 0xfffff)) |
1940 | return nrv_alloc("Infinity", rve, 8); | ||
1883 | #endif | 1941 | #endif |
1884 | "NaN"; | 1942 | return nrv_alloc("NaN", rve, 3); |
1885 | if (rve) | ||
1886 | *rve = | ||
1887 | #ifdef IEEE_Arith | ||
1888 | s[3] ? s + 8 : | ||
1889 | #endif | ||
1890 | s + 3; | ||
1891 | return s; | ||
1892 | } | 1943 | } |
1893 | #endif | 1944 | #endif |
1894 | #ifdef IBM | 1945 | #ifdef IBM |
@@ -1896,10 +1947,7 @@ __dtoa(double _d, int mode, int ndigits, int *decpt, int *sign, char **rve) | |||
1896 | #endif | 1947 | #endif |
1897 | if (!value(d)) { | 1948 | if (!value(d)) { |
1898 | *decpt = 1; | 1949 | *decpt = 1; |
1899 | s = "0"; | 1950 | return nrv_alloc("0", rve, 1); |
1900 | if (rve) | ||
1901 | *rve = s + 1; | ||
1902 | return s; | ||
1903 | } | 1951 | } |
1904 | 1952 | ||
1905 | b = d2b(value(d), &be, &bbits); | 1953 | b = d2b(value(d), &be, &bbits); |
@@ -2021,11 +2069,7 @@ __dtoa(double _d, int mode, int ndigits, int *decpt, int *sign, char **rve) | |||
2021 | if (i <= 0) | 2069 | if (i <= 0) |
2022 | i = 1; | 2070 | i = 1; |
2023 | } | 2071 | } |
2024 | j = sizeof(ULong); | 2072 | s = s0 = rv_alloc(i); |
2025 | for(result_k = 0; sizeof(Bigint) - sizeof(ULong) + j <= i; | ||
2026 | j <<= 1) result_k++; | ||
2027 | result = Balloc(result_k); | ||
2028 | s = s0 = (char *)result; | ||
2029 | 2073 | ||
2030 | if (ilim >= 0 && ilim <= Quick_max && try_quick) { | 2074 | if (ilim >= 0 && ilim <= Quick_max && try_quick) { |
2031 | 2075 | ||