patch 88484 for bug 14044. checks for out of memory conditon in jsdtoa.c. sr=brendan, r=khanson

git-svn-id: svn://10.0.0.236/trunk@123918 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
khanson%netscape.com
2002-06-24 06:14:02 +00:00
parent 7fb41ca544
commit e76ec12e0a
3 changed files with 428 additions and 154 deletions

View File

@@ -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<<Log2P);
if (!mhi)
goto nomem2;
}
b = lshift(b, e + s2);
if (!b)
goto nomem2;
s = i2b(1);
if (!s)
goto nomem2;
s = lshift(s, s2);
if (!s)
goto nomem2;
/* At this point we have the following:
* s = 2^s2;
* 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. */

View File

@@ -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);

View File

@@ -47,7 +47,6 @@
* JS number type and wrapper class.
*/
#include "jsstddef.h"
#include <errno.h>
#ifdef XP_PC
#include <float.h>
#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;
}