diff options
Diffstat (limited to 'missing/dtoa.c')
| -rw-r--r-- | missing/dtoa.c | 334 |
1 files changed, 213 insertions, 121 deletions
diff --git a/missing/dtoa.c b/missing/dtoa.c index cbee13ee81..ba8cd46ebd 100644 --- a/missing/dtoa.c +++ b/missing/dtoa.c @@ -98,17 +98,6 @@ * if memory is available and otherwise does something you deem * appropriate. If MALLOC is undefined, malloc will be invoked * directly -- and assumed always to succeed. - * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making - * memory allocations from a private pool of memory when possible. - * When used, the private pool is PRIVATE_MEM bytes long: 2304 bytes, - * unless #defined to be a different length. This default length - * suffices to get rid of MALLOC calls except for unusual cases, - * such as decimal-to-binary conversion of a very long string of - * digits. The longest string dtoa can return is about 751 bytes - * long. For conversions by strtod of strings of 800 digits and - * all dtoa conversions in single-threaded executions with 8-byte - * pointers, PRIVATE_MEM >= 7400 appears to suffice; with 4-byte - * pointers, PRIVATE_MEM >= 7112 appears adequate. * #define INFNAN_CHECK on IEEE systems to cause strtod to check for * Infinity and NaN (case insensitively). On some systems (e.g., * some HP systems), it may be necessary to #define NAN_WORD0 @@ -183,15 +172,22 @@ #undef Long #undef ULong -#if SIZEOF_INT == 4 +#include <assert.h> +#include <limits.h> +#include <stddef.h> +#include <stdint.h> + +#if (INT_MAX >> 30) && !(INT_MAX >> 31) #define Long int #define ULong unsigned int -#elif SIZEOF_LONG == 4 +#elif (LONG_MAX >> 30) && !(LONG_MAX >> 31) #define Long long int #define ULong unsigned long int +#else +#error No 32bit integer #endif -#if HAVE_LONG_LONG +#if defined(HAVE_LONG_LONG) && (HAVE_LONG_LONG) #define Llong LONG_LONG #else #define NO_LONG_LONG @@ -202,6 +198,11 @@ #define Bug(x) {fprintf(stderr, "%s\n", (x)); exit(EXIT_FAILURE);} #endif +#ifndef ISDIGIT +#include <ctype.h> +#define ISDIGIT(c) isdigit(c) +#endif +#include <errno.h> #include <stdlib.h> #include <string.h> @@ -209,23 +210,41 @@ #include <locale.h> #endif +#if defined(HAVE_STDCKDINT_H) || !defined(__has_include) +#elif __has_include(<stdckdint.h>) +# define HAVE_STDCKDINT_H 1 +#endif +#ifdef HAVE_STDCKDINT_H +# include <stdckdint.h> +#endif + +#if !defined(ckd_add) +static inline int /* bool */ +ckd_add(int *result, int x, int y) +{ + if (x < 0) { + if (y < INT_MIN - x) return 1; + } + else if (x > 0) { + if (y > INT_MAX - x) return 1; + } + *result = x + y; + return 0; +} +#endif + #ifdef MALLOC extern void *MALLOC(size_t); #else -#define MALLOC xmalloc +#define MALLOC malloc #endif #ifdef FREE extern void FREE(void*); #else -#define FREE xfree -#endif - -#ifndef Omit_Private_Memory -#ifndef PRIVATE_MEM -#define PRIVATE_MEM 2304 +#define FREE free #endif -#define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double)) -static double private_mem[PRIVATE_mem], *pmem_next = private_mem; +#ifndef NO_SANITIZE +#define NO_SANITIZE(x, y) y #endif #undef IEEE_Arith @@ -280,7 +299,7 @@ extern "C" { #endif #ifndef hexdigit -static const char hexdigits[] = "0123456789abcdef0123456789ABCDEF"; +static const char hexdigit[] = "0123456789abcdef0123456789ABCDEF"; #endif #if defined(IEEE_LITTLE_ENDIAN) + defined(IEEE_BIG_ENDIAN) + defined(VAX) + defined(IBM) != 1 @@ -489,6 +508,19 @@ extern double rnd_prod(double, double), rnd_quot(double, double); #define FREE_DTOA_LOCK(n) /*unused right now*/ #endif +#ifndef ATOMIC_PTR_CAS +#define ATOMIC_PTR_CAS(var, old, new) ((var) = (new), (void *)(old)) +#endif +#ifndef LIKELY +#define LIKELY(x) (x) +#endif +#ifndef UNLIKELY +#define UNLIKELY(x) (x) +#endif +#ifndef ASSUME +#define ASSUME(x) (void)(x) +#endif + #define Kmax 15 struct Bigint { @@ -499,57 +531,29 @@ struct Bigint { typedef struct Bigint Bigint; -static Bigint *freelist[Kmax+1]; - static Bigint * Balloc(int k) { int x; Bigint *rv; -#ifndef Omit_Private_Memory - size_t len; -#endif - ACQUIRE_DTOA_LOCK(0); - if (k <= Kmax && (rv = freelist[k]) != 0) { - freelist[k] = rv->next; - } - else { - x = 1 << k; -#ifdef Omit_Private_Memory - rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong)); -#else - len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1) - /sizeof(double); - if (k <= Kmax && pmem_next - private_mem + len <= PRIVATE_mem) { - rv = (Bigint*)pmem_next; - pmem_next += len; - } - else - rv = (Bigint*)MALLOC(len*sizeof(double)); -#endif - rv->k = k; - rv->maxwds = x; - } - FREE_DTOA_LOCK(0); + x = 1 << k; + rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong)); + if (!rv) return NULL; + rv->k = k; + rv->maxwds = x; rv->sign = rv->wds = 0; return rv; } static void -Bfree(Bigint *v) +Bclear(Bigint **vp) { - if (v) { - if (v->k > Kmax) { - FREE(v); - return; - } - ACQUIRE_DTOA_LOCK(0); - v->next = freelist[v->k]; - freelist[v->k] = v; - FREE_DTOA_LOCK(0); - } + Bigint *v = *vp; + *vp = NULL; + if (v) FREE(v); } +#define Bfree(v) Bclear(&(v)) #define Bcopy(x,y) memcpy((char *)&(x)->sign, (char *)&(y)->sign, \ (y)->wds*sizeof(Long) + 2*sizeof(int)) @@ -595,6 +599,10 @@ multadd(Bigint *b, int m, int a) /* multiply by m and add a */ if (carry) { if (wds >= b->maxwds) { b1 = Balloc(b->k+1); + if (!b1) { + Bfree(b); + return NULL; + } Bcopy(b1, b); Bfree(b); b = b1; @@ -616,10 +624,12 @@ s2b(const char *s, int nd0, int nd, ULong y9) for (k = 0, y = 1; x > y; y <<= 1, k++) ; #ifdef Pack_32 b = Balloc(k); + if (!b) return NULL; b->x[0] = y9; b->wds = 1; #else b = Balloc(k+1); + if (!b) return NULL; b->x[0] = y9 & 0xffff; b->wds = (b->x[1] = y9 >> 16) ? 2 : 1; #endif @@ -629,13 +639,16 @@ s2b(const char *s, int nd0, int nd, ULong y9) s += 9; do { b = multadd(b, 10, *s++ - '0'); + if (!b) return NULL; } while (++i < nd0); s++; } else s += 10; - for (; i < nd; i++) + for (; i < nd; i++) { b = multadd(b, 10, *s++ - '0'); + if (!b) return NULL; + } return b; } @@ -717,11 +730,14 @@ i2b(int i) Bigint *b; b = Balloc(1); + if (!b) return NULL; b->x[0] = i; b->wds = 1; return b; } +#define Bzero_p(b) (!(b)->x[0] && (b)->wds <= 1) + static Bigint * mult(Bigint *a, Bigint *b) { @@ -738,6 +754,14 @@ mult(Bigint *a, Bigint *b) #endif #endif + if (Bzero_p(a) || Bzero_p(b)) { + c = Balloc(0); + if (!c) return NULL; + c->wds = 1; + c->x[0] = 0; + return c; + } + if (a->wds < b->wds) { c = a; a = b; @@ -750,6 +774,7 @@ mult(Bigint *a, Bigint *b) if (wc > a->maxwds) k++; c = Balloc(k); + if (!c) return NULL; for (x = c->x, xa = x + wc; x < xa; x++) *x = 0; xa = a->x; @@ -830,48 +855,46 @@ pow5mult(Bigint *b, int k) { Bigint *b1, *p5, *p51; int i; - static int p05[3] = { 5, 25, 125 }; + static const int p05[3] = { 5, 25, 125 }; - if ((i = k & 3) != 0) + if ((i = k & 3) != 0) { b = multadd(b, p05[i-1], 0); + if (!b) return NULL; + } + +#define b_cache(var, addr, new_expr) \ + if ((var = addr) != 0) {} else { \ + Bigint *tmp = 0; \ + ACQUIRE_DTOA_LOCK(1); \ + if (!(var = addr) && (var = (new_expr)) != 0) { \ + var->next = 0; \ + tmp = ATOMIC_PTR_CAS(addr, NULL, var); \ + } \ + FREE_DTOA_LOCK(1); \ + if (UNLIKELY(tmp)) { \ + Bfree(var); \ + var = tmp; \ + } \ + else if (!var) { \ + Bfree(b); \ + return NULL; \ + } \ + } if (!(k >>= 2)) return b; - if (!(p5 = p5s)) { - /* first time */ -#ifdef MULTIPLE_THREADS - ACQUIRE_DTOA_LOCK(1); - if (!(p5 = p5s)) { - p5 = p5s = i2b(625); - p5->next = 0; - } - FREE_DTOA_LOCK(1); -#else - p5 = p5s = i2b(625); - p5->next = 0; -#endif - } + /* first time */ + b_cache(p5, p5s, i2b(625)); for (;;) { if (k & 1) { b1 = mult(b, p5); Bfree(b); b = b1; + if (!b) return NULL; } if (!(k >>= 1)) break; - if (!(p51 = p5->next)) { -#ifdef MULTIPLE_THREADS - ACQUIRE_DTOA_LOCK(1); - if (!(p51 = p5->next)) { - p51 = p5->next = mult(p5,p5); - p51->next = 0; - } - FREE_DTOA_LOCK(1); -#else - p51 = p5->next = mult(p5,p5); - p51->next = 0; -#endif - } + b_cache(p51, p5->next, mult(p5, p5)); p5 = p51; } return b; @@ -884,6 +907,8 @@ lshift(Bigint *b, int k) Bigint *b1; ULong *x, *x1, *xe, z; + if (!k || Bzero_p(b)) return b; + #ifdef Pack_32 n = k >> 5; #else @@ -894,6 +919,10 @@ lshift(Bigint *b, int k) for (i = b->maxwds; n1 > i; i <<= 1) k1++; b1 = Balloc(k1); + if (!b1) { + Bfree(b); + return NULL; + } x1 = b1->x; for (i = 0; i < n; i++) *x1++ = 0; @@ -979,6 +1008,7 @@ diff(Bigint *a, Bigint *b) i = cmp(a,b); if (!i) { c = Balloc(0); + if (!c) return NULL; c->wds = 1; c->x[0] = 0; return c; @@ -992,6 +1022,7 @@ diff(Bigint *a, Bigint *b) else i = 0; c = Balloc(a->k); + if (!c) return NULL; c->sign = i; wa = a->wds; xa = a->x; @@ -1177,6 +1208,7 @@ d2b(double d_, int *e, int *bits) #else b = Balloc(2); #endif + if (!b) return NULL; x = b->x; z = d0 & Frac_mask; @@ -1497,9 +1529,10 @@ break2: aadj = 1.0; nd0 = -4; - if (!*++s || !(s1 = strchr(hexdigit, *s))) goto ret0; + if (!*++s || (!(s1 = strchr(hexdigit, *s)) && *s != '.')) goto ret0; if (*s == '0') { while (*++s == '0'); + if (!*s) goto ret; s1 = strchr(hexdigit, *s); } if (s1 != NULL) { @@ -1510,9 +1543,7 @@ break2: } while (*++s && (s1 = strchr(hexdigit, *s))); } - if (*s == '.') { - dsign = 1; - if (!*++s || !(s1 = strchr(hexdigit, *s))) goto ret0; + if ((*s == '.') && *++s && (s1 = strchr(hexdigit, *s))) { if (nd0 < 0) { while (*s == '0') { s++; @@ -1522,14 +1553,11 @@ break2: for (; *s && (s1 = strchr(hexdigit, *s)); ++s) { adj += aadj * ((s1 - hexdigit) & 15); if ((aadj /= 16) == 0.0) { - while (strchr(hexdigit, *++s)); + while (*++s && strchr(hexdigit, *s)); break; } } } - else { - dsign = 0; - } if (*s == 'P' || *s == 'p') { dsign = 0x2C - *++s; /* +: 2B, -: 2D */ @@ -1552,9 +1580,6 @@ break2: } while ('0' <= c && c <= '9'); nd0 += nd * dsign; } - else { - if (dsign) goto ret0; - } dval(rv) = ldexp(adj, nd0); goto ret; } @@ -1591,9 +1616,9 @@ break2: } #endif if (c == '.') { - if (!ISDIGIT(s[1])) - goto dig_done; c = *++s; + if (!ISDIGIT(c)) + goto dig_done; if (!nd) { for (; c == '0'; c = *++s) nz++; @@ -1934,12 +1959,16 @@ undfl: /* Put digits into bd: true value = bd * 10^e */ bd0 = s2b(s0, nd0, nd, y); + if (!bd0) goto ret; for (;;) { bd = Balloc(bd0->k); + if (!bd) goto retfree; Bcopy(bd, bd0); bb = d2b(dval(rv), &bbe, &bbbits); /* rv = bb * 2^bbe */ + if (!bb) goto retfree; bs = i2b(1); + if (!bs) goto retfree; if (e >= 0) { bb2 = bb5 = 0; @@ -1996,19 +2025,30 @@ undfl: } if (bb5 > 0) { bs = pow5mult(bs, bb5); + if (!bs) goto retfree; bb1 = mult(bs, bb); Bfree(bb); bb = bb1; + if (!bb) goto retfree; } - if (bb2 > 0) + if (bb2 > 0) { bb = lshift(bb, bb2); - if (bd5 > 0) + if (!bb) goto retfree; + } + if (bd5 > 0) { bd = pow5mult(bd, bd5); - if (bd2 > 0) + if (!bd) goto retfree; + } + if (bd2 > 0) { bd = lshift(bd, bd2); - if (bs2 > 0) + if (!bd) goto retfree; + } + if (bs2 > 0) { bs = lshift(bs, bs2); + if (!bs) goto retfree; + } delta = diff(bb, bd); + if (!delta) goto retfree; dsign = delta->sign; delta->sign = 0; i = cmp(delta, bs); @@ -2041,6 +2081,7 @@ undfl: #endif { delta = lshift(delta,Log2P); + if (!delta) goto nomem; if (cmp(delta, bs) <= 0) adj = -0.5; } @@ -2130,6 +2171,7 @@ apply_adj: break; } delta = lshift(delta,Log2P); + if (!delta) goto retfree; if (cmp(delta, bs) > 0) goto drop_down; break; @@ -2520,10 +2562,10 @@ static char *dtoa_result; static char * rv_alloc(int i) { - return dtoa_result = xmalloc(i); + return dtoa_result = MALLOC(i); } #else -#define rv_alloc(i) xmalloc(i) +#define rv_alloc(i) MALLOC(i) #endif static char * @@ -2532,6 +2574,7 @@ nrv_alloc(const char *s, char **rve, size_t n) char *rv, *t; t = rv = rv_alloc(n); + if (!rv) return NULL; while ((*t = *s++) != 0) t++; if (rve) *rve = t; @@ -2550,7 +2593,7 @@ nrv_alloc(const char *s, char **rve, size_t n) static void freedtoa(char *s) { - xfree(s); + FREE(s); } #endif @@ -2704,6 +2747,7 @@ dtoa(double d_, int mode, int ndigits, int *decpt, int *sign, char **rve) #endif b = d2b(dval(d), &be, &bbits); + if (!b) return NULL; #ifdef Sudden_Underflow i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)); #else @@ -2823,13 +2867,20 @@ dtoa(double d_, int mode, int ndigits, int *decpt, int *sign, char **rve) leftright = 0; /* no break */ case 5: - i = ndigits + k + 1; + if (ckd_add(&i, ndigits, k + 1)) { /* k + 1 should be safe */ + Bfree(b); + return NULL; + } ilim = i; ilim1 = i - 1; if (i <= 0) i = 1; } s = s0 = rv_alloc(i+1); + if (!s) { + Bfree(b); + return NULL; + } #ifdef Honor_FLT_ROUNDS if (mode > 1 && rounding != 1) @@ -3010,6 +3061,7 @@ bump_up: b2 += i; s2 += i; mhi = i2b(1); + if (!mhi) goto nomem; } if (m2 > 0 && s2 > 0) { i = m2 < s2 ? m2 : s2; @@ -3021,19 +3073,28 @@ bump_up: if (leftright) { if (m5 > 0) { mhi = pow5mult(mhi, m5); + if (!mhi) goto nomem; b1 = mult(mhi, b); Bfree(b); b = b1; + if (!b) goto nomem; } - if ((j = b5 - m5) != 0) + if ((j = b5 - m5) != 0) { b = pow5mult(b, j); + if (!b) goto nomem; + } } - else + else { b = pow5mult(b, b5); + if (!b) goto nomem; + } } S = i2b(1); - if (s5 > 0) + if (!S) goto nomem; + if (s5 > 0) { S = pow5mult(S, s5); + if (!S) goto nomem; + } /* Check for special case that d is a normalized power of 2. */ @@ -3081,16 +3142,23 @@ bump_up: m2 += i; s2 += i; } - if (b2 > 0) + if (b2 > 0) { b = lshift(b, b2); - if (s2 > 0) + if (!b) goto nomem; + } + if (s2 > 0) { S = lshift(S, s2); + if (!S) goto nomem; + } if (k_check) { if (cmp(b,S) < 0) { k--; b = multadd(b, 10, 0); /* we botched the k estimate */ - if (leftright) + if (!b) goto nomem; + if (leftright) { mhi = multadd(mhi, 10, 0); + if (!mhi) goto nomem; + } ilim = ilim1; } } @@ -3107,8 +3175,10 @@ one_digit: goto ret; } if (leftright) { - if (m2 > 0) + if (m2 > 0) { mhi = lshift(mhi, m2); + if (!mhi) goto nomem; + } /* Compute mlo -- check for special case * that d is a normalized power of 2. @@ -3117,8 +3187,10 @@ one_digit: mlo = mhi; if (spec_case) { mhi = Balloc(mhi->k); + if (!mhi) goto nomem; Bcopy(mhi, mlo); mhi = lshift(mhi, Log2P); + if (!mhi) goto nomem; } for (i = 1;;i++) { @@ -3128,6 +3200,7 @@ one_digit: */ j = cmp(b, mlo); delta = diff(S, mhi); + if (!delta) goto nomem; j1 = delta->sign ? 1 : cmp(b, delta); Bfree(delta); #ifndef ROUND_BIASED @@ -3168,6 +3241,7 @@ one_digit: #endif /*Honor_FLT_ROUNDS*/ if (j1 > 0) { b = lshift(b, 1); + if (!b) goto nomem; j1 = cmp(b, S); if ((j1 > 0 || (j1 == 0 && (dig & 1))) && dig++ == '9') goto round_9_up; @@ -3196,11 +3270,16 @@ keep_dig: if (i == ilim) break; b = multadd(b, 10, 0); - if (mlo == mhi) + if (!b) goto nomem; + if (mlo == mhi) { mlo = mhi = multadd(mhi, 10, 0); + if (!mlo) goto nomem; + } else { mlo = multadd(mlo, 10, 0); + if (!mlo) goto nomem; mhi = multadd(mhi, 10, 0); + if (!mhi) goto nomem; } } } @@ -3216,6 +3295,7 @@ keep_dig: if (i >= ilim) break; b = multadd(b, 10, 0); + if (!b) goto nomem; } /* Round off last digit */ @@ -3227,6 +3307,7 @@ keep_dig: } #endif b = lshift(b, 1); + if (!b) goto nomem; j = cmp(b, S); if (j > 0 || (j == 0 && (dig & 1))) { roundoff: @@ -3268,6 +3349,16 @@ ret1: if (rve) *rve = s; return s0; + nomem: + if (S) Bfree(S); + if (mhi) { + if (mlo && mlo != mhi) + Bfree(mlo); + Bfree(mhi); + } + if (b) Bfree(b); + FREE(s0); + return NULL; } /*- @@ -3376,6 +3467,7 @@ hdtoa(double d, const char *xdigs, int ndigits, int *decpt, int *sign, char **rv */ bufsize = (ndigits > 0) ? ndigits : SIGFIGS; s0 = rv_alloc(bufsize+1); + if (!s0) return NULL; /* Round to the desired number of digits. */ if (SIGFIGS > ndigits && ndigits > 0) { |
