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:
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;