mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 754989 - Nuke dead cross-compartment wrappers during brain transplant (r=bholley)
This commit is contained in:
parent
74fcb7d4a3
commit
520e8ad0c3
@ -1539,6 +1539,8 @@ JS_TransplantObject(JSContext *cx, JSObject *origobj, JSObject *target)
|
||||
{
|
||||
AssertNoGC(cx);
|
||||
JS_ASSERT(origobj != target);
|
||||
JS_ASSERT(!IsCrossCompartmentWrapper(origobj));
|
||||
JS_ASSERT(!IsCrossCompartmentWrapper(target));
|
||||
|
||||
JSCompartment *destination = target->compartment();
|
||||
WrapperMap &map = destination->crossCompartmentWrappers;
|
||||
@ -1547,7 +1549,7 @@ JS_TransplantObject(JSContext *cx, JSObject *origobj, JSObject *target)
|
||||
|
||||
if (origobj->compartment() == destination) {
|
||||
// If the original object is in the same compartment as the
|
||||
// destination, then we know that we won't find wrapper in the
|
||||
// destination, then we know that we won't find a wrapper in the
|
||||
// destination's cross compartment map and that the same
|
||||
// object will continue to work.
|
||||
if (!origobj->swap(cx, target))
|
||||
@ -1558,7 +1560,12 @@ JS_TransplantObject(JSContext *cx, JSObject *origobj, JSObject *target)
|
||||
// the new compartment. If there is, we use its identity and swap
|
||||
// in the contents of |target|.
|
||||
newIdentity = &p->value.toObject();
|
||||
|
||||
// When we remove origv from the wrapper map, its wrapper, newIdentity,
|
||||
// must immediately cease to be a cross-compartment wrapper. Neuter it.
|
||||
map.remove(p);
|
||||
NukeCrossCompartmentWrapper(newIdentity);
|
||||
|
||||
if (!newIdentity->swap(cx, target))
|
||||
return NULL;
|
||||
} else {
|
||||
@ -1579,8 +1586,7 @@ JS_TransplantObject(JSContext *cx, JSObject *origobj, JSObject *target)
|
||||
return NULL;
|
||||
if (!origobj->swap(cx, newIdentityWrapper))
|
||||
return NULL;
|
||||
origobj->compartment()->crossCompartmentWrappers.put(ObjectValue(*newIdentity),
|
||||
origv);
|
||||
origobj->compartment()->crossCompartmentWrappers.put(ObjectValue(*newIdentity), origv);
|
||||
}
|
||||
|
||||
// The new identity object might be one of several things. Return it to avoid
|
||||
@ -1615,8 +1621,12 @@ RemapWrappers(JSContext *cx, JSObject *orig, JSObject *target)
|
||||
JSObject *wobj = &begin->toObject();
|
||||
JSCompartment *wcompartment = wobj->compartment();
|
||||
WrapperMap &pmap = wcompartment->crossCompartmentWrappers;
|
||||
|
||||
// When we remove origv from the wrapper map, its wrapper, wobj, must
|
||||
// immediately cease to be a cross-compartment wrapper. Neuter it.
|
||||
JS_ASSERT(pmap.lookup(origv));
|
||||
pmap.remove(origv);
|
||||
NukeCrossCompartmentWrapper(wobj);
|
||||
|
||||
// First, we wrap it in the new compartment. This will return
|
||||
// a new wrapper.
|
||||
@ -1654,6 +1664,10 @@ js_TransplantObjectWithWrapper(JSContext *cx,
|
||||
JSObject *targetwrapper)
|
||||
{
|
||||
AssertNoGC(cx);
|
||||
JS_ASSERT(!IsCrossCompartmentWrapper(origobj));
|
||||
JS_ASSERT(!IsCrossCompartmentWrapper(origwrapper));
|
||||
JS_ASSERT(!IsCrossCompartmentWrapper(origwrapper));
|
||||
JS_ASSERT(!IsCrossCompartmentWrapper(origwrapper));
|
||||
|
||||
JSObject *newWrapper;
|
||||
JSCompartment *destination = targetobj->compartment();
|
||||
@ -1669,7 +1683,12 @@ js_TransplantObjectWithWrapper(JSContext *cx,
|
||||
// There is. Make the existing cross-compartment wrapper a same-
|
||||
// compartment wrapper.
|
||||
newWrapper = &p->value.toObject();
|
||||
|
||||
// When we remove origv from the wrapper map, its wrapper, newWrapper,
|
||||
// must immediately cease to be a cross-compartment wrapper. Neuter it.
|
||||
map.remove(p);
|
||||
NukeCrossCompartmentWrapper(newWrapper);
|
||||
|
||||
if (!newWrapper->swap(cx, targetwrapper))
|
||||
return NULL;
|
||||
} else {
|
||||
|
@ -1007,6 +1007,23 @@ DeadObjectProxy::getElementIfPresent(JSContext *cx, JSObject *obj, JSObject *rec
|
||||
DeadObjectProxy DeadObjectProxy::singleton;
|
||||
int DeadObjectProxy::sDeadObjectFamily;
|
||||
|
||||
void
|
||||
js::NukeCrossCompartmentWrapper(JSObject *wrapper)
|
||||
{
|
||||
JS_ASSERT(IsCrossCompartmentWrapper(wrapper));
|
||||
|
||||
SetProxyPrivate(wrapper, NullValue());
|
||||
SetProxyHandler(wrapper, &DeadObjectProxy::singleton);
|
||||
|
||||
if (IsFunctionProxy(wrapper)) {
|
||||
wrapper->setReservedSlot(JSSLOT_PROXY_CALL, NullValue());
|
||||
wrapper->setReservedSlot(JSSLOT_PROXY_CONSTRUCT, NullValue());
|
||||
}
|
||||
|
||||
wrapper->setReservedSlot(JSSLOT_PROXY_EXTRA + 0, NullValue());
|
||||
wrapper->setReservedSlot(JSSLOT_PROXY_EXTRA + 1, NullValue());
|
||||
}
|
||||
|
||||
/*
|
||||
* NukeChromeCrossCompartmentWrappersForGlobal reaches into chrome and cuts
|
||||
* all of the cross-compartment wrappers that point to objects parented to
|
||||
@ -1053,17 +1070,7 @@ js::NukeChromeCrossCompartmentWrappersForGlobal(JSContext *cx, JSObject *obj,
|
||||
if (&wrapped->global() == global) {
|
||||
// We found a wrapper to nuke.
|
||||
e.removeFront();
|
||||
|
||||
SetProxyPrivate(wobj, JSVAL_NULL);
|
||||
SetProxyHandler(wobj, &DeadObjectProxy::singleton);
|
||||
|
||||
if (IsFunctionProxy(wobj)) {
|
||||
wobj->setReservedSlot(JSSLOT_PROXY_CALL, JSVAL_NULL);
|
||||
wobj->setReservedSlot(JSSLOT_PROXY_CONSTRUCT, JSVAL_NULL);
|
||||
}
|
||||
|
||||
wobj->setReservedSlot(JSSLOT_PROXY_EXTRA + 0, JSVAL_NULL);
|
||||
wobj->setReservedSlot(JSSLOT_PROXY_EXTRA + 1, JSVAL_NULL);
|
||||
NukeCrossCompartmentWrapper(wobj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -223,16 +223,21 @@ IsWrapper(const JSObject *obj)
|
||||
// stopAtOuter is true, then this returns the outer window if it was
|
||||
// previously wrapped. Otherwise, this returns the first object for
|
||||
// which JSObject::isWrapper returns false.
|
||||
JS_FRIEND_API(JSObject *) UnwrapObject(JSObject *obj, bool stopAtOuter = true,
|
||||
unsigned *flagsp = NULL);
|
||||
JS_FRIEND_API(JSObject *)
|
||||
UnwrapObject(JSObject *obj, bool stopAtOuter = true, unsigned *flagsp = NULL);
|
||||
|
||||
// Given a JSObject, returns that object stripped of wrappers. At each stage,
|
||||
// the security wrapper has the opportunity to veto the unwrap. Since checked
|
||||
// code should never be unwrapping outer window wrappers, we always stop at
|
||||
// outer windows.
|
||||
JS_FRIEND_API(JSObject *) UnwrapObjectChecked(JSContext *cx, JSObject *obj);
|
||||
JS_FRIEND_API(JSObject *)
|
||||
UnwrapObjectChecked(JSContext *cx, JSObject *obj);
|
||||
|
||||
bool IsCrossCompartmentWrapper(const JSObject *obj);
|
||||
bool
|
||||
IsCrossCompartmentWrapper(const JSObject *obj);
|
||||
|
||||
void
|
||||
NukeCrossCompartmentWrapper(JSObject *wrapper);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user