Bug 996785 - Fix CPOW wrapping and compartment ownership (r=mrbkap)

This commit is contained in:
Bill McCloskey 2014-05-16 16:40:37 -07:00
parent f080a0f66d
commit 366c658c5d
3 changed files with 51 additions and 15 deletions

View File

@ -7,6 +7,7 @@
#include "JavaScriptShared.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/TabChild.h"
#include "jsfriendapi.h"
#include "xpcprivate.h"
@ -356,10 +357,41 @@ JavaScriptShared::ConvertID(const JSIID &from, nsID *to)
to->m3[7] = from.m3_7();
}
void
JavaScriptShared::ReportNonexistentObject(JSContext *cx)
JSObject *
JavaScriptShared::findObjectById(JSContext *cx, uint32_t objId)
{
JS_ReportError(cx, "operation not possible on dead CPOW");
RootedObject obj(cx, findObjectById(objId));
if (!obj) {
JS_ReportError(cx, "operation not possible on dead CPOW");
return nullptr;
}
// Objects are stored in objects_ unwrapped. We want to wrap the object
// before returning it so that all operations happen on Xray wrappers. If
// the object is a DOM element, we try to obtain the corresponding
// TabChildGlobal and wrap in that.
RootedObject global(cx, GetGlobalForObjectCrossCompartment(obj));
nsCOMPtr<nsIGlobalObject> nativeGlobal = xpc::GetNativeForGlobal(global);
nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(nativeGlobal);
if (window) {
dom::TabChild *tabChild = dom::TabChild::GetFrom(window);
if (tabChild) {
nsCOMPtr<nsIContentFrameMessageManager> mm;
tabChild->GetMessageManager(getter_AddRefs(mm));
nsCOMPtr<nsIGlobalObject> tabChildNativeGlobal = do_QueryInterface(mm);
RootedObject tabChildGlobal(cx, tabChildNativeGlobal->GetGlobalJSObject());
JSAutoCompartment ac(cx, tabChildGlobal);
if (!JS_WrapObject(cx, &obj))
return nullptr;
return obj;
}
}
// If there's no TabChildGlobal, we use the junk scope.
JSAutoCompartment ac(cx, xpc::GetJunkScope());
if (!JS_WrapObject(cx, &obj))
return nullptr;
return obj;
}
static const uint64_t DefaultPropertyOp = 1;

View File

@ -116,20 +116,13 @@ class JavaScriptShared
static void ConvertID(const nsID &from, JSIID *to);
static void ConvertID(const JSIID &from, nsID *to);
void ReportNonexistentObject(JSContext *cx);
JSObject *findCPOWById(uint32_t objId) {
return cpows_.find(objId);
}
JSObject *findObjectById(uint32_t objId) {
return objects_.find(objId);
}
JSObject *findObjectById(JSContext *cx, uint32_t objId) {
if (JSObject *result = objects_.find(objId))
return result;
ReportNonexistentObject(cx);
return nullptr;
}
JSObject *findObjectById(JSContext *cx, uint32_t objId);
protected:
JSRuntime *rt_;

View File

@ -631,12 +631,18 @@ WrapperOwner::ok(JSContext *cx, const ReturnStatus &status)
}
bool
WrapperOwner::toObjectVariant(JSContext *cx, JSObject *obj, ObjectVariant *objVarp)
WrapperOwner::toObjectVariant(JSContext *cx, JSObject *objArg, ObjectVariant *objVarp)
{
RootedObject obj(cx, objArg);
JS_ASSERT(obj);
JSObject *unwrapped = js::CheckedUnwrap(obj, false);
if (unwrapped && IsCPOW(unwrapped) && OwnerOf(unwrapped) == this) {
*objVarp = LocalObject(idOf(unwrapped));
// We always save objects unwrapped in the CPOW table. If we stored
// wrappers, then the wrapper might be GCed while the target remained alive.
// Whenever operating on an object that comes from the table, we wrap it
// in findObjectById.
obj = js::CheckedUnwrap(obj, false);
if (obj && IsCPOW(obj) && OwnerOf(obj) == this) {
*objVarp = LocalObject(idOf(obj));
return true;
}
@ -646,6 +652,11 @@ WrapperOwner::toObjectVariant(JSContext *cx, JSObject *obj, ObjectVariant *objVa
return true;
}
// Need to call PreserveWrapper on |obj| in case it's a reflector.
// FIXME: What if it's an XPCWrappedNative?
if (mozilla::dom::IsDOMObject(obj))
mozilla::dom::TryPreserveWrapper(obj);
id = ++lastId_;
if (id > MAX_CPOW_IDS) {
JS_ReportError(cx, "CPOW id limit reached");