mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Backout bug 658909 for Marionette bustage.
This commit is contained in:
parent
5bc91d7db4
commit
d8a7fada3c
@ -3196,8 +3196,8 @@ nsDOMClassInfo::ResolveConstructor(JSContext *cx, JSObject *obj,
|
||||
// window.classname, just fall through and let the JS engine
|
||||
// return the Object constructor.
|
||||
|
||||
if (!::JS_DefinePropertyById(cx, obj, sConstructor_id, val, JS_PropertyStub,
|
||||
JS_StrictPropertyStub, JSPROP_ENUMERATE)) {
|
||||
if (!::JS_DefinePropertyById(cx, obj, sConstructor_id, val, nullptr, nullptr,
|
||||
JSPROP_ENUMERATE)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
@ -3757,7 +3757,7 @@ nsWindowSH::GlobalScopePolluterNewResolve(JSContext *cx, JSHandleObject obj,
|
||||
NS_ENSURE_SUCCESS(rv, JS_FALSE);
|
||||
|
||||
if (!JS_WrapValue(cx, &v) ||
|
||||
!JS_DefinePropertyById(cx, obj, id, v, JS_PropertyStub, JS_StrictPropertyStub, 0)) {
|
||||
!JS_DefinePropertyById(cx, obj, id, v, nullptr, nullptr, 0)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
@ -4099,8 +4099,7 @@ DefineInterfaceConstants(JSContext *cx, JSObject *obj, const nsIID *aIID)
|
||||
}
|
||||
}
|
||||
|
||||
if (!::JS_DefineProperty(cx, obj, c->GetName(), v,
|
||||
JS_PropertyStub, JS_StrictPropertyStub,
|
||||
if (!::JS_DefineProperty(cx, obj, c->GetName(), v, nullptr, nullptr,
|
||||
JSPROP_ENUMERATE | JSPROP_READONLY |
|
||||
JSPROP_PERMANENT)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
@ -4209,8 +4208,7 @@ IDBConstantGetter(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHan
|
||||
if (!xpc::StringToJsval(cx, valStr, &value)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
if (!::JS_DefineProperty(cx, obj, c.name, value,
|
||||
JS_PropertyStub, JS_StrictPropertyStub,
|
||||
if (!::JS_DefineProperty(cx, obj, c.name, value, nullptr, nullptr,
|
||||
JSPROP_ENUMERATE)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
@ -4244,7 +4242,7 @@ DefineIDBInterfaceConstants(JSContext *cx, JSObject *obj, const nsIID *aIID)
|
||||
}
|
||||
|
||||
if (!JS_DefineProperty(cx, obj, c.name, JSVAL_VOID,
|
||||
IDBConstantGetter, JS_StrictPropertyStub,
|
||||
IDBConstantGetter, nullptr,
|
||||
JSPROP_ENUMERATE)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
@ -4292,8 +4290,8 @@ public:
|
||||
JSBool ok = JS_WrapValue(cx, &thisAsVal) &&
|
||||
::JS_DefineUCProperty(cx, target,
|
||||
reinterpret_cast<const jschar *>(mClassName),
|
||||
NS_strlen(mClassName), thisAsVal, JS_PropertyStub,
|
||||
JS_StrictPropertyStub, 0);
|
||||
NS_strlen(mClassName), thisAsVal, nullptr,
|
||||
nullptr, 0);
|
||||
|
||||
return ok ? NS_OK : NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
@ -4901,8 +4899,7 @@ ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindow *aWin, JSContext *cx,
|
||||
|
||||
// Per ECMA, the prototype property is {DontEnum, DontDelete, ReadOnly}
|
||||
if (!JS_WrapValue(cx, &v) ||
|
||||
!JS_DefineProperty(cx, class_obj, "prototype", v,
|
||||
JS_PropertyStub, JS_StrictPropertyStub,
|
||||
!JS_DefineProperty(cx, class_obj, "prototype", v, nullptr, nullptr,
|
||||
JSPROP_PERMANENT | JSPROP_READONLY)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
@ -5016,8 +5013,8 @@ nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
|
||||
ac.destroy();
|
||||
if (!JS_WrapObject(cx, &interfaceObject) ||
|
||||
!JS_DefinePropertyById(cx, obj, id,
|
||||
JS::ObjectValue(*interfaceObject), JS_PropertyStub,
|
||||
JS_StrictPropertyStub, 0)) {
|
||||
JS::ObjectValue(*interfaceObject), nullptr,
|
||||
nullptr, 0)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
@ -5201,8 +5198,7 @@ nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
JSBool ok = ::JS_DefinePropertyById(cx, obj, id, prop_val,
|
||||
JS_PropertyStub, JS_StrictPropertyStub,
|
||||
JSBool ok = ::JS_DefinePropertyById(cx, obj, id, prop_val, nullptr, nullptr,
|
||||
JSPROP_ENUMERATE);
|
||||
|
||||
*did_resolve = true;
|
||||
@ -5243,10 +5239,8 @@ static nsresult
|
||||
LocationSetterGuts(JSContext *cx, JSObject *obj, jsval *vp)
|
||||
{
|
||||
// This function duplicates some of the logic in XPC_WN_HelperSetProperty
|
||||
obj = js::UnwrapObjectChecked(obj, /* stopAtOuter = */ false);
|
||||
if (!IS_WN_WRAPPER(obj))
|
||||
return NS_ERROR_XPC_BAD_CONVERT_JS;
|
||||
XPCWrappedNative *wrapper = XPCWrappedNative::Get(obj);
|
||||
XPCWrappedNative *wrapper =
|
||||
XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj);
|
||||
|
||||
// The error checks duplicate code in THROW_AND_RETURN_IF_BAD_WRAPPER
|
||||
NS_ENSURE_TRUE(!wrapper || wrapper->IsValid(), NS_ERROR_XPC_HAS_BEEN_SHUTDOWN);
|
||||
@ -5426,7 +5420,7 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
JSBool ok = JS_WrapValue(cx, &v) &&
|
||||
JS_DefinePropertyById(cx, obj, id, v, JS_PropertyStub,
|
||||
JS_DefinePropertyById(cx, obj, id, v, nullptr,
|
||||
LocationSetterUnwrapper,
|
||||
JSPROP_PERMANENT | JSPROP_ENUMERATE);
|
||||
|
||||
@ -5452,7 +5446,7 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
|
||||
// Hold on to the top window object as a global property so we
|
||||
// don't need to worry about losing expando properties etc.
|
||||
if (!JS_DefinePropertyById(cx, obj, id, v, JS_PropertyStub, JS_StrictPropertyStub,
|
||||
if (!JS_DefinePropertyById(cx, obj, id, v, nullptr, nullptr,
|
||||
JSPROP_READONLY | JSPROP_PERMANENT |
|
||||
JSPROP_ENUMERATE)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
@ -5506,7 +5500,7 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
|
||||
if (!::JS_DefinePropertyById(cx, windowObj, id, JSVAL_VOID,
|
||||
JS_DATA_TO_FUNC_PTR(JSPropertyOp, funObj),
|
||||
JS_StrictPropertyStub,
|
||||
nullptr,
|
||||
JSPROP_ENUMERATE | JSPROP_GETTER |
|
||||
JSPROP_SHARED)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
@ -5547,8 +5541,7 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
|
||||
// Hold on to the navigator object as a global property so we
|
||||
// don't need to worry about losing expando properties etc.
|
||||
if (!::JS_DefinePropertyById(cx, obj, id, v,
|
||||
JS_PropertyStub, JS_StrictPropertyStub,
|
||||
if (!::JS_DefinePropertyById(cx, obj, id, v, nullptr, nullptr,
|
||||
JSPROP_READONLY | JSPROP_PERMANENT |
|
||||
JSPROP_ENUMERATE)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
@ -5577,8 +5570,7 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
// define it ourselves.
|
||||
|
||||
*_retval = JS_WrapValue(cx, &v) &&
|
||||
JS_DefineProperty(cx, obj, "document", v,
|
||||
JS_PropertyStub, JS_StrictPropertyStub,
|
||||
JS_DefineProperty(cx, obj, "document", v, NULL, NULL,
|
||||
JSPROP_READONLY | JSPROP_ENUMERATE);
|
||||
if (!*_retval) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
@ -5846,8 +5838,7 @@ nsNavigatorSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
JSBool ok = ::JS_DefinePropertyById(cx, obj, id, prop_val,
|
||||
JS_PropertyStub, JS_StrictPropertyStub,
|
||||
JSBool ok = ::JS_DefinePropertyById(cx, obj, id, prop_val, nullptr, nullptr,
|
||||
JSPROP_ENUMERATE);
|
||||
|
||||
*_retval = true;
|
||||
@ -6657,7 +6648,7 @@ nsDocumentSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
getter_AddRefs(holder));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
JSBool ok = ::JS_DefinePropertyById(cx, obj, id, v, JS_PropertyStub,
|
||||
JSBool ok = ::JS_DefinePropertyById(cx, obj, id, v, nullptr,
|
||||
LocationSetter<nsIDOMDocument>,
|
||||
JSPROP_PERMANENT | JSPROP_ENUMERATE);
|
||||
|
||||
|
@ -46,7 +46,7 @@ class JS_FRIEND_API(Wrapper) : public DirectProxyHandler
|
||||
* object (via UnwrapObjectChecked) will throw. Otherwise, they will succeed.
|
||||
*/
|
||||
void setSafeToUnwrap(bool safe) { mSafeToUnwrap = safe; }
|
||||
virtual bool isSafeToUnwrap() { return mSafeToUnwrap; }
|
||||
bool isSafeToUnwrap() { return mSafeToUnwrap; }
|
||||
|
||||
static JSObject *New(JSContext *cx, JSObject *obj, JSObject *proto,
|
||||
JSObject *parent, Wrapper *handler);
|
||||
|
@ -7,12 +7,10 @@
|
||||
/* Call context. */
|
||||
|
||||
#include "mozilla/Util.h"
|
||||
#include "AccessCheck.h"
|
||||
|
||||
#include "xpcprivate.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace xpc;
|
||||
|
||||
XPCCallContext::XPCCallContext(XPCContext::LangType callerLanguage,
|
||||
JSContext* cx /* = nullptr */,
|
||||
@ -28,10 +26,7 @@ XPCCallContext::XPCCallContext(XPCContext::LangType callerLanguage,
|
||||
mJSContext(cx),
|
||||
mContextPopRequired(false),
|
||||
mDestroyJSContextInDestructor(false),
|
||||
mCallerLanguage(callerLanguage),
|
||||
mFlattenedJSObject(nullptr),
|
||||
mWrapper(nullptr),
|
||||
mTearOff(nullptr)
|
||||
mCallerLanguage(callerLanguage)
|
||||
{
|
||||
Init(callerLanguage, callerLanguage == NATIVE_CALLER, obj, funobj,
|
||||
INIT_SHOULD_LOOKUP_WRAPPER, name, argc, argv, rval);
|
||||
@ -60,8 +55,6 @@ XPCCallContext::XPCCallContext(XPCContext::LangType callerLanguage,
|
||||
nullptr, nullptr);
|
||||
}
|
||||
|
||||
#define IS_TEAROFF_CLASS(clazz) ((clazz) == &XPC_WN_Tearoff_JSClass)
|
||||
|
||||
void
|
||||
XPCCallContext::Init(XPCContext::LangType callerLanguage,
|
||||
JSBool callBeginRequest,
|
||||
@ -146,28 +139,10 @@ XPCCallContext::Init(XPCContext::LangType callerLanguage,
|
||||
|
||||
mTearOff = nullptr;
|
||||
if (wrapperInitOptions == INIT_SHOULD_LOOKUP_WRAPPER) {
|
||||
// If the object is a security wrapper, GetWrappedNativeOfJSObject can't
|
||||
// handle it. Do special handling here to make cross-origin Xrays work.
|
||||
JSObject *unwrapped = js::UnwrapObjectChecked(obj, /* stopAtOuter = */ false);
|
||||
if (!unwrapped) {
|
||||
mWrapper = UnwrapThisIfAllowed(obj, funobj, argc);
|
||||
if (!mWrapper) {
|
||||
JS_ReportError(mJSContext, "Permission denied to call method on |this|");
|
||||
mState = INIT_FAILED;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
js::Class *clasp = js::GetObjectClass(unwrapped);
|
||||
if (IS_WRAPPER_CLASS(clasp)) {
|
||||
if (IS_SLIM_WRAPPER_OBJECT(unwrapped))
|
||||
mFlattenedJSObject = unwrapped;
|
||||
else
|
||||
mWrapper = XPCWrappedNative::Get(unwrapped);
|
||||
} else if (IS_TEAROFF_CLASS(clasp)) {
|
||||
mTearOff = (XPCWrappedNativeTearOff*)js::GetObjectPrivate(unwrapped);
|
||||
mWrapper = XPCWrappedNative::Get(js::GetObjectParent(unwrapped));
|
||||
}
|
||||
}
|
||||
mWrapper = XPCWrappedNative::GetWrappedNativeOfJSObject(mJSContext, obj,
|
||||
funobj,
|
||||
&mFlattenedJSObject,
|
||||
&mTearOff);
|
||||
if (mWrapper) {
|
||||
mFlattenedJSObject = mWrapper->GetFlatJSObject();
|
||||
|
||||
@ -453,58 +428,3 @@ XPCLazyCallContext::AssertContextIsTopOfStack(JSContext* cx)
|
||||
NS_ASSERTION(cx == topJSContext, "wrong context on XPCJSContextStack!");
|
||||
}
|
||||
#endif
|
||||
|
||||
XPCWrappedNative*
|
||||
XPCCallContext::UnwrapThisIfAllowed(JSObject *obj, JSObject *fun, unsigned argc)
|
||||
{
|
||||
// We should only get here for objects that aren't safe to unwrap.
|
||||
MOZ_ASSERT(!js::UnwrapObjectChecked(obj));
|
||||
MOZ_ASSERT(js::IsObjectInContextCompartment(obj, mJSContext));
|
||||
|
||||
// Determine if we're allowed to unwrap the security wrapper to invoke the
|
||||
// method.
|
||||
//
|
||||
// We have the Interface and Member that this corresponds to, but
|
||||
// unfortunately our access checks are based on the object class name and
|
||||
// property name. So we cheat a little bit here - we verify that the object
|
||||
// does indeed implement the method's Interface, and then just check that we
|
||||
// can successfully access property with method's name from the object.
|
||||
|
||||
// First, get the XPCWN out of the underlying object. We should have a wrapper
|
||||
// here, potentially an outer window proxy, and then an XPCWN.
|
||||
MOZ_ASSERT(js::IsWrapper(obj));
|
||||
JSObject *unwrapped = js::UnwrapObject(obj, /* stopAtOuter = */ false);
|
||||
MOZ_ASSERT(unwrapped == JS_ObjectToInnerObject(mJSContext, js::Wrapper::wrappedObject(obj)));
|
||||
|
||||
// Make sure we have an XPCWN, and grab it.
|
||||
MOZ_ASSERT(!IS_SLIM_WRAPPER(unwrapped), "security wrapping morphs slim wrappers");
|
||||
if (!IS_WRAPPER_CLASS(js::GetObjectClass(unwrapped)))
|
||||
return nullptr;
|
||||
XPCWrappedNative *wn = (XPCWrappedNative*)js::GetObjectPrivate(unwrapped);
|
||||
|
||||
// Next, get the call info off the function object.
|
||||
XPCNativeInterface *interface;
|
||||
XPCNativeMember *member;
|
||||
XPCNativeMember::GetCallInfo(fun, &interface, &member);
|
||||
|
||||
// To be extra safe, make sure that the underlying native implements the
|
||||
// interface before unwrapping. Even if we didn't check this, we'd still
|
||||
// theoretically fail during tearoff lookup for mismatched methods.
|
||||
if (!wn->HasInterfaceNoQI(*interface->GetIID()))
|
||||
return nullptr;
|
||||
|
||||
// See if the access is permitted.
|
||||
//
|
||||
// NB: This calculation of SET vs GET is a bit wonky, but that's what
|
||||
// XPC_WN_GetterSetter does.
|
||||
bool set = argc && argc != NO_ARGS && member->IsWritableAttribute();
|
||||
js::Wrapper::Action act = set ? js::Wrapper::SET : js::Wrapper::GET;
|
||||
js::Wrapper *handler = js::Wrapper::wrapperHandler(obj);
|
||||
bool ignored;
|
||||
if (!handler->enter(mJSContext, obj, member->GetName(), act, &ignored))
|
||||
return nullptr;
|
||||
|
||||
// Ok, this call is safe.
|
||||
return wn;
|
||||
}
|
||||
|
||||
|
@ -3064,37 +3064,12 @@ xpc::SandboxCallableProxyHandler::call(JSContext *cx, JSObject *proxy,
|
||||
MOZ_ASSERT(js::GetObjectJSClass(sandboxGlobal) == &SandboxClass);
|
||||
|
||||
// If our this object is the sandbox global, we call with this set to the
|
||||
// original proto instead.
|
||||
//
|
||||
// There are two different ways we can compute |this|. If we use
|
||||
// JS_THIS_VALUE, we'll get the bonafide |this| value as passed by the
|
||||
// caller, which may be undefined if a global function was invoked without
|
||||
// an explicit invocant. If we use JS_THIS or JS_THIS_OBJECT, the |this|
|
||||
// in |vp| will be coerced to the global, which is not the correct
|
||||
// behavior in ES5 strict mode. And we have no way to compute strictness
|
||||
// here.
|
||||
//
|
||||
// The naive approach is simply to use JS_THIS_VALUE here. If |this| was
|
||||
// explicit, we can remap it appropriately. If it was implicit, then we
|
||||
// leave it as undefined, and let the callee sort it out. Since the callee
|
||||
// is generally in the same compartment as its global (eg the Window's
|
||||
// compartment, not the Sandbox's), the callee will generally compute the
|
||||
// correct |this|.
|
||||
//
|
||||
// However, this breaks down in the Xray case. If the sandboxPrototype
|
||||
// is an Xray wrapper, then we'll end up reifying the native methods in
|
||||
// the Sandbox's scope, which means that they'll compute |this| to be the
|
||||
// Sandbox, breaking old-style XPC_WN_CallMethod methods.
|
||||
//
|
||||
// Luckily, the intent of Xrays is to provide a vanilla view of a foreign
|
||||
// DOM interface, which means that we don't care about script-enacted
|
||||
// strictness in the prototype's home compartment. Indeed, since DOM
|
||||
// methods are always non-strict, we can just assume non-strict semantics
|
||||
// if the sandboxPrototype is an Xray Wrapper, which lets us appropriately
|
||||
// remap |this|.
|
||||
JS::Value thisVal =
|
||||
WrapperFactory::IsXrayWrapper(sandboxProxy) ? JS_THIS(cx, vp)
|
||||
: JS_THIS_VALUE(cx, vp);
|
||||
// original proto instead. Note that we very carefully avoid using JS_THIS
|
||||
// or JS_THIS_OBJECT here, because we do NOT want to box undefined into the
|
||||
// global. Instead, we just pass it through to our callable, and it will
|
||||
// compute the global based on its own scope chain, which will do the right
|
||||
// thing.
|
||||
JS::Value thisVal = JS_THIS_VALUE(cx, vp);
|
||||
if (thisVal == ObjectValue(*sandboxGlobal)) {
|
||||
thisVal = ObjectValue(*js::GetProxyTargetObject(sandboxProxy));
|
||||
}
|
||||
|
@ -1032,25 +1032,22 @@ XPCConvert::JSObject2NativeInterface(JSContext* cx,
|
||||
// If we're looking at a security wrapper, see now if we're allowed to
|
||||
// pass it to C++. If we are, then fall through to the code below. If
|
||||
// we aren't, throw an exception eagerly.
|
||||
JSObject* inner = js::UnwrapObjectChecked(src, /* stopAtOuter = */ false);
|
||||
|
||||
// Hack - For historical reasons, wrapped chrome JS objects have been
|
||||
// passable as native interfaces. We'd like to fix this, but it
|
||||
// involves fixing the contacts API and PeerConnection to stop using
|
||||
// COWs. This needs to happen, but for now just preserve the old
|
||||
// behavior.
|
||||
if (!inner && MOZ_UNLIKELY(xpc::WrapperFactory::IsCOW(src)))
|
||||
inner = js::UnwrapObject(src);
|
||||
if (!inner) {
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_XPC_SECURITY_MANAGER_VETO;
|
||||
return false;
|
||||
JSObject* inner = nullptr;
|
||||
if (XPCWrapper::IsSecurityWrapper(src)) {
|
||||
inner = XPCWrapper::Unwrap(cx, src, false);
|
||||
if (!inner) {
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_XPC_SECURITY_MANAGER_VETO;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Is this really a native xpcom object with a wrapper?
|
||||
XPCWrappedNative* wrappedNative = nullptr;
|
||||
if (IS_WN_WRAPPER(inner))
|
||||
wrappedNative = XPCWrappedNative::Get(inner);
|
||||
XPCWrappedNative* wrappedNative =
|
||||
XPCWrappedNative::GetWrappedNativeOfJSObject(cx,
|
||||
inner
|
||||
? inner
|
||||
: src);
|
||||
if (wrappedNative) {
|
||||
iface = wrappedNative->GetIdentityObject();
|
||||
return NS_SUCCEEDED(iface->QueryInterface(*iid, dest));
|
||||
@ -1177,12 +1174,9 @@ XPCConvert::JSValToXPCException(XPCCallContext& ccx,
|
||||
}
|
||||
|
||||
// is this really a native xpcom object with a wrapper?
|
||||
JSObject *unwrapped = js::UnwrapObjectChecked(obj, /* stopAtOuter = */ false);
|
||||
if (!unwrapped)
|
||||
return NS_ERROR_XPC_SECURITY_MANAGER_VETO;
|
||||
XPCWrappedNative* wrapper = IS_WN_WRAPPER(unwrapped) ? XPCWrappedNative::Get(unwrapped)
|
||||
: nullptr;
|
||||
if (wrapper) {
|
||||
XPCWrappedNative* wrapper;
|
||||
if (nullptr != (wrapper =
|
||||
XPCWrappedNative::GetWrappedNativeOfJSObject(cx,obj))) {
|
||||
nsISupports* supports = wrapper->GetIdentityObject();
|
||||
nsCOMPtr<nsIException> iface = do_QueryInterface(supports);
|
||||
if (iface) {
|
||||
|
@ -447,41 +447,6 @@ nsJSIID::Enumerate(nsIXPConnectWrappedNative *wrapper,
|
||||
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); */
|
||||
NS_IMETHODIMP
|
||||
nsJSIID::HasInstance(nsIXPConnectWrappedNative *wrapper,
|
||||
@ -497,15 +462,10 @@ nsJSIID::HasInstance(nsIXPConnectWrappedNative *wrapper,
|
||||
|
||||
NS_ASSERTION(obj, "when is an object not an object?");
|
||||
|
||||
nsISupports *identity = nullptr;
|
||||
// is this really a native xpcom object with a wrapper?
|
||||
const nsIID* iid;
|
||||
mInfo->GetIIDShared(&iid);
|
||||
|
||||
obj = FindObjectForHasInstance(cx, obj);
|
||||
if (!obj)
|
||||
return NS_OK;
|
||||
|
||||
if (IS_SLIM_WRAPPER(obj)) {
|
||||
XPCWrappedNativeProto* proto = GetSlimWrapperProto(obj);
|
||||
if (proto->GetSet()->HasInterfaceWithAncestor(iid)) {
|
||||
@ -520,15 +480,22 @@ nsJSIID::HasInstance(nsIXPConnectWrappedNative *wrapper,
|
||||
#endif
|
||||
if (!MorphSlimWrapper(cx, obj))
|
||||
return NS_ERROR_FAILURE;
|
||||
} else if (mozilla::dom::UnwrapDOMObjectToISupports(obj, identity)) {
|
||||
nsCOMPtr<nsISupports> supp;
|
||||
identity->QueryInterface(*iid, getter_AddRefs(supp));
|
||||
*bp = supp;
|
||||
return NS_OK;
|
||||
} else {
|
||||
JSObject* unsafeObj =
|
||||
XPCWrapper::Unwrap(cx, obj, /* stopAtOuter = */ false);
|
||||
JSObject* cur = unsafeObj ? unsafeObj : obj;
|
||||
nsISupports *identity;
|
||||
if (mozilla::dom::UnwrapDOMObjectToISupports(cur, identity)) {
|
||||
nsCOMPtr<nsISupports> supp;
|
||||
identity->QueryInterface(*iid, getter_AddRefs(supp));
|
||||
*bp = supp;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(IS_WN_WRAPPER(obj));
|
||||
XPCWrappedNative* other_wrapper = XPCWrappedNative::Get(obj);
|
||||
XPCWrappedNative* other_wrapper =
|
||||
XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj);
|
||||
|
||||
if (!other_wrapper)
|
||||
return NS_OK;
|
||||
|
||||
@ -849,14 +816,16 @@ nsJSCID::HasInstance(nsIXPConnectWrappedNative *wrapper,
|
||||
NS_ASSERTION(obj, "when is an object not an object?");
|
||||
|
||||
// is this really a native xpcom object with a wrapper?
|
||||
nsIClassInfo* ci = nullptr;
|
||||
obj = FindObjectForHasInstance(cx, obj);
|
||||
if (!obj || !IS_WRAPPER_CLASS(js::GetObjectClass(obj)))
|
||||
return rv;
|
||||
if (IS_SLIM_WRAPPER_OBJECT(obj))
|
||||
ci = GetSlimWrapperProto(obj)->GetClassInfo();
|
||||
else if (XPCWrappedNative* other_wrapper = XPCWrappedNative::Get(obj))
|
||||
ci = other_wrapper->GetClassInfo();
|
||||
JSObject* obj2;
|
||||
XPCWrappedNative* other_wrapper =
|
||||
XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj, nullptr, &obj2);
|
||||
|
||||
if (!other_wrapper && !obj2)
|
||||
return NS_OK;
|
||||
|
||||
nsIClassInfo* ci = other_wrapper ?
|
||||
other_wrapper->GetClassInfo() :
|
||||
GetSlimWrapperProto(obj2)->GetClassInfo();
|
||||
|
||||
// We consider CID equality to be the thing that matters here.
|
||||
// This is perhaps debatable.
|
||||
@ -903,10 +872,8 @@ xpc_JSObjectToID(JSContext *cx, JSObject* obj)
|
||||
return nullptr;
|
||||
|
||||
// NOTE: this call does NOT addref
|
||||
XPCWrappedNative* wrapper = nullptr;
|
||||
obj = js::UnwrapObjectChecked(obj);
|
||||
if (obj && IS_WN_WRAPPER(obj))
|
||||
wrapper = XPCWrappedNative::Get(obj);
|
||||
XPCWrappedNative* wrapper =
|
||||
XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj);
|
||||
if (wrapper &&
|
||||
(wrapper->HasInterfaceNoQI(NS_GET_IID(nsIJSID)) ||
|
||||
wrapper->HasInterfaceNoQI(NS_GET_IID(nsIJSIID)) ||
|
||||
@ -921,10 +888,8 @@ xpc_JSObjectIsID(JSContext *cx, JSObject* obj)
|
||||
{
|
||||
NS_ASSERTION(cx && obj, "bad param");
|
||||
// NOTE: this call does NOT addref
|
||||
XPCWrappedNative* wrapper = nullptr;
|
||||
obj = js::UnwrapObjectChecked(obj);
|
||||
if (obj && IS_WN_WRAPPER(obj))
|
||||
wrapper = XPCWrappedNative::Get(obj);
|
||||
XPCWrappedNative* wrapper =
|
||||
XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj);
|
||||
return wrapper &&
|
||||
(wrapper->HasInterfaceNoQI(NS_GET_IID(nsIJSID)) ||
|
||||
wrapper->HasInterfaceNoQI(NS_GET_IID(nsIJSIID)) ||
|
||||
|
@ -2427,21 +2427,27 @@ PreserveWrapper(JSContext *cx, JSObject *obj)
|
||||
if (!ccx.IsValid())
|
||||
return false;
|
||||
|
||||
if (!IS_WRAPPER_CLASS(js::GetObjectClass(obj)))
|
||||
return mozilla::dom::TryPreserveWrapper(obj);
|
||||
|
||||
JSObject *obj2 = nullptr;
|
||||
nsIXPConnectWrappedNative *wrapper =
|
||||
XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj, nullptr, &obj2);
|
||||
nsISupports *supports = nullptr;
|
||||
if (IS_WN_WRAPPER_OBJECT(obj))
|
||||
supports = XPCWrappedNative::Get(obj)->Native();
|
||||
else
|
||||
supports = static_cast<nsISupports*>(xpc_GetJSPrivate(obj));
|
||||
|
||||
// For pre-Paris DOM bindings objects, we only support Node.
|
||||
if (nsCOMPtr<nsINode> node = do_QueryInterface(supports)) {
|
||||
nsContentUtils::PreserveWrapper(supports, node);
|
||||
return true;
|
||||
if (wrapper) {
|
||||
supports = wrapper->Native();
|
||||
} else if (obj2) {
|
||||
supports = static_cast<nsISupports*>(xpc_GetJSPrivate(obj2));
|
||||
}
|
||||
return false;
|
||||
|
||||
if (supports) {
|
||||
// For pre-Paris DOM bindings objects, we only support Node.
|
||||
if (nsCOMPtr<nsINode> node = do_QueryInterface(supports)) {
|
||||
nsContentUtils::PreserveWrapper(supports, node);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return mozilla::dom::TryPreserveWrapper(obj);
|
||||
}
|
||||
|
||||
static nsresult
|
||||
|
@ -28,20 +28,21 @@ XPCVariant::XPCVariant(JSContext* cx, jsval aJSVal)
|
||||
{
|
||||
nsVariant::Initialize(&mData);
|
||||
if (!JSVAL_IS_PRIMITIVE(mJSVal)) {
|
||||
// XXXbholley - The innerization here was from bug 638026. Blake says
|
||||
// the basic problem was that we were storing the C++ inner but the JS
|
||||
// outer, which meant that, after navigation, the JS inner could be
|
||||
// collected, which would cause us to try to recreate the JS inner at
|
||||
// some later point after teardown, which would crash. This is shouldn't
|
||||
// be a problem anymore because SetParentToWindow will do the right
|
||||
// thing, but I'm saving the cleanup here for another day. Blake thinks
|
||||
// that we should just not store the WN if we're creating a variant for
|
||||
// an outer window.
|
||||
JSObject *obj = JS_ObjectToInnerObject(cx, JSVAL_TO_OBJECT(mJSVal));
|
||||
|
||||
mJSVal = OBJECT_TO_JSVAL(obj);
|
||||
|
||||
JSObject *unwrapped = js::UnwrapObjectChecked(obj, /* stopAtOuter = */ false);
|
||||
mReturnRawObject = !(unwrapped && IS_WN_WRAPPER(unwrapped));
|
||||
// If the incoming object is an XPCWrappedNative, then it could be a
|
||||
// double-wrapped object, and we should return the double-wrapped
|
||||
// object back out to script.
|
||||
|
||||
JSObject* proto;
|
||||
XPCWrappedNative* wn =
|
||||
XPCWrappedNative::GetWrappedNativeOfJSObject(cx,
|
||||
JSVAL_TO_OBJECT(mJSVal),
|
||||
nullptr,
|
||||
&proto);
|
||||
mReturnRawObject = !wn && !proto;
|
||||
} else
|
||||
mReturnRawObject = false;
|
||||
}
|
||||
|
@ -1751,6 +1751,134 @@ XPCWrappedNative::RescueOrphans(XPCCallContext& ccx)
|
||||
return ::RescueOrphans(ccx, mFlatJSObject);
|
||||
}
|
||||
|
||||
#define IS_TEAROFF_CLASS(clazz) \
|
||||
((clazz) == &XPC_WN_Tearoff_JSClass)
|
||||
|
||||
// static
|
||||
XPCWrappedNative*
|
||||
XPCWrappedNative::GetWrappedNativeOfJSObject(JSContext* cx,
|
||||
JSObject* obj,
|
||||
JSObject* funobj,
|
||||
JSObject** pobj2,
|
||||
XPCWrappedNativeTearOff** pTearOff)
|
||||
{
|
||||
NS_PRECONDITION(obj, "bad param");
|
||||
|
||||
// fubobj must be null if called without cx.
|
||||
NS_PRECONDITION(cx || !funobj, "bad param");
|
||||
|
||||
// *pTeaorOff must be null if pTearOff is given
|
||||
NS_PRECONDITION(!pTearOff || !*pTearOff, "bad param");
|
||||
|
||||
JSObject* cur;
|
||||
|
||||
XPCWrappedNativeProto* proto = nullptr;
|
||||
nsIClassInfo* protoClassInfo = nullptr;
|
||||
|
||||
// When an object is unwrapped (near the bottom of this function), we need
|
||||
// to enter its compartment. Unfortunately, given the crazy usage of gotos,
|
||||
// scoped JSAutoCompartments are pretty much impossible. So instead, we use
|
||||
// a single Maybe<JSAutoCompartment>, and let anyone who wants to enter a
|
||||
// compartment destroy and then reconstruct it.
|
||||
Maybe<JSAutoCompartment> mac;
|
||||
if (cx)
|
||||
mac.construct(cx, obj);
|
||||
|
||||
// If we were passed a function object then we need to find the correct
|
||||
// wrapper out of those that might be in the callee obj's proto chain.
|
||||
|
||||
if (funobj) {
|
||||
JSObject* funObjParent = js::UnwrapObject(js::GetObjectParent(funobj));
|
||||
funObjParent = JS_ObjectToInnerObject(cx, funObjParent);
|
||||
NS_ASSERTION(funObjParent, "funobj has no parent");
|
||||
|
||||
js::Class* funObjParentClass = js::GetObjectClass(funObjParent);
|
||||
|
||||
if (IS_PROTO_CLASS(funObjParentClass)) {
|
||||
NS_ASSERTION(js::GetObjectParent(funObjParent), "funobj's parent (proto) is global");
|
||||
proto = (XPCWrappedNativeProto*) js::GetObjectPrivate(funObjParent);
|
||||
if (proto)
|
||||
protoClassInfo = proto->GetClassInfo();
|
||||
} else if (IS_WRAPPER_CLASS(funObjParentClass)) {
|
||||
cur = funObjParent;
|
||||
goto return_wrapper;
|
||||
} else if (IS_TEAROFF_CLASS(funObjParentClass)) {
|
||||
NS_ASSERTION(js::GetObjectParent(funObjParent), "funobj's parent (tearoff) is global");
|
||||
cur = funObjParent;
|
||||
goto return_tearoff;
|
||||
} else {
|
||||
NS_ERROR("function object has parent of unknown class!");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
restart:
|
||||
if (cx) {
|
||||
mac.destroy();
|
||||
mac.construct(cx, obj);
|
||||
}
|
||||
for (cur = obj; cur; ) {
|
||||
// this is on two lines to make the compiler happy given the goto.
|
||||
js::Class* clazz;
|
||||
clazz = js::GetObjectClass(cur);
|
||||
|
||||
if (IS_WRAPPER_CLASS(clazz)) {
|
||||
return_wrapper:
|
||||
JSBool isWN = IS_WN_WRAPPER_OBJECT(cur);
|
||||
XPCWrappedNative* wrapper =
|
||||
isWN ? (XPCWrappedNative*) js::GetObjectPrivate(cur) : nullptr;
|
||||
if (proto) {
|
||||
XPCWrappedNativeProto* wrapper_proto =
|
||||
isWN ? wrapper->GetProto() : GetSlimWrapperProto(cur);
|
||||
if (proto != wrapper_proto &&
|
||||
(!protoClassInfo || !wrapper_proto ||
|
||||
protoClassInfo != wrapper_proto->GetClassInfo()))
|
||||
goto next;
|
||||
}
|
||||
if (pobj2)
|
||||
*pobj2 = isWN ? nullptr : cur;
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
if (IS_TEAROFF_CLASS(clazz)) {
|
||||
return_tearoff:
|
||||
XPCWrappedNative* wrapper =
|
||||
(XPCWrappedNative*) js::GetObjectPrivate(js::GetObjectParent(cur));
|
||||
if (proto && proto != wrapper->GetProto() &&
|
||||
(proto->GetScope() != wrapper->GetScope() ||
|
||||
!protoClassInfo || !wrapper->GetProto() ||
|
||||
protoClassInfo != wrapper->GetProto()->GetClassInfo()))
|
||||
goto next;
|
||||
if (pobj2)
|
||||
*pobj2 = nullptr;
|
||||
XPCWrappedNativeTearOff* to = (XPCWrappedNativeTearOff*) js::GetObjectPrivate(cur);
|
||||
if (!to)
|
||||
return nullptr;
|
||||
if (pTearOff)
|
||||
*pTearOff = to;
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
// Unwrap any wrapper wrappers.
|
||||
JSObject *unsafeObj;
|
||||
unsafeObj = cx
|
||||
? XPCWrapper::Unwrap(cx, cur, /* stopAtOuter = */ false)
|
||||
: js::UnwrapObject(cur, /* stopAtOuter = */ false);
|
||||
if (unsafeObj) {
|
||||
obj = unsafeObj;
|
||||
goto restart;
|
||||
}
|
||||
|
||||
next:
|
||||
if (!js::GetObjectProto(cx, cur, &cur))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (pobj2)
|
||||
*pobj2 = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JSBool
|
||||
XPCWrappedNative::ExtendSet(XPCCallContext& ccx, XPCNativeInterface* aInterface)
|
||||
{
|
||||
|
@ -14,7 +14,8 @@
|
||||
|
||||
// static
|
||||
JSBool
|
||||
XPCNativeMember::GetCallInfo(JSObject* funobj,
|
||||
XPCNativeMember::GetCallInfo(XPCCallContext& ccx,
|
||||
JSObject* funobj,
|
||||
XPCNativeInterface** pInterface,
|
||||
XPCNativeMember** pMember)
|
||||
{
|
||||
|
@ -9,7 +9,6 @@
|
||||
|
||||
#include "xpcprivate.h"
|
||||
#include "XPCWrapper.h"
|
||||
#include "AccessCheck.h"
|
||||
#include "nsWrapperCacheInlines.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
@ -664,17 +663,19 @@ MarkWrappedNative(JSTracer *trc, JSObject *obj)
|
||||
if (clazz->flags & JSCLASS_DOM_GLOBAL) {
|
||||
mozilla::dom::TraceProtoAndIfaceCache(trc, obj);
|
||||
}
|
||||
MOZ_ASSERT(IS_WRAPPER_CLASS(clazz));
|
||||
|
||||
if (IS_WN_WRAPPER_OBJECT(obj)) {
|
||||
XPCWrappedNative *wrapper = XPCWrappedNative::Get(obj);
|
||||
if (wrapper) {
|
||||
if (wrapper->IsValid())
|
||||
wrapper->TraceInside(trc);
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(IS_SLIM_WRAPPER_OBJECT(obj));
|
||||
TraceInsideSlimWrapper(trc, obj);
|
||||
JSObject *obj2;
|
||||
|
||||
// Pass null for the first JSContext* parameter to skip any security
|
||||
// checks and to avoid potential state change there.
|
||||
XPCWrappedNative* wrapper =
|
||||
XPCWrappedNative::GetWrappedNativeOfJSObject(nullptr, obj, nullptr, &obj2);
|
||||
|
||||
if (wrapper) {
|
||||
if (wrapper->IsValid())
|
||||
wrapper->TraceInside(trc);
|
||||
} else if (obj2) {
|
||||
TraceInsideSlimWrapper(trc, obj2);
|
||||
}
|
||||
}
|
||||
|
||||
@ -848,21 +849,13 @@ XPC_WN_MaybeResolvingStrictPropertyStub(JSContext *cx, JSHandleObject obj, JSHan
|
||||
#define PRE_HELPER_STUB \
|
||||
XPCWrappedNative* wrapper; \
|
||||
nsIXPCScriptable* si; \
|
||||
JSObject *unwrapped = js::UnwrapObjectChecked(obj, false); \
|
||||
if (!unwrapped) { \
|
||||
JS_ReportError(cx, "Permission denied to operate on object."); \
|
||||
return false; \
|
||||
if (IS_SLIM_WRAPPER(obj)) { \
|
||||
wrapper = nullptr; \
|
||||
si = GetSlimWrapperProto(obj)->GetScriptableInfo()->GetCallback(); \
|
||||
} \
|
||||
if (!IS_WRAPPER_CLASS(js::GetObjectClass(unwrapped))) { \
|
||||
return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx); \
|
||||
} \
|
||||
if (IS_SLIM_WRAPPER_OBJECT(unwrapped)) { \
|
||||
wrapper = nullptr; \
|
||||
si = GetSlimWrapperProto(unwrapped)->GetScriptableInfo() \
|
||||
->GetCallback(); \
|
||||
} else { \
|
||||
MOZ_ASSERT(IS_WN_WRAPPER_OBJECT(unwrapped)); \
|
||||
wrapper = XPCWrappedNative::Get(unwrapped); \
|
||||
else \
|
||||
{ \
|
||||
wrapper = XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj); \
|
||||
THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); \
|
||||
si = wrapper->GetScriptableCallback(); \
|
||||
} \
|
||||
@ -1357,6 +1350,11 @@ XPCNativeScriptableShared::PopulateJSClass()
|
||||
if (mFlags.WantCheckAccess())
|
||||
mJSClass.base.checkAccess = XPC_WN_Helper_CheckAccess;
|
||||
|
||||
// Note that we *must* set the ObjectOps (even for the cases were it does
|
||||
// not do much) because with these dynamically generated JSClasses, the
|
||||
// code in XPCWrappedNative::GetWrappedNativeOfJSObject() needs to look
|
||||
// for that these callback pointers in order to identify that a given
|
||||
// JSObject represents a wrapper.
|
||||
js::ObjectOps *ops = &mJSClass.base.ops;
|
||||
ops->enumerate = XPC_WN_JSOp_Enumerate;
|
||||
ops->thisObject = XPC_WN_JSOp_ThisObject;
|
||||
@ -1384,33 +1382,6 @@ XPCNativeScriptableShared::PopulateJSClass()
|
||||
/***************************************************************************/
|
||||
/***************************************************************************/
|
||||
|
||||
// Compatibility hack.
|
||||
//
|
||||
// XPConnect used to do all sorts of funny tricks to find the "correct"
|
||||
// |this| object for a given method (often to the detriment of proper
|
||||
// call/apply). When these tricks were removed, a fair amount of chrome
|
||||
// code broke, because it was relying on being able to grab methods off
|
||||
// some XPCOM object (like the nsITelemetry service) and invoke them without
|
||||
// a proper |this|. So, if it's quite clear that we're in this situation and
|
||||
// about to use a |this| argument that just won't work, fix things up.
|
||||
//
|
||||
// This hack is only useful for getters/setters if someone sets an XPCOM object
|
||||
// as the prototype for a vanilla JS object and expects the XPCOM attributes to
|
||||
// work on the derived object, which we really don't want to support. But we
|
||||
// handle it anyway, for now, to minimize regression risk on an already-risky
|
||||
// landing.
|
||||
MOZ_ALWAYS_INLINE JSObject*
|
||||
FixUpThisIfBroken(JSObject *obj, JSObject *funobj)
|
||||
{
|
||||
if (MOZ_UNLIKELY(funobj &&
|
||||
(js::GetObjectClass(js::GetObjectParent(funobj)) == &XPC_WN_NoHelper_JSClass.base) &&
|
||||
(js::GetObjectClass(obj) != &XPC_WN_NoHelper_JSClass.base)))
|
||||
{
|
||||
return js::GetObjectParent(funobj);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
JSBool
|
||||
XPC_WN_CallMethod(JSContext *cx, unsigned argc, jsval *vp)
|
||||
{
|
||||
@ -1433,7 +1404,6 @@ XPC_WN_CallMethod(JSContext *cx, unsigned argc, jsval *vp)
|
||||
if (IS_SLIM_WRAPPER(obj) && !MorphSlimWrapper(cx, obj))
|
||||
return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);
|
||||
|
||||
obj = FixUpThisIfBroken(obj, funobj);
|
||||
XPCCallContext ccx(JS_CALLER, cx, obj, funobj, JSID_VOID, argc, JS_ARGV(cx, vp), vp);
|
||||
XPCWrappedNative* wrapper = ccx.GetWrapper();
|
||||
THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
|
||||
@ -1441,7 +1411,7 @@ XPC_WN_CallMethod(JSContext *cx, unsigned argc, jsval *vp)
|
||||
XPCNativeInterface* iface;
|
||||
XPCNativeMember* member;
|
||||
|
||||
if (!XPCNativeMember::GetCallInfo(funobj, &iface, &member))
|
||||
if (!XPCNativeMember::GetCallInfo(ccx, funobj, &iface, &member))
|
||||
return Throw(NS_ERROR_XPC_CANT_GET_METHOD_INFO, cx);
|
||||
ccx.SetCallInfo(iface, member, false);
|
||||
return XPCWrappedNative::CallMethod(ccx);
|
||||
@ -1471,18 +1441,17 @@ XPC_WN_GetterSetter(JSContext *cx, unsigned argc, jsval *vp)
|
||||
if (IS_SLIM_WRAPPER(obj) && !MorphSlimWrapper(cx, obj))
|
||||
return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);
|
||||
|
||||
|
||||
obj = FixUpThisIfBroken(obj, funobj);
|
||||
XPCCallContext ccx(JS_CALLER, cx, obj, funobj, JSID_VOID, argc, JS_ARGV(cx, vp), vp);
|
||||
XPCCallContext ccx(JS_CALLER, cx, obj, funobj);
|
||||
XPCWrappedNative* wrapper = ccx.GetWrapper();
|
||||
THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
|
||||
|
||||
XPCNativeInterface* iface;
|
||||
XPCNativeMember* member;
|
||||
|
||||
if (!XPCNativeMember::GetCallInfo(funobj, &iface, &member))
|
||||
if (!XPCNativeMember::GetCallInfo(ccx, funobj, &iface, &member))
|
||||
return Throw(NS_ERROR_XPC_CANT_GET_METHOD_INFO, cx);
|
||||
|
||||
ccx.SetArgsAndResultPtr(argc, JS_ARGV(cx, vp), vp);
|
||||
if (argc && member->IsWritableAttribute()) {
|
||||
ccx.SetCallInfo(iface, member, true);
|
||||
JSBool retval = XPCWrappedNative::SetAttribute(ccx);
|
||||
|
@ -1332,18 +1332,15 @@ nsXPConnect::GetNativeOfWrapper(JSContext * aJSContext,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
aJSObj = js::UnwrapObjectChecked(aJSObj, /* stopAtOuter = */ false);
|
||||
if (!aJSObj) {
|
||||
JS_ReportError(aJSContext, "Permission denied to get native of security wrapper");
|
||||
return nullptr;
|
||||
}
|
||||
if (IS_WRAPPER_CLASS(js::GetObjectClass(aJSObj))) {
|
||||
if (IS_SLIM_WRAPPER_OBJECT(aJSObj))
|
||||
return (nsISupports*)xpc_GetJSPrivate(aJSObj);
|
||||
else if (XPCWrappedNative *wn = XPCWrappedNative::Get(aJSObj))
|
||||
return wn->Native();
|
||||
return nullptr;
|
||||
}
|
||||
JSObject* obj2 = nullptr;
|
||||
nsIXPConnectWrappedNative* wrapper =
|
||||
XPCWrappedNative::GetWrappedNativeOfJSObject(aJSContext, aJSObj, nullptr,
|
||||
&obj2);
|
||||
if (wrapper)
|
||||
return wrapper->Native();
|
||||
|
||||
if (obj2)
|
||||
return (nsISupports*)xpc_GetJSPrivate(obj2);
|
||||
|
||||
JSObject* unsafeObj =
|
||||
XPCWrapper::Unwrap(aJSContext, aJSObj, /* stopAtOuter = */ false);
|
||||
|
@ -1248,9 +1248,6 @@ private:
|
||||
jsval *argv,
|
||||
jsval *rval);
|
||||
|
||||
XPCWrappedNative* UnwrapThisIfAllowed(JSObject *obj, JSObject *fun,
|
||||
unsigned argc);
|
||||
|
||||
private:
|
||||
// posible values for mState
|
||||
enum State {
|
||||
@ -1753,7 +1750,8 @@ private:
|
||||
class XPCNativeMember
|
||||
{
|
||||
public:
|
||||
static JSBool GetCallInfo(JSObject* funobj,
|
||||
static JSBool GetCallInfo(XPCCallContext& ccx,
|
||||
JSObject* funobj,
|
||||
XPCNativeInterface** pInterface,
|
||||
XPCNativeMember** pMember);
|
||||
|
||||
@ -2687,11 +2685,6 @@ public:
|
||||
void
|
||||
SetSet(XPCNativeSet* set) {XPCAutoLock al(GetLock()); mSet = set;}
|
||||
|
||||
static XPCWrappedNative* Get(JSObject *obj) {
|
||||
MOZ_ASSERT(IS_WN_WRAPPER(obj));
|
||||
return (XPCWrappedNative*)js::GetObjectPrivate(obj);
|
||||
}
|
||||
|
||||
private:
|
||||
inline void
|
||||
ExpireWrapper()
|
||||
@ -2751,19 +2744,30 @@ public:
|
||||
XPCNativeInterface* Interface,
|
||||
XPCWrappedNative** wrapper);
|
||||
|
||||
// If pobj2 is not null and *pobj2 is not null after the call then *pobj2
|
||||
// points to an object for which IS_SLIM_WRAPPER_OBJECT is true.
|
||||
// cx is null when invoked from the marking phase of the GC. In this case
|
||||
// fubobj must be null as well.
|
||||
static XPCWrappedNative*
|
||||
GetWrappedNativeOfJSObject(JSContext* cx, JSObject* obj,
|
||||
JSObject* funobj = nullptr,
|
||||
JSObject** pobj2 = nullptr,
|
||||
XPCWrappedNativeTearOff** pTearOff = nullptr);
|
||||
static XPCWrappedNative*
|
||||
GetAndMorphWrappedNativeOfJSObject(JSContext* cx, JSObject* obj)
|
||||
{
|
||||
obj = js::UnwrapObjectChecked(obj, /* stopAtOuter = */ false);
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
if (!IS_WRAPPER_CLASS(js::GetObjectClass(obj)))
|
||||
return nullptr;
|
||||
JSObject *obj2 = nullptr;
|
||||
XPCWrappedNative* wrapper =
|
||||
GetWrappedNativeOfJSObject(cx, obj, nullptr, &obj2);
|
||||
if (wrapper || !obj2)
|
||||
return wrapper;
|
||||
|
||||
if (IS_SLIM_WRAPPER_OBJECT(obj) && !MorphSlimWrapper(cx, obj))
|
||||
return nullptr;
|
||||
MOZ_ASSERT(IS_WN_WRAPPER(obj));
|
||||
return XPCWrappedNative::Get(obj);
|
||||
NS_ASSERTION(IS_SLIM_WRAPPER(obj2),
|
||||
"Hmm, someone changed GetWrappedNativeOfJSObject?");
|
||||
SLIM_LOG_WILL_MORPH(cx, obj2);
|
||||
return MorphSlimWrapper(cx, obj2) ?
|
||||
(XPCWrappedNative*)xpc_GetJSPrivate(obj2) :
|
||||
nullptr;
|
||||
}
|
||||
|
||||
static nsresult
|
||||
|
@ -29,7 +29,6 @@ MOCHITEST_CHROME_FILES = \
|
||||
file_bug618176.xul \
|
||||
test_bug654370.xul \
|
||||
test_bug658560.xul \
|
||||
test_bug658909.xul \
|
||||
test_bug664689.xul \
|
||||
test_bug679861.xul \
|
||||
test_bug706301.xul \
|
||||
|
@ -1,92 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=658909
|
||||
-->
|
||||
<window title="Mozilla Bug 658909"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
|
||||
<!-- test results are displayed in the html:body -->
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=658909"
|
||||
target="_blank">Mozilla Bug 658909</a>
|
||||
</body>
|
||||
|
||||
<!-- test code goes here -->
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
/** Test for call/apply-ing Xray methods.**/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
gLoadCount = 0;
|
||||
function frameLoaded() {
|
||||
if (++gLoadCount == frames.length)
|
||||
go();
|
||||
}
|
||||
|
||||
function msg(a, b, testName) {
|
||||
return "(" + a.name + ", " + b.name + "): " + testName;
|
||||
}
|
||||
|
||||
var testFunctions = {
|
||||
testDocumentElement: function(a, b, name) {
|
||||
var getter = Object.prototype.__lookupGetter__.call(a.document, 'documentElement');
|
||||
is(getter.call(b.document), b.document.documentElement, msg(a, b, name));
|
||||
},
|
||||
|
||||
testInvalidCall: function(a, b, name) {
|
||||
var getter = Object.prototype.__lookupGetter__.call(a.document, 'documentElement');
|
||||
var threw = false;
|
||||
try { getter.call(b.document.body); } catch (e) { threw = true; };
|
||||
ok(threw, msg(a, b, name));
|
||||
},
|
||||
|
||||
testStatus: function(a, b, name) {
|
||||
var setter = Object.prototype.__lookupSetter__.call(a, 'status');
|
||||
is(b.status, "", "Empty status");
|
||||
setter.call(b, "foopy");
|
||||
is(b.status, "foopy", msg(a, b, name));
|
||||
b.status = "";
|
||||
},
|
||||
|
||||
testCreateElement: function(a, b, name) {
|
||||
is(a.document.createElement.call(b.document, 'div').ownerDocument, b.document, msg(a, b, name));
|
||||
},
|
||||
|
||||
testWindowName: function(a, b, name) {
|
||||
var getter = Object.prototype.__lookupGetter__.call(a, 'name');
|
||||
is(getter.call(b), b.name, msg(a, b, name));
|
||||
},
|
||||
|
||||
testCanvas: function(a, b, name) {
|
||||
var canvasA = a.document.createElement('canvas');
|
||||
var canvasB = b.document.createElement('canvas');
|
||||
var contextA = canvasA.getContext('2d');
|
||||
var contextB = canvasB.getContext('2d');
|
||||
var getter = Object.prototype.__lookupGetter__.call(contextA, 'canvas');
|
||||
is(getter.call(contextB), canvasB, msg(a, b, name));
|
||||
}
|
||||
};
|
||||
|
||||
function go() {
|
||||
for (var i = 0; i < frames.length; ++i)
|
||||
frames[i].name = 'frame' + i;
|
||||
for (var i = 0; i < frames.length; ++i) {
|
||||
for (var j = 0; j < frames.length; ++j) {
|
||||
for (var k in testFunctions)
|
||||
testFunctions[k](frames[i], frames[j], k);
|
||||
}
|
||||
}
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
|
||||
]]>
|
||||
</script>
|
||||
<iframe id="frame1" onload="frameLoaded();" type="content" src="http://example.org/tests/js/xpconnect/tests/mochitest/file_empty.html" />
|
||||
<iframe id="frame2" onload="frameLoaded();" type="content" src="http://example.org/tests/js/xpconnect/tests/mochitest/file_empty.html" />
|
||||
<iframe id="frame3" onload="frameLoaded();" type="content" src="http://example.com/tests/js/xpconnect/tests/mochitest/file_empty.html" />
|
||||
</window>
|
@ -55,10 +55,18 @@ function mergeObjects(a, b) {
|
||||
function getAllTests() {
|
||||
var innerTests = getTests(false);
|
||||
var outerTests = getTests(true);
|
||||
outerTests.getLocationApply1.skipMessageCheck = true;
|
||||
outerTests.getLocationApply2.skipMessageCheck = true;
|
||||
outerTests.getLocationApply3.skipMessageCheck = true;
|
||||
outerTests.getLocationViaPrototype.skipMessageCheck = true;
|
||||
outerTests.getHrefViaApply.skipMessageCheck = true;
|
||||
outerTests.getHrefViaPrototype.skipMessageCheck = true;
|
||||
return mergeObjects(mungeNames(innerTests, '_inner'),
|
||||
mungeNames(outerTests, '_outer'));
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -13,13 +13,17 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=802557
|
||||
/** Test for Bug 802557 **/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function checkThrows(fun, desc) {
|
||||
// In the case of apply()ing on a Location object that's script access only,
|
||||
// we just throw a very bland XPConnect message. In other cases though, we want
|
||||
// to check the message to make sure we're throwing a security exception and not
|
||||
// something else.
|
||||
function checkThrows(fun, desc, skipMessageCheck) {
|
||||
try {
|
||||
fun();
|
||||
ok(false, "Didn't throw when " + desc);
|
||||
} catch(e) {
|
||||
ok(true, "Threw when " + desc + " " + e);
|
||||
ok(/denied|insecure/.exec(e), "Should be security exception");
|
||||
(skipMessageCheck ? todo : ok)(/denied|insecure/.exec(e), "Should be security exception");
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,7 +59,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=802557
|
||||
else if (loadCount == 2) {
|
||||
gGetters.forEach(function(item) {
|
||||
checkThrows(function() { item[0].call(gLoc); },
|
||||
'call()ing ' + item[1] + ' after navigation cross-origin');
|
||||
'call()ing ' + item[1] + ' after navigation cross-origin',
|
||||
/* skipMessageCheck = */ false);
|
||||
});
|
||||
ifr.src = 'http://mochi.test:8888/tests/js/xpconnect/tests/mochitest/file_bug802557.html';
|
||||
}
|
||||
@ -69,7 +74,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=802557
|
||||
else if (loadCount == 4) {
|
||||
for (fun in gTestFunctions) {
|
||||
var f = gTestFunctions[fun];
|
||||
checkThrows(f, "calling " + fun);
|
||||
checkThrows(f, "calling " + fun, f.skipMessageCheck);
|
||||
}
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
@ -166,10 +166,7 @@ IsPermitted(const char *name, JSFlatString *prop, bool set)
|
||||
static bool
|
||||
IsFrameId(JSContext *cx, JSObject *obj, jsid id)
|
||||
{
|
||||
obj = JS_ObjectToInnerObject(cx, obj);
|
||||
MOZ_ASSERT(!js::IsWrapper(obj));
|
||||
XPCWrappedNative *wn = IS_WN_WRAPPER(obj) ? XPCWrappedNative::Get(obj)
|
||||
: nullptr;
|
||||
XPCWrappedNative *wn = XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj);
|
||||
if (!wn) {
|
||||
return false;
|
||||
}
|
||||
@ -270,19 +267,6 @@ AccessCheck::isScriptAccessOnly(JSContext *cx, JSObject *wrapper)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
OnlyIfSubjectIsSystem::isSafeToUnwrap()
|
||||
{
|
||||
if (XPCJSRuntime::Get()->XBLScopesEnabled())
|
||||
return false;
|
||||
// It's nasty to use the context stack here, but the alternative is passing cx all
|
||||
// the way down through UnwrapObjectChecked, which we just undid in a 100k patch. :-(
|
||||
JSContext *cx = nsContentUtils::GetCurrentJSContext();
|
||||
if (!cx)
|
||||
return true;
|
||||
return AccessCheck::isSystemOnlyAccessPermitted(cx);
|
||||
}
|
||||
|
||||
enum Access { READ = (1<<0), WRITE = (1<<1), NO_ACCESS = 0 };
|
||||
|
||||
static bool
|
||||
|
@ -50,9 +50,6 @@ struct Opaque : public Policy {
|
||||
{
|
||||
return false;
|
||||
}
|
||||
static bool isSafeToUnwrap() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// This policy only permits access to the object if the subject can touch
|
||||
@ -70,8 +67,6 @@ struct OnlyIfSubjectIsSystem : public Policy {
|
||||
{
|
||||
return AccessCheck::isSystemOnlyAccessPermitted(cx);
|
||||
}
|
||||
|
||||
static bool isSafeToUnwrap();
|
||||
};
|
||||
|
||||
// This policy only permits access to properties that are safe to be used
|
||||
@ -87,10 +82,6 @@ struct CrossOriginAccessiblePropertiesOnly : public Policy {
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool isSafeToUnwrap() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// This policy only permits access to properties if they appear in the
|
||||
@ -103,10 +94,6 @@ struct ExposedPropertiesOnly : public Policy {
|
||||
return act == js::Wrapper::GET;
|
||||
}
|
||||
static bool allowNativeCall(JSContext *cx, JS::IsAcceptableThis test, JS::NativeImpl impl);
|
||||
|
||||
static bool isSafeToUnwrap() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Components specific policy
|
||||
@ -119,10 +106,6 @@ struct ComponentsObjectPolicy : public Policy {
|
||||
static bool allowNativeCall(JSContext *cx, JS::IsAcceptableThis test, JS::NativeImpl impl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool isSafeToUnwrap() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -29,13 +29,6 @@ FilteringWrapper<Base, Policy>::~FilteringWrapper()
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Base, typename Policy>
|
||||
bool
|
||||
FilteringWrapper<Base, Policy>::isSafeToUnwrap()
|
||||
{
|
||||
return Policy::isSafeToUnwrap();
|
||||
}
|
||||
|
||||
template <typename Policy>
|
||||
static bool
|
||||
Filter(JSContext *cx, JSObject *wrapper, AutoIdVector &props)
|
||||
|
@ -19,9 +19,6 @@ class FilteringWrapper : public Base {
|
||||
FilteringWrapper(unsigned flags);
|
||||
virtual ~FilteringWrapper();
|
||||
|
||||
// This is potentially dynamic until XBL scopes are no longer behind a pref.
|
||||
virtual bool isSafeToUnwrap();
|
||||
|
||||
virtual bool getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, js::PropertyDescriptor *desc, unsigned flags) MOZ_OVERRIDE;
|
||||
virtual bool getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, js::PropertyDescriptor *desc, unsigned flags) MOZ_OVERRIDE;
|
||||
virtual bool getOwnPropertyNames(JSContext *cx, JSObject *wrapper, js::AutoIdVector &props) MOZ_OVERRIDE;
|
||||
|
@ -39,13 +39,6 @@ Wrapper XrayWaiver(WrapperFactory::WAIVE_XRAY_WRAPPER_FLAG);
|
||||
// off it.
|
||||
WaiveXrayWrapper WaiveXrayWrapper::singleton(0);
|
||||
|
||||
bool
|
||||
WrapperFactory::IsCOW(JSObject *obj)
|
||||
{
|
||||
return IsWrapper(obj) &&
|
||||
Wrapper::wrapperHandler(obj) == &ChromeObjectWrapper::singleton;
|
||||
}
|
||||
|
||||
JSObject *
|
||||
WrapperFactory::GetXrayWaiver(JSObject *obj)
|
||||
{
|
||||
@ -291,8 +284,8 @@ DEBUG_CheckUnwrapSafety(JSObject *obj, js::Wrapper *handler,
|
||||
// The Components object that is restricted regardless of origin.
|
||||
MOZ_ASSERT(!handler->isSafeToUnwrap());
|
||||
} else if (AccessCheck::needsSystemOnlyWrapper(obj)) {
|
||||
// SOWs have a dynamic unwrap check, so we can't really say anything useful
|
||||
// about them here :-(
|
||||
// SOWs are opaque to everyone but Chrome and XBL scopes.
|
||||
MOZ_ASSERT(handler->isSafeToUnwrap() == nsContentUtils::CanAccessNativeAnon());
|
||||
} else {
|
||||
// Otherwise, it should depend on whether the target subsumes the origin.
|
||||
MOZ_ASSERT(handler->isSafeToUnwrap() == AccessCheck::subsumes(target, origin));
|
||||
@ -506,8 +499,7 @@ WrapperFactory::WrapForSameCompartment(JSContext *cx, JSObject *obj)
|
||||
|
||||
// The WN knows what to do.
|
||||
JSObject *wrapper = wn->GetSameCompartmentSecurityWrapper(cx);
|
||||
MOZ_ASSERT_IF(wrapper != obj && IsComponentsObject(js::UnwrapObject(obj)),
|
||||
!Wrapper::wrapperHandler(wrapper)->isSafeToUnwrap());
|
||||
MOZ_ASSERT_IF(wrapper != obj, !Wrapper::wrapperHandler(wrapper)->isSafeToUnwrap());
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
|
@ -35,12 +35,6 @@ class WrapperFactory {
|
||||
return HasWrapperFlag(wrapper, WAIVE_XRAY_WRAPPER_FLAG);
|
||||
}
|
||||
|
||||
static bool IsSecurityWrapper(JSObject *obj) {
|
||||
return !js::UnwrapObjectChecked(obj);
|
||||
}
|
||||
|
||||
static bool IsCOW(JSObject *wrapper);
|
||||
|
||||
static JSObject *GetXrayWaiver(JSObject *obj);
|
||||
static JSObject *CreateXrayWaiver(JSContext *cx, JSObject *obj);
|
||||
static JSObject *WaiveXray(JSContext *cx, JSObject *obj);
|
||||
|
Loading…
Reference in New Issue
Block a user