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 /src/lib/libc/stdlib | |
| 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()
Diffstat (limited to '')
| -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 | ||
