Bug 616491 - Limit YARR stack size to 1MB. r=mjrosenb, a=sledru
authorSean Stangl <sstangl@mozilla.com>
Wed, 26 Mar 2014 14:47:11 -0700
changeset 192448 e0cac690e8ae01f816bb0f536289ceb675e10d16
parent 192447 883979177a5149a44ed836566f059e9fcef7a7c6
child 192449 1b0d28323d93f7e0ee9b482411c5c295353483d2
push id474
push userasasaki@mozilla.com
push dateMon, 02 Jun 2014 21:01:02 +0000
treeherdermozilla-release@967f4cf1b31c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmjrosenb, sledru
bugs616491
milestone30.0a2
Bug 616491 - Limit YARR stack size to 1MB. r=mjrosenb, a=sledru
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;