Bug 1394146 - Avoid overflow on backwards iteration of IC entries. r=jandem
authorSean Stangl <sstangl@mozilla.com>
Thu, 21 Sep 2017 15:37:00 -0400
changeset 382382 9f05ef54c84d9b63fb3ad2dd2916df34cb35df8d
parent 382381 2fac6141f39e2ef741884165f56a675561924f39
child 382383 14cf84cd05639c0bd7db54118102b1742e90cadf
push id32555
push userarchaeopteryx@coole-files.de
push dateFri, 22 Sep 2017 09:43:20 +0000
treeherdermozilla-central@82b2ae0b03ca [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1394146
milestone58.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1394146 - Avoid overflow on backwards iteration of IC entries. r=jandem
js/src/jit/BaselineJIT.cpp
js/src/jit/IonControlFlow.cpp
--- a/js/src/jit/BaselineJIT.cpp
+++ b/js/src/jit/BaselineJIT.cpp
@@ -664,22 +664,26 @@ BaselineICEntry*
 BaselineScript::maybeICEntryFromPCOffset(uint32_t pcOffset)
 {
     // Multiple IC entries can have the same PC offset, but this method only looks for
     // those which have isForOp() set.
     size_t mid;
     if (!ComputeBinarySearchMid(this, pcOffset, &mid))
         return nullptr;
 
+    MOZ_ASSERT(mid < numICEntries());
+
     // Found an IC entry with a matching PC offset.  Search backward, and then
     // forward from this IC entry, looking for one with the same PC offset which
     // has isForOp() set.
-    for (size_t i = mid; i < numICEntries() && icEntry(i).pcOffset() == pcOffset; i--) {
+    for (size_t i = mid; icEntry(i).pcOffset() == pcOffset; i--) {
         if (icEntry(i).isForOp())
             return &icEntry(i);
+        if (i == 0)
+            break;
     }
     for (size_t i = mid+1; i < numICEntries() && icEntry(i).pcOffset() == pcOffset; i++) {
         if (icEntry(i).isForOp())
             return &icEntry(i);
     }
     return nullptr;
 }
 
@@ -723,20 +727,23 @@ BaselineScript::icEntryFromPCOffset(uint
 
 BaselineICEntry&
 BaselineScript::callVMEntryFromPCOffset(uint32_t pcOffset)
 {
     // Like icEntryFromPCOffset, but only looks for the fake ICEntries
     // inserted by VM calls.
     size_t mid;
     MOZ_ALWAYS_TRUE(ComputeBinarySearchMid(this, pcOffset, &mid));
+    MOZ_ASSERT(mid < numICEntries());
 
-    for (size_t i = mid; i < numICEntries() && icEntry(i).pcOffset() == pcOffset; i--) {
+    for (size_t i = mid; icEntry(i).pcOffset() == pcOffset; i--) {
         if (icEntry(i).kind() == ICEntry::Kind_CallVM)
             return icEntry(i);
+        if (i == 0)
+            break;
     }
     for (size_t i = mid+1; i < numICEntries() && icEntry(i).pcOffset() == pcOffset; i++) {
         if (icEntry(i).kind() == ICEntry::Kind_CallVM)
             return icEntry(i);
     }
     MOZ_CRASH("Invalid PC offset for callVM entry.");
 }
 
--- a/js/src/jit/IonControlFlow.cpp
+++ b/js/src/jit/IonControlFlow.cpp
@@ -1614,34 +1614,38 @@ ControlFlowGenerator::processBreak(JSOp 
     MOZ_ASSERT(SN_TYPE(sn) == SRC_BREAK ||
                SN_TYPE(sn) == SRC_BREAK2LABEL);
 
     // Find the break target.
     jsbytecode* target = pc + GetJumpOffset(pc);
     DebugOnly<bool> found = false;
 
     if (SN_TYPE(sn) == SRC_BREAK2LABEL) {
-        for (size_t i = labels_.length() - 1; i < labels_.length(); i--) {
+        for (size_t i = labels_.length() - 1; ; i--) {
             CFGState& cfg = cfgStack_[labels_[i].cfgEntry];
             MOZ_ASSERT(cfg.state == CFGState::LABEL);
             if (cfg.stopAt == target) {
                 cfg.label.breaks = new(alloc()) DeferredEdge(current, cfg.label.breaks);
                 found = true;
                 break;
             }
+            if (i == 0)
+                break;
         }
     } else {
-        for (size_t i = loops_.length() - 1; i < loops_.length(); i--) {
+        for (size_t i = loops_.length() - 1; ; i--) {
             CFGState& cfg = cfgStack_[loops_[i].cfgEntry];
             MOZ_ASSERT(cfg.isLoop());
             if (cfg.loop.exitpc == target) {
                 cfg.loop.breaks = new(alloc()) DeferredEdge(current, cfg.loop.breaks);
                 found = true;
                 break;
             }
+            if (i == 0)
+                break;
         }
     }
 
     current->setStopPc(pc);
 
     MOZ_ASSERT(found);
 
     current = nullptr;
@@ -1660,24 +1664,26 @@ EffectiveContinue(jsbytecode* pc)
 ControlFlowGenerator::ControlStatus
 ControlFlowGenerator::processContinue(JSOp op)
 {
     MOZ_ASSERT(op == JSOP_GOTO);
 
     // Find the target loop.
     CFGState* found = nullptr;
     jsbytecode* target = pc + GetJumpOffset(pc);
-    for (size_t i = loops_.length() - 1; i < loops_.length(); i--) {
+    for (size_t i = loops_.length() - 1; ; i--) {
         // +1 to skip JSOP_JUMPTARGET.
         if (loops_[i].continuepc == target + 1 ||
             EffectiveContinue(loops_[i].continuepc) == target)
         {
             found = &cfgStack_[loops_[i].cfgEntry];
             break;
         }
+        if (i == 0)
+            break;
     }
 
     // There must always be a valid target loop structure. If not, there's
     // probably an off-by-something error in which pc we track.
     MOZ_ASSERT(found);
     CFGState& state = *found;
 
     state.loop.continues = new(alloc()) DeferredEdge(current, state.loop.continues);
@@ -1693,21 +1699,23 @@ ControlFlowGenerator::processContinue(JS
 ControlFlowGenerator::ControlStatus
 ControlFlowGenerator::processSwitchBreak(JSOp op)
 {
     MOZ_ASSERT(op == JSOP_GOTO);
 
     // Find the target switch.
     CFGState* found = nullptr;
     jsbytecode* target = pc + GetJumpOffset(pc);
-    for (size_t i = switches_.length() - 1; i < switches_.length(); i--) {
+    for (size_t i = switches_.length() - 1; ; i--) {
         if (switches_[i].continuepc == target) {
             found = &cfgStack_[switches_[i].cfgEntry];
             break;
         }
+        if (i == 0)
+            break;
     }
 
     // There must always be a valid target loop structure. If not, there's
     // probably an off-by-something error in which pc we track.
     MOZ_ASSERT(found);
     CFGState& state = *found;
 
     DeferredEdge** breaks = nullptr;