tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit bc7ee6d4faa5754fe29b26f1c69033e7f78d00e6
parent 091d1f53bd22e6f0c8dfef8262e4313c08f04632
Author: Atila Butkovits <abutkovits@mozilla.com>
Date:   Fri, 17 Oct 2025 16:18:43 +0300

Revert "Bug 1992107: Handle near overrecursion in RegExpDepthCheck. r=iain" for causing failures at RegExpCompiler.

This reverts commit 7c3cc4a7aa4ee76df736855165b44cca0d1a20c9.

Diffstat:
Mjs/public/friend/StackLimits.h | 17+++++------------
Mjs/src/irregexp/RegExpAPI.cpp | 30+++++++++++++++++++++---------
Djs/src/jit-test/tests/regexp/over-recursion-with-leaf-nodes.js | 25-------------------------
3 files changed, 26 insertions(+), 46 deletions(-)

diff --git a/js/public/friend/StackLimits.h b/js/public/friend/StackLimits.h @@ -163,8 +163,6 @@ class MOZ_RAII AutoCheckRecursionLimit { FrontendContext* fc) const; [[nodiscard]] MOZ_ALWAYS_INLINE bool checkWithExtra(JSContext* cx, size_t extra) const; - [[nodiscard]] MOZ_ALWAYS_INLINE bool checkWithExtraDontReport( - JSContext* cx, size_t extra) const; [[nodiscard]] MOZ_ALWAYS_INLINE bool checkWithStackPointerDontReport( JSContext* cx, void* sp) const; [[nodiscard]] MOZ_ALWAYS_INLINE bool checkWithStackPointerDontReport( @@ -287,22 +285,17 @@ MOZ_ALWAYS_INLINE bool AutoCheckRecursionLimit::checkWithStackPointerDontReport( MOZ_ALWAYS_INLINE bool AutoCheckRecursionLimit::checkWithExtra( JSContext* cx, size_t extra) const { - if (MOZ_UNLIKELY(!checkWithExtraDontReport(cx, extra))) { - ReportOverRecursed(cx); - return false; - } - return true; -} - -MOZ_ALWAYS_INLINE bool AutoCheckRecursionLimit::checkWithExtraDontReport( - JSContext* cx, size_t extra) const { char* sp = reinterpret_cast<char*>(__builtin_frame_address(0)); #if JS_STACK_GROWTH_DIRECTION > 0 sp += extra; #else sp -= extra; #endif - return checkWithStackPointerDontReport(cx, sp); + if (MOZ_UNLIKELY(!checkWithStackPointerDontReport(cx, sp))) { + ReportOverRecursed(cx); + return false; + } + return true; } MOZ_ALWAYS_INLINE bool AutoCheckRecursionLimit::checkSystem( diff --git a/js/src/irregexp/RegExpAPI.cpp b/js/src/irregexp/RegExpAPI.cpp @@ -417,10 +417,12 @@ class RegExpDepthCheck final : public v8::internal::RegExpVisitor { } // Leaf nodes with no children -#define LEAF_DEPTH(Kind) \ - void* Visit##Kind(v8::internal::RegExp##Kind* node, void*) override { \ - AutoCheckRecursionLimit recursion(cx_); \ - return (void*)recursion.checkWithExtraDontReport(cx_, FRAME_PADDING); \ +#define LEAF_DEPTH(Kind) \ + void* Visit##Kind(v8::internal::RegExp##Kind* node, void*) override { \ + uint8_t padding[FRAME_PADDING]; \ + dummy_ = padding; /* Prevent padding from being optimized away.*/ \ + AutoCheckRecursionLimit recursion(cx_); \ + return (void*)recursion.checkDontReport(cx_); \ } LEAF_DEPTH(Assertion) @@ -435,8 +437,10 @@ class RegExpDepthCheck final : public v8::internal::RegExpVisitor { // Wrapper nodes with one child #define WRAPPER_DEPTH(Kind) \ void* Visit##Kind(v8::internal::RegExp##Kind* node, void*) override { \ + uint8_t padding[FRAME_PADDING]; \ + dummy_ = padding; /* Prevent padding from being optimized away.*/ \ AutoCheckRecursionLimit recursion(cx_); \ - if (!recursion.checkWithExtraDontReport(cx_, FRAME_PADDING)) { \ + if (!recursion.checkDontReport(cx_)) { \ return nullptr; \ } \ return node->body()->Accept(this, nullptr); \ @@ -450,8 +454,10 @@ class RegExpDepthCheck final : public v8::internal::RegExpVisitor { void* VisitAlternative(v8::internal::RegExpAlternative* node, void*) override { + uint8_t padding[FRAME_PADDING]; + dummy_ = padding; /* Prevent padding from being optimized away.*/ AutoCheckRecursionLimit recursion(cx_); - if (!recursion.checkWithExtraDontReport(cx_, FRAME_PADDING)) { + if (!recursion.checkDontReport(cx_)) { return nullptr; } for (auto* child : *node->nodes()) { @@ -463,8 +469,10 @@ class RegExpDepthCheck final : public v8::internal::RegExpVisitor { } void* VisitDisjunction(v8::internal::RegExpDisjunction* node, void*) override { + uint8_t padding[FRAME_PADDING]; + dummy_ = padding; /* Prevent padding from being optimized away.*/ AutoCheckRecursionLimit recursion(cx_); - if (!recursion.checkWithExtraDontReport(cx_, FRAME_PADDING)) { + if (!recursion.checkDontReport(cx_)) { return nullptr; } for (auto* child : *node->alternatives()) { @@ -476,8 +484,10 @@ class RegExpDepthCheck final : public v8::internal::RegExpVisitor { } void* VisitClassSetExpression(v8::internal::RegExpClassSetExpression* node, void*) override { + uint8_t padding[FRAME_PADDING]; + dummy_ = padding; /* Prevent padding from being optimized away.*/ AutoCheckRecursionLimit recursion(cx_); - if (!recursion.checkWithExtraDontReport(cx_, FRAME_PADDING)) { + if (!recursion.checkDontReport(cx_)) { return nullptr; } for (auto* child : *node->operands()) { @@ -490,6 +500,7 @@ class RegExpDepthCheck final : public v8::internal::RegExpVisitor { private: JSContext* cx_; + void* dummy_ = nullptr; // This size is picked to be comfortably larger than any // RegExp*::ToNode stack frame. @@ -783,7 +794,8 @@ bool CompilePattern(JSContext* cx, MutableHandleRegExpShared re, // Avoid stack overflow while recursively walking the AST. RegExpDepthCheck depthCheck(cx); if (!depthCheck.check(data.tree)) { - ReportOverRecursed(cx); + JS_ReportErrorASCII(cx, "regexp too big"); + cx->reportResourceExhaustion(); return false; } diff --git a/js/src/jit-test/tests/regexp/over-recursion-with-leaf-nodes.js b/js/src/jit-test/tests/regexp/over-recursion-with-leaf-nodes.js @@ -1,25 +0,0 @@ -function hasChildNodes() { - // Recurse so we get close to the stack limit. - try { - hasChildNodes(); - } catch { - // Ignore over-recursion error. - } - - // RegExp with child nodes. - return RegExp(".|.").test(""); -} -hasChildNodes(); - -function hasLeafNode() { - // Recurse so we get close to the stack limit. - try { - hasLeafNode(); - } catch { - // Ignore over-recursion error. - } - - // RegExp consisting of a single leaf node. - return RegExp(".").test(""); -} -hasLeafNode();