Fixed crash when charCodeAt failed (with NaN) while recording (bug 457795, r=gal).
authorDavid Anderson <danderson@mozilla.com>
Mon, 29 Sep 2008 23:20:34 -0500
changeset 20003 419ce5b4c0d6aced2aab1e40a78fa489ebddf8d0
parent 20002 25c30c40c71025ed7099f25186d111a814c0c914
child 20004 c0895d880428e14f7cb576f08a0389debc6946c7
push id2577
push userbrendan@mozilla.com
push dateWed, 01 Oct 2008 04:35:27 +0000
treeherdermozilla-central@a613924403d6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgal
bugs457795
milestone1.9.1b1pre
Fixed crash when charCodeAt failed (with NaN) while recording (bug 457795, r=gal).
js/src/jstracer.cpp
js/src/trace-test.js
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -2851,17 +2851,17 @@ extern void
 js_InitJIT(JSTraceMonitor *tm)
 {
 #if defined NANOJIT_IA32
     if (!did_we_check_sse2) {
         avmplus::AvmCore::cmov_available =
         avmplus::AvmCore::sse2_available = js_CheckForSSE2();
         did_we_check_sse2 = true;
     }
-#else if defined NANOJIT_AMD64
+#elif defined NANOJIT_AMD64
     avmplus::AvmCore::cmov_available =
     avmplus::AvmCore::sse2_available = true;
 #endif
     if (!tm->fragmento) {
         JS_ASSERT(!tm->globalSlots && !tm->globalTypeMap && !tm->recoveryDoublePool);
         Fragmento* fragmento = new (&gc) Fragmento(core, 24);
         verbose_only(fragmento->labels = new (&gc) LabelMap(core, NULL);)
         fragmento->assm()->setCallTable(builtins);
@@ -5280,16 +5280,36 @@ TraceRecorder::record_JSOP_CALL()
           case 1:
             HANDLE_ARG(0);
             /* FALL THROUGH */
           case 0:
             break;
           default:
             JS_NOT_REACHED("illegal number of args to traceable native");
         }
+        
+        /* If we got this far, and we have a charCodeAt, check that charCodeAt isn't going to 
+         * return a NaN. 
+         */
+        if (known->builtin == F_String_p_charCodeAt) {
+            JSString* str = JSVAL_TO_STRING(thisval);
+            jsval& arg = arg1_ins ? arg1 : stackval(-1);
+
+            JS_ASSERT(JSVAL_IS_STRING(thisval)); 
+            JS_ASSERT(isNumber(arg));
+
+            if (JSVAL_IS_INT(arg)) {
+                if (size_t(JSVAL_TO_INT(arg)) >= JSSTRING_LENGTH(str))
+                    ABORT_TRACE("invalid charCodeAt index");
+            } else {
+                double d = js_DoubleToInteger(*JSVAL_TO_DOUBLE(arg));
+                if (d < 0 || JSSTRING_LENGTH(str) <= d)
+                    ABORT_TRACE("invalid charCodeAt index");
+            }
+        }
 
 #undef HANDLE_ARG
 
 #if defined _DEBUG
         JS_ASSERT(args[0] != (LIns *)0xcdcdcdcd);
 #endif
 
         LIns* res_ins = lir->insCall(known->builtin, args);
--- a/js/src/trace-test.js
+++ b/js/src/trace-test.js
@@ -1740,11 +1740,25 @@ test(testConstantBooleanExpr);
 function testNegativeGETELEMIndex()
 {
     for (let i=0;i<3;++i) /x/[-4];
     return "ok";
 }
 testNegativeGETELEMIndex.expected = "ok";
 test(testNegativeGETELEMIndex);
 
+function doTestInvalidCharCodeAt(input)
+{
+    var q = "";
+    for (var i = 0; i < 10; i++)
+       q += input.charCodeAt(i); 
+    return q;
+}
+function testInvalidCharCodeAt()
+{
+    return doTestInvalidCharCodeAt("");
+}
+testInvalidCharCodeAt.expected = "NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN";
+test(testInvalidCharCodeAt);
+
 /* Keep these at the end so that we can see the summary after the trace-debug spew. */
 print("\npassed:", passes.length && passes.join(","));
 print("\nFAILED:", fails.length && fails.join(","));