Bug 922009 - MOZ_CRASH when trying to transplant objects with SCSWs. r=mrbkap

This commit is contained in:
Bobby Holley 2013-10-17 10:00:02 +02:00
Родитель 9cb1da54a5
Коммит 2dcd8b769e
9 изменённых файлов: 5 добавлений и 171 удалений

Просмотреть файл

@ -1756,20 +1756,9 @@ ReparentWrapper(JSContext* aCx, JS::HandleObject aObjArg)
if (ww != aObj) {
MOZ_ASSERT(cache->HasSystemOnlyWrapper());
JS::RootedObject newwrapper(aCx,
xpc::WrapperFactory::WrapSOWObject(aCx, newobj));
if (!newwrapper) {
MOZ_CRASH();
}
// Oops. We don't support transplanting objects with SOWs anymore.
MOZ_CRASH();
// Ok, now we do the special object-plus-wrapper transplant.
ww = xpc::TransplantObjectWithWrapper(aCx, aObj, ww, newobj, newwrapper);
if (!ww) {
MOZ_CRASH();
}
aObj = newobj;
SetSystemOnlyWrapperSlot(aObj, JS::ObjectValue(*ww));
} else {
aObj = xpc::TransplantObject(aCx, aObj, newobj);
if (!aObj) {

Просмотреть файл

@ -1267,96 +1267,6 @@ JS_TransplantObject(JSContext *cx, HandleObject origobj, HandleObject target)
return newIdentity;
}
/*
* Some C++ objects (such as the location object and XBL) require both an XPConnect
* reflector and a security wrapper for that reflector. We expect that there are
* no live references to the reflector, so when we perform the transplant we turn
* the security wrapper into a cross-compartment wrapper. Just in case there
* happen to be live references to the reflector, we swap it out to limit the harm.
*/
JS_FRIEND_API(JSObject *)
js_TransplantObjectWithWrapper(JSContext *cx,
HandleObject origobj,
HandleObject origwrapper,
HandleObject targetobj,
HandleObject targetwrapper)
{
AutoMaybeTouchDeadZones agc(cx);
AutoDisableProxyCheck adpc(cx->runtime());
AssertHeapIsIdle(cx);
JS_ASSERT(!origobj->is<CrossCompartmentWrapperObject>());
JS_ASSERT(!origwrapper->is<CrossCompartmentWrapperObject>());
JS_ASSERT(!targetobj->is<CrossCompartmentWrapperObject>());
JS_ASSERT(!targetwrapper->is<CrossCompartmentWrapperObject>());
RootedObject newWrapper(cx);
JSCompartment *destination = targetobj->compartment();
// |origv| is the map entry we're looking up. The map entries are going to
// be for |origobj|, not |origwrapper|.
Value origv = ObjectValue(*origobj);
// There might already be a wrapper for the original object in the new
// compartment.
if (WrapperMap::Ptr p = destination->lookupWrapper(origv)) {
// 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.
destination->removeWrapper(p);
NukeCrossCompartmentWrapper(cx, newWrapper);
if (!JSObject::swap(cx, newWrapper, targetwrapper))
MOZ_CRASH();
} else {
// Otherwise, use the passed-in wrapper as the same-compartment wrapper.
newWrapper = targetwrapper;
}
// Now, iterate through other scopes looking for references to the old
// object. Note that the entries in the maps are for |origobj| and not
// |origwrapper|. They need to be updated to point at the new object.
if (!RemapAllWrappersForObject(cx, origobj, targetobj))
MOZ_CRASH();
// Lastly, update things in the original compartment. Our invariants dictate
// that the original compartment can only have one cross-compartment wrapper
// to the new object. So we choose to update |origwrapper|, not |origobj|,
// since there are probably no live direct intra-compartment references to
// |origobj|.
{
AutoCompartment ac(cx, origobj);
// We can't be sure that the reflector is completely dead. This is bad,
// because it is in a weird state. To minimize potential harm we create
// a new unreachable dummy object and swap it with the reflector.
// After the swap we have a possibly-live object that isn't dangerous,
// and a possibly-dangerous object that isn't live.
ProxyOptions options;
if (!IsBackgroundFinalized(origobj->tenuredGetAllocKind()))
options.setForceForegroundFinalization(true);
RootedObject reflectorGuts(cx, NewDeadProxyObject(cx, JS_GetGlobalForObject(cx, origobj),
options));
if (!reflectorGuts || !JSObject::swap(cx, origobj, reflectorGuts))
MOZ_CRASH();
// Turn origwrapper into a CCW to the new object.
RootedObject wrapperGuts(cx, targetobj);
if (!JS_WrapObject(cx, &wrapperGuts))
MOZ_CRASH();
JS_ASSERT(Wrapper::wrappedObject(wrapperGuts) == targetobj);
if (!JSObject::swap(cx, origwrapper, wrapperGuts))
MOZ_CRASH();
origwrapper->compartment()->putWrapper(ObjectValue(*targetobj),
ObjectValue(*origwrapper));
}
return newWrapper;
}
/*
* Recompute all cross-compartment wrappers for an object, resetting state.
* Gecko uses this to clear Xray wrappers when doing a navigation that reuses

Просмотреть файл

@ -1768,13 +1768,6 @@ JS_WrapId(JSContext *cx, jsid *idp);
extern JS_PUBLIC_API(JSObject *)
JS_TransplantObject(JSContext *cx, JS::Handle<JSObject*> origobj, JS::Handle<JSObject*> target);
extern JS_FRIEND_API(JSObject *)
js_TransplantObjectWithWrapper(JSContext *cx,
JS::Handle<JSObject*> origobj,
JS::Handle<JSObject*> origwrapper,
JS::Handle<JSObject*> targetobj,
JS::Handle<JSObject*> targetwrapper);
extern JS_PUBLIC_API(bool)
JS_RefreshCrossCompartmentWrappers(JSContext *cx, JSObject *ob);

Просмотреть файл

@ -1463,18 +1463,10 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCWrappedNativeScope* aOldScope,
if (ww) {
RootedObject newwrapper(cx);
MOZ_ASSERT(wrapper->NeedsSOW(), "weird wrapper wrapper");
newwrapper = xpc::WrapperFactory::WrapSOWObject(cx, newobj);
if (!newwrapper)
MOZ_CRASH();
// Ok, now we do the special object-plus-wrapper transplant.
ww = xpc::TransplantObjectWithWrapper(cx, flat, ww, newobj,
newwrapper);
if (!ww)
MOZ_CRASH();
// Oops. We don't support transplanting objects with SOWs anymore.
MOZ_CRASH();
flat = newobj;
wrapper->SetWrapper(ww);
} else {
flat = xpc::TransplantObject(cx, flat, newobj);
if (!flat)

Просмотреть файл

@ -38,11 +38,6 @@ namespace xpc {
JSObject *
TransplantObject(JSContext *cx, JS::HandleObject origobj, JS::HandleObject target);
JSObject *
TransplantObjectWithWrapper(JSContext *cx,
JS::HandleObject origobj, JS::HandleObject origwrapper,
JS::HandleObject targetobj, JS::HandleObject targetwrapper);
// Return a raw XBL scope object corresponding to contentScope, which must
// be an object whose global is a DOM window.
//

Просмотреть файл

@ -1,21 +0,0 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<bindings xmlns="http://www.mozilla.org/xbl"
xmlns:html="http://www.w3.org/1999/xhtml">
<binding id="testBinding2">
<implementation>
<constructor>
document.body.appendChild(parent.wrappedJSObject.nac);
parent.wrappedJSObject.ok(true, "Didn't crash");
parent.wrappedJSObject.SimpleTest.finish();
</constructor>
</implementation>
</binding>
</bindings>
<script type="application/javascript">
</script>
</head>
<body>
<div id="bindingSink" style="-moz-binding: url(#testBinding2);"></div>
</body>
</html>

Просмотреть файл

@ -30,7 +30,6 @@ support-files =
file_exnstack.html
file_expandosharing.html
file_mozMatchesSelector.html
file_nac.xhtml
file_nodelists.html
file_wrappers-2.html
inner.html

Просмотреть файл

@ -45,11 +45,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=914618
checkThrows(new iwin.Function('nac.toString();'));
checkThrows(new iwin.Function('nac.textContent;'));
// Try adopting the NAC into another scope using a different XBL binding.
// The <constructor> in file_nac.xhtml will call SimpleTest.finish().
var ifr2 = document.createElement('iframe');
document.body.appendChild(ifr2);
ifr2.contentWindow.location = 'file_nac.xhtml';
SimpleTest.finish();
}
]]>

Просмотреть файл

@ -667,25 +667,6 @@ TransplantObject(JSContext *cx, JS::HandleObject origobj, JS::HandleObject targe
return newIdentity;
}
JSObject *
TransplantObjectWithWrapper(JSContext *cx,
HandleObject origobj, HandleObject origwrapper,
HandleObject targetobj, HandleObject targetwrapper)
{
RootedObject oldWaiver(cx, WrapperFactory::GetXrayWaiver(origobj));
RootedObject newSameCompartmentWrapper(cx,
js_TransplantObjectWithWrapper(cx, origobj, origwrapper, targetobj,
targetwrapper));
if (!newSameCompartmentWrapper || !oldWaiver)
return newSameCompartmentWrapper;
RootedObject newIdentity(cx, Wrapper::wrappedObject(newSameCompartmentWrapper));
MOZ_ASSERT(!js::IsWrapper(newIdentity));
if (!FixWaiverAfterTransplant(cx, oldWaiver, newIdentity))
return nullptr;
return newSameCompartmentWrapper;
}
nsIGlobalObject *
GetNativeForGlobal(JSObject *obj)
{