diff --git a/js/src/js.msg b/js/src/js.msg index b979b6e74e5c..f08a05ea77d3 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -313,7 +313,7 @@ MSG_DEF(JSMSG_CANT_CHANGE_EXTENSIBILITY, 259, 0, JSEXN_TYPEERR, "can't change ob MSG_DEF(JSMSG_SC_BAD_SERIALIZED_DATA, 260, 1, JSEXN_INTERNALERR, "bad serialized structured data ({0})") MSG_DEF(JSMSG_SC_UNSUPPORTED_TYPE, 261, 0, JSEXN_TYPEERR, "unsupported type for structured data") MSG_DEF(JSMSG_SC_RECURSION, 262, 0, JSEXN_INTERNALERR, "recursive object") -MSG_DEF(JSMSG_UNUSED263, 263, 0, JSEXN_NONE, "") +MSG_DEF(JSMSG_DEBUG_CANT_DEBUG_GLOBAL, 263, 0, JSEXN_ERR, "passing non-debuggable global to addDebuggee") MSG_DEF(JSMSG_BAD_CLONE_VERSION, 264, 0, JSEXN_ERR, "unsupported structured clone version") MSG_DEF(JSMSG_CANT_CLONE_OBJECT, 265, 0, JSEXN_TYPEERR, "can't clone object") MSG_DEF(JSMSG_DEBUG_RESUMPTION_VALUE_DISALLOWED, 266, 0, JSEXN_TYPEERR, "resumption values are disallowed in this hook") diff --git a/js/src/jsapi.h b/js/src/jsapi.h index b2d0a45b7a41..7da0c0f8260e 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -3223,9 +3223,11 @@ SameZoneAs(JSObject *obj) struct JS_PUBLIC_API(CompartmentOptions) { ZoneSpecifier zoneSpec; JSVersion version; + bool invisibleToDebugger; explicit CompartmentOptions() : zoneSpec(JS::FreshZone) , version(JSVERSION_UNKNOWN) + , invisibleToDebugger(false) {} CompartmentOptions &setZone(ZoneSpecifier spec) { zoneSpec = spec; return *this; } @@ -3234,6 +3236,15 @@ struct JS_PUBLIC_API(CompartmentOptions) { version = version_; return *this; } + + // Certain scopes (i.e. XBL compilation scopes) are implementation details + // of the embedding, and references to them should never leak out to script. + // This flag causes the this compartment to skip firing onNewGlobalObject + // and makes addDebuggee a no-op for this global. + CompartmentOptions &setInvisibleToDebugger(bool invisible) { + invisibleToDebugger = invisible; + return *this; + } }; } /* namespace JS */ diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 806092e3fa32..00b2f5c71ec4 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -1339,6 +1339,8 @@ void Debugger::slowPathOnNewGlobalObject(JSContext *cx, Handle global) { JS_ASSERT(!JS_CLIST_IS_EMPTY(&cx->runtime()->onNewGlobalObjectWatchers)); + if (global->compartment()->options().invisibleToDebugger) + return; /* * Make a copy of the runtime's onNewGlobalObjectWatchers before running the @@ -1958,7 +1960,7 @@ Debugger::addAllGlobalsAsDebuggees(JSContext *cx, unsigned argc, Value *vp) THIS_DEBUGGER(cx, argc, vp, "addAllGlobalsAsDebuggees", args, dbg); AutoDebugModeGC dmgc(cx->runtime()); for (CompartmentsIter c(cx->runtime()); !c.done(); c.next()) { - if (c == dbg->object->compartment()) + if (c == dbg->object->compartment() || c->options().invisibleToDebugger) continue; c->zone()->scheduledForDestruction = false; GlobalObject *global = c->maybeGlobal(); @@ -2134,7 +2136,16 @@ Debugger::addDebuggeeGlobal(JSContext *cx, if (debuggees.has(global)) return true; + // Callers should generally be unable to get a reference to a debugger- + // invisible global in order to pass it to addDebuggee. But this is possible + // with certain testing aides we expose in the shell, so just make addDebuggee + // throw in that case. JSCompartment *debuggeeCompartment = global->compartment(); + if (debuggeeCompartment->options().invisibleToDebugger) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_DEBUG_CANT_DEBUG_GLOBAL); + return false; + } /* * Check for cycles. If global's compartment is reachable from this