Bug 658909 - Remove GWNOJO from XPCJSID. r=mrbkap

This commit is contained in:
Bobby Holley 2013-03-16 22:58:15 -07:00
parent a8c785d855
commit 8e8f39d378

View File

@ -447,6 +447,41 @@ nsJSIID::Enumerate(nsIXPConnectWrappedNative *wrapper,
return NS_OK; return NS_OK;
} }
/*
* HasInstance hooks need to find an appropriate reflector in order to function
* properly. There are two complexities that we need to handle:
*
* 1 - Cross-compartment wrappers. Chrome uses over 100 compartments, all with
* system principal. The success of an instanceof check should not depend
* on which compartment an object comes from. At the same time, we want to
* make sure we don't unwrap important security wrappers.
* UnwrapObjectChecked does the right thing here.
*
* 2 - Prototype chains. Suppose someone creates a vanilla JS object |a| and
* sets its __proto__ to some WN |b|. If |b instanceof nsIFoo| returns true,
* one would expect |a instanceof nsIFoo| to return true as well, since
* instanceof is transitive up the prototype chain in ECMAScript. Moreover,
* there's chrome code that relies on this.
*
* This static method handles both complexities, returning either an XPCWN, a
* slim wrapper, a DOM object, or null. The object may well be cross-compartment
* from |cx|.
*/
static JSObject *
FindObjectForHasInstance(JSContext *cx, JSObject *obj)
{
while (obj && !IS_WRAPPER_CLASS(js::GetObjectClass(obj)) &&
!mozilla::dom::IsDOMObject(obj))
{
if (js::IsWrapper(obj))
obj = js::UnwrapObjectChecked(obj, /* stopAtOuter = */ false);
else if (!js::GetObjectProto(cx, obj, &obj))
return nullptr;
}
return obj;
}
/* bool hasInstance (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in jsval val, out bool bp); */ /* bool hasInstance (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in jsval val, out bool bp); */
NS_IMETHODIMP NS_IMETHODIMP
nsJSIID::HasInstance(nsIXPConnectWrappedNative *wrapper, nsJSIID::HasInstance(nsIXPConnectWrappedNative *wrapper,
@ -462,10 +497,15 @@ nsJSIID::HasInstance(nsIXPConnectWrappedNative *wrapper,
NS_ASSERTION(obj, "when is an object not an object?"); NS_ASSERTION(obj, "when is an object not an object?");
nsISupports *identity = nullptr;
// is this really a native xpcom object with a wrapper? // is this really a native xpcom object with a wrapper?
const nsIID* iid; const nsIID* iid;
mInfo->GetIIDShared(&iid); mInfo->GetIIDShared(&iid);
obj = FindObjectForHasInstance(cx, obj);
if (!obj)
return NS_OK;
if (IS_SLIM_WRAPPER(obj)) { if (IS_SLIM_WRAPPER(obj)) {
XPCWrappedNativeProto* proto = GetSlimWrapperProto(obj); XPCWrappedNativeProto* proto = GetSlimWrapperProto(obj);
if (proto->GetSet()->HasInterfaceWithAncestor(iid)) { if (proto->GetSet()->HasInterfaceWithAncestor(iid)) {
@ -480,22 +520,15 @@ nsJSIID::HasInstance(nsIXPConnectWrappedNative *wrapper,
#endif #endif
if (!MorphSlimWrapper(cx, obj)) if (!MorphSlimWrapper(cx, obj))
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} else { } else if (mozilla::dom::UnwrapDOMObjectToISupports(obj, identity)) {
JSObject* unsafeObj = nsCOMPtr<nsISupports> supp;
XPCWrapper::Unwrap(cx, obj, /* stopAtOuter = */ false); identity->QueryInterface(*iid, getter_AddRefs(supp));
JSObject* cur = unsafeObj ? unsafeObj : obj; *bp = supp;
nsISupports *identity; return NS_OK;
if (mozilla::dom::UnwrapDOMObjectToISupports(cur, identity)) {
nsCOMPtr<nsISupports> supp;
identity->QueryInterface(*iid, getter_AddRefs(supp));
*bp = supp;
return NS_OK;
}
} }
XPCWrappedNative* other_wrapper = MOZ_ASSERT(IS_WN_WRAPPER(obj));
XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj); XPCWrappedNative* other_wrapper = XPCWrappedNative::Get(obj);
if (!other_wrapper) if (!other_wrapper)
return NS_OK; return NS_OK;
@ -816,16 +849,14 @@ nsJSCID::HasInstance(nsIXPConnectWrappedNative *wrapper,
NS_ASSERTION(obj, "when is an object not an object?"); NS_ASSERTION(obj, "when is an object not an object?");
// is this really a native xpcom object with a wrapper? // is this really a native xpcom object with a wrapper?
JSObject* obj2; nsIClassInfo* ci = nullptr;
XPCWrappedNative* other_wrapper = obj = FindObjectForHasInstance(cx, obj);
XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj, nullptr, &obj2); if (!obj || !IS_WRAPPER_CLASS(js::GetObjectClass(obj)))
return rv;
if (!other_wrapper && !obj2) if (IS_SLIM_WRAPPER_OBJECT(obj))
return NS_OK; ci = GetSlimWrapperProto(obj)->GetClassInfo();
else if (XPCWrappedNative* other_wrapper = XPCWrappedNative::Get(obj))
nsIClassInfo* ci = other_wrapper ? ci = other_wrapper->GetClassInfo();
other_wrapper->GetClassInfo() :
GetSlimWrapperProto(obj2)->GetClassInfo();
// We consider CID equality to be the thing that matters here. // We consider CID equality to be the thing that matters here.
// This is perhaps debatable. // This is perhaps debatable.
@ -872,8 +903,10 @@ xpc_JSObjectToID(JSContext *cx, JSObject* obj)
return nullptr; return nullptr;
// NOTE: this call does NOT addref // NOTE: this call does NOT addref
XPCWrappedNative* wrapper = XPCWrappedNative* wrapper = nullptr;
XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj); obj = js::UnwrapObjectChecked(obj);
if (obj && IS_WN_WRAPPER(obj))
wrapper = XPCWrappedNative::Get(obj);
if (wrapper && if (wrapper &&
(wrapper->HasInterfaceNoQI(NS_GET_IID(nsIJSID)) || (wrapper->HasInterfaceNoQI(NS_GET_IID(nsIJSID)) ||
wrapper->HasInterfaceNoQI(NS_GET_IID(nsIJSIID)) || wrapper->HasInterfaceNoQI(NS_GET_IID(nsIJSIID)) ||
@ -888,8 +921,10 @@ xpc_JSObjectIsID(JSContext *cx, JSObject* obj)
{ {
NS_ASSERTION(cx && obj, "bad param"); NS_ASSERTION(cx && obj, "bad param");
// NOTE: this call does NOT addref // NOTE: this call does NOT addref
XPCWrappedNative* wrapper = XPCWrappedNative* wrapper = nullptr;
XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj); obj = js::UnwrapObjectChecked(obj);
if (obj && IS_WN_WRAPPER(obj))
wrapper = XPCWrappedNative::Get(obj);
return wrapper && return wrapper &&
(wrapper->HasInterfaceNoQI(NS_GET_IID(nsIJSID)) || (wrapper->HasInterfaceNoQI(NS_GET_IID(nsIJSID)) ||
wrapper->HasInterfaceNoQI(NS_GET_IID(nsIJSIID)) || wrapper->HasInterfaceNoQI(NS_GET_IID(nsIJSIID)) ||