diff --git a/js/src/xpconnect/src/XPCNativeWrapper.cpp b/js/src/xpconnect/src/XPCNativeWrapper.cpp index f42cd80aa4c..1ff00428ee8 100644 --- a/js/src/xpconnect/src/XPCNativeWrapper.cpp +++ b/js/src/xpconnect/src/XPCNativeWrapper.cpp @@ -251,8 +251,10 @@ RewrapIfDeepWrapper(JSContext *cx, JSObject *obj, jsval v, jsval *rval) XPCWrappedNative* wrappedNative = XPCWrappedNative::GetAndMorphWrappedNativeOfJSObject(cx, nativeObj); - if (!wrappedNative) - return XPCSafeJSObjectWrapper::WrapObject(cx, nsnull, v, rval); + if (!wrappedNative) { + return XPCSafeJSObjectWrapper::WrapObject(cx, JS_GetScopeChain(cx), + v, rval); + } if (HAS_FLAGS(flags, FLAG_EXPLICIT)) { #ifdef DEBUG_XPCNativeWrapper @@ -278,6 +280,7 @@ RewrapIfDeepWrapper(JSContext *cx, JSObject *obj, jsval v, jsval *rval) // GetWrappedNativeOfJSObject will give the right thing -- the unique deep // implicit wrapper associated with wrappedNative. JSObject* wrapperObj = XPCNativeWrapper::GetNewOrUsed(cx, wrappedNative, + JS_GetScopeChain(cx), nsnull); if (!wrapperObj) { return JS_FALSE; @@ -912,7 +915,8 @@ MirrorWrappedNativeParent(JSContext *cx, XPCWrappedNative *wrapper, // scope. In that case, the best we can do is just use the // non-native-wrapped sandbox global object for our parent. if (parent_wrapper) { - *result = XPCNativeWrapper::GetNewOrUsed(cx, parent_wrapper, nsnull); + *result = XPCNativeWrapper::GetNewOrUsed(cx, parent_wrapper, nsnull, + nsnull); if (!*result) return JS_FALSE; } else { @@ -1230,7 +1234,7 @@ XPCNativeWrapper::AttachNewConstructorObject(XPCCallContext &ccx, // static JSObject * XPCNativeWrapper::GetNewOrUsed(JSContext *cx, XPCWrappedNative *wrapper, - nsIPrincipal *aObjectPrincipal) + JSObject *scope, nsIPrincipal *aObjectPrincipal) { if (aObjectPrincipal) { nsIScriptSecurityManager *ssm = GetSecurityManager(); @@ -1259,7 +1263,7 @@ XPCNativeWrapper::GetNewOrUsed(JSContext *cx, XPCWrappedNative *wrapper, // Make sure v doesn't get collected while we're re-wrapping it. AUTO_MARK_JSVAL(ccx, v); - if (XPCSafeJSObjectWrapper::WrapObject(cx, nsnull, v, &v)) + if (XPCSafeJSObjectWrapper::WrapObject(cx, scope, v, &v)) return JSVAL_TO_OBJECT(v); return nsnull; diff --git a/js/src/xpconnect/src/XPCNativeWrapper.h b/js/src/xpconnect/src/XPCNativeWrapper.h index 780e38c16dc..74f8b68f130 100644 --- a/js/src/xpconnect/src/XPCNativeWrapper.h +++ b/js/src/xpconnect/src/XPCNativeWrapper.h @@ -51,7 +51,7 @@ AttachNewConstructorObject(XPCCallContext &ccx, JSObject *aGlobalObject); JSObject * GetNewOrUsed(JSContext *cx, XPCWrappedNative *wrapper, - nsIPrincipal *aObjectPrincipal); + JSObject *scope, nsIPrincipal *aObjectPrincipal); JSBool CreateExplicitWrapper(JSContext *cx, XPCWrappedNative *wrapper, JSBool deep, jsval *rval); diff --git a/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp b/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp index 0217ed04b56..2f78d428016 100644 --- a/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp +++ b/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp @@ -286,11 +286,6 @@ AttachNewConstructorObject(XPCCallContext &ccx, JSObject *aGlobalObject) return PR_FALSE; } - // Null out the class object's parent to prevent code in this class - // from thinking the class object is a wrapper for the global - // object. - ::JS_SetParent(ccx, class_obj, nsnull); - // Make sure our prototype chain is empty and that people can't mess // with XPCSafeJSObjectWrapper.prototype. ::JS_SetPrototype(ccx, class_obj, nsnull); @@ -307,7 +302,7 @@ AttachNewConstructorObject(XPCCallContext &ccx, JSObject *aGlobalObject) } JSObject * -GetUnsafeObject(JSObject *obj) +GetUnsafeObject(JSContext *cx, JSObject *obj) { obj = FindSafeObject(obj); @@ -315,7 +310,13 @@ GetUnsafeObject(JSObject *obj) return nsnull; } - return STOBJ_GET_PARENT(obj); + jsval v; + if (!JS_GetReservedSlot(cx, obj, XPCWrapper::sWrappedObjSlot, &v)) { + JS_ClearPendingException(cx); + return nsnull; + } + + return JSVAL_IS_OBJECT(v) ? JSVAL_TO_OBJECT(v) : nsnull; } } // namespace XPCSafeJSObjectWrapper @@ -408,13 +409,13 @@ WrapJSValue(JSContext *cx, JSObject *obj, jsval val, jsval *rval) } static jsval -UnwrapJSValue(jsval val) +UnwrapJSValue(JSContext *cx, jsval val) { if (JSVAL_IS_PRIMITIVE(val)) { return val; } - JSObject *unsafeObj = GetUnsafeObject(JSVAL_TO_OBJECT(val)); + JSObject *unsafeObj = GetUnsafeObject(cx, JSVAL_TO_OBJECT(val)); if (unsafeObj) { return OBJECT_TO_JSVAL(unsafeObj); } @@ -443,7 +444,7 @@ XPC_SJOW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) return ok; } - JSObject *unsafeObj = GetUnsafeObject(obj); + JSObject *unsafeObj = GetUnsafeObject(cx, obj); if (!unsafeObj) { return ThrowException(NS_ERROR_UNEXPECTED, cx); } @@ -460,7 +461,7 @@ XPC_SJOW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) static JSBool XPC_SJOW_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { - JSObject *unsafeObj = GetUnsafeObject(obj); + JSObject *unsafeObj = GetUnsafeObject(cx, obj); if (!unsafeObj) { return ThrowException(NS_ERROR_UNEXPECTED, cx); } @@ -533,7 +534,7 @@ XPC_SJOW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp, obj = FindSafeObject(obj); NS_ASSERTION(obj != nsnull, "FindSafeObject() returned null in class hook!"); - JSObject *unsafeObj = GetUnsafeObject(obj); + JSObject *unsafeObj = GetUnsafeObject(cx, obj); if (!unsafeObj) { return ThrowException(NS_ERROR_UNEXPECTED, cx); } @@ -556,7 +557,7 @@ XPC_SJOW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp, } if (aIsSet) { - *vp = UnwrapJSValue(*vp); + *vp = UnwrapJSValue(cx, *vp); } JSBool ok = aIsSet @@ -595,7 +596,7 @@ XPC_SJOW_Enumerate(JSContext *cx, JSObject *obj) // enumerated identifiers from the unsafe object to the safe // wrapper. - JSObject *unsafeObj = GetUnsafeObject(obj); + JSObject *unsafeObj = GetUnsafeObject(cx, obj); if (!unsafeObj) { return JS_TRUE; } @@ -621,7 +622,7 @@ XPC_SJOW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, obj = FindSafeObject(obj); NS_ASSERTION(obj != nsnull, "FindSafeObject() returned null in class hook!"); - JSObject *unsafeObj = GetUnsafeObject(obj); + JSObject *unsafeObj = GetUnsafeObject(cx, obj); if (!unsafeObj) { // No unsafe object, nothing to resolve here. @@ -679,7 +680,7 @@ XPC_SJOW_CheckAccess(JSContext *cx, JSObject *obj, jsval id, return JS_FALSE; } - JSObject *unsafeObj = GetUnsafeObject(obj); + JSObject *unsafeObj = GetUnsafeObject(cx, obj); if (!unsafeObj) { return JS_TRUE; } @@ -732,7 +733,7 @@ XPC_SJOW_Call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, } } - unsafeObj = GetUnsafeObject(obj); + unsafeObj = GetUnsafeObject(cx, obj); if (!unsafeObj) { return ThrowException(NS_ERROR_UNEXPECTED, cx); } @@ -742,7 +743,7 @@ XPC_SJOW_Call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, } JSObject *safeObj = JSVAL_TO_OBJECT(argv[-2]); - JSObject *funToCall = GetUnsafeObject(safeObj); + JSObject *funToCall = GetUnsafeObject(cx, safeObj); if (!funToCall) { // Someone has called XPCSafeJSObjectWrapper.prototype() causing @@ -762,7 +763,7 @@ XPC_SJOW_Call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, SafeCallGuard guard(cx, FindObjectPrincipals(cx, safeObj, funToCall)); for (uintN i = 0; i < argc; ++i) { - argv[i] = UnwrapJSValue(argv[i]); + argv[i] = UnwrapJSValue(cx, argv[i]); } if (!JS_CallFunctionValue(cx, callThisObj, OBJECT_TO_JSVAL(funToCall), @@ -782,9 +783,10 @@ XPC_SJOW_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, return ThrowException(NS_ERROR_XPC_NOT_ENOUGH_ARGS, cx); } - // |obj| almost always has the wrong proto and parent so we have to create - // our own object anyway. Set |obj| to null so we don't use it by accident. - obj = nsnull; + // We're not going to use obj because we have callers who aren't the JS + // engine, but we can use it to figure out what scope we're creating this + // SJOW for. + JSObject *scope = JS_GetGlobalForObject(cx, obj); if (JSVAL_IS_PRIMITIVE(argv[0])) { JSStackFrame *fp = nsnull; @@ -810,7 +812,7 @@ XPC_SJOW_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, } SLIM_LOG_WILL_MORPH(cx, objToWrap); - if(IS_SLIM_WRAPPER(objToWrap) && !MorphSlimWrapper(cx, objToWrap)) { + if (IS_SLIM_WRAPPER(objToWrap) && !MorphSlimWrapper(cx, objToWrap)) { return ThrowException(NS_ERROR_FAILURE, cx); } @@ -820,7 +822,7 @@ XPC_SJOW_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, return JS_FALSE; } - JSObject *unsafeObj = GetUnsafeObject(objToWrap); + JSObject *unsafeObj = GetUnsafeObject(cx, objToWrap); if (unsafeObj) { // We're asked to wrap an already wrapped object. Re-wrap the @@ -829,23 +831,21 @@ XPC_SJOW_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, objToWrap = unsafeObj; } - // Don't use the object the JS engine created for us, it is in most - // cases incorectly parented and has a proto from the wrong scope. JSObject *wrapperObj = - ::JS_NewObjectWithGivenProto(cx, &SJOWClass.base, nsnull, - objToWrap); + JS_NewObjectWithGivenProto(cx, &SJOWClass.base, nsnull, scope); if (!wrapperObj) { // JS_NewObjectWithGivenProto already threw. return JS_FALSE; } - if (!::JS_SetReservedSlot(cx, wrapperObj, sFlagsSlot, JSVAL_ZERO)) { + *rval = OBJECT_TO_JSVAL(wrapperObj); + if (!JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sWrappedObjSlot, + OBJECT_TO_JSVAL(objToWrap)) || + !JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sFlagsSlot, JSVAL_ZERO)) { return JS_FALSE; } - *rval = OBJECT_TO_JSVAL(wrapperObj); - return JS_TRUE; } @@ -854,8 +854,8 @@ XPC_SJOW_Create(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JSObject *callee = JSVAL_TO_OBJECT(argv[-2]); - NS_ASSERTION(GetUnsafeObject(callee), "How'd we get here?"); - JSObject *unsafeObj = GetUnsafeObject(callee); + NS_ASSERTION(GetUnsafeObject(cx, callee), "How'd we get here?"); + JSObject *unsafeObj = GetUnsafeObject(cx, callee); // Check that the caller can access the unsafe object. if (!CanCallerAccess(cx, unsafeObj)) { @@ -884,10 +884,10 @@ XPC_SJOW_Equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) if (JSVAL_IS_PRIMITIVE(v)) { *bp = JS_FALSE; } else { - JSObject *unsafeObj = GetUnsafeObject(obj); + JSObject *unsafeObj = GetUnsafeObject(cx, obj); JSObject *other = JSVAL_TO_OBJECT(v); - JSObject *otherUnsafe = GetUnsafeObject(other); + JSObject *otherUnsafe = GetUnsafeObject(cx, other); // An object is equal to a SJOW if: // - The other object is the same SJOW. @@ -915,7 +915,7 @@ XPC_SJOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly) obj = FindSafeObject(obj); NS_ASSERTION(obj != nsnull, "FindSafeObject() returned null in class hook!"); - JSObject *unsafeObj = GetUnsafeObject(obj); + JSObject *unsafeObj = GetUnsafeObject(cx, obj); if (!unsafeObj) { ThrowException(NS_ERROR_INVALID_ARG, cx); @@ -944,13 +944,16 @@ XPC_SJOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly) // Create our dummy SJOW. JSObject *wrapperIter = - ::JS_NewObjectWithGivenProto(cx, &SJOWClass.base, nsnull, - unsafeObj); + JS_NewObjectWithGivenProto(cx, &SJOWClass.base, nsnull, + JS_GetGlobalForObject(cx, obj)); if (!wrapperIter) { return nsnull; } - if (!::JS_SetReservedSlot(cx, wrapperIter, sFlagsSlot, JSVAL_ZERO)) { + if (!JS_SetReservedSlot(cx, wrapperIter, XPCWrapper::sWrappedObjSlot, + OBJECT_TO_JSVAL(unsafeObj)) || + !JS_SetReservedSlot(cx, wrapperIter, XPCWrapper::sFlagsSlot, + JSVAL_ZERO)) { return nsnull; } @@ -964,7 +967,7 @@ XPC_SJOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly) static JSObject * XPC_SJOW_WrappedObject(JSContext *cx, JSObject *obj) { - return GetUnsafeObject(obj); + return GetUnsafeObject(cx, obj); } static JSBool @@ -976,7 +979,7 @@ XPC_SJOW_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, return ThrowException(NS_ERROR_INVALID_ARG, cx); } - JSObject *unsafeObj = GetUnsafeObject(obj); + JSObject *unsafeObj = GetUnsafeObject(cx, obj); if (!unsafeObj) { // No unsafe object, nothing to stringify here, return "[object diff --git a/js/src/xpconnect/src/XPCWrapper.cpp b/js/src/xpconnect/src/XPCWrapper.cpp index 0b3c404ed9b..f671b67ff25 100644 --- a/js/src/xpconnect/src/XPCWrapper.cpp +++ b/js/src/xpconnect/src/XPCWrapper.cpp @@ -75,7 +75,8 @@ Unwrap(JSContext *cx, JSObject *wrapper) } if (clasp == &XPCSafeJSObjectWrapper::SJOWClass.base) { - JSObject *wrappedObj = STOBJ_GET_PARENT(wrapper); + JSObject *wrappedObj = + XPCSafeJSObjectWrapper::GetUnsafeObject(cx, wrapper); if (NS_FAILED(XPCCrossOriginWrapper::CanAccessWrapper(cx, wrappedObj, nsnull))) { JS_ClearPendingException(cx); diff --git a/js/src/xpconnect/src/XPCWrapper.h b/js/src/xpconnect/src/XPCWrapper.h index 0c7d89b9171..dd833a78e25 100644 --- a/js/src/xpconnect/src/XPCWrapper.h +++ b/js/src/xpconnect/src/XPCWrapper.h @@ -131,7 +131,7 @@ WrapObject(JSContext *cx, JSObject *parent, jsval v, jsval *vp); namespace XPCSafeJSObjectWrapper { JSObject * -GetUnsafeObject(JSObject *obj); +GetUnsafeObject(JSContext *cx, JSObject *obj); JSBool WrapObject(JSContext *cx, JSObject *scope, jsval v, jsval *vp); diff --git a/js/src/xpconnect/src/nsXPConnect.cpp b/js/src/xpconnect/src/nsXPConnect.cpp index 81c1c4e7498..2a485db42d9 100644 --- a/js/src/xpconnect/src/nsXPConnect.cpp +++ b/js/src/xpconnect/src/nsXPConnect.cpp @@ -2569,12 +2569,12 @@ nsXPConnect::GetWrapperForObject(JSContext* aJSContext, } wrappedObj = XPCNativeWrapper::GetNewOrUsed(aJSContext, wrapper, - aPrincipal); + aScope, aPrincipal); } else if(aFilenameFlags & JSFILENAME_SYSTEM) { jsval val = OBJECT_TO_JSVAL(aObject); - if(XPCSafeJSObjectWrapper::WrapObject(aJSContext, nsnull, val, &val)) + if(XPCSafeJSObjectWrapper::WrapObject(aJSContext, aScope, val, &val)) wrappedObj = JSVAL_TO_OBJECT(val); } else diff --git a/js/src/xpconnect/src/xpcconvert.cpp b/js/src/xpconnect/src/xpcconvert.cpp index ae4f50aa18e..a46138bfb24 100644 --- a/js/src/xpconnect/src/xpcconvert.cpp +++ b/js/src/xpconnect/src/xpcconvert.cpp @@ -1352,7 +1352,7 @@ XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx, destObj = XPCNativeWrapper::GetNewOrUsed(ccx, wrapper, - objPrincipal); + scope, objPrincipal); triedWrapping = JS_TRUE; } else if (flags & JSFILENAME_SYSTEM) @@ -1362,7 +1362,7 @@ XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx, "XPCSafeJSObjectWrapper\n"); #endif - if(XPCSafeJSObjectWrapper::WrapObject(ccx, nsnull, v, &v)) + if(XPCSafeJSObjectWrapper::WrapObject(ccx, scope, v, &v)) destObj = JSVAL_TO_OBJECT(v); triedWrapping = JS_TRUE; } diff --git a/js/src/xpconnect/src/xpcwrappednativejsops.cpp b/js/src/xpconnect/src/xpcwrappednativejsops.cpp index 53f351d038f..60586b7cfcc 100644 --- a/js/src/xpconnect/src/xpcwrappednativejsops.cpp +++ b/js/src/xpconnect/src/xpcwrappednativejsops.cpp @@ -818,7 +818,7 @@ XPC_GetIdentityObject(JSContext *cx, JSObject *obj) wrapper = XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj); if(!wrapper) { - JSObject *unsafeObj = XPCSafeJSObjectWrapper::GetUnsafeObject(obj); + JSObject *unsafeObj = XPCSafeJSObjectWrapper::GetUnsafeObject(cx, obj); if(unsafeObj) return XPC_GetIdentityObject(cx, unsafeObj); @@ -855,7 +855,7 @@ XPC_WN_Equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) if(!*bp && !JSVAL_IS_PRIMITIVE(v) && STOBJ_GET_CLASS(JSVAL_TO_OBJECT(v)) == &XPCSafeJSObjectWrapper::SJOWClass.base) { - v = OBJECT_TO_JSVAL(XPCSafeJSObjectWrapper::GetUnsafeObject(JSVAL_TO_OBJECT(v))); + v = OBJECT_TO_JSVAL(XPCSafeJSObjectWrapper::GetUnsafeObject(cx, JSVAL_TO_OBJECT(v))); rv = si->GetCallback()->Equality(wrapper, cx, obj, v, bp); if(NS_FAILED(rv))