diff --git a/mozilla/js/src/jsdtoa.c b/mozilla/js/src/jsdtoa.c index 09d91170a18..3f2af35157b 100644 --- a/mozilla/js/src/jsdtoa.c +++ b/mozilla/js/src/jsdtoa.c @@ -90,9 +90,9 @@ /* strtod for IEEE-arithmetic machines. * * This strtod returns a nearest machine number to the input decimal - * string (or sets err to ERANGE). With IEEE arithmetic, ties are - * broken by the IEEE round-even rule. Otherwise ties are broken by - * biased rounding (add half and chop). + * string (or sets err to JS_DTOA_ERANGE or JS_DTOA_ENOMEM). With IEEE + * arithmetic, ties are broken by the IEEE round-even rule. Otherwise + * ties are broken by biased rounding (add half and chop). * * Inspired loosely by William D. Clinger's paper "How to Read Floating * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101]. @@ -205,7 +205,6 @@ extern void *MALLOC(size_t); static double private_mem[PRIVATE_mem], *pmem_next = private_mem; #endif -#include "errno.h" #ifdef Bad_float_h #undef __STDC__ @@ -327,6 +326,52 @@ struct Bigint { ULong x[1]; /* wds words of number in little endian order */ }; +#ifdef ENABLE_OOM_TESTING +/* Out-of-memory testing. Use a good testcase (over and over) and then use + * these routines to cause a memory failure on every possible Balloc allocation, + * to make sure that all out-of-memory paths can be followed. See bug 14044. + */ + +static int allocationNum; /* which allocation is next? */ +static int desiredFailure; /* which allocation should fail? */ + +/** + * js_BigintTestingReset + * + * Call at the beginning of a test run to set the allocation failure position. + * (Set to 0 to just have the engine count allocations without failing.) + */ +JS_PUBLIC_API(void) +js_BigintTestingReset(int newFailure) +{ + allocationNum = 0; + desiredFailure = newFailure; +} + +/** + * js_BigintTestingWhere + * + * Report the current allocation position. This is really only useful when you + * want to learn how many allocations a test run has. + */ +JS_PUBLIC_API(int) +js_BigintTestingWhere() +{ + return allocationNum; +} + + +/* + * So here's what you do: Set up a fantastic test case that exercises the + * elements of the code you wish. Set the failure point at 0 and run the test, + * then get the allocation position. This number is the number of allocations + * your test makes. Now loop from 1 to that number, setting the failure point + * at each loop count, and run the test over and over, causing failures at each + * step. Any memory failure *should* cause a Out-Of-Memory exception; if it + * doesn't, then there's still an error here. + */ +#endif + typedef struct Bigint Bigint; static Bigint *freelist[Kmax+1]; @@ -343,6 +388,13 @@ static Bigint *Balloc(int32 k) uint32 len; #endif +#ifdef ENABLE_OOM_TESTING + if (++allocationNum == desiredFailure) { + printf("Forced Failing Allocation number %d\n", allocationNum); + return NULL; + } +#endif + if ((rv = freelist[k]) != NULL) freelist[k] = rv->next; if (rv == NULL) { @@ -359,6 +411,8 @@ static Bigint *Balloc(int32 k) else rv = (Bigint*)MALLOC(len*sizeof(double)); #endif + if (!rv) + return NULL; rv->k = k; rv->maxwds = x; } @@ -377,7 +431,9 @@ static void Bfree(Bigint *v) #define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \ y->wds*sizeof(Long) + 2*sizeof(int32)) -/* Return b*m + a. Deallocate the old b. Both a and m must be between 0 and 65535 inclusive. */ +/* Return b*m + a. Deallocate the old b. Both a and m must be between 0 and + * 65535 inclusive. NOTE: old b is deallocated on memory failure. + */ static Bigint *multadd(Bigint *b, int32 m, int32 a) { int32 i, wds; @@ -390,6 +446,17 @@ static Bigint *multadd(Bigint *b, int32 m, int32 a) #endif Bigint *b1; +#ifdef ENABLE_OOM_TESTING + if (++allocationNum == desiredFailure) { + /* Faux allocation, because I'm not getting all of the failure paths + * without it. + */ + printf("Forced Failing Allocation number %d\n", allocationNum); + Bfree(b); + return NULL; + } +#endif + wds = b->wds; x = b->x; i = 0; @@ -411,6 +478,10 @@ static Bigint *multadd(Bigint *b, int32 m, int32 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; @@ -430,20 +501,28 @@ static Bigint *s2b(CONST char *s, int32 nd0, int32 nd, ULong y9) x = (nd + 8) / 9; for(k = 0, y = 1; x > y; y <<= 1, k++) ; b = Balloc(k); + if (!b) + return NULL; b->x[0] = y9; b->wds = 1; i = 9; if (9 < nd0) { s += 9; - do b = multadd(b, 10, *s++ - '0'); - while(++i < nd0); + 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; } @@ -529,6 +608,8 @@ static Bigint *i2b(int32 i) Bigint *b; b = Balloc(1); + if (!b) + return NULL; b->x[0] = i; b->wds = 1; return b; @@ -562,6 +643,8 @@ static Bigint *mult(CONST Bigint *a, CONST Bigint *b) if (wc > a->maxwds) k++; c = Balloc(k); + if (!c) + return NULL; for(xc = c->x, xce = xc + wc; xc < xce; xc++) *xc = 0; xa = a->x; @@ -639,14 +722,18 @@ static PRLock *p5s_lock; #endif /* Return b * 5^k. Deallocate the old b. k must be nonnegative. */ +/* NOTE: old b is deallocated on memory failure. */ static Bigint *pow5mult(Bigint *b, int32 k) { Bigint *b1, *p5, *p51; int32 i; static CONST int32 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; + } if (!(k >>= 2)) return b; @@ -658,6 +745,10 @@ static Bigint *pow5mult(Bigint *b, int32 k) */ Bigint *wasted_effort = NULL; p5 = i2b(625); + if (!p5) { + Bfree(b); + return NULL; + } /* lock and check again */ PR_Lock(p5s_lock); if (!p5s) { @@ -676,6 +767,10 @@ static Bigint *pow5mult(Bigint *b, int32 k) #else /* first time */ p5 = p5s = i2b(625); + if (!p5) { + Bfree(b); + return NULL; + } p5->next = 0; #endif } @@ -683,6 +778,8 @@ static Bigint *pow5mult(Bigint *b, int32 k) if (k & 1) { b1 = mult(b, p5); Bfree(b); + if (!b1) + return NULL; b = b1; } if (!(k >>= 1)) @@ -691,6 +788,10 @@ static Bigint *pow5mult(Bigint *b, int32 k) #ifdef JS_THREADSAFE Bigint *wasted_effort = NULL; p51 = mult(p5, p5); + if (!p51) { + Bfree(b); + return NULL; + } PR_Lock(p5s_lock); if (!p5->next) { p5->next = p51; @@ -704,8 +805,13 @@ static Bigint *pow5mult(Bigint *b, int32 k) Bfree(wasted_effort); } #else - p51 = p5->next = mult(p5,p5); + p51 = mult(p5,p5); + if (!p51) { + Bfree(b); + return NULL; + } p51->next = 0; + p5->next = p51; #endif } p5 = p51; @@ -713,7 +819,8 @@ static Bigint *pow5mult(Bigint *b, int32 k) return b; } -/* Return b * 2^k. Deallocate the old b. k must be nonnegative. */ +/* Return b * 2^k. Deallocate the old b. k must be nonnegative. + * NOTE: on memory failure, old b is deallocated. */ static Bigint *lshift(Bigint *b, int32 k) { int32 i, k1, n, n1; @@ -726,6 +833,8 @@ static Bigint *lshift(Bigint *b, int32 k) for(i = b->maxwds; n1 > i; i <<= 1) k1++; b1 = Balloc(k1); + if (!b1) + goto done; x1 = b1->x; for(i = 0; i < n; i++) *x1++ = 0; @@ -746,6 +855,7 @@ static Bigint *lshift(Bigint *b, int32 k) *x1++ = *x++; while(x < xe); b1->wds = n1 - 1; +done: Bfree(b); return b1; } @@ -794,6 +904,8 @@ static Bigint *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; @@ -807,6 +919,8 @@ static Bigint *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; @@ -939,6 +1053,8 @@ static Bigint *d2b(double d, int32 *e, int32 *bits) #define set_d1(x) set_word1(d, x) b = Balloc(1); + if (!b) + return NULL; x = b->x; z = d0 & Frac_mask; @@ -1069,8 +1185,7 @@ void js_FinishDtoa(void) Bigint *temp; #ifdef JS_THREADSAFE - if (initialized == JS_TRUE) - { + if (initialized == JS_TRUE) { PR_DestroyLock(freelist_lock); PR_DestroyLock(p5s_lock); initialized = JS_FALSE; @@ -1080,11 +1195,9 @@ void js_FinishDtoa(void) /* clear down the freelist array and p5s */ /* static Bigint *freelist[Kmax+1]; */ - for (count = 0; count <= Kmax; count++) - { + for (count = 0; count <= Kmax; count++) { Bigint **listp = &freelist[count]; - while ((temp = *listp) != NULL) - { + while ((temp = *listp) != NULL) { *listp = temp->next; free(temp); } @@ -1092,8 +1205,7 @@ void js_FinishDtoa(void) } /* static Bigint *p5s; */ - while (p5s) - { + while (p5s) { temp = p5s; p5s = p5s->next; free(temp); @@ -1315,7 +1427,7 @@ dig_done: if (e1 &= ~15) { if (e1 > DBL_MAX_10_EXP) { ovfl: - *err = ERANGE; + *err = JS_DTOA_ERANGE; #ifdef __STDC__ rv = HUGE_VAL; #else @@ -1386,7 +1498,7 @@ dig_done: if (!rv) { undfl: rv = 0.; - *err = ERANGE; + *err = JS_DTOA_ERANGE; if (bd0) goto retfree; goto ret; @@ -1407,12 +1519,20 @@ dig_done: /* Put digits into bd: true value = bd * 10^e */ bd0 = s2b(s0, nd0, nd, y); + if (!bd0) + goto nomem; for(;;) { bd = Balloc(bd0->k); + if (!bd) + goto nomem; Bcopy(bd, bd0); bb = d2b(rv, &bbe, &bbbits); /* rv = bb * 2^bbe */ + if (!bb) + goto nomem; bs = i2b(1); + if (!bs) + goto nomem; if (e >= 0) { bb2 = bb5 = 0; @@ -1456,19 +1576,37 @@ dig_done: } if (bb5 > 0) { bs = pow5mult(bs, bb5); + if (!bs) + goto nomem; bb1 = mult(bs, bb); + if (!bb1) + goto nomem; Bfree(bb); bb = bb1; } - if (bb2 > 0) + if (bb2 > 0) { bb = lshift(bb, bb2); - if (bd5 > 0) + if (!bb) + goto nomem; + } + if (bd5 > 0) { bd = pow5mult(bd, bd5); - if (bd2 > 0) + if (!bd) + goto nomem; + } + if (bd2 > 0) { bd = lshift(bd, bd2); - if (bs2 > 0) + if (!bd) + goto nomem; + } + if (bs2 > 0) { bs = lshift(bs, bs2); + if (!bs) + goto nomem; + } delta = diff(bb, bd); + if (!delta) + goto nomem; dsign = delta->sign; delta->sign = 0; i = cmp(delta, bs); @@ -1490,6 +1628,8 @@ dig_done: break; } delta = lshift(delta,Log2P); + if (!delta) + goto nomem; if (cmp(delta, bs) > 0) goto drop_down; break; @@ -1675,6 +1815,7 @@ dig_done: Bfree(bd); Bfree(bs); Bfree(delta); + bb = bd = bs = delta = NULL; } #ifdef Avoid_Underflow if (scale) { @@ -1709,6 +1850,15 @@ ret: if (se) *se = (char *)s; return sign ? -rv : rv; + +nomem: + Bfree(bb); + Bfree(bd); + Bfree(bs); + Bfree(bd0); + Bfree(delta); + *err = JS_DTOA_ENOMEM; + return 0; } @@ -1983,6 +2133,8 @@ js_dtoa(double d, int mode, JSBool biasUp, int ndigits, } b = d2b(d, &be, &bbits); + if (!b) + goto nomem; #ifdef Sudden_Underflow i = (int32)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)); #else @@ -2286,6 +2438,8 @@ js_dtoa(double d, int mode, JSBool biasUp, int ndigits, b2 += i; s2 += i; mhi = i2b(1); + if (!mhi) + goto nomem; /* (mhi * 2^m2 * 5^m5) / (2^s2 * 5^s5) = one-half of last printed (when mode >= 2) or input (when mode < 2) significant digit, divided by 10^k. */ } @@ -2303,22 +2457,37 @@ js_dtoa(double d, int mode, JSBool biasUp, int ndigits, if (leftright) { if (m5 > 0) { mhi = pow5mult(mhi, m5); + if (!mhi) + goto nomem; b1 = mult(mhi, b); + if (!b1) + goto nomem; Bfree(b); b = b1; } - 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; + } } /* Now we have d/10^k = (b * 2^b2) / (2^s2 * 5^s5) and (mhi * 2^m2) / (2^s2 * 5^s5) = one-half of last printed or input significant digit, divided by 10^k. */ S = i2b(1); - if (s5 > 0) + if (!S) + goto nomem; + if (s5 > 0) { S = pow5mult(S, s5); + if (!S) + goto nomem; + } /* Now we have d/10^k = (b * 2^b2) / (S * 2^s2) and (mhi * 2^m2) / (S * 2^s2) = one-half of last printed or input significant digit, divided by 10^k. */ @@ -2361,18 +2530,29 @@ js_dtoa(double d, int mode, JSBool biasUp, int ndigits, s2 += i; } /* Now S*2^s2 has exactly four leading zero bits in its most significant word. */ - 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; + } /* Now we have d/10^k = b/S and (mhi * 2^m2) / S = maximum acceptable error, divided by 10^k. */ 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; } } @@ -2381,7 +2561,13 @@ js_dtoa(double d, int mode, JSBool biasUp, int ndigits, if (ilim <= 0 && mode > 2) { /* We're doing fixed-mode output and d is less than the minimum nonzero output in this mode. Output either zero or the minimum nonzero output depending on which is closer to d. */ - if (ilim < 0 || (i = cmp(b,S = multadd(S,5,0))) < 0 || (i == 0 && !biasUp)) { + if (ilim < 0) + goto no_digits; + S = multadd(S,5,0); + if (!S) + goto nomem; + i = cmp(b,S); + if (i < 0 || (i == 0 && !biasUp)) { /* Always emit at least one digit. If the number appears to be zero using the current mode, then emit one '0' digit and set decpt to 1. */ /*no_digits: @@ -2395,8 +2581,11 @@ js_dtoa(double d, int mode, JSBool biasUp, int ndigits, 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. @@ -2405,8 +2594,12 @@ js_dtoa(double d, int mode, JSBool biasUp, int ndigits, mlo = mhi; if (spec_case) { mhi = Balloc(mhi->k); + if (!mhi) + goto nomem; Bcopy(mhi, mlo); mhi = lshift(mhi, Log2P); + if (!mhi) + goto nomem; } /* mlo/S = maximum acceptable error, divided by 10^k, if the output is less than d. */ /* mhi/S = maximum acceptable error, divided by 10^k, if the output is greater than d. */ @@ -2419,6 +2612,8 @@ js_dtoa(double d, int mode, JSBool biasUp, int ndigits, j = cmp(b, mlo); /* j is b/S compared with mlo/S. */ delta = diff(S, mhi); + if (!delta) + goto nomem; j1 = delta->sign ? 1 : cmp(b, delta); Bfree(delta); /* j1 is b/S compared with 1 - mhi/S. */ @@ -2441,6 +2636,8 @@ js_dtoa(double d, int mode, JSBool biasUp, int ndigits, /* Either dig or dig+1 would work here as the least significant decimal digit. Use whichever would produce a decimal value closer to d. */ b = lshift(b, 1); + if (!b) + goto nomem; j1 = cmp(b, S); if (((j1 > 0) || (j1 == 0 && (dig & 1 || biasUp))) && (dig++ == '9')) @@ -2462,11 +2659,20 @@ js_dtoa(double d, int mode, JSBool biasUp, int ndigits, 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 (!mhi) + goto nomem; + } else { mlo = multadd(mlo, 10, 0); + if (!mlo) + goto nomem; mhi = multadd(mhi, 10, 0); + if (!mhi) + goto nomem; } } } @@ -2476,11 +2682,15 @@ js_dtoa(double d, int mode, JSBool biasUp, int ndigits, if (i >= ilim) break; b = multadd(b, 10, 0); + if (!b) + goto nomem; } /* Round off last digit */ b = lshift(b, 1); + if (!b) + goto nomem; j = cmp(b, S); if ((j > 0) || (j == 0 && (dig & 1 || biasUp))) { roundoff: @@ -2512,6 +2722,16 @@ js_dtoa(double d, int mode, JSBool biasUp, int ndigits, *rve = s; *decpt = k + 1; return JS_TRUE; + +nomem: + Bfree(S); + if (mhi) { + if (mlo && mlo != mhi) + Bfree(mlo); + Bfree(mhi); + } + Bfree(b); + return JS_FALSE; } @@ -2737,12 +2957,17 @@ JS_dtobasestr(int base, double d) } while (n); else *p++ = '0'; } else { - /* XXX We really should check for null here, but none of the routines we call is out-of-memory-safe, - * so this change would need to be made pervasively in this file. */ int32 e; int32 bits; /* Number of significant bits in di; not used. */ Bigint *b = d2b(di, &e, &bits); + if (!b) + goto nomem1; b = lshift(b, e); + if (!b) { + nomem1: + Bfree(b); + return NULL; + } do { digit = divrem(b, base); JS_ASSERT(digit < (uint32)base); @@ -2763,9 +2988,20 @@ JS_dtobasestr(int base, double d) /* We have a fraction. */ int32 e, bbits, s2, done; Bigint *b, *s, *mlo, *mhi; + + b = s = mlo = mhi = NULL; *p++ = '.'; b = d2b(df, &e, &bbits); + if (!b) { + nomem2: + Bfree(b); + Bfree(s); + if (mlo != mhi) + Bfree(mlo); + Bfree(mhi); + return NULL; + } JS_ASSERT(e < 0); /* At this point df = b * 2^e. e must be less than zero because 0 < df < 1. */ @@ -2778,6 +3014,8 @@ JS_dtobasestr(int base, double d) /* 1/2^s2 = (nextDouble(d) - d)/2 */ JS_ASSERT(-s2 < e); mlo = i2b(1); + if (!mlo) + goto nomem2; mhi = mlo; if (!word1(d) && !(word0(d) & Bndry_mask) #ifndef Sudden_Underflow @@ -2788,10 +3026,18 @@ JS_dtobasestr(int base, double d) significant digit instead of one half of it when the output string's value is less than d. */ s2 += Log2P; mhi = i2b(1< df = b/2^s2 > 0; @@ -2804,18 +3050,29 @@ JS_dtobasestr(int base, double d) Bigint *delta; b = multadd(b, base, 0); + if (!b) + goto nomem2; digit = quorem2(b, s2); - if (mlo == mhi) + if (mlo == mhi) { mlo = mhi = multadd(mlo, base, 0); + if (!mhi) + goto nomem2; + } else { mlo = multadd(mlo, base, 0); + if (!mlo) + goto nomem2; mhi = multadd(mhi, base, 0); + if (!mhi) + goto nomem2; } /* Do we yet have the shortest string that will round to d? */ j = cmp(b, mlo); /* j is b/2^s2 compared with mlo/2^s2. */ delta = diff(s, mhi); + if (!delta) + goto nomem2; j1 = delta->sign ? 1 : cmp(b, delta); Bfree(delta); /* j1 is b/2^s2 compared with 1 - mhi/2^s2. */ @@ -2836,6 +3093,8 @@ JS_dtobasestr(int base, double d) /* Either dig or dig+1 would work here as the least significant digit. Use whichever would produce an output value closer to d. */ b = lshift(b, 1); + if (!b) + goto nomem2; j1 = cmp(b, s); if (j1 > 0) /* The even test (|| (j1 == 0 && (digit & 1))) is not here because it messes up odd base output * such as 3.5 in base 3. */ diff --git a/mozilla/js/src/jsdtoa.h b/mozilla/js/src/jsdtoa.h index 6b51b05ee82..c0605050a83 100644 --- a/mozilla/js/src/jsdtoa.h +++ b/mozilla/js/src/jsdtoa.h @@ -52,7 +52,12 @@ JS_BEGIN_EXTERN_C * the character terminating the scan is returned in the location pointed * to by se. If no number can be formed, se is set to s00r, and * zero is returned. + * + * *err is set to zero on success; it's set to JS_DTOA_ERANGE on range + * errors and JS_DTOA_ENOMEM on memory failure. */ +#define JS_DTOA_ERANGE 1 +#define JS_DTOA_ENOMEM 2 JS_FRIEND_API(double) JS_strtod(const char *s00, char **se, int *err); diff --git a/mozilla/js/src/jsnum.c b/mozilla/js/src/jsnum.c index 32e35989897..a9653e37f49 100644 --- a/mozilla/js/src/jsnum.c +++ b/mozilla/js/src/jsnum.c @@ -47,7 +47,6 @@ * JS number type and wrapper class. */ #include "jsstddef.h" -#include #ifdef XP_PC #include #endif @@ -829,7 +828,7 @@ js_strtod(JSContext *cx, const jschar *s, const jschar **ep, jsdouble *dp) /* Use cbuf to avoid malloc */ if (length >= sizeof cbuf) { - cstr = (char *) malloc(length + 1); + cstr = (char *) JS_malloc(cx, length + 1); if (!cstr) return JS_FALSE; } else { @@ -837,33 +836,39 @@ js_strtod(JSContext *cx, const jschar *s, const jschar **ep, jsdouble *dp) } for (i = 0; i <= length; i++) { - if (s1[i] >> 8) { - cstr[i] = 0; - break; - } - cstr[i] = (char)s1[i]; + if (s1[i] >> 8) { + cstr[i] = 0; + break; + } + cstr[i] = (char)s1[i]; } istr = cstr; if ((negative = (*istr == '-')) != 0 || *istr == '+') - istr++; + istr++; if (!strncmp(istr, js_Infinity_str, sizeof js_Infinity_str - 1)) { - d = *(negative ? cx->runtime->jsNegativeInfinity : cx->runtime->jsPositiveInfinity); - estr = istr + 8; + d = *(negative ? cx->runtime->jsNegativeInfinity : cx->runtime->jsPositiveInfinity); + estr = istr + 8; } else { - int err; - d = JS_strtod(cstr, &estr, &err); - if (err == ERANGE) { - if (d == HUGE_VAL) - d = *cx->runtime->jsPositiveInfinity; - else if (d == -HUGE_VAL) - d = *cx->runtime->jsNegativeInfinity; + int err; + d = JS_strtod(cstr, &estr, &err); + if (err == JS_DTOA_ENOMEM) { + JS_ReportOutOfMemory(cx); + if (cstr != cbuf) + JS_free(cx, cstr); + return JS_FALSE; + } + if (err == JS_DTOA_ERANGE) { + if (d == HUGE_VAL) + d = *cx->runtime->jsPositiveInfinity; + else if (d == -HUGE_VAL) + d = *cx->runtime->jsNegativeInfinity; } #ifdef HPUX if (d == 0.0 && negative) { /* * "-0", "-1e-2000" come out as positive zero - * here on HPUX. Force a negative zero instead. + * here on HPUX. Force a negative zero instead. */ JSDOUBLE_HI32(d) = JSDOUBLE_HI32_SIGNBIT; JSDOUBLE_LO32(d) = 0; @@ -873,7 +878,7 @@ js_strtod(JSContext *cx, const jschar *s, const jschar **ep, jsdouble *dp) i = estr - cstr; if (cstr != cbuf) - free(cstr); + JS_free(cx, cstr); *ep = i ? s1 + i : s; *dp = d; return JS_TRUE; @@ -881,11 +886,11 @@ js_strtod(JSContext *cx, const jschar *s, const jschar **ep, jsdouble *dp) struct BinaryDigitReader { - uintN base; /* Base of number; must be a power of 2 */ - uintN digit; /* Current digit value in radix given by base */ - uintN digitMask; /* Mask to extract the next bit from digit */ - const jschar *digits; /* Pointer to the remaining digits */ - const jschar *end; /* Pointer to first non-digit */ + uintN base; /* Base of number; must be a power of 2 */ + uintN digit; /* Current digit value in radix given by base */ + uintN digitMask; /* Mask to extract the next bit from digit */ + const jschar *digits; /* Pointer to the remaining digits */ + const jschar *end; /* Pointer to first non-digit */ }; /* Return the next binary digit from the number or -1 if done */ @@ -894,18 +899,18 @@ static intN GetNextBinaryDigit(struct BinaryDigitReader *bdr) intN bit; if (bdr->digitMask == 0) { - uintN c; + uintN c; - if (bdr->digits == bdr->end) - return -1; + if (bdr->digits == bdr->end) + return -1; - c = *bdr->digits++; - if ('0' <= c && c <= '9') - bdr->digit = c - '0'; - else if ('a' <= c && c <= 'z') - bdr->digit = c - 'a' + 10; - else bdr->digit = c - 'A' + 10; - bdr->digitMask = bdr->base >> 1; + c = *bdr->digits++; + if ('0' <= c && c <= '9') + bdr->digit = c - '0'; + else if ('a' <= c && c <= 'z') + bdr->digit = c - 'a' + 10; + else bdr->digit = c - 'A' + 10; + bdr->digitMask = bdr->base >> 1; } bit = (bdr->digit & bdr->digitMask) != 0; bdr->digitMask >>= 1; @@ -921,24 +926,24 @@ js_strtointeger(JSContext *cx, const jschar *s, const jschar **ep, jsint base, j const jschar *s1 = js_SkipWhiteSpace(s); if ((negative = (*s1 == '-')) != 0 || *s1 == '+') - s1++; + s1++; if (base == 0) { - /* No base supplied, or some base that evaluated to 0. */ - if (*s1 == '0') { - /* It's either hex or octal; only increment char if str isn't '0' */ - if (s1[1] == 'X' || s1[1] == 'x') { /* Hex */ - s1 += 2; - base = 16; - } else { /* Octal */ - base = 8; + /* No base supplied, or some base that evaluated to 0. */ + if (*s1 == '0') { + /* It's either hex or octal; only increment char if str isn't '0' */ + if (s1[1] == 'X' || s1[1] == 'x') { /* Hex */ + s1 += 2; + base = 16; + } else { /* Octal */ + base = 8; } - } else { - base = 10; /* Default to decimal. */ + } else { + base = 10; /* Default to decimal. */ } } else if (base == 16 && *s1 == '0' && (s1[1] == 'X' || s1[1] == 'x')) { - /* If base is 16, ignore hex prefix. */ - s1 += 2; + /* If base is 16, ignore hex prefix. */ + s1 += 2; } /* @@ -948,46 +953,51 @@ js_strtointeger(JSContext *cx, const jschar *s, const jschar **ep, jsint base, j start = s1; /* Mark - if string is empty, we return NaN. */ value = 0.0; while (1) { - uintN digit; - jschar c = *s1; - if ('0' <= c && c <= '9') - digit = c - '0'; - else if ('a' <= c && c <= 'z') - digit = c - 'a' + 10; - else if ('A' <= c && c <= 'Z') - digit = c - 'A' + 10; - else - break; - if (digit >= (uintN)base) - break; - value = value * base + digit; - s1++; + uintN digit; + jschar c = *s1; + if ('0' <= c && c <= '9') + digit = c - '0'; + else if ('a' <= c && c <= 'z') + digit = c - 'a' + 10; + else if ('A' <= c && c <= 'Z') + digit = c - 'A' + 10; + else + break; + if (digit >= (uintN)base) + break; + value = value * base + digit; + s1++; } if (value >= 9007199254740992.0) { - if (base == 10) { + if (base == 10) { /* * If we're accumulating a decimal number and the number is >= * 2^53, then the result from the repeated multiply-add above may * be inaccurate. Call JS_strtod to get the correct answer. */ - size_t i; - size_t length = s1 - start; - char *cstr = (char *) malloc(length + 1); - char *estr; + size_t i; + size_t length = s1 - start; + char *cstr = (char *) JS_malloc(cx, length + 1); + char *estr; int err=0; - if (!cstr) - return JS_FALSE; - for (i = 0; i != length; i++) - cstr[i] = (char)start[i]; - cstr[length] = 0; + if (!cstr) + return JS_FALSE; + for (i = 0; i != length; i++) + cstr[i] = (char)start[i]; + cstr[length] = 0; - value = JS_strtod(cstr, &estr, &err); - if (err == ERANGE && value == HUGE_VAL) - value = *cx->runtime->jsPositiveInfinity; - free(cstr); - } else if ((base & (base - 1)) == 0) { + value = JS_strtod(cstr, &estr, &err); + if (err == JS_DTOA_ENOMEM) { + JS_ReportOutOfMemory(cx); + JS_free(cx, cstr); + return JS_FALSE; + } + if (err == JS_DTOA_ERANGE && value == HUGE_VAL) + value = *cx->runtime->jsPositiveInfinity; + JS_free(cx, cstr); + } else if ((base & (base - 1)) == 0) { /* * The number may also be inaccurate for power-of-two bases. This * happens if the addition in value * base + digit causes a round- @@ -998,56 +1008,56 @@ js_strtointeger(JSContext *cx, const jschar *s, const jschar **ep, jsint base, j * example occurs when reading the number 0x1000000000000081, which * rounds to 0x1000000000000000 instead of 0x1000000000000100. */ - struct BinaryDigitReader bdr; - intN bit, bit2; - intN j; + struct BinaryDigitReader bdr; + intN bit, bit2; + intN j; - bdr.base = base; - bdr.digitMask = 0; - bdr.digits = start; - bdr.end = s1; - value = 0.0; + bdr.base = base; + bdr.digitMask = 0; + bdr.digits = start; + bdr.end = s1; + value = 0.0; - /* Skip leading zeros. */ - do { - bit = GetNextBinaryDigit(&bdr); - } while (bit == 0); + /* Skip leading zeros. */ + do { + bit = GetNextBinaryDigit(&bdr); + } while (bit == 0); - if (bit == 1) { - /* Gather the 53 significant bits (including the leading 1) */ - value = 1.0; - for (j = 52; j; j--) { - bit = GetNextBinaryDigit(&bdr); - if (bit < 0) - goto done; - value = value*2 + bit; - } - /* bit2 is the 54th bit (the first dropped from the mantissa) */ - bit2 = GetNextBinaryDigit(&bdr); - if (bit2 >= 0) { - jsdouble factor = 2.0; - intN sticky = 0; /* sticky is 1 if any bit beyond the 54th is 1 */ - intN bit3; + if (bit == 1) { + /* Gather the 53 significant bits (including the leading 1) */ + value = 1.0; + for (j = 52; j; j--) { + bit = GetNextBinaryDigit(&bdr); + if (bit < 0) + goto done; + value = value*2 + bit; + } + /* bit2 is the 54th bit (the first dropped from the mantissa) */ + bit2 = GetNextBinaryDigit(&bdr); + if (bit2 >= 0) { + jsdouble factor = 2.0; + intN sticky = 0; /* sticky is 1 if any bit beyond the 54th is 1 */ + intN bit3; - while ((bit3 = GetNextBinaryDigit(&bdr)) >= 0) { - sticky |= bit3; - factor *= 2; - } - value += bit2 & (bit | sticky); - value *= factor; - } - done:; - } - } + while ((bit3 = GetNextBinaryDigit(&bdr)) >= 0) { + sticky |= bit3; + factor *= 2; + } + value += bit2 & (bit | sticky); + value *= factor; + } + done:; + } + } } /* We don't worry about inaccurate numbers for any other base. */ if (s1 == start) { - *dp = 0.0; - *ep = s; + *dp = 0.0; + *ep = s; } else { - *dp = negative ? -value : value; - *ep = s1; + *dp = negative ? -value : value; + *ep = s1; } return JS_TRUE; }