From 5dfc1b29e9b8540e607e2588be1a11fc0f198305 Mon Sep 17 00:00:00 2001 From: Sean Stangl Date: Thu, 14 Oct 2010 19:24:09 -0400 Subject: [PATCH] Detect some OOM conditions. b=602935, r=jorendorff. --- js/src/jsdbgapi.cpp | 2 + js/src/jsdtoa.cpp | 353 ++++++++++++++++++++-------------------- js/src/jsinterp.cpp | 2 + js/src/jsstr.cpp | 14 -- js/src/jsstr.h | 3 - js/src/jstracer.cpp | 10 +- js/src/jstypedarray.cpp | 31 ++-- 7 files changed, 206 insertions(+), 209 deletions(-) diff --git a/js/src/jsdbgapi.cpp b/js/src/jsdbgapi.cpp index a7df71e4068d..9af87e218960 100644 --- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -2315,6 +2315,8 @@ ethogram_construct(JSContext *cx, uintN argc, jsval *vp) EthogramEventBuffer *p; p = (EthogramEventBuffer *) JS_malloc(cx, sizeof(EthogramEventBuffer)); + if (!p) + return JS_FALSE; p->mReadPos = p->mWritePos = 0; p->mScripts = NULL; diff --git a/js/src/jsdtoa.cpp b/js/src/jsdtoa.cpp index d4734fc949d6..e03fa52912b3 100644 --- a/js/src/jsdtoa.cpp +++ b/js/src/jsdtoa.cpp @@ -328,201 +328,202 @@ js_dtobasestr(DtoaState *state, int base, double dinput) dval(d) = dinput; buffer = (char*) js_malloc(DTOBASESTR_BUFFER_SIZE); - if (buffer) { - p = buffer; - if (dval(d) < 0.0 + if (!buffer) + return NULL; + p = buffer; + + if (dval(d) < 0.0 #if defined(XP_WIN) || defined(XP_OS2) - && !((word0(d) & Exp_mask) == Exp_mask && ((word0(d) & Frac_mask) || word1(d))) /* Visual C++ doesn't know how to compare against NaN */ + && !((word0(d) & Exp_mask) == Exp_mask && ((word0(d) & Frac_mask) || word1(d))) /* Visual C++ doesn't know how to compare against NaN */ #endif - ) { - *p++ = '-'; - dval(d) = -dval(d); - } + ) { + *p++ = '-'; + dval(d) = -dval(d); + } - /* Check for Infinity and NaN */ - if ((word0(d) & Exp_mask) == Exp_mask) { - strcpy(p, !word1(d) && !(word0(d) & Frac_mask) ? "Infinity" : "NaN"); - return buffer; - } + /* Check for Infinity and NaN */ + if ((word0(d) & Exp_mask) == Exp_mask) { + strcpy(p, !word1(d) && !(word0(d) & Frac_mask) ? "Infinity" : "NaN"); + return buffer; + } - /* Output the integer part of d with the digits in reverse order. */ - pInt = p; - dval(di) = floor(dval(d)); - if (dval(di) <= 4294967295.0) { - uint32 n = (uint32)dval(di); - if (n) - do { - uint32 m = n / base; - digit = n - m*base; - n = m; - JS_ASSERT(digit < (uint32)base); - *p++ = BASEDIGIT(digit); - } while (n); - else *p++ = '0'; - } else { - int e; - int bits; /* Number of significant bits in di; not used. */ - Bigint *b = d2b(PASS_STATE di, &e, &bits); - if (!b) - goto nomem1; - b = lshift(PASS_STATE b, e); - if (!b) { - nomem1: - Bfree(PASS_STATE b); - js_free(buffer); - return NULL; - } + /* Output the integer part of d with the digits in reverse order. */ + pInt = p; + dval(di) = floor(dval(d)); + if (dval(di) <= 4294967295.0) { + uint32 n = (uint32)dval(di); + if (n) do { - digit = divrem(b, base); + uint32 m = n / base; + digit = n - m*base; + n = m; JS_ASSERT(digit < (uint32)base); *p++ = BASEDIGIT(digit); - } while (b->wds); + } while (n); + else *p++ = '0'; + } else { + int e; + int bits; /* Number of significant bits in di; not used. */ + Bigint *b = d2b(PASS_STATE di, &e, &bits); + if (!b) + goto nomem1; + b = lshift(PASS_STATE b, e); + if (!b) { + nomem1: Bfree(PASS_STATE b); + js_free(buffer); + return NULL; } - /* Reverse the digits of the integer part of d. */ - q = p-1; - while (q > pInt) { - char ch = *pInt; - *pInt++ = *q; - *q-- = ch; - } + do { + digit = divrem(b, base); + JS_ASSERT(digit < (uint32)base); + *p++ = BASEDIGIT(digit); + } while (b->wds); + Bfree(PASS_STATE b); + } + /* Reverse the digits of the integer part of d. */ + q = p-1; + while (q > pInt) { + char ch = *pInt; + *pInt++ = *q; + *q-- = ch; + } - dval(df) = dval(d) - dval(di); - if (dval(df) != 0.0) { - /* We have a fraction. */ - int e, bbits; - int32 s2, done; - Bigint *b, *s, *mlo, *mhi; + dval(df) = dval(d) - dval(di); + if (dval(df) != 0.0) { + /* We have a fraction. */ + int e, bbits; + int32 s2, done; + Bigint *b, *s, *mlo, *mhi; - b = s = mlo = mhi = NULL; + b = s = mlo = mhi = NULL; - *p++ = '.'; - b = d2b(PASS_STATE df, &e, &bbits); - if (!b) { - nomem2: - Bfree(PASS_STATE b); - Bfree(PASS_STATE s); - if (mlo != mhi) - Bfree(PASS_STATE mlo); - Bfree(PASS_STATE mhi); - js_free(buffer); - return NULL; - } - JS_ASSERT(e < 0); - /* At this point df = b * 2^e. e must be less than zero because 0 < df < 1. */ - - s2 = -(int32)(word0(d) >> Exp_shift1 & Exp_mask>>Exp_shift1); -#ifndef Sudden_Underflow - if (!s2) - s2 = -1; -#endif - s2 += Bias + P; - /* 1/2^s2 = (nextDouble(d) - d)/2 */ - JS_ASSERT(-s2 < e); - mlo = i2b(PASS_STATE 1); - if (!mlo) - goto nomem2; - mhi = mlo; - if (!word1(d) && !(word0(d) & Bndry_mask) -#ifndef Sudden_Underflow - && word0(d) & (Exp_mask & Exp_mask << 1) -#endif - ) { - /* The special case. Here we want to be within a quarter of the last input - significant digit instead of one half of it when the output string's value is less than d. */ - s2 += Log2P; - mhi = i2b(PASS_STATE 1< df = b/2^s2 > 0; - * (d - prevDouble(d))/2 = mlo/2^s2; - * (nextDouble(d) - d)/2 = mhi/2^s2. */ - - done = JS_FALSE; - do { - int32 j, j1; - Bigint *delta; - - b = multadd(PASS_STATE b, base, 0); - if (!b) - goto nomem2; - digit = quorem2(b, s2); - if (mlo == mhi) { - mlo = mhi = multadd(PASS_STATE mlo, base, 0); - if (!mhi) - goto nomem2; - } - else { - mlo = multadd(PASS_STATE mlo, base, 0); - if (!mlo) - goto nomem2; - mhi = multadd(PASS_STATE 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(PASS_STATE s, mhi); - if (!delta) - goto nomem2; - j1 = delta->sign ? 1 : cmp(b, delta); - Bfree(PASS_STATE delta); - /* j1 is b/2^s2 compared with 1 - mhi/2^s2. */ - -#ifndef ROUND_BIASED - if (j1 == 0 && !(word1(d) & 1)) { - if (j > 0) - digit++; - done = JS_TRUE; - } else -#endif - if (j < 0 || (j == 0 -#ifndef ROUND_BIASED - && !(word1(d) & 1) -#endif - )) { - if (j1 > 0) { - /* 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(PASS_STATE 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. */ - digit++; - } - done = JS_TRUE; - } else if (j1 > 0) { - digit++; - done = JS_TRUE; - } - JS_ASSERT(digit < (uint32)base); - *p++ = BASEDIGIT(digit); - } while (!done); + *p++ = '.'; + b = d2b(PASS_STATE df, &e, &bbits); + if (!b) { + nomem2: Bfree(PASS_STATE b); Bfree(PASS_STATE s); if (mlo != mhi) Bfree(PASS_STATE mlo); Bfree(PASS_STATE mhi); + js_free(buffer); + return NULL; } - JS_ASSERT(p < buffer + DTOBASESTR_BUFFER_SIZE); - *p = '\0'; + JS_ASSERT(e < 0); + /* At this point df = b * 2^e. e must be less than zero because 0 < df < 1. */ + + s2 = -(int32)(word0(d) >> Exp_shift1 & Exp_mask>>Exp_shift1); +#ifndef Sudden_Underflow + if (!s2) + s2 = -1; +#endif + s2 += Bias + P; + /* 1/2^s2 = (nextDouble(d) - d)/2 */ + JS_ASSERT(-s2 < e); + mlo = i2b(PASS_STATE 1); + if (!mlo) + goto nomem2; + mhi = mlo; + if (!word1(d) && !(word0(d) & Bndry_mask) +#ifndef Sudden_Underflow + && word0(d) & (Exp_mask & Exp_mask << 1) +#endif + ) { + /* The special case. Here we want to be within a quarter of the last input + significant digit instead of one half of it when the output string's value is less than d. */ + s2 += Log2P; + mhi = i2b(PASS_STATE 1< df = b/2^s2 > 0; + * (d - prevDouble(d))/2 = mlo/2^s2; + * (nextDouble(d) - d)/2 = mhi/2^s2. */ + + done = JS_FALSE; + do { + int32 j, j1; + Bigint *delta; + + b = multadd(PASS_STATE b, base, 0); + if (!b) + goto nomem2; + digit = quorem2(b, s2); + if (mlo == mhi) { + mlo = mhi = multadd(PASS_STATE mlo, base, 0); + if (!mhi) + goto nomem2; + } + else { + mlo = multadd(PASS_STATE mlo, base, 0); + if (!mlo) + goto nomem2; + mhi = multadd(PASS_STATE 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(PASS_STATE s, mhi); + if (!delta) + goto nomem2; + j1 = delta->sign ? 1 : cmp(b, delta); + Bfree(PASS_STATE delta); + /* j1 is b/2^s2 compared with 1 - mhi/2^s2. */ + +#ifndef ROUND_BIASED + if (j1 == 0 && !(word1(d) & 1)) { + if (j > 0) + digit++; + done = JS_TRUE; + } else +#endif + if (j < 0 || (j == 0 +#ifndef ROUND_BIASED + && !(word1(d) & 1) +#endif + )) { + if (j1 > 0) { + /* 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(PASS_STATE 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. */ + digit++; + } + done = JS_TRUE; + } else if (j1 > 0) { + digit++; + done = JS_TRUE; + } + JS_ASSERT(digit < (uint32)base); + *p++ = BASEDIGIT(digit); + } while (!done); + Bfree(PASS_STATE b); + Bfree(PASS_STATE s); + if (mlo != mhi) + Bfree(PASS_STATE mlo); + Bfree(PASS_STATE mhi); } + JS_ASSERT(p < buffer + DTOBASESTR_BUFFER_SIZE); + *p = '\0'; return buffer; } diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index 75d2c6f92caf..457b69ec0bca 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -1657,6 +1657,8 @@ js_DumpOpMeters() # define SIGNIFICANT(count,total) (200. * (count) >= (total)) graph = (Edge *) js_calloc(nedges * sizeof graph[0]); + if (!graph) + return; for (i = nedges = 0; i < JSOP_LIMIT; i++) { from = js_CodeName[i]; for (j = 0; j < JSOP_LIMIT; j++) { diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index fa9434e7081f..416944344496 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -404,20 +404,6 @@ js_ConcatStrings(JSContext *cx, JSString *left, JSString *right) return FinishConcat(cx, leftRopeTop, rightRopeTop, left, right, length, buf); } -JSString * JS_FASTCALL -js_ConcatStringsZ(JSContext *cx, const char *left, JSString *right) -{ - const size_t leftLength = strlen(left); - const size_t newLength = leftLength + right->length(); - const size_t newSize = (newLength + 1) * sizeof(jschar); - jschar *chars = static_cast(cx->malloc(newSize)); - for (size_t i = 0; i < leftLength; ++i) - chars[i] = left[i]; - js_strncpy(chars + leftLength, right->chars(), right->length()); - JSString *str = js_NewString(cx, chars, newLength); - return str; -} - const jschar * JSString::undepend(JSContext *cx) { diff --git a/js/src/jsstr.h b/js/src/jsstr.h index 6ea99d91d8d9..860d198a9055 100644 --- a/js/src/jsstr.h +++ b/js/src/jsstr.h @@ -76,9 +76,6 @@ js_GetDependentStringChars(JSString *str); extern JSString * JS_FASTCALL js_ConcatStrings(JSContext *cx, JSString *left, JSString *right); -extern JSString * JS_FASTCALL -js_ConcatStringsZ(JSContext *cx, const char *left, JSString *right); - JS_STATIC_ASSERT(JS_BITS_PER_WORD >= 32); struct JSRopeBufferInfo { diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 2b993245936e..80611fe3f66e 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -4594,10 +4594,12 @@ TraceRecorder::compile() /* Associate a filename and line number with the fragment. */ const char* filename = cx->fp()->script()->filename; char* label = (char*)js_malloc((filename ? strlen(filename) : 7) + 16); - sprintf(label, "%s:%u", filename ? filename : "", - js_FramePCToLineNumber(cx, cx->fp())); - lirbuf->printer->addrNameMap->addAddrRange(fragment, sizeof(Fragment), 0, label); - js_free(label); + if (label) { + sprintf(label, "%s:%u", filename ? filename : "", + js_FramePCToLineNumber(cx, cx->fp())); + lirbuf->printer->addrNameMap->addAddrRange(fragment, sizeof(Fragment), 0, label); + js_free(label); + } #endif Assembler *assm = traceMonitor->assembler; diff --git a/js/src/jstypedarray.cpp b/js/src/jstypedarray.cpp index 513ce0081595..b2d8b84c923b 100644 --- a/js/src/jstypedarray.cpp +++ b/js/src/jstypedarray.cpp @@ -927,7 +927,8 @@ class TypedArrayTemplate return false; } - tarray->copyFrom(src, offset); + if (!tarray->copyFrom(cx, src, offset)) + return false; } else if (arg0->wrappedObject(cx)->isArray()) { jsuint len; if (!js_GetLengthProperty(cx, arg0, &len)) @@ -1007,7 +1008,8 @@ class TypedArrayTemplate if (!createBufferWithSizeAndCount(cx, sizeof(NativeType), tarray->length)) return false; - copyFrom(tarray); + if (!copyFrom(cx, tarray)) + return false; } else if (other->getClass() == &ArrayBuffer::jsclass) { ArrayBuffer *abuf = ArrayBuffer::fromJSObject(other); @@ -1154,21 +1156,19 @@ class TypedArrayTemplate return true; } - void - copyFrom(TypedArray *tarray, jsuint offset = 0) + bool + copyFrom(JSContext *cx, TypedArray *tarray, jsuint offset = 0) { JS_ASSERT(offset <= length); JS_ASSERT(tarray->length <= length - offset); - if (tarray->buffer == buffer) { - copyFromWithOverlap(tarray, offset); - return; - } + if (tarray->buffer == buffer) + return copyFromWithOverlap(cx, tarray, offset); NativeType *dest = static_cast(data) + offset; if (tarray->type == type) { memcpy(dest, tarray->data, tarray->byteLength); - return; + return true; } uintN srclen = tarray->length; @@ -1226,10 +1226,12 @@ class TypedArrayTemplate JS_NOT_REACHED("copyFrom with a TypedArray of unknown type"); break; } + + return true; } - void - copyFromWithOverlap(TypedArray *tarray, jsuint offset = 0) + bool + copyFromWithOverlap(JSContext *cx, TypedArray *tarray, jsuint offset = 0) { JS_ASSERT(offset < length); @@ -1237,12 +1239,16 @@ class TypedArrayTemplate if (tarray->type == type) { memmove(dest, tarray->data, tarray->byteLength); - return; + return true; } // We have to make a copy of the source array here, since // there's overlap, and we have to convert types. void *srcbuf = js_malloc(tarray->byteLength); + if (!srcbuf) { + js_ReportOutOfMemory(cx); + return false; + } memcpy(srcbuf, tarray->data, tarray->byteLength); switch (tarray->type) { @@ -1301,6 +1307,7 @@ class TypedArrayTemplate } js_free(srcbuf); + return true; } bool