Bug 813366: Remove the deliberate crashes in Yarr, by making it fallible, r=till a=sylvestre
authorHannes Verschore <hv1989@gmail.com>
Wed, 30 Apr 2014 10:02:56 +0200
changeset 199081 b7c28ae275957cd402043bfe1283c5b16fa580f3
parent 199080 7ea30f70ccd6180bed246ccfb2b358b62e0f36e5
child 199082 1389f09bbbc9757a0fc7f4577a23d06d3074a0c1
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstill, sylvestre
bugs813366
milestone31.0a2
Bug 813366: Remove the deliberate crashes in Yarr, by making it fallible, r=till a=sylvestre
js/src/tests/js1_8_5/regress/regress-yarr-regexp.js
js/src/yarr/CheckedArithmetic.h
js/src/yarr/YarrJIT.cpp
js/src/yarr/YarrPattern.cpp
--- a/js/src/tests/js1_8_5/regress/regress-yarr-regexp.js
+++ b/js/src/tests/js1_8_5/regress/regress-yarr-regexp.js
@@ -7,14 +7,14 @@ reportCompare(["abc", "abc", ""].toSourc
 
 reportCompare(["a", ""].toSource(), toSource(/((?:)*?)a/.exec("a")));
 reportCompare(["a", ""].toSource(), toSource(/((?:.)*?)a/.exec("a")));
 reportCompare(["a", ""].toSource(), toSource(/a((?:.)*)/.exec("a")));
 
 reportCompare(["B", "B"].toSource(), toSource(/([A-Z])/.exec("fooBar")));
 
 // These just mustn't crash. See bug 872971
-reportCompare(/x{2147483648}x/.test('1'), false);
-reportCompare(/x{2147483648,}x/.test('1'), false);
-reportCompare(/x{2147483647,2147483648}x/.test('1'), false);
+try { reportCompare(/x{2147483648}x/.test('1'), false); } catch (e) {}
+try { reportCompare(/x{2147483648,}x/.test('1'), false); } catch (e) {}
+try { reportCompare(/x{2147483647,2147483648}x/.test('1'), false); } catch (e) {}
 // Same for these. See bug 813366
-reportCompare("".match(/.{2147483647}11/), null);
-reportCompare("".match(/(?:(?=g)).{2147483648,}/ + ""), null);
+try { reportCompare("".match(/.{2147483647}11/), null); } catch (e) {}
+try { reportCompare("".match(/(?:(?=g)).{2147483648,}/ + ""), null); } catch (e) {}
--- a/js/src/yarr/CheckedArithmetic.h
+++ b/js/src/yarr/CheckedArithmetic.h
@@ -105,17 +105,17 @@ protected:
 
 public:
     bool hasOverflowed() const { return m_overflowed; }
 
 private:
     unsigned char m_overflowed;
 };
 
-template <typename T, class OverflowHandler = CrashOnOverflow> class Checked;
+template <typename T, class OverflowHandler = RecordOverflow> class Checked;
 template <typename T> struct RemoveChecked;
 template <typename T> struct RemoveChecked<Checked<T> >;
 
 template <typename Target, typename Source, bool targetSigned = ::std::numeric_limits<Target>::is_signed, bool sourceSigned = ::std::numeric_limits<Source>::is_signed> struct BoundsChecker;
 template <typename Target, typename Source> struct BoundsChecker<Target, Source, false, false> {
     static bool inBounds(Source value)
     {
         // Same signedness so implicit type conversion will always increase precision
--- a/js/src/yarr/YarrJIT.cpp
+++ b/js/src/yarr/YarrJIT.cpp
@@ -606,20 +606,21 @@ class YarrGenerator : private MacroAssem
 
     // Generation methods:
     // ===================
 
     // This method provides a default implementation of backtracking common
     // to many terms; terms commonly jump out of the forwards  matching path
     // on any failed conditions, and add these jumps to the m_jumps list. If
     // no special handling is required we can often just backtrack to m_jumps.
-    void backtrackTermDefault(size_t opIndex)
+    bool backtrackTermDefault(size_t opIndex)
     {
         YarrOp& op = m_ops[opIndex];
         m_backtrackingState.append(op.m_jumps);
+        return true;
     }
 
     bool generateAssertionBOL(size_t opIndex)
     {
         YarrOp& op = m_ops[opIndex];
         PatternTerm* term = op.m_term;
 
         if (m_pattern.m_multiline) {
@@ -638,19 +639,19 @@ class YarrGenerator : private MacroAssem
             // Erk, really should poison out these alternatives early. :-/
             if (term->inputPosition)
                 op.m_jumps.append(jump());
             else
                 op.m_jumps.append(branch32(NotEqual, index, Imm32(m_checked)));
         }
         return true;
     }
-    void backtrackAssertionBOL(size_t opIndex)
+    bool backtrackAssertionBOL(size_t opIndex)
     {
-        backtrackTermDefault(opIndex);
+        return backtrackTermDefault(opIndex);
     }
 
     bool generateAssertionEOL(size_t opIndex)
     {
         YarrOp& op = m_ops[opIndex];
         PatternTerm* term = op.m_term;
 
         if (m_pattern.m_multiline) {
@@ -669,19 +670,19 @@ class YarrGenerator : private MacroAssem
             if (term->inputPosition == m_checked)
                 op.m_jumps.append(notAtEndOfInput());
             // Erk, really should poison out these alternatives early. :-/
             else
                 op.m_jumps.append(jump());
         }
         return true;
     }
-    void backtrackAssertionEOL(size_t opIndex)
+    bool backtrackAssertionEOL(size_t opIndex)
     {
-        backtrackTermDefault(opIndex);
+        return backtrackTermDefault(opIndex);
     }
 
     // Also falls though on nextIsNotWordChar.
     void matchAssertionWordchar(size_t opIndex, JumpList& nextIsWordChar, JumpList& nextIsNotWordChar)
     {
         YarrOp& op = m_ops[opIndex];
         PatternTerm* term = op.m_term;
 
@@ -735,19 +736,19 @@ class YarrGenerator : private MacroAssem
         }
 
         op.m_jumps.append(wordCharThenWordChar);
 
         nonWordCharThenWordChar.link(this);
         wordCharThenNonWordChar.link(this);
         return true;
     }
-    void backtrackAssertionWordBoundary(size_t opIndex)
+    bool backtrackAssertionWordBoundary(size_t opIndex)
     {
-        backtrackTermDefault(opIndex);
+        return backtrackTermDefault(opIndex);
     }
 
     bool generatePatternCharacterOnce(size_t opIndex)
     {
         YarrOp& op = m_ops[opIndex];
 
         if (op.m_isDeadCode)
             return true;
@@ -860,35 +861,40 @@ class YarrGenerator : private MacroAssem
             }
         }
 
         if (ignoreCaseMask)
             or32(Imm32(ignoreCaseMask), character);
         op.m_jumps.append(branch32(NotEqual, character, Imm32(allCharacters | ignoreCaseMask)));
         return true;
     }
-    void backtrackPatternCharacterOnce(size_t opIndex)
+    bool backtrackPatternCharacterOnce(size_t opIndex)
     {
-        backtrackTermDefault(opIndex);
+        return backtrackTermDefault(opIndex);
     }
 
     bool generatePatternCharacterFixed(size_t opIndex)
     {
         YarrOp& op = m_ops[opIndex];
         PatternTerm* term = op.m_term;
         UChar ch = term->patternCharacter;
 
         const RegisterID character = regT0;
         const RegisterID countRegister = regT1;
 
         move(index, countRegister);
+        if (term->quantityCount.hasOverflowed())
+            return false;
         sub32(Imm32(term->quantityCount.unsafeGet()), countRegister);
 
         Label loop(this);
-        BaseIndex address(input, countRegister, m_charScale, (Checked<int>(term->inputPosition - m_checked + Checked<int64_t>(term->quantityCount)) * static_cast<int>(m_charSize == Char8 ? sizeof(char) : sizeof(UChar))).unsafeGet());
+        int offset;
+        if ((Checked<int>(term->inputPosition - m_checked + Checked<int64_t>(term->quantityCount)) * static_cast<int>(m_charSize == Char8 ? sizeof(char) : sizeof(UChar))).safeGet(offset))
+            return false;
+        BaseIndex address(input, countRegister, m_charScale, offset);
 
         if (m_charSize == Char8)
             load8(address, character);
         else
             load16(address, character);
 
         // For case-insesitive compares, non-ascii characters that have different
         // upper & lower case representations are converted to a character class.
@@ -899,19 +905,19 @@ class YarrGenerator : private MacroAssem
         }
 
         op.m_jumps.append(branch32(NotEqual, character, Imm32(ch)));
         add32(TrustedImm32(1), countRegister);
         branch32(NotEqual, countRegister, index).linkTo(loop, this);
 
         return true;
     }
-    void backtrackPatternCharacterFixed(size_t opIndex)
+    bool backtrackPatternCharacterFixed(size_t opIndex)
     {
-        backtrackTermDefault(opIndex);
+        return backtrackTermDefault(opIndex);
     }
 
     bool generatePatternCharacterGreedy(size_t opIndex)
     {
         YarrOp& op = m_ops[opIndex];
         PatternTerm* term = op.m_term;
         UChar ch = term->patternCharacter;
 
@@ -924,86 +930,96 @@ class YarrGenerator : private MacroAssem
         if (!((ch > 0xff) && (m_charSize == Char8))) {
             JumpList failures;
             Label loop(this);
             failures.append(atEndOfInput());
             failures.append(jumpIfCharNotEquals(ch, term->inputPosition - m_checked, character));
 
             add32(TrustedImm32(1), countRegister);
             add32(TrustedImm32(1), index);
-            if (term->quantityCount == quantifyInfinite)
+            if (term->quantityCount == quantifyInfinite) {
                 jump(loop);
-            else
+            } else {
+                if (term->quantityCount.hasOverflowed())
+                    return false;
                 branch32(NotEqual, countRegister, Imm32(term->quantityCount.unsafeGet())).linkTo(loop, this);
+            }
 
             failures.link(this);
         }
         op.m_reentry = label();
 
         storeToFrame(countRegister, term->frameLocation);
         return true;
     }
-    void backtrackPatternCharacterGreedy(size_t opIndex)
+    bool backtrackPatternCharacterGreedy(size_t opIndex)
     {
         YarrOp& op = m_ops[opIndex];
         PatternTerm* term = op.m_term;
 
         const RegisterID countRegister = regT1;
 
         m_backtrackingState.link(this);
 
         loadFromFrame(term->frameLocation, countRegister);
         m_backtrackingState.append(branchTest32(Zero, countRegister));
         sub32(TrustedImm32(1), countRegister);
         sub32(TrustedImm32(1), index);
         jump(op.m_reentry);
+
+        return true;
     }
 
     bool generatePatternCharacterNonGreedy(size_t opIndex)
     {
         YarrOp& op = m_ops[opIndex];
         PatternTerm* term = op.m_term;
 
         const RegisterID countRegister = regT1;
 
         move(TrustedImm32(0), countRegister);
         op.m_reentry = label();
         storeToFrame(countRegister, term->frameLocation);
         return true;
     }
-    void backtrackPatternCharacterNonGreedy(size_t opIndex)
+    bool backtrackPatternCharacterNonGreedy(size_t opIndex)
     {
         YarrOp& op = m_ops[opIndex];
         PatternTerm* term = op.m_term;
         UChar ch = term->patternCharacter;
 
         const RegisterID character = regT0;
         const RegisterID countRegister = regT1;
 
         m_backtrackingState.link(this);
 
         loadFromFrame(term->frameLocation, countRegister);
 
         // Unless have a 16 bit pattern character and an 8 bit string - short circuit
         if (!((ch > 0xff) && (m_charSize == Char8))) {
             JumpList nonGreedyFailures;
             nonGreedyFailures.append(atEndOfInput());
-            if (term->quantityCount != quantifyInfinite)
+            if (term->quantityCount != quantifyInfinite) {
+                if (term->quantityCount.hasOverflowed())
+                    return false;
                 nonGreedyFailures.append(branch32(Equal, countRegister, Imm32(term->quantityCount.unsafeGet())));
+            }
             nonGreedyFailures.append(jumpIfCharNotEquals(ch, term->inputPosition - m_checked, character));
 
             add32(TrustedImm32(1), countRegister);
             add32(TrustedImm32(1), index);
 
             jump(op.m_reentry);
             nonGreedyFailures.link(this);
         }
 
         sub32(countRegister, index);
         m_backtrackingState.fallthrough();
+
+        return true;
     }
 
     bool generateCharacterClassOnce(size_t opIndex)
     {
         YarrOp& op = m_ops[opIndex];
         PatternTerm* term = op.m_term;
 
         const RegisterID character = regT0;
@@ -1015,54 +1031,65 @@ class YarrGenerator : private MacroAssem
         if (term->invert())
             op.m_jumps.append(matchDest);
         else {
             op.m_jumps.append(jump());
             matchDest.link(this);
         }
         return true;
     }
-    void backtrackCharacterClassOnce(size_t opIndex)
+    bool backtrackCharacterClassOnce(size_t opIndex)
     {
-        backtrackTermDefault(opIndex);
+        return backtrackTermDefault(opIndex);
     }
 
     bool generateCharacterClassFixed(size_t opIndex)
     {
         YarrOp& op = m_ops[opIndex];
         PatternTerm* term = op.m_term;
 
         const RegisterID character = regT0;
         const RegisterID countRegister = regT1;
 
         move(index, countRegister);
+        if (term->quantityCount.hasOverflowed())
+            return false;
         sub32(Imm32(term->quantityCount.unsafeGet()), countRegister);
 
         Label loop(this);
         JumpList matchDest;
-        if (m_charSize == Char8)
-            load8(BaseIndex(input, countRegister, TimesOne, (Checked<int>(term->inputPosition - m_checked + Checked<int64_t>(term->quantityCount)) * static_cast<int>(sizeof(char))).unsafeGet()), character);
-        else
-            load16(BaseIndex(input, countRegister, TimesTwo, (Checked<int>(term->inputPosition - m_checked + Checked<int64_t>(term->quantityCount)) * static_cast<int>(sizeof(UChar))).unsafeGet()), character);
+
+        int offset;
+        Checked<int64_t> checkedOffset(term->inputPosition - m_checked + Checked<int64_t>(term->quantityCount));
+
+        if (m_charSize == Char8) {
+            if ((Checked<int>(checkedOffset) * static_cast<int>(sizeof(char))).safeGet(offset))
+                return false;
+            load8(BaseIndex(input, countRegister, TimesOne, offset), character);
+        } else {
+            if ((Checked<int>(checkedOffset) * static_cast<int>(sizeof(UChar))).safeGet(offset))
+                return false;
+            load16(BaseIndex(input, countRegister, TimesTwo, offset), character);
+        }
         matchCharacterClass(character, matchDest, term->characterClass);
 
         if (term->invert())
             op.m_jumps.append(matchDest);
         else {
             op.m_jumps.append(jump());
             matchDest.link(this);
         }
 
         add32(TrustedImm32(1), countRegister);
         branch32(NotEqual, countRegister, index).linkTo(loop, this);
         return true;
     }
-    void backtrackCharacterClassFixed(size_t opIndex)
+    bool backtrackCharacterClassFixed(size_t opIndex)
     {
-        backtrackTermDefault(opIndex);
+        return backtrackTermDefault(opIndex);
     }
 
     bool generateCharacterClassGreedy(size_t opIndex)
     {
         YarrOp& op = m_ops[opIndex];
         PatternTerm* term = op.m_term;
 
         const RegisterID character = regT0;
@@ -1083,70 +1110,77 @@ class YarrGenerator : private MacroAssem
             matchCharacterClass(character, matchDest, term->characterClass);
             failures.append(jump());
             matchDest.link(this);
         }
 
         add32(TrustedImm32(1), countRegister);
         add32(TrustedImm32(1), index);
         if (term->quantityCount != quantifyInfinite) {
-            branch32(NotEqual, countRegister, Imm32(term->quantityCount.unsafeGet())).linkTo(loop, this);
+            unsigned quantityCount;
+            if (term->quantityCount.safeGet(quantityCount))
+                return false;
+            branch32(NotEqual, countRegister, Imm32(quantityCount)).linkTo(loop, this);
             failures.append(jump());
         } else
             jump(loop);
 
         failures.link(this);
         op.m_reentry = label();
 
         storeToFrame(countRegister, term->frameLocation);
         return true;
     }
-    void backtrackCharacterClassGreedy(size_t opIndex)
+    bool backtrackCharacterClassGreedy(size_t opIndex)
     {
         YarrOp& op = m_ops[opIndex];
         PatternTerm* term = op.m_term;
 
         const RegisterID countRegister = regT1;
 
         m_backtrackingState.link(this);
 
         loadFromFrame(term->frameLocation, countRegister);
         m_backtrackingState.append(branchTest32(Zero, countRegister));
         sub32(TrustedImm32(1), countRegister);
         sub32(TrustedImm32(1), index);
         jump(op.m_reentry);
+
+        return true;
     }
 
     bool generateCharacterClassNonGreedy(size_t opIndex)
     {
         YarrOp& op = m_ops[opIndex];
         PatternTerm* term = op.m_term;
 
         const RegisterID countRegister = regT1;
 
         move(TrustedImm32(0), countRegister);
         op.m_reentry = label();
         storeToFrame(countRegister, term->frameLocation);
         return true;
     }
-    void backtrackCharacterClassNonGreedy(size_t opIndex)
+    bool backtrackCharacterClassNonGreedy(size_t opIndex)
     {
         YarrOp& op = m_ops[opIndex];
         PatternTerm* term = op.m_term;
 
         const RegisterID character = regT0;
         const RegisterID countRegister = regT1;
 
         JumpList nonGreedyFailures;
 
         m_backtrackingState.link(this);
 
         loadFromFrame(term->frameLocation, countRegister);
 
         nonGreedyFailures.append(atEndOfInput());
+        if (term->quantityCount.hasOverflowed())
+            return false;
         nonGreedyFailures.append(branch32(Equal, countRegister, Imm32(term->quantityCount.unsafeGet())));
 
         JumpList matchDest;
         readCharacter(term->inputPosition - m_checked, character);
         matchCharacterClass(character, matchDest, term->characterClass);
 
         if (term->invert())
             nonGreedyFailures.append(matchDest);
@@ -1158,16 +1192,18 @@ class YarrGenerator : private MacroAssem
         add32(TrustedImm32(1), countRegister);
         add32(TrustedImm32(1), index);
 
         jump(op.m_reentry);
 
         nonGreedyFailures.link(this);
         sub32(countRegister, index);
         m_backtrackingState.fallthrough();
+
+        return true;
     }
 
     bool generateDotStarEnclosure(size_t opIndex)
     {
         YarrOp& op = m_ops[opIndex];
         PatternTerm* term = op.m_term;
 
         const RegisterID character = regT0;
@@ -1217,19 +1253,19 @@ class YarrGenerator : private MacroAssem
 
         if (!m_pattern.m_multiline && term->anchors.eolAnchor)
             op.m_jumps.append(branch32(NotEqual, matchPos, length));
 
         move(matchPos, index);
         return true;
     }
 
-    void backtrackDotStarEnclosure(size_t opIndex)
+    bool backtrackDotStarEnclosure(size_t opIndex)
     {
-        backtrackTermDefault(opIndex);
+        return backtrackTermDefault(opIndex);
     }
 
     // Code generation/backtracking for simple terms
     // (pattern characters, character classes, and assertions).
     // These methods farm out work to the set of functions above.
     bool generateTerm(size_t opIndex)
     {
         YarrOp& op = m_ops[opIndex];
@@ -1285,83 +1321,74 @@ class YarrGenerator : private MacroAssem
         case PatternTerm::TypeBackReference:
             return false;
         case PatternTerm::TypeDotStarEnclosure:
             return generateDotStarEnclosure(opIndex);
         }
 
         return false;
     }
-    void backtrackTerm(size_t opIndex)
+    bool backtrackTerm(size_t opIndex)
     {
         YarrOp& op = m_ops[opIndex];
         PatternTerm* term = op.m_term;
 
         switch (term->type) {
         case PatternTerm::TypePatternCharacter:
             switch (term->quantityType) {
             case QuantifierFixedCount:
                 if (term->quantityCount == 1)
-                    backtrackPatternCharacterOnce(opIndex);
+                    return backtrackPatternCharacterOnce(opIndex);
                 else
-                    backtrackPatternCharacterFixed(opIndex);
-                break;
+                    return backtrackPatternCharacterFixed(opIndex);
             case QuantifierGreedy:
-                backtrackPatternCharacterGreedy(opIndex);
-                break;
+                return backtrackPatternCharacterGreedy(opIndex);
             case QuantifierNonGreedy:
-                backtrackPatternCharacterNonGreedy(opIndex);
-                break;
+                return backtrackPatternCharacterNonGreedy(opIndex);
             }
             break;
 
         case PatternTerm::TypeCharacterClass:
             switch (term->quantityType) {
             case QuantifierFixedCount:
                 if (term->quantityCount == 1)
-                    backtrackCharacterClassOnce(opIndex);
+                    return backtrackCharacterClassOnce(opIndex);
                 else
-                    backtrackCharacterClassFixed(opIndex);
-                break;
+                    return backtrackCharacterClassFixed(opIndex);
             case QuantifierGreedy:
-                backtrackCharacterClassGreedy(opIndex);
-                break;
+                return backtrackCharacterClassGreedy(opIndex);
             case QuantifierNonGreedy:
-                backtrackCharacterClassNonGreedy(opIndex);
-                break;
+                return backtrackCharacterClassNonGreedy(opIndex);
             }
             break;
 
         case PatternTerm::TypeAssertionBOL:
-            backtrackAssertionBOL(opIndex);
-            break;
+            return backtrackAssertionBOL(opIndex);
 
         case PatternTerm::TypeAssertionEOL:
-            backtrackAssertionEOL(opIndex);
-            break;
+            return backtrackAssertionEOL(opIndex);
 
         case PatternTerm::TypeAssertionWordBoundary:
-            backtrackAssertionWordBoundary(opIndex);
-            break;
+            return backtrackAssertionWordBoundary(opIndex);
 
         case PatternTerm::TypeForwardReference:
-            break;
+            return true;
 
         case PatternTerm::TypeParenthesesSubpattern:
         case PatternTerm::TypeParentheticalAssertion:
             ASSERT_NOT_REACHED();
+            return false;
 
         case PatternTerm::TypeDotStarEnclosure:
-            backtrackDotStarEnclosure(opIndex);
-            break;
+            return backtrackDotStarEnclosure(opIndex);
 
         case PatternTerm::TypeBackReference:
-            m_shouldFallBack = true;
-            break;
+            return false;
         }
+        return true;
     }
 
     bool generate()
     {
         // Forwards generate the matching code.
         ASSERT(m_ops.size());
         size_t opIndex = 0;
 
@@ -1774,29 +1801,30 @@ class YarrGenerator : private MacroAssem
             }
 
             ++opIndex;
         } while (opIndex < m_ops.size());
 
         return true;
     }
 
-    void backtrack()
+    bool backtrack()
     {
         // Backwards generate the backtracking code.
         size_t opIndex = m_ops.size();
         ASSERT(opIndex);
 
         do {
             --opIndex;
             YarrOp& op = m_ops[opIndex];
             switch (op.m_op) {
 
             case OpTerm:
-                backtrackTerm(opIndex);
+                if (!backtrackTerm(opIndex))
+                    return false;
                 break;
 
             // OpBodyAlternativeBegin/Next/End
             //
             // For each Begin/Next node representing an alternative, we need to decide what to do
             // in two circumstances:
             //  - If we backtrack back into this node, from within the alternative.
             //  - If the input check at the head of the alternative fails (if this exists).
@@ -2305,16 +2333,18 @@ class YarrGenerator : private MacroAssem
                 break;
             }
 
             case OpMatchFailed:
                 break;
             }
 
         } while (opIndex);
+
+        return true;
     }
 
     // Compilation methods:
     // ====================
 
     // opCompileParenthesesSubpattern
     // Emits ops for a subpattern (set of parentheses). These consist
     // of a set of alternatives wrapped in an outer set of nodes for
@@ -2690,21 +2720,20 @@ public:
 
         // If we encountered anything we can't handle in the JIT code
         // (e.g. backreferences) then return early.
         if (m_shouldFallBack) {
             jitObject.setFallBack(true);
             return;
         }
 
-        if (!generate()) {
+        if (!generate() || !backtrack()) {
             jitObject.setFallBack(true);
             return;
         }
-        backtrack();
 
         // Link & finalize the code.
         ExecutablePool *pool;
         bool ok;
         LinkBuffer linkBuffer(this, globalData->regexAllocator, &pool, &ok, REGEXP_CODE);
 
         // Attempt to detect OOM during linkBuffer creation.
         if (linkBuffer.unsafeCode() == nullptr) {
--- a/js/src/yarr/YarrPattern.cpp
+++ b/js/src/yarr/YarrPattern.cpp
@@ -587,92 +587,104 @@ public:
 
         for (unsigned i = 0; i < alternative->m_terms.size(); ++i) {
             PatternTerm& term = alternative->m_terms[i];
 
             switch (term.type) {
             case PatternTerm::TypeAssertionBOL:
             case PatternTerm::TypeAssertionEOL:
             case PatternTerm::TypeAssertionWordBoundary:
-                term.inputPosition = currentInputPosition.unsafeGet();
+                if (Checked<int>(currentInputPosition).safeGet(term.inputPosition))
+                    return RuntimeError;
                 break;
 
             case PatternTerm::TypeBackReference:
-                term.inputPosition = currentInputPosition.unsafeGet();
+                if (Checked<int>(currentInputPosition).safeGet(term.inputPosition))
+                    return RuntimeError;
                 term.frameLocation = currentCallFrameSize;
                 currentCallFrameSize += YarrStackSpaceForBackTrackInfoBackReference;
                 alternative->m_hasFixedSize = false;
                 break;
 
             case PatternTerm::TypeForwardReference:
                 break;
 
             case PatternTerm::TypePatternCharacter:
-                term.inputPosition = currentInputPosition.unsafeGet();
+                if (Checked<int>(currentInputPosition).safeGet(term.inputPosition))
+                    return RuntimeError;
                 if (term.quantityType != QuantifierFixedCount) {
                     term.frameLocation = currentCallFrameSize;
                     currentCallFrameSize += YarrStackSpaceForBackTrackInfoPatternCharacter;
                     alternative->m_hasFixedSize = false;
                 } else
                     currentInputPosition += term.quantityCount;
                 break;
 
             case PatternTerm::TypeCharacterClass:
-                term.inputPosition = currentInputPosition.unsafeGet();
+                if (Checked<int>(currentInputPosition).safeGet(term.inputPosition))
+                    return RuntimeError;
                 if (term.quantityType != QuantifierFixedCount) {
                     term.frameLocation = currentCallFrameSize;
                     currentCallFrameSize += YarrStackSpaceForBackTrackInfoCharacterClass;
                     alternative->m_hasFixedSize = false;
                 } else
                     currentInputPosition += term.quantityCount;
                 break;
 
             case PatternTerm::TypeParenthesesSubpattern:
                 // Note: for fixed once parentheses we will ensure at least the minimum is available; others are on their own.
                 term.frameLocation = currentCallFrameSize;
+                unsigned position;
+                if (currentInputPosition.safeGet(position))
+                    return RuntimeError;
                 if (term.quantityCount == 1 && !term.parentheses.isCopy) {
                     if (term.quantityType != QuantifierFixedCount)
                         currentCallFrameSize += YarrStackSpaceForBackTrackInfoParenthesesOnce;
-                    if (ErrorCode error = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize, currentInputPosition.unsafeGet(), &currentCallFrameSize))
+                    if (ErrorCode error = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize, position, &currentCallFrameSize))
                         return error;
                     // If quantity is fixed, then pre-check its minimum size.
                     if (term.quantityType == QuantifierFixedCount)
                         currentInputPosition += term.parentheses.disjunction->m_minimumSize;
-                    term.inputPosition = currentInputPosition.unsafeGet();
+                    if (Checked<int>(currentInputPosition).safeGet(term.inputPosition))
+                        return RuntimeError;
                 } else if (term.parentheses.isTerminal) {
                     currentCallFrameSize += YarrStackSpaceForBackTrackInfoParenthesesTerminal;
-                    if (ErrorCode error = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize, currentInputPosition.unsafeGet(), &currentCallFrameSize))
+                    if (ErrorCode error = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize, position, &currentCallFrameSize))
                         return error;
-                    term.inputPosition = currentInputPosition.unsafeGet();
+                    if (Checked<int>(currentInputPosition).safeGet(term.inputPosition))
+                        return RuntimeError;
                 } else {
-                    term.inputPosition = currentInputPosition.unsafeGet();
+                    if (Checked<int>(currentInputPosition).safeGet(term.inputPosition))
+                        return RuntimeError;
                     unsigned dummy;
-                    if (ErrorCode error = setupDisjunctionOffsets(term.parentheses.disjunction, BASE_FRAME_SIZE, currentInputPosition.unsafeGet(), &dummy))
+                    if (ErrorCode error = setupDisjunctionOffsets(term.parentheses.disjunction, BASE_FRAME_SIZE, position, &dummy))
                         return error;
                     currentCallFrameSize += YarrStackSpaceForBackTrackInfoParentheses;
                 }
                 // Fixed count of 1 could be accepted, if they have a fixed size *AND* if all alternatives are of the same length.
                 alternative->m_hasFixedSize = false;
                 break;
 
             case PatternTerm::TypeParentheticalAssertion:
-                term.inputPosition = currentInputPosition.unsafeGet();
+                if (Checked<int>(currentInputPosition).safeGet(term.inputPosition))
+                    return RuntimeError;
                 term.frameLocation = currentCallFrameSize;
-                if (ErrorCode error = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize + YarrStackSpaceForBackTrackInfoParentheticalAssertion, currentInputPosition.unsafeGet(), &currentCallFrameSize))
+                if (ErrorCode error = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize + YarrStackSpaceForBackTrackInfoParentheticalAssertion, term.inputPosition, &currentCallFrameSize))
                     return error;
                 break;
 
             case PatternTerm::TypeDotStarEnclosure:
                 alternative->m_hasFixedSize = false;
                 term.inputPosition = initialInputPosition;
                 break;
             }
         }
 
-        alternative->m_minimumSize = (currentInputPosition - initialInputPosition).unsafeGet();
+        if ((currentInputPosition - initialInputPosition).safeGet(alternative->m_minimumSize))
+            return RuntimeError;
         *callFrameSizeOut = currentCallFrameSize;
         return NoError;
     }
 
     ErrorCode setupDisjunctionOffsets(PatternDisjunction* disjunction, unsigned initialCallFrameSize, unsigned initialInputPosition, unsigned *maximumCallFrameSizeOut)
     {
         if ((disjunction != m_pattern.m_body) && (disjunction->m_alternatives.size() > 1))
             initialCallFrameSize += YarrStackSpaceForBackTrackInfoAlternative;