Bug 616491 - Limit YARR stack size to 1MB. r=mjrosenb
authorSean Stangl <sstangl@mozilla.com>
Wed, 26 Mar 2014 14:47:11 -0700
changeset 175647 fe0c6926b8b4c9f75d48f2e1de8c7064cd6ac901
parent 175646 de2d3a740e06cdb3279cbb8e88cb63db62445ebe
child 175648 ae8a5c6d6340d45fea76aa2a70364f2be3315518
push id26496
push userkwierso@gmail.com
push dateFri, 28 Mar 2014 02:28:34 +0000
treeherdermozilla-central@3c09159e01da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmjrosenb
bugs616491
milestone31.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 616491 - Limit YARR stack size to 1MB. r=mjrosenb
js/src/yarr/YarrPattern.cpp
--- a/js/src/yarr/YarrPattern.cpp
+++ b/js/src/yarr/YarrPattern.cpp
@@ -276,16 +276,17 @@ private:
     Vector<UChar> m_matchesUnicode;
     Vector<CharacterRange> m_rangesUnicode;
 };
 
 class YarrPatternConstructor {
 public:
     YarrPatternConstructor(YarrPattern& pattern)
         : m_pattern(pattern)
+        , m_stackBase(nullptr)
         , m_characterClassConstructor(pattern.m_ignoreCase)
         , m_invertParentheticalAssertion(false)
     {
         m_pattern.m_body = js_new<PatternDisjunction>();
         m_alternative = m_pattern.m_body->addNewAlternative();
         m_pattern.m_disjunctions.append(m_pattern.m_body);
     }
 
@@ -568,16 +569,24 @@ public:
     void disjunction()
     {
         m_alternative = m_alternative->m_parent->addNewAlternative();
     }
 
     ErrorCode setupAlternativeOffsets(PatternAlternative* alternative, unsigned currentCallFrameSize, unsigned initialInputPosition,
                                       unsigned *callFrameSizeOut)
     {
+        /*
+         * Attempt detection of over-recursion:
+         * "1MB should be enough stack for anyone."
+         */
+        uint8_t stackDummy_;
+        if (m_stackBase - &stackDummy_ > 1024*1024)
+            return PatternTooLarge;
+
         alternative->m_hasFixedSize = true;
         Checked<unsigned> currentInputPosition = initialInputPosition;
 
         for (unsigned i = 0; i < alternative->m_terms.size(); ++i) {
             PatternTerm& term = alternative->m_terms[i];
 
             switch (term.type) {
             case PatternTerm::TypeAssertionBOL:
@@ -836,18 +845,23 @@ public:
 
                 terms.append(PatternTerm(startsWithBOL, endsWithEOL));
                 
                 m_pattern.m_containsBOL = false;
             }
         }
     }
 
+    void setStackBase(uint8_t *stackBase) {
+        m_stackBase = stackBase;
+    }
+
 private:
     YarrPattern& m_pattern;
+    uint8_t * m_stackBase;
     PatternAlternative* m_alternative;
     CharacterClassConstructor m_characterClassConstructor;
     bool m_invertCharacterClass;
     bool m_invertParentheticalAssertion;
 };
 
 ErrorCode YarrPattern::compile(const String& patternString)
 {
@@ -868,16 +882,19 @@ ErrorCode YarrPattern::compile(const Str
         ErrorCode error =
 #endif
             parse(constructor, patternString, numSubpatterns);
 
         ASSERT(!error);
         ASSERT(numSubpatterns == m_numSubpatterns);
     }
 
+    uint8_t stackDummy_;
+    constructor.setStackBase(&stackDummy_);
+
     constructor.checkForTerminalParentheses();
     constructor.optimizeDotStarWrappedExpressions();
     constructor.optimizeBOL();
         
     if (ErrorCode error = constructor.setupOffsets())
         return error;
 
     return NoError;