tor-browser

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

commit 40fae03a754652c2f50e582698646bd2fb3563a1
parent be4ddfb1f4e5c2c1cfdc8fec68aee231b2a3bbdc
Author: Jon Coppeard <jcoppeard@mozilla.com>
Date:   Tue,  2 Dec 2025 09:22:07 +0000

Bug 2003219 - Unwrap regexp before calling Print*Help shell functions r=arai

Getters can nuke a CCW to a RegExpObject so we can't assume we can unwrap this
and cast it to a RegExpObject later.

Differential Revision: https://phabricator.services.mozilla.com/D274723

Diffstat:
Ajs/src/jit-test/tests/basic/bug-2003219.js | 13+++++++++++++
Mjs/src/shell/js.cpp | 29+++++++++++------------------
2 files changed, 24 insertions(+), 18 deletions(-)

diff --git a/js/src/jit-test/tests/basic/bug-2003219.js b/js/src/jit-test/tests/basic/bug-2003219.js @@ -0,0 +1,13 @@ +var otherGlobal = newGlobal({newCompartment: true}); +var ccwRegex = otherGlobal.eval("/test/"); + +// Define a getter for "lazy" that nukes CCWs when accessed during enumeration +Object.defineProperty(this, "lazy", { + get: function() { + otherGlobal.eval("nukeAllCCWs()"); + return false; + }, + configurable: true +}); + +help(ccwRegex); diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp @@ -11035,17 +11035,12 @@ static bool MatchPattern(JSContext* cx, JS::Handle<RegExpObject*> regex, } static bool PrintEnumeratedHelp(JSContext* cx, HandleObject obj, - HandleObject pattern, bool brief) { + Handle<RegExpObject*> pattern, bool brief) { RootedIdVector idv(cx); if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY | JSITER_HIDDEN, &idv)) { return false; } - Rooted<RegExpObject*> regex(cx); - if (pattern) { - regex = &UncheckedUnwrap(pattern)->as<RegExpObject>(); - } - for (size_t i = 0; i < idv.length(); i++) { RootedValue v(cx); RootedId id(cx, idv[i]); @@ -11057,7 +11052,7 @@ static bool PrintEnumeratedHelp(JSContext* cx, HandleObject obj, } RootedObject funcObj(cx, &v.toObject()); - if (regex) { + if (pattern) { // Only pay attention to objects with a 'help' property, which will // either be documented functions or interface objects. if (!JS_GetProperty(cx, funcObj, "help", &v)) { @@ -11083,7 +11078,7 @@ static bool PrintEnumeratedHelp(JSContext* cx, HandleObject obj, Rooted<JSString*> inputStr(cx, v.toString()); bool result = false; - if (!MatchPattern(cx, regex, inputStr, &result)) { + if (!MatchPattern(cx, pattern, inputStr, &result)) { return false; } if (!result) { @@ -11099,22 +11094,18 @@ static bool PrintEnumeratedHelp(JSContext* cx, HandleObject obj, return true; } -static bool PrintExtraGlobalEnumeratedHelp(JSContext* cx, HandleObject pattern, +static bool PrintExtraGlobalEnumeratedHelp(JSContext* cx, + Handle<RegExpObject*> pattern, bool brief) { - Rooted<RegExpObject*> regex(cx); - if (pattern) { - regex = &UncheckedUnwrap(pattern)->as<RegExpObject>(); - } - for (const auto& item : extraGlobalBindingsWithHelp) { - if (regex) { + if (pattern) { JS::Rooted<JSString*> name(cx, JS_NewStringCopyZ(cx, item.name)); if (!name) { return false; } bool result = false; - if (!MatchPattern(cx, regex, name, &result)) { + if (!MatchPattern(cx, pattern, name, &result)) { return false; } if (!result) { @@ -11171,10 +11162,12 @@ static bool Help(JSContext* cx, unsigned argc, Value* vp) { if (isRegexp) { // help(/pattern/) - if (!PrintEnumeratedHelp(cx, global, obj, false)) { + Rooted<RegExpObject*> pattern(cx, + &UncheckedUnwrap(obj)->as<RegExpObject>()); + if (!PrintEnumeratedHelp(cx, global, pattern, false)) { return false; } - if (!PrintExtraGlobalEnumeratedHelp(cx, obj, false)) { + if (!PrintExtraGlobalEnumeratedHelp(cx, pattern, false)) { return false; } return true;