mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-03-02 22:37:50 +00:00
Bug 1512260 - Make wrapper nuking work with a target realm instead of target compartment. r=kmag
For *incoming* wrappers this preserves behavior. We nuke *outgoing* wrappers when all realms in the compartment have been nuked. To implement this I moved the wasNuked flag from XPConnect to JS::Compartment as nukedOutgoingWrappers and to JS::Realm as nukedIncomingWrappers. The code to create a dead wrapper in the nuked compartment/realm case was also moved into the JS engine. I added a shell test for it. Differential Revision: https://phabricator.services.mozilla.com/D14149 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
fa80837513
commit
b8a316aca4
@ -109,21 +109,19 @@ WindowDestroyedEvent::Run() {
|
||||
JS::Rooted<JSObject*> obj(cx, currentInner->FastGetGlobalJSObject());
|
||||
if (obj && !js::IsSystemRealm(js::GetNonCCWObjectRealm(obj))) {
|
||||
JS::Realm* realm = js::GetNonCCWObjectRealm(obj);
|
||||
JS::Compartment* cpt = JS::GetCompartmentForRealm(realm);
|
||||
|
||||
nsCOMPtr<nsIPrincipal> pc =
|
||||
nsJSPrincipals::get(JS::GetRealmPrincipals(realm));
|
||||
|
||||
if (BasePrincipal::Cast(pc)->AddonPolicy()) {
|
||||
// We want to nuke all references to the add-on compartment.
|
||||
xpc::NukeAllWrappersForCompartment(
|
||||
cx, cpt,
|
||||
mIsInnerWindow ? js::DontNukeWindowReferences
|
||||
: js::NukeWindowReferences);
|
||||
// We want to nuke all references to the add-on realm.
|
||||
xpc::NukeAllWrappersForRealm(cx, realm,
|
||||
mIsInnerWindow
|
||||
? js::DontNukeWindowReferences
|
||||
: js::NukeWindowReferences);
|
||||
} else {
|
||||
// We only want to nuke wrappers for the chrome->content case
|
||||
js::NukeCrossCompartmentWrappers(
|
||||
cx, BrowserCompartmentMatcher(), cpt,
|
||||
cx, BrowserCompartmentMatcher(), realm,
|
||||
mIsInnerWindow ? js::DontNukeWindowReferences
|
||||
: js::NukeWindowReferences,
|
||||
js::NukeIncomingReferences);
|
||||
|
@ -58,8 +58,8 @@ NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(CallbackObject)
|
||||
if (MOZ_UNLIKELY(!callback)) {
|
||||
return true;
|
||||
}
|
||||
auto pvt = xpc::CompartmentPrivate::Get(callback);
|
||||
if (MOZ_LIKELY(tmp->mIncumbentGlobal && pvt) && MOZ_UNLIKELY(pvt->wasNuked)) {
|
||||
if (MOZ_LIKELY(tmp->mIncumbentGlobal) &&
|
||||
MOZ_UNLIKELY(js::NukedObjectRealm(tmp->CallbackGlobalPreserveColor()))) {
|
||||
// It's not safe to release our global reference or drop our JS objects at
|
||||
// this point, so defer their finalization until CC is finished.
|
||||
AddForDeferredFinalization(new JSObjectsDropper(tmp));
|
||||
|
@ -127,6 +127,10 @@ class CallbackObject : public nsISupports {
|
||||
// because the value of mCallback cannot change after if has been set.
|
||||
return JS::Handle<JSObject*>::fromMarkedLocation(mCallback.address());
|
||||
}
|
||||
JS::Handle<JSObject*> CallbackGlobalPreserveColor() const {
|
||||
// The comment in CallbackPreserveColor applies here as well.
|
||||
return JS::Handle<JSObject*>::fromMarkedLocation(mCallbackGlobal.address());
|
||||
}
|
||||
|
||||
/*
|
||||
* If the callback is known to be non-gray, then this method can be
|
||||
|
49
js/src/jit-test/tests/realms/nuking.js
Normal file
49
js/src/jit-test/tests/realms/nuking.js
Normal file
@ -0,0 +1,49 @@
|
||||
// Ensure nuking happens on a single target realm instead of compartment.
|
||||
|
||||
var g1 = newGlobal();
|
||||
var g2 = newGlobal({sameCompartmentAs: g1});
|
||||
g2.other = g1;
|
||||
|
||||
var o1 = g1.Math;
|
||||
var o2 = g2.Math;
|
||||
|
||||
g1.nukeAllCCWs();
|
||||
|
||||
// o1 is now dead.
|
||||
ex = null;
|
||||
try {
|
||||
assertEq(o1.abs(1), 1);
|
||||
} catch (e) {
|
||||
ex = e;
|
||||
}
|
||||
assertEq(ex.toString().includes("dead object"), true);
|
||||
|
||||
// o2 still works.
|
||||
assertEq(o2.abs(1), 1);
|
||||
|
||||
// g2 can still access g1 because they're same-compartment.
|
||||
assertEq(g2.evaluate("other.Math.abs(-2)"), 2);
|
||||
|
||||
// Attempting to create a new wrapper targeting nuked realm g1 should return a
|
||||
// dead wrapper now. Note that we can't use g1 directly because that's now a
|
||||
// dead object, so we try to get to g1 via g2.
|
||||
ex = null;
|
||||
try {
|
||||
g2.other.toString();
|
||||
} catch (e) {
|
||||
ex = e;
|
||||
}
|
||||
assertEq(ex.toString().includes("dead object"), true);
|
||||
|
||||
// Nuke g2 too. We have nuked all realms in its compartment so we should now
|
||||
// throw if we try to create a new outgoing wrapper.
|
||||
g2.evaluate("(" + function() {
|
||||
nukeAllCCWs();
|
||||
var ex = null;
|
||||
try {
|
||||
newGlobal().Array();
|
||||
} catch (e) {
|
||||
ex = e;
|
||||
}
|
||||
assertEq(ex.toString().includes('dead object'), true);
|
||||
} + ")()");
|
@ -525,10 +525,6 @@ JS_FRIEND_API JSObject* JS_NewDeadWrapper(JSContext* cx, JSObject* origObj) {
|
||||
return NewDeadProxyObject(cx, origObj);
|
||||
}
|
||||
|
||||
JS_FRIEND_API bool JS_IsScriptSourceObject(JSObject* obj) {
|
||||
return obj->is<ScriptSourceObject>();
|
||||
}
|
||||
|
||||
void js::TraceWeakMaps(WeakMapTracer* trc) {
|
||||
WeakMapBase::traceAllMappings(trc);
|
||||
}
|
||||
|
@ -106,11 +106,6 @@ extern JS_FRIEND_API bool JS_IsDeadWrapper(JSObject* obj);
|
||||
extern JS_FRIEND_API JSObject* JS_NewDeadWrapper(
|
||||
JSContext* cx, JSObject* origObject = nullptr);
|
||||
|
||||
/**
|
||||
* Determine whether the given object is a ScriptSourceObject.
|
||||
*/
|
||||
extern JS_FRIEND_API bool JS_IsScriptSourceObject(JSObject* obj);
|
||||
|
||||
/*
|
||||
* Used by the cycle collector to trace through a shape or object group and
|
||||
* all cycle-participating data it reaches, using bounded stack space.
|
||||
@ -1184,10 +1179,15 @@ struct CompartmentsWithPrincipals : public CompartmentFilter {
|
||||
};
|
||||
|
||||
extern JS_FRIEND_API bool NukeCrossCompartmentWrappers(
|
||||
JSContext* cx, const CompartmentFilter& sourceFilter,
|
||||
JS::Compartment* target, NukeReferencesToWindow nukeReferencesToWindow,
|
||||
JSContext* cx, const CompartmentFilter& sourceFilter, JS::Realm* target,
|
||||
NukeReferencesToWindow nukeReferencesToWindow,
|
||||
NukeReferencesFromTarget nukeReferencesFromTarget);
|
||||
|
||||
extern JS_FRIEND_API bool AllowNewWrapper(JS::Compartment* target,
|
||||
JSObject* obj);
|
||||
|
||||
extern JS_FRIEND_API bool NukedObjectRealm(JSObject* obj);
|
||||
|
||||
/* Specify information about DOMProxy proxies in the DOM, for use by ICs. */
|
||||
|
||||
/*
|
||||
|
@ -460,30 +460,47 @@ JS_FRIEND_API void js::NukeCrossCompartmentWrapper(JSContext* cx,
|
||||
NukeRemovedCrossCompartmentWrapper(cx, wrapper);
|
||||
}
|
||||
|
||||
// Returns true iff all realms in the compartment have been nuked.
|
||||
static bool NukedAllRealms(JS::Compartment* comp) {
|
||||
for (RealmsInCompartmentIter realm(comp); !realm.done(); realm.next()) {
|
||||
if (!realm->nukedIncomingWrappers) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* NukeChromeCrossCompartmentWrappersForGlobal reaches into chrome and cuts
|
||||
* all of the cross-compartment wrappers that point to objects parented to
|
||||
* obj's global. The snag here is that we need to avoid cutting wrappers that
|
||||
* point to the window object on page navigation (inner window destruction)
|
||||
* and only do that on tab close (outer window destruction). Thus the
|
||||
* option of how to handle the global object.
|
||||
* all of the cross-compartment wrappers that point to an object in the |target|
|
||||
* realm. The snag here is that we need to avoid cutting wrappers that point to
|
||||
* the window object on page navigation (inner window destruction) and only do
|
||||
* that on tab close (outer window destruction). Thus the option of how to
|
||||
* handle the global object.
|
||||
*/
|
||||
JS_FRIEND_API bool js::NukeCrossCompartmentWrappers(
|
||||
JSContext* cx, const CompartmentFilter& sourceFilter,
|
||||
JS::Compartment* target, js::NukeReferencesToWindow nukeReferencesToWindow,
|
||||
JSContext* cx, const CompartmentFilter& sourceFilter, JS::Realm* target,
|
||||
js::NukeReferencesToWindow nukeReferencesToWindow,
|
||||
js::NukeReferencesFromTarget nukeReferencesFromTarget) {
|
||||
CHECK_THREAD(cx);
|
||||
JSRuntime* rt = cx->runtime();
|
||||
|
||||
// If we're nuking all wrappers into the target realm, prevent us from
|
||||
// creating new wrappers for it in the future.
|
||||
if (nukeReferencesFromTarget == NukeAllReferences) {
|
||||
target->nukedIncomingWrappers = true;
|
||||
}
|
||||
|
||||
for (CompartmentsIter c(rt); !c.done(); c.next()) {
|
||||
if (!sourceFilter.match(c)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the compartment matches both the source and target filter, we may
|
||||
// want to cut both incoming and outgoing wrappers.
|
||||
// If the realm matches both the source and target filter, we may want to
|
||||
// cut outgoing wrappers too, if we nuked all realms in the compartment.
|
||||
bool nukeAll =
|
||||
(nukeReferencesFromTarget == NukeAllReferences && target == c.get());
|
||||
(nukeReferencesFromTarget == NukeAllReferences &&
|
||||
target->compartment() == c.get() && NukedAllRealms(c.get()));
|
||||
|
||||
// Iterate only the wrappers that have target compartment matched unless
|
||||
// |nukeAll| is true. The string wrappers that we're not interested in
|
||||
@ -492,9 +509,10 @@ JS_FRIEND_API bool js::NukeCrossCompartmentWrappers(
|
||||
// initializing NonStringWrapperEnum.
|
||||
mozilla::Maybe<Compartment::NonStringWrapperEnum> e;
|
||||
if (MOZ_LIKELY(!nukeAll)) {
|
||||
e.emplace(c, target);
|
||||
e.emplace(c, target->compartment());
|
||||
} else {
|
||||
e.emplace(c);
|
||||
c.get()->nukedOutgoingWrappers = true;
|
||||
}
|
||||
for (; !e->empty(); e->popFront()) {
|
||||
// Skip debugger references because NukeCrossCompartmentWrapper()
|
||||
@ -511,6 +529,13 @@ JS_FRIEND_API bool js::NukeCrossCompartmentWrappers(
|
||||
// the wrapper, this could save us a bit of time.
|
||||
JSObject* wrapped = UncheckedUnwrap(k.as<JSObject*>());
|
||||
|
||||
// Don't nuke wrappers for objects in other realms in the target
|
||||
// compartment unless nukeAll is set because in that case we want to nuke
|
||||
// all outgoing wrappers for the current compartment.
|
||||
if (!nukeAll && wrapped->nonCCWRealm() != target) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// We never nuke script source objects, since only ever used internally by
|
||||
// the JS engine, and are expected to remain valid throughout a scripts
|
||||
// lifetime.
|
||||
@ -534,6 +559,31 @@ JS_FRIEND_API bool js::NukeCrossCompartmentWrappers(
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_FRIEND_API bool js::AllowNewWrapper(JS::Compartment* target, JSObject* obj) {
|
||||
// Disallow creating new wrappers if we nuked the object realm or target
|
||||
// compartment. However, we always need to provide live wrappers for
|
||||
// ScriptSourceObjects, since they're used for cross-compartment cloned
|
||||
// scripts, and need to remain accessible even after the original realm has
|
||||
// been nuked.
|
||||
|
||||
MOZ_ASSERT(obj->compartment() != target);
|
||||
|
||||
if (obj->is<ScriptSourceObject>()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (target->nukedOutgoingWrappers ||
|
||||
obj->nonCCWRealm()->nukedIncomingWrappers) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_FRIEND_API bool js::NukedObjectRealm(JSObject* obj) {
|
||||
return obj->nonCCWRealm()->nukedIncomingWrappers;
|
||||
}
|
||||
|
||||
// Given a cross-compartment wrapper |wobj|, update it to point to
|
||||
// |newTarget|. This recomputes the wrapper with JS_WrapValue, and thus can be
|
||||
// useful even if wrapper already points to newTarget.
|
||||
|
@ -6229,7 +6229,7 @@ static bool NukeAllCCWs(JSContext* cx, unsigned argc, Value* vp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
NukeCrossCompartmentWrappers(cx, AllCompartments(), cx->compartment(),
|
||||
NukeCrossCompartmentWrappers(cx, AllCompartments(), cx->realm(),
|
||||
NukeWindowReferences, NukeAllReferences);
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
@ -8490,7 +8490,7 @@ JS_FN_HELP("parseBin", BinParse, 1, 0,
|
||||
|
||||
JS_FN_HELP("nukeAllCCWs", NukeAllCCWs, 0, 0,
|
||||
"nukeAllCCWs()",
|
||||
" Like nukeCCW, but for all CrossCompartmentWrappers targeting the current compartment."),
|
||||
" Like nukeCCW, but for all CrossCompartmentWrappers targeting the current realm."),
|
||||
|
||||
JS_FN_HELP("recomputeWrappers", RecomputeWrappers, 2, 0,
|
||||
"recomputeWrappers([src, [target]])",
|
||||
|
@ -224,6 +224,17 @@ bool Compartment::getNonWrapperObjectForCurrentCompartment(
|
||||
return true;
|
||||
}
|
||||
|
||||
// Disallow creating new wrappers if we nuked the object's realm or the
|
||||
// current compartment.
|
||||
if (!AllowNewWrapper(this, obj)) {
|
||||
JSObject* res = NewDeadProxyObject(cx);
|
||||
if (!res) {
|
||||
return false;
|
||||
}
|
||||
obj.set(res);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Invoke the prewrap callback. The prewrap callback is responsible for
|
||||
// doing similar reification as above, but can account for any additional
|
||||
// embedder requirements.
|
||||
|
@ -446,6 +446,12 @@ class JS::Compartment {
|
||||
bool hasEnteredRealm = false;
|
||||
} gcState;
|
||||
|
||||
// True if all outgoing wrappers have been nuked. This happens when all realms
|
||||
// have been nuked and NukeCrossCompartmentWrappers is called with the
|
||||
// NukeAllReferences option. This prevents us from creating new wrappers for
|
||||
// the compartment.
|
||||
bool nukedOutgoingWrappers = false;
|
||||
|
||||
JS::Zone* zone() { return zone_; }
|
||||
const JS::Zone* zone() const { return zone_; }
|
||||
|
||||
|
@ -441,6 +441,11 @@ class JS::Realm : public JS::shadow::Realm {
|
||||
bool firedOnNewGlobalObject = false;
|
||||
#endif
|
||||
|
||||
// True if all incoming wrappers have been nuked. This happens when
|
||||
// NukeCrossCompartmentWrappers is called with the NukeAllReferences option.
|
||||
// This prevents us from creating new wrappers for the compartment.
|
||||
bool nukedIncomingWrappers = false;
|
||||
|
||||
private:
|
||||
void updateDebuggerObservesFlag(unsigned flag);
|
||||
|
||||
|
@ -2077,7 +2077,7 @@ nsXPCComponents_Utils::NukeSandbox(HandleValue obj, JSContext* cx) {
|
||||
RootedObject sb(cx, UncheckedUnwrap(wrapper));
|
||||
NS_ENSURE_TRUE(IsSandbox(sb), NS_ERROR_INVALID_ARG);
|
||||
|
||||
xpc::NukeAllWrappersForCompartment(cx, GetObjectCompartment(sb));
|
||||
xpc::NukeAllWrappersForRealm(cx, GetNonCCWObjectRealm(sb));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -195,7 +195,6 @@ CompartmentPrivate::CompartmentPrivate(JS::Compartment* c,
|
||||
isSandboxCompartment(false),
|
||||
universalXPConnectEnabled(false),
|
||||
forcePermissiveCOWs(false),
|
||||
wasNuked(false),
|
||||
mWrappedJSMap(JSObject2WrappedJSMap::newMap(XPC_JS_MAP_LENGTH)) {
|
||||
MOZ_COUNT_CTOR(xpc::CompartmentPrivate);
|
||||
mozilla::PodArrayZero(wrapperDenialWarnings);
|
||||
@ -590,36 +589,26 @@ nsGlobalWindowInner* CurrentWindowOrNull(JSContext* cx) {
|
||||
return glob ? WindowOrNull(glob) : nullptr;
|
||||
}
|
||||
|
||||
// Nukes all wrappers into or out of the given compartment, and prevents new
|
||||
// wrappers from being created. Additionally marks the compartment as
|
||||
// Nukes all wrappers into or out of the given realm, and prevents new
|
||||
// wrappers from being created. Additionally marks the realm as
|
||||
// unscriptable after wrappers have been nuked.
|
||||
//
|
||||
// Note: This should *only* be called for browser or extension compartments.
|
||||
// Note: This should *only* be called for browser or extension realms.
|
||||
// Wrappers between web compartments must never be cut in web-observable
|
||||
// ways.
|
||||
void NukeAllWrappersForCompartment(
|
||||
JSContext* cx, JS::Compartment* compartment,
|
||||
void NukeAllWrappersForRealm(
|
||||
JSContext* cx, JS::Realm* realm,
|
||||
js::NukeReferencesToWindow nukeReferencesToWindow) {
|
||||
// First, nuke all wrappers into or out of the target compartment. Once
|
||||
// the compartment is marked as nuked, WrapperFactory will refuse to
|
||||
// create new live wrappers for it, in either direction. This means that
|
||||
// we need to be sure that we don't have any existing cross-compartment
|
||||
// wrappers which may be replaced with dead wrappers during unrelated
|
||||
// wrapper recomputation *before* we set that bit.
|
||||
js::NukeCrossCompartmentWrappers(cx, js::AllCompartments(), compartment,
|
||||
// We do the following:
|
||||
// * Nuke all wrappers into the realm.
|
||||
// * Nuke all wrappers out of the realm's compartment, once we have nuked all
|
||||
// realms in it.
|
||||
js::NukeCrossCompartmentWrappers(cx, js::AllCompartments(), realm,
|
||||
nukeReferencesToWindow,
|
||||
js::NukeAllReferences);
|
||||
|
||||
// At this point, we should cross-compartment wrappers for the nuked
|
||||
// compartment. Set the wasNuked bit so WrapperFactory will return a
|
||||
// DeadObjectProxy when asked to create a new wrapper for it, and mark as
|
||||
// unscriptable.
|
||||
xpc::CompartmentPrivate::Get(compartment)->wasNuked = true;
|
||||
|
||||
auto blockScriptability = [](JSContext*, void*, Handle<Realm*> realm) {
|
||||
xpc::RealmPrivate::Get(realm)->scriptability.Block();
|
||||
};
|
||||
JS::IterateRealmsInCompartment(cx, compartment, nullptr, blockScriptability);
|
||||
// Mark the realm as unscriptable.
|
||||
xpc::RealmPrivate::Get(realm)->scriptability.Block();
|
||||
}
|
||||
|
||||
} // namespace xpc
|
||||
|
@ -2807,10 +2807,6 @@ class CompartmentPrivate {
|
||||
// Using it in production is inherently unsafe.
|
||||
bool forcePermissiveCOWs;
|
||||
|
||||
// True if this compartment has been nuked. If true, any wrappers into or
|
||||
// out of it should be considered invalid.
|
||||
bool wasNuked;
|
||||
|
||||
// Whether we've emitted a warning about a property that was filtered out
|
||||
// by a security wrapper. See XrayWrapper.cpp.
|
||||
bool wrapperDenialWarnings[WrapperDenialTypeCount];
|
||||
|
@ -409,10 +409,9 @@ bool StringToJsval(JSContext* cx, mozilla::dom::DOMString& str,
|
||||
nsIPrincipal* GetCompartmentPrincipal(JS::Compartment* compartment);
|
||||
nsIPrincipal* GetRealmPrincipal(JS::Realm* realm);
|
||||
|
||||
void NukeAllWrappersForCompartment(
|
||||
JSContext* cx, JS::Compartment* compartment,
|
||||
js::NukeReferencesToWindow nukeReferencesToWindow =
|
||||
js::NukeWindowReferences);
|
||||
void NukeAllWrappersForRealm(JSContext* cx, JS::Realm* realm,
|
||||
js::NukeReferencesToWindow nukeReferencesToWindow =
|
||||
js::NukeWindowReferences);
|
||||
|
||||
void SetLocationForGlobal(JSObject* global, const nsACString& location);
|
||||
void SetLocationForGlobal(JSObject* global, nsIURI* locationURI);
|
||||
|
@ -180,23 +180,6 @@ void WrapperFactory::PrepareForWrapping(JSContext* cx, HandleObject scope,
|
||||
return;
|
||||
}
|
||||
|
||||
// If we've somehow gotten to this point after either the source or target
|
||||
// compartment has been nuked, return a DeadObjectProxy to prevent further
|
||||
// access.
|
||||
// However, we always need to provide live wrappers for ScriptSourceObjects,
|
||||
// since they're used for cross-compartment cloned scripts, and need to
|
||||
// remain accessible even after the original compartment has been nuked.
|
||||
JS::Compartment* origin = js::GetObjectCompartment(obj);
|
||||
JS::Compartment* target = js::GetObjectCompartment(scope);
|
||||
if (!JS_IsScriptSourceObject(obj) &&
|
||||
(CompartmentPrivate::Get(origin)->wasNuked ||
|
||||
CompartmentPrivate::Get(target)->wasNuked)) {
|
||||
NS_WARNING("Trying to create a wrapper into or out of a nuked compartment");
|
||||
|
||||
retObj.set(JS_NewDeadWrapper(cx));
|
||||
return;
|
||||
}
|
||||
|
||||
// If we've got a WindowProxy, there's nothing special that needs to be
|
||||
// done here, and we can move on to the next phase of wrapping. We handle
|
||||
// this case first to allow us to assert against wrappers below.
|
||||
@ -348,12 +331,9 @@ static void DEBUG_CheckUnwrapSafety(HandleObject obj,
|
||||
const js::Wrapper* handler,
|
||||
JS::Compartment* origin,
|
||||
JS::Compartment* target) {
|
||||
if (!JS_IsScriptSourceObject(obj) &&
|
||||
(CompartmentPrivate::Get(origin)->wasNuked ||
|
||||
CompartmentPrivate::Get(target)->wasNuked)) {
|
||||
// If either compartment has already been nuked, we should have returned
|
||||
// a dead wrapper from our prewrap callback, and this function should
|
||||
// not be called.
|
||||
if (!js::AllowNewWrapper(target, obj)) {
|
||||
// The JS engine should have returned a dead wrapper in this case and we
|
||||
// shouldn't even get here.
|
||||
MOZ_ASSERT_UNREACHABLE("CheckUnwrapSafety called for a dead wrapper");
|
||||
} else if (AccessCheck::isChrome(target) ||
|
||||
xpc::IsUniversalXPConnectEnabled(target)) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user