Bug 475864 - Move native anonymous content checks into a wrapper so that quickstubs don't sidestep them. r=jst sr=bzbarsky

This commit is contained in:
Blake Kaplan 2009-04-23 00:21:22 -07:00
parent 7b5c2380ff
commit 54734b9d0b
20 changed files with 934 additions and 178 deletions

View File

@ -250,11 +250,6 @@ public:
return !!(GetFlags() & nsIClassInfo::DOM_OBJECT);
}
PRBool IsContentNode()
{
return !!(GetFlags() & nsIClassInfo::CONTENT_NODE);
}
const char* GetName()
{
if (!mName) {
@ -744,15 +739,6 @@ nsScriptSecurityManager::CheckPropertyAccessImpl(PRUint32 aAction,
rv = NS_OK;
}
if (NS_SUCCEEDED(rv) && classInfoData.IsContentNode())
{
// No access to anonymous content from the web! (bug 164086)
nsIContent *content = static_cast<nsIContent*>(aObj);
if (content->IsInNativeAnonymousSubtree()) {
rv = NS_ERROR_DOM_SECURITY_ERR;
}
}
if (NS_SUCCEEDED(rv))
{
#ifdef DEBUG_CAPS_CheckPropertyAccessImpl

View File

@ -173,29 +173,6 @@ public:
*/
virtual nsIContent* FindFirstNonNativeAnonymous() const;
/**
* Returns PR_TRUE if |this| or any of its ancestors is native anonymous.
*/
PRBool IsInNativeAnonymousSubtree() const
{
#ifdef DEBUG
if (HasFlag(NODE_IS_IN_ANONYMOUS_SUBTREE)) {
return PR_TRUE;
}
nsIContent* content = GetBindingParent();
while (content) {
if (content->IsRootOfNativeAnonymousSubtree()) {
NS_ERROR("Element not marked to be in native anonymous subtree!");
break;
}
content = content->GetBindingParent();
}
return PR_FALSE;
#else
return HasFlag(NODE_IS_IN_ANONYMOUS_SUBTREE);
#endif
}
/**
* Returns true if and only if this node has a parent, but is not in
* its parent's child list.

View File

@ -770,6 +770,22 @@ public:
#endif
}
/**
* Returns PR_TRUE if |this| or any of its ancestors is native anonymous.
*/
PRBool IsInNativeAnonymousSubtree() const
{
#ifdef DEBUG
if (HasFlag(NODE_IS_IN_ANONYMOUS_SUBTREE)) {
return PR_TRUE;
}
CheckNotNativeAnonymous();
return PR_FALSE;
#else
return HasFlag(NODE_IS_IN_ANONYMOUS_SUBTREE);
#endif
}
/**
* Get the root content of an editor. So, this node must be a descendant of
* an editor. Note that this should be only used for getting input or textarea
@ -892,6 +908,12 @@ protected:
return IsEditableInternal();
}
#ifdef DEBUG
// Note: virtual so that IsInNativeAnonymousSubtree can be called accross
// module boundaries.
virtual void CheckNotNativeAnonymous() const;
#endif
nsresult GetParentNode(nsIDOMNode** aParentNode);
nsresult GetChildNodes(nsIDOMNodeList** aChildNodes);
nsresult GetFirstChild(nsIDOMNode** aFirstChild);

View File

@ -1,4 +1,5 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 sw=2 et tw=79: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
@ -446,6 +447,23 @@ nsINode::GetChildNodesList()
return slots->mChildNodes;
}
#ifdef DEBUG
void
nsINode::CheckNotNativeAnonymous() const
{
if (!IsNodeOfType(eCONTENT))
return;
nsIContent* content = static_cast<const nsIContent *>(this)->GetBindingParent();
while (content) {
if (content->IsRootOfNativeAnonymousSubtree()) {
NS_ERROR("Element not marked to be in native anonymous subtree!");
break;
}
content = content->GetBindingParent();
}
}
#endif
nsresult
nsINode::GetParentNode(nsIDOMNode** aParentNode)
{

View File

@ -6922,7 +6922,8 @@ nsNodeSH::PreCreate(nsISupports *nativeObj, JSContext *cx, JSObject *globalObj,
*parentObj = globalObj;
return NS_OK;
return node->IsInNativeAnonymousSubtree() ?
NS_SUCCESS_CHROME_ACCESS_ONLY : NS_OK;
}
// If we have a document, make sure one of these is true
@ -6983,7 +6984,8 @@ nsNodeSH::PreCreate(nsISupports *nativeObj, JSContext *cx, JSObject *globalObj,
*parentObj = globalObj;
return NS_OK;
return node->IsInNativeAnonymousSubtree() ?
NS_SUCCESS_CHROME_ACCESS_ONLY : NS_OK;
}
}
@ -6997,7 +6999,8 @@ nsNodeSH::PreCreate(nsISupports *nativeObj, JSContext *cx, JSObject *globalObj,
(wrapper = static_cast<nsIXPConnectJSObjectHolder*>(doc->GetWrapper()))) {
wrapper->GetJSObject(parentObj);
if(*parentObj) {
return NS_OK;
return node->IsInNativeAnonymousSubtree() ?
NS_SUCCESS_CHROME_ACCESS_ONLY : NS_OK;
}
}
@ -7005,10 +7008,12 @@ nsNodeSH::PreCreate(nsISupports *nativeObj, JSContext *cx, JSObject *globalObj,
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
nsresult rv = WrapNative(cx, globalObj, native_parent, &v,
getter_AddRefs(holder));
NS_ENSURE_SUCCESS(rv, rv);
*parentObj = JSVAL_TO_OBJECT(v);
return rv;
return node->IsInNativeAnonymousSubtree() ?
NS_SUCCESS_CHROME_ACCESS_ONLY : NS_OK;
}
NS_IMETHODIMP

View File

@ -46,6 +46,8 @@
%{ C++
#define NS_SUCCESS_I_DID_SOMETHING \
(NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_XPCONNECT,1))
#define NS_SUCCESS_CHROME_ACCESS_ONLY \
(NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_XPCONNECT,2))
%}
/**

View File

@ -791,6 +791,8 @@ interface nsIXPConnect : nsISupports
* XPCCrossOriginWrapper for the given object based on the principal, scope,
* and filename flags that are passed in.
*
* Note: In C++, the out jsval parameter must already be a strong GC root.
*
* @param aJSContext
* A JSContext.
* @param aObject

View File

@ -109,6 +109,7 @@ CPPSRCS = \
xpcJSWeakReference.cpp \
XPCSafeJSObjectWrapper.cpp \
XPCCrossOriginWrapper.cpp \
XPCSystemOnlyWrapper.cpp \
XPCWrapper.cpp \
xpcquickstubs.cpp \
dom_quickstubs.cpp \

View File

@ -164,21 +164,7 @@ static inline
JSObject *
GetWrappedObject(JSContext *cx, JSObject *wrapper)
{
if (STOBJ_GET_CLASS(wrapper) != &sXPC_XOW_JSClass.base) {
return nsnull;
}
jsval v;
if (!JS_GetReservedSlot(cx, wrapper, XPCWrapper::sWrappedObjSlot, &v)) {
JS_ClearPendingException(cx);
return nsnull;
}
if (!JSVAL_IS_OBJECT(v)) {
return nsnull;
}
return JSVAL_TO_OBJECT(v);
return XPCWrapper::UnwrapGeneric(cx, &sXPC_XOW_JSClass, wrapper);
}
JSBool
@ -343,7 +329,8 @@ XPC_XOW_FunctionWrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
JSObject *funObj = JSVAL_TO_OBJECT(argv[-2]);
jsval funToCall;
if (!JS_GetReservedSlot(cx, funObj, 0, &funToCall)) {
if (!JS_GetReservedSlot(cx, funObj, XPCWrapper::eWrappedFunctionSlot,
&funToCall)) {
return JS_FALSE;
}
@ -433,8 +420,10 @@ XPC_XOW_WrapFunction(JSContext *cx, JSObject *outerObj, JSObject *funobj,
JSObject *funWrapperObj = JS_GetFunctionObject(funWrapper);
*rval = OBJECT_TO_JSVAL(funWrapperObj);
if (!JS_SetReservedSlot(cx, funWrapperObj, XPCWrapper::eXOWWrappedFunctionSlot, funobjVal) ||
!JS_SetReservedSlot(cx, funWrapperObj, XPCWrapper::eAllAccessSlot, JSVAL_FALSE)) {
if (!JS_SetReservedSlot(cx, funWrapperObj, XPCWrapper::eWrappedFunctionSlot,
funobjVal) ||
!JS_SetReservedSlot(cx, funWrapperObj, XPCWrapper::eAllAccessSlot,
JSVAL_FALSE)) {
return JS_FALSE;
}
@ -535,8 +524,8 @@ XPC_XOW_WrapObject(JSContext *cx, JSObject *parent, jsval *vp,
}
if (!JS_SetReservedSlot(cx, outerObj, XPCWrapper::sWrappedObjSlot, *vp) ||
!JS_SetReservedSlot(cx, outerObj, XPCWrapper::sResolvingSlot,
JSVAL_FALSE) ||
!JS_SetReservedSlot(cx, outerObj, XPCWrapper::sFlagsSlot,
JSVAL_ZERO) ||
!JS_SetReservedSlot(cx, outerObj, XPC_XOW_ScopeSlot,
PRIVATE_TO_JSVAL(parentScope))) {
return JS_FALSE;
@ -557,11 +546,11 @@ XPC_XOW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
obj = GetWrapper(obj);
jsval resolving;
if (!JS_GetReservedSlot(cx, obj, XPCWrapper::sResolvingSlot, &resolving)) {
if (!JS_GetReservedSlot(cx, obj, XPCWrapper::sFlagsSlot, &resolving)) {
return JS_FALSE;
}
if (JSVAL_TO_BOOLEAN(resolving)) {
if (HAS_FLAGS(resolving, FLAG_RESOLVING)) {
// Allow us to define a property on ourselves.
return JS_TRUE;
}
@ -586,7 +575,7 @@ XPC_XOW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
}
// Same origin, pass this request along.
return XPCWrapper::AddProperty(cx, obj, wrappedObj, id, vp);
return XPCWrapper::AddProperty(cx, obj, JS_TRUE, wrappedObj, id, vp);
}
static JSBool
@ -838,23 +827,26 @@ XPC_XOW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
if (id == GetRTStringByIndex(cx, XPCJSRuntime::IDX_TO_STRING)) {
jsval oldSlotVal;
if (!::JS_GetReservedSlot(cx, obj, XPCWrapper::sResolvingSlot, &oldSlotVal) ||
!::JS_SetReservedSlot(cx, obj, XPCWrapper::sResolvingSlot, JSVAL_TRUE)) {
if (!JS_GetReservedSlot(cx, obj, XPCWrapper::sFlagsSlot, &oldSlotVal) ||
!JS_SetReservedSlot(cx, obj, XPCWrapper::sFlagsSlot,
INT_TO_JSVAL(JSVAL_TO_INT(oldSlotVal) |
FLAG_RESOLVING))) {
return JS_FALSE;
}
JSBool ok = JS_DefineFunction(cx, obj, "toString",
XPC_XOW_toString, 0, 0) != nsnull;
if (ok && (ok = ::JS_SetReservedSlot(cx, obj, XPCWrapper::sResolvingSlot,
oldSlotVal))) {
JS_SetReservedSlot(cx, obj, XPCWrapper::sFlagsSlot, oldSlotVal);
if (ok) {
*objp = obj;
}
return ok;
}
return XPCWrapper::NewResolve(cx, obj, wrappedObj, id, flags, objp);
return XPCWrapper::NewResolve(cx, obj, JS_TRUE, wrappedObj, id, flags, objp);
}
static JSBool
@ -1131,8 +1123,8 @@ XPC_XOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly)
// Initialize our XOW.
jsval v = OBJECT_TO_JSVAL(wrappedObj);
if (!JS_SetReservedSlot(cx, wrapperIter, XPCWrapper::sWrappedObjSlot, v) ||
!JS_SetReservedSlot(cx, wrapperIter, XPCWrapper::sResolvingSlot,
JSVAL_FALSE) ||
!JS_SetReservedSlot(cx, wrapperIter, XPCWrapper::sFlagsSlot,
JSVAL_ZERO) ||
!JS_SetReservedSlot(cx, wrapperIter, XPC_XOW_ScopeSlot,
PRIVATE_TO_JSVAL(nsnull))) {
return nsnull;

View File

@ -488,7 +488,7 @@ XPC_SJOW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
jsval isResolving;
JSBool ok = ::JS_GetReservedSlot(cx, obj, XPC_SJOW_SLOT_IS_RESOLVING,
&isResolving);
if (!ok || JSVAL_TO_BOOLEAN(isResolving)) {
if (!ok || HAS_FLAGS(isResolving, FLAG_RESOLVING)) {
return ok;
}
@ -503,7 +503,7 @@ XPC_SJOW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
return JS_FALSE;
}
return XPCWrapper::AddProperty(cx, obj, unsafeObj, id, vp);
return XPCWrapper::AddProperty(cx, obj, JS_FALSE, unsafeObj, id, vp);
}
static JSBool
@ -678,7 +678,7 @@ XPC_SJOW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
XPC_SJOW_toString, 0, 0) != nsnull;
}
return XPCWrapper::NewResolve(cx, obj, unsafeObj, id, flags, objp);
return XPCWrapper::NewResolve(cx, obj, JS_FALSE, unsafeObj, id, flags, objp);
}
static JSBool
@ -956,7 +956,7 @@ XPC_SJOW_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
}
if (!::JS_SetReservedSlot(cx, wrapperObj, XPC_SJOW_SLOT_IS_RESOLVING,
BOOLEAN_TO_JSVAL(JS_FALSE))) {
JSVAL_ZERO)) {
return JS_FALSE;
}
@ -1043,7 +1043,7 @@ XPC_SJOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly)
}
if (!::JS_SetReservedSlot(cx, wrapperIter, XPC_SJOW_SLOT_IS_RESOLVING,
BOOLEAN_TO_JSVAL(JS_FALSE))) {
JSVAL_ZERO)) {
return nsnull;
}

View File

@ -0,0 +1,638 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 sw=2 et tw=78 sts=2: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Blake Kaplan <mrbkap@gmail.com> (original author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "xpcprivate.h"
#include "nsDOMError.h"
#include "jsdbgapi.h"
#include "jscntxt.h" // For JSAutoTempValueRooter.
#include "XPCNativeWrapper.h"
#include "XPCWrapper.h"
// This file implements a wrapper around trusted objects that allows them to
// be safely injected into untrusted code.
static JSBool
XPC_SOW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
static JSBool
XPC_SOW_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
static JSBool
XPC_SOW_GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
static JSBool
XPC_SOW_SetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
static JSBool
XPC_SOW_Enumerate(JSContext *cx, JSObject *obj);
static JSBool
XPC_SOW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
JSObject **objp);
static JSBool
XPC_SOW_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp);
static JSBool
XPC_SOW_CheckAccess(JSContext *cx, JSObject *obj, jsval id, JSAccessMode mode,
jsval *vp);
static JSBool
XPC_SOW_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp);
static JSBool
XPC_SOW_Equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp);
static JSObject *
XPC_SOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly);
static JSObject *
XPC_SOW_WrappedObject(JSContext *cx, JSObject *obj);
JSExtendedClass sXPC_SOW_JSClass = {
// JSClass (JSExtendedClass.base) initialization
{ "SystemOnlyWrapper",
JSCLASS_NEW_RESOLVE | JSCLASS_IS_EXTENDED |
JSCLASS_HAS_RESERVED_SLOTS(XPCWrapper::sNumSlots),
XPC_SOW_AddProperty, XPC_SOW_DelProperty,
XPC_SOW_GetProperty, XPC_SOW_SetProperty,
XPC_SOW_Enumerate, (JSResolveOp)XPC_SOW_NewResolve,
XPC_SOW_Convert, JS_FinalizeStub,
nsnull, XPC_SOW_CheckAccess,
nsnull, nsnull,
nsnull, XPC_SOW_HasInstance,
nsnull, nsnull
},
// JSExtendedClass initialization
XPC_SOW_Equality,
nsnull, // outerObject
nsnull, // innerObject
XPC_SOW_Iterator,
XPC_SOW_WrappedObject,
JSCLASS_NO_RESERVED_MEMBERS
};
static JSBool
XPC_SOW_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval);
// Throws an exception on context |cx|.
static inline JSBool
ThrowException(nsresult rv, JSContext *cx)
{
return XPCWrapper::ThrowException(rv, cx);
}
// Like GetWrappedObject, but works on other types of wrappers, too.
// TODO Move to XPCWrapper?
static inline JSObject *
GetWrappedJSObject(JSContext *cx, JSObject *obj)
{
JSClass *clasp = STOBJ_GET_CLASS(obj);
if (!(clasp->flags & JSCLASS_IS_EXTENDED)) {
return obj;
}
JSExtendedClass *xclasp = (JSExtendedClass *)clasp;
if (!xclasp->wrappedObject) {
return obj;
}
return xclasp->wrappedObject(cx, obj);
}
// Get the (possibly non-existant) SOW off of an object
static inline
JSObject *
GetWrapper(JSObject *obj)
{
while (STOBJ_GET_CLASS(obj) != &sXPC_SOW_JSClass.base) {
obj = STOBJ_GET_PROTO(obj);
if (!obj) {
break;
}
}
return obj;
}
static inline
JSObject *
GetWrappedObject(JSContext *cx, JSObject *wrapper)
{
return XPCWrapper::UnwrapGeneric(cx, &sXPC_SOW_JSClass, wrapper);
}
JSBool
AllowedToAct(JSContext *cx, jsval idval)
{
nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
if (!ssm) {
return JS_TRUE;
}
JSStackFrame *fp;
nsIPrincipal *principal = ssm->GetCxSubjectPrincipalAndFrame(cx, &fp);
if (!principal) {
return ThrowException(NS_ERROR_UNEXPECTED, cx);
}
void *annotation = JS_GetFrameAnnotation(cx, fp);
PRBool privileged;
if (fp &&
NS_SUCCEEDED(principal->IsCapabilityEnabled("UniversalXPConnect",
annotation,
&privileged)) &&
privileged) {
// UniversalXPConnect things are allowed to touch us.
return JS_TRUE;
}
// XXX HACK EWW! Allow chrome://global/ access to these things, even
// if they've been cloned into less privileged contexts.
static const char prefix[] = "chrome://global/";
const char *filename = fp->script->filename;
if (filename && !strncmp(filename, prefix, NS_ARRAY_LENGTH(prefix) - 1)) {
return JS_TRUE;
}
if (JSVAL_IS_VOID(idval)) {
ThrowException(NS_ERROR_XPC_SECURITY_MANAGER_VETO, cx);
} else {
// TODO Localize me?
JSString *str = JS_ValueToString(cx, idval);
if (str) {
JS_ReportError(cx, "Permission denied to access property '%hs' from a non-chrome context",
JS_GetStringChars(str));
}
}
return JS_FALSE;
}
static JSBool
XPC_SOW_FunctionWrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval)
{
if (!AllowedToAct(cx, JSVAL_VOID)) {
return JS_FALSE;
}
JSObject *wrappedObj;
// Allow 'this' to be either a SOW, in which case we unwrap it or something
// that isn't a SOW. We disallow invalid SOWs that have no wrapped object.
// We do this so that it's possible to use this function with .call on
// related objects that are not system only.
wrappedObj = GetWrapper(obj);
if (wrappedObj) {
wrappedObj = GetWrappedObject(cx, wrappedObj);
if (!wrappedObj) {
return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx);
}
} else {
wrappedObj = obj;
}
JSObject *funObj = JSVAL_TO_OBJECT(argv[-2]);
jsval funToCall;
if (!JS_GetReservedSlot(cx, funObj, XPCWrapper::eWrappedFunctionSlot,
&funToCall)) {
return JS_FALSE;
}
return JS_CallFunctionValue(cx, wrappedObj, funToCall, argc, argv, rval);
}
JSBool
XPC_SOW_WrapFunction(JSContext *cx, JSObject *outerObj, JSObject *funobj,
jsval *rval)
{
jsval funobjVal = OBJECT_TO_JSVAL(funobj);
JSFunction *wrappedFun =
reinterpret_cast<JSFunction *>(xpc_GetJSPrivate(funobj));
JSNative native = JS_GetFunctionNative(cx, wrappedFun);
if (!native || native == XPC_SOW_FunctionWrapper) {
*rval = funobjVal;
return JS_TRUE;
}
JSFunction *funWrapper =
JS_NewFunction(cx, XPC_SOW_FunctionWrapper,
JS_GetFunctionArity(wrappedFun), 0,
JS_GetGlobalForObject(cx, outerObj),
JS_GetFunctionName(wrappedFun));
if (!funWrapper) {
return JS_FALSE;
}
JSObject *funWrapperObj = JS_GetFunctionObject(funWrapper);
*rval = OBJECT_TO_JSVAL(funWrapperObj);
return JS_SetReservedSlot(cx, funWrapperObj,
XPCWrapper::eWrappedFunctionSlot,
funobjVal);
}
static JSBool
XPC_SOW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
NS_ASSERTION(STOBJ_GET_CLASS(obj) == &sXPC_SOW_JSClass.base, "Wrong object");
jsval resolving;
if (!JS_GetReservedSlot(cx, obj, XPCWrapper::sFlagsSlot, &resolving)) {
return JS_FALSE;
}
if (HAS_FLAGS(resolving, FLAG_RESOLVING)) {
// Allow us to define a property on ourselves.
return JS_TRUE;
}
if (!AllowedToAct(cx, id)) {
return JS_FALSE;
}
JSObject *wrappedObj = GetWrappedObject(cx, obj);
if (!wrappedObj) {
return JS_TRUE;
}
return XPCWrapper::AddProperty(cx, obj, JS_TRUE, wrappedObj, id, vp);
}
static JSBool
XPC_SOW_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
JSObject *wrappedObj = GetWrappedObject(cx, obj);
if (!wrappedObj) {
return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx);
}
if (!AllowedToAct(cx, id)) {
return JS_FALSE;
}
return XPCWrapper::DelProperty(cx, wrappedObj, id, vp);
}
static JSBool
XPC_SOW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp,
JSBool isSet)
{
if (id == GetRTStringByIndex(cx, XPCJSRuntime::IDX_TO_STRING)) {
return JS_TRUE;
}
obj = GetWrapper(obj);
if (!obj) {
return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx);
}
if (!AllowedToAct(cx, id)) {
return JS_FALSE;
}
JSAutoTempValueRooter tvr(cx, 1, vp);
JSObject *wrappedObj = GetWrappedObject(cx, obj);
if (!wrappedObj) {
return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx);
}
if (isSet && id == GetRTStringByIndex(cx, XPCJSRuntime::IDX_PROTO)) {
// No setting __proto__ on my object.
return ThrowException(NS_ERROR_INVALID_ARG, cx); // XXX better error message
}
jsid interned_id;
if (!JS_ValueToId(cx, id, &interned_id)) {
return JS_FALSE;
}
return isSet
? JS_SetPropertyById(cx, wrappedObj, interned_id, vp)
: JS_GetPropertyById(cx, wrappedObj, interned_id, vp);
}
static JSBool
XPC_SOW_GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
return XPC_SOW_GetOrSetProperty(cx, obj, id, vp, JS_FALSE);
}
static JSBool
XPC_SOW_SetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
return XPC_SOW_GetOrSetProperty(cx, obj, id, vp, JS_TRUE);
}
static JSBool
XPC_SOW_Enumerate(JSContext *cx, JSObject *obj)
{
obj = GetWrapper(obj);
JSObject *wrappedObj = GetWrappedObject(cx, obj);
if (!wrappedObj) {
// Nothing to enumerate.
return JS_TRUE;
}
if (!AllowedToAct(cx, JSVAL_VOID)) {
return JS_FALSE;
}
return XPCWrapper::Enumerate(cx, obj, wrappedObj);
}
static JSBool
XPC_SOW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
JSObject **objp)
{
obj = GetWrapper(obj);
JSObject *wrappedObj = GetWrappedObject(cx, obj);
if (!wrappedObj) {
// No wrappedObj means that this is probably the prototype.
*objp = nsnull;
return JS_TRUE;
}
if (!AllowedToAct(cx, id)) {
return JS_FALSE;
}
if (id == GetRTStringByIndex(cx, XPCJSRuntime::IDX_TO_STRING)) {
jsval oldSlotVal;
if (!JS_GetReservedSlot(cx, obj, XPCWrapper::sFlagsSlot, &oldSlotVal) ||
!JS_SetReservedSlot(cx, obj, XPCWrapper::sFlagsSlot,
INT_TO_JSVAL(JSVAL_TO_INT(oldSlotVal) |
FLAG_RESOLVING))) {
return JS_FALSE;
}
JSBool ok = JS_DefineFunction(cx, obj, "toString",
XPC_SOW_toString, 0, 0) != nsnull;
JS_SetReservedSlot(cx, obj, XPCWrapper::sFlagsSlot, oldSlotVal);
if (ok) {
*objp = obj;
}
return ok;
}
return XPCWrapper::NewResolve(cx, obj, JS_TRUE, wrappedObj, id, flags, objp);
}
static JSBool
XPC_SOW_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
{
if (!AllowedToAct(cx, JSVAL_VOID)) {
return JS_FALSE;
}
// Don't do any work to convert to object.
if (type == JSTYPE_OBJECT) {
*vp = OBJECT_TO_JSVAL(obj);
return JS_TRUE;
}
JSObject *wrappedObj = GetWrappedObject(cx, obj);
if (!wrappedObj) {
// Converting the prototype to something.
if (type == JSTYPE_STRING || type == JSTYPE_VOID) {
return XPC_SOW_toString(cx, obj, 0, nsnull, vp);
}
*vp = OBJECT_TO_JSVAL(obj);
return JS_TRUE;
}
return STOBJ_GET_CLASS(wrappedObj)->convert(cx, wrappedObj, type, vp);
}
static JSBool
XPC_SOW_CheckAccess(JSContext *cx, JSObject *obj, jsval prop, JSAccessMode mode,
jsval *vp)
{
// Simply forward checkAccess to our wrapped object. It's already expecting
// untrusted things to ask it about accesses.
JSObject *wrappedObj = GetWrappedObject(cx, obj);
if (!wrappedObj) {
*vp = JSVAL_VOID;
return JS_TRUE;
}
uintN junk;
jsid id;
return JS_ValueToId(cx, prop, &id) &&
JS_CheckAccess(cx, wrappedObj, id, mode, vp, &junk);
}
static JSBool
XPC_SOW_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
{
if (!AllowedToAct(cx, JSVAL_VOID)) {
return JS_FALSE;
}
JSObject *iface = GetWrappedObject(cx, obj);
if (!iface) {
*bp = JS_FALSE;
return JS_TRUE;
}
JSClass *clasp = STOBJ_GET_CLASS(iface);
*bp = JS_FALSE;
if (!clasp->hasInstance) {
return JS_TRUE;
}
// Prematurely unwrap the left hand side. This isn't necessary, but could be
// faster than waiting until XPCWrappedNative::GetWrappedNativeOfJSObject to
// do it.
if (!JSVAL_IS_PRIMITIVE(v)) {
JSObject *test = JSVAL_TO_OBJECT(v);
// GetWrappedObject does a class check.
test = GetWrappedObject(cx, test);
if (test) {
v = OBJECT_TO_JSVAL(test);
}
}
return clasp->hasInstance(cx, iface, v, bp);
}
static JSBool
XPC_SOW_Equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
{
// Delegate to our wrapped object.
if (JSVAL_IS_PRIMITIVE(v)) {
*bp = JS_FALSE;
return JS_TRUE;
}
if (obj == JSVAL_TO_OBJECT(v)) {
*bp = JS_TRUE;
return JS_TRUE;
}
JSObject *lhs = GetWrappedObject(cx, obj);
JSObject *rhs = GetWrappedJSObject(cx, JSVAL_TO_OBJECT(v));
if (lhs == rhs) {
*bp = JS_TRUE;
return JS_TRUE;
}
if (lhs) {
// Delegate to our wrapped object if we can.
JSClass *clasp = STOBJ_GET_CLASS(lhs);
if (clasp->flags & JSCLASS_IS_EXTENDED) {
JSExtendedClass *xclasp = (JSExtendedClass *) clasp;
// NB: JSExtendedClass.equality is a required field.
return xclasp->equality(cx, lhs, OBJECT_TO_JSVAL(rhs), bp);
}
}
// We know rhs is non-null.
JSClass *clasp = STOBJ_GET_CLASS(rhs);
if (clasp->flags & JSCLASS_IS_EXTENDED) {
JSExtendedClass *xclasp = (JSExtendedClass *) clasp;
// NB: JSExtendedClass.equality is a required field.
return xclasp->equality(cx, rhs, OBJECT_TO_JSVAL(lhs), bp);
}
*bp = JS_FALSE;
return JS_TRUE;
}
static JSObject *
XPC_SOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly)
{
JSObject *wrappedObj = GetWrappedObject(cx, obj);
if (!wrappedObj) {
ThrowException(NS_ERROR_INVALID_ARG, cx);
return nsnull;
}
JSObject *wrapperIter = JS_NewObject(cx, &sXPC_SOW_JSClass.base, nsnull,
JS_GetGlobalForObject(cx, obj));
if (!wrapperIter) {
return nsnull;
}
JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter));
// Initialize our SOW.
jsval v = OBJECT_TO_JSVAL(wrappedObj);
if (!JS_SetReservedSlot(cx, wrapperIter, XPCWrapper::sWrappedObjSlot, v) ||
!JS_SetReservedSlot(cx, wrapperIter, XPCWrapper::sFlagsSlot,
JSVAL_ZERO)) {
return nsnull;
}
return XPCWrapper::CreateIteratorObj(cx, wrapperIter, obj, wrappedObj,
keysonly);
}
static JSObject *
XPC_SOW_WrappedObject(JSContext *cx, JSObject *obj)
{
return GetWrappedObject(cx, obj);
}
static JSBool
XPC_SOW_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval)
{
if (!AllowedToAct(cx, JSVAL_VOID)) {
return JS_FALSE;
}
obj = GetWrapper(obj);
if (!obj) {
return ThrowException(NS_ERROR_UNEXPECTED, cx);
}
JSObject *wrappedObj = GetWrappedObject(cx, obj);
if (!wrappedObj) {
// Someone's calling toString on our prototype.
NS_NAMED_LITERAL_CSTRING(protoString, "[object XPCCrossOriginWrapper]");
JSString *str =
JS_NewStringCopyN(cx, protoString.get(), protoString.Length());
if (!str) {
return JS_FALSE;
}
*rval = STRING_TO_JSVAL(str);
return JS_TRUE;
}
XPCWrappedNative *wn =
XPCWrappedNative::GetWrappedNativeOfJSObject(cx, wrappedObj);
return XPCWrapper::NativeToString(cx, wn, argc, argv, rval, JS_FALSE);
}
JSBool
XPC_SOW_WrapObject(JSContext *cx, JSObject *parent, jsval v,
jsval *vp)
{
JSObject *wrapperObj =
JS_NewObjectWithGivenProto(cx, &sXPC_SOW_JSClass.base, NULL, parent);
if (!wrapperObj) {
return JS_FALSE;
}
*vp = OBJECT_TO_JSVAL(wrapperObj);
JSAutoTempValueRooter tvr(cx, *vp);
if (!JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sWrappedObjSlot, v) ||
!JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sFlagsSlot,
JSVAL_ZERO)) {
return JS_FALSE;
}
return JS_TRUE;
}

View File

@ -41,12 +41,13 @@
* ***** END LICENSE BLOCK ***** */
#include "XPCWrapper.h"
#include "XPCNativeWrapper.h"
const PRUint32
XPCWrapper::sWrappedObjSlot = 1;
const PRUint32
XPCWrapper::sResolvingSlot = 0;
XPCWrapper::sFlagsSlot = 0;
const PRUint32
XPCWrapper::sNumSlots = 2;
@ -59,6 +60,44 @@ XPCWrapper::sSecMgrSetProp = nsIXPCSecurityManager::ACCESS_SET_PROPERTY;
const PRUint32
XPCWrapper::sSecMgrGetProp = nsIXPCSecurityManager::ACCESS_GET_PROPERTY;
// static
JSObject *
XPCWrapper::Unwrap(JSContext *cx, JSObject *wrapper)
{
JSClass *clasp = STOBJ_GET_CLASS(wrapper);
if (clasp == &sXPC_XOW_JSClass.base) {
return UnwrapXOW(cx, wrapper);
}
if (XPCNativeWrapper::IsNativeWrapperClass(clasp)) {
XPCWrappedNative *wrappedObj;
if (!XPCNativeWrapper::GetWrappedNative(cx, wrapper, &wrappedObj) ||
!wrappedObj) {
return nsnull;
}
return wrappedObj->GetFlatJSObject();
}
if (clasp == &sXPC_SJOW_JSClass.base) {
JSObject *wrappedObj = STOBJ_GET_PARENT(wrapper);
if (NS_FAILED(CanAccessWrapper(cx, wrappedObj))) {
JS_ClearPendingException(cx);
return nsnull;
}
return wrappedObj;
}
if (clasp == &sXPC_SOW_JSClass.base) {
return UnwrapSOW(cx, wrapper);
}
return nsnull;
}
static void
IteratorFinalize(JSContext *cx, JSObject *obj)
{
@ -197,18 +236,17 @@ XPCWrapper::CreateIteratorObj(JSContext *cx, JSObject *tempWrapper,
// static
JSBool
XPCWrapper::AddProperty(JSContext *cx, JSObject *wrapperObj,
JSObject *innerObj, jsval id, jsval *vp)
JSBool wantGetterSetter, JSObject *innerObj, jsval id,
jsval *vp)
{
jsid interned_id;
if (!::JS_ValueToId(cx, id, &interned_id)) {
return JS_FALSE;
}
JSBool isXOW = (STOBJ_GET_CLASS(wrapperObj) == &sXPC_XOW_JSClass.base);
JSPropertyDescriptor desc;
if (!GetPropertyAttrs(cx, wrapperObj, interned_id, JSRESOLVE_QUALIFIED,
isXOW, &desc)) {
wantGetterSetter, &desc)) {
return JS_FALSE;
}
@ -289,18 +327,16 @@ XPCWrapper::Enumerate(JSContext *cx, JSObject *wrapperObj, JSObject *innerObj)
// static
JSBool
XPCWrapper::NewResolve(JSContext *cx, JSObject *wrapperObj,
JSObject *innerObj, jsval id, uintN flags,
JSObject **objp, JSBool preserveVal)
JSBool wantDetails, JSObject *innerObj, jsval id,
uintN flags, JSObject **objp)
{
jsid interned_id;
if (!::JS_ValueToId(cx, id, &interned_id)) {
return JS_FALSE;
}
JSBool isXOW = (STOBJ_GET_CLASS(wrapperObj) == &sXPC_XOW_JSClass.base);
JSPropertyDescriptor desc;
if (!GetPropertyAttrs(cx, innerObj, interned_id, flags, isXOW, &desc)) {
if (!GetPropertyAttrs(cx, innerObj, interned_id, flags, wantDetails, &desc)) {
return JS_FALSE;
}
@ -309,21 +345,22 @@ XPCWrapper::NewResolve(JSContext *cx, JSObject *wrapperObj,
return JS_TRUE;
}
if (!preserveVal) {
desc.value = JSVAL_VOID;
}
desc.value = JSVAL_VOID;
jsval oldSlotVal;
if (!::JS_GetReservedSlot(cx, wrapperObj, sResolvingSlot, &oldSlotVal) ||
!::JS_SetReservedSlot(cx, wrapperObj, sResolvingSlot, JSVAL_TRUE)) {
jsval oldFlags;
if (!::JS_GetReservedSlot(cx, wrapperObj, sFlagsSlot, &oldFlags) ||
!::JS_SetReservedSlot(cx, wrapperObj, sFlagsSlot,
INT_TO_JSVAL(JSVAL_TO_INT(oldFlags) |
FLAG_RESOLVING))) {
return JS_FALSE;
}
JSBool ok = JS_DefinePropertyById(cx, wrapperObj, interned_id, desc.value,
desc.getter, desc.setter, desc.attrs);
if (ok && (ok = ::JS_SetReservedSlot(cx, wrapperObj, sResolvingSlot,
oldSlotVal))) {
JS_SetReservedSlot(cx, wrapperObj, sFlagsSlot, oldFlags);
if (ok) {
*objp = wrapperObj;
}
@ -348,18 +385,11 @@ XPCWrapper::ResolveNativeProperty(JSContext *cx, JSObject *wrapperObj,
// Mark ourselves as resolving so our AddProperty hook can do the
// right thing here.
jsval oldFlags;
if (isNativeWrapper) {
if (!::JS_GetReservedSlot(cx, wrapperObj, 0, &oldFlags) ||
!::JS_SetReservedSlot(cx, wrapperObj, 0,
INT_TO_JSVAL(JSVAL_TO_INT(oldFlags) |
FLAG_RESOLVING))) {
return JS_FALSE;
}
} else {
if (!::JS_GetReservedSlot(cx, wrapperObj, sResolvingSlot, &oldFlags) ||
!::JS_SetReservedSlot(cx, wrapperObj, sResolvingSlot, JSVAL_TRUE)) {
return JS_FALSE;
}
if (!::JS_GetReservedSlot(cx, wrapperObj, sFlagsSlot, &oldFlags) ||
!::JS_SetReservedSlot(cx, wrapperObj, sFlagsSlot,
INT_TO_JSVAL(JSVAL_TO_INT(oldFlags) |
FLAG_RESOLVING))) {
return JS_FALSE;
}
XPCWrappedNative* oldResolvingWrapper = nsnull;
@ -379,9 +409,7 @@ XPCWrapper::ResolveNativeProperty(JSContext *cx, JSObject *wrapperObj,
ccx.SetResolvingWrapper(oldResolvingWrapper);
}
if (!::JS_SetReservedSlot(cx, wrapperObj,
isNativeWrapper ? 0 : sResolvingSlot,
oldFlags)) {
if (!::JS_SetReservedSlot(cx, wrapperObj, sFlagsSlot, oldFlags)) {
return JS_FALSE;
}
@ -405,7 +433,13 @@ XPCWrapper::ResolveNativeProperty(JSContext *cx, JSObject *wrapperObj,
return retval;
}
return NewResolve(cx, wrapperObj, innerObj, id, flags, objp, JS_TRUE);
// The scriptable helper resolved this property to a *different* object.
// We don't know what to do for now (this can't currently happen in
// Mozilla) so throw.
// I suspect that we'd need to redo the security check on the new object
// (if it has a different class than the original object) and then call
// ResolveNativeProperty with *that* as the inner object.
return ThrowException(NS_ERROR_NOT_IMPLEMENTED, cx);
}
}
@ -507,8 +541,10 @@ XPCWrapper::ResolveNativeProperty(JSContext *cx, JSObject *wrapperObj,
// XPCNativeWrapper doesn't need to do this.
jsval oldFlags;
if (!isNativeWrapper &&
(!::JS_GetReservedSlot(cx, wrapperObj, sResolvingSlot, &oldFlags) ||
!::JS_SetReservedSlot(cx, wrapperObj, sResolvingSlot, JSVAL_TRUE))) {
(!::JS_GetReservedSlot(cx, wrapperObj, sFlagsSlot, &oldFlags) ||
!::JS_SetReservedSlot(cx, wrapperObj, sFlagsSlot,
INT_TO_JSVAL(JSVAL_TO_INT(oldFlags) |
FLAG_RESOLVING)))) {
return JS_FALSE;
}
@ -519,7 +555,7 @@ XPCWrapper::ResolveNativeProperty(JSContext *cx, JSObject *wrapperObj,
}
if (!isNativeWrapper &&
!::JS_SetReservedSlot(cx, wrapperObj, sResolvingSlot, oldFlags)) {
!::JS_SetReservedSlot(cx, wrapperObj, sFlagsSlot, oldFlags)) {
return JS_FALSE;
}

View File

@ -81,6 +81,10 @@ XPC_XOW_WrapperMoved(JSContext *cx, XPCWrappedNative *innerObj,
nsresult
CanAccessWrapper(JSContext *cx, JSObject *wrappedObj);
// Used by UnwrapSOW below.
JSBool
AllowedToAct(JSContext *cx, jsval idval);
JSBool
XPCNativeWrapperCtor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval);
@ -107,8 +111,9 @@ XPC_XOW_ClassNeedsXOW(const char *name)
return JS_FALSE;
}
extern JSExtendedClass sXPC_XOW_JSClass;
extern JSExtendedClass sXPC_SJOW_JSClass;
extern JSExtendedClass sXPC_SOW_JSClass;
extern JSExtendedClass sXPC_XOW_JSClass;
// This class wraps some common functionality between the three existing
// wrappers. Its main purpose is to allow XPCCrossOriginWrapper to act both
@ -125,11 +130,11 @@ public:
static const PRUint32 sWrappedObjSlot;
/**
* Used by the cross origin and safe wrappers: the slot that tells the
* AddProperty code that we're resolving a property, and therefore to not do
* a security check.
* Used by all wrappers to store flags about their state. For example,
* it is used when resolving a property to tell to the addProperty hook
* that it shouldn't perform any security checks.
*/
static const PRUint32 sResolvingSlot;
static const PRUint32 sFlagsSlot;
/**
* The base number of slots needed by code using the above constants.
@ -143,7 +148,7 @@ public:
static JSNative sEvalNative;
typedef enum FunctionObjectSlot {
eXOWWrappedFunctionSlot = 0,
eWrappedFunctionSlot = 0,
eAllAccessSlot = 1
};
@ -214,10 +219,24 @@ public:
}
/**
* Unwraps a XPCCrossOriginWrapper into its wrapped native.
* Given an arbitrary object, Unwrap will return the wrapped object if the
* passed-in object is a wrapper that Unwrap knows about *and* the
* currently running code has permission to access both the wrapper and
* wrapped object.
*
* Since this is meant to be called from functions like
* XPCWrappedNative::GetWrappedNativeOfJSObject, it does not set an
* exception on |cx|.
*/
static JSObject *Unwrap(JSContext *cx, JSObject *wrapper) {
if (STOBJ_GET_CLASS(wrapper) != &sXPC_XOW_JSClass.base) {
static JSObject *Unwrap(JSContext *cx, JSObject *wrapper);
/**
* Unwraps objects whose class is |xclasp|.
*/
static JSObject *UnwrapGeneric(JSContext *cx, const JSExtendedClass *xclasp,
JSObject *wrapper)
{
if (STOBJ_GET_CLASS(wrapper) != &xclasp->base) {
return nsnull;
}
@ -231,14 +250,39 @@ public:
return nsnull;
}
JSObject *wrappedObj = JSVAL_TO_OBJECT(v);
nsresult rv = CanAccessWrapper(cx, wrappedObj);
if (NS_FAILED(rv)) {
JS_ClearPendingException(cx);
return JSVAL_TO_OBJECT(v);
}
static JSObject *UnwrapSOW(JSContext *cx, JSObject *wrapper) {
wrapper = UnwrapGeneric(cx, &sXPC_SOW_JSClass, wrapper);
if (!wrapper) {
return nsnull;
}
return wrappedObj;
if (!AllowedToAct(cx, JSVAL_VOID)) {
JS_ClearPendingException(cx);
wrapper = nsnull;
}
return wrapper;
}
/**
* Unwraps a XOW into its wrapped native.
*/
static JSObject *UnwrapXOW(JSContext *cx, JSObject *wrapper) {
wrapper = UnwrapGeneric(cx, &sXPC_XOW_JSClass, wrapper);
if (!wrapper) {
return nsnull;
}
nsresult rv = CanAccessWrapper(cx, wrapper);
if (NS_FAILED(rv)) {
JS_ClearPendingException(cx);
wrapper = nsnull;
}
return wrapper;
}
/**
@ -283,7 +327,8 @@ public:
* Called for the common part of adding a property to obj.
*/
static JSBool AddProperty(JSContext *cx, JSObject *wrapperObj,
JSObject *innerObj, jsval id, jsval *vp);
JSBool wantGetterSetter, JSObject *innerObj,
jsval id, jsval *vp);
/**
* Called for the common part of deleting a property from obj.
@ -302,8 +347,8 @@ public:
* and is therefore unsuitable for cross-origin resolution.
*/
static JSBool NewResolve(JSContext *cx, JSObject *wrapperObj,
JSObject *innerObj, jsval id, uintN flags,
JSObject **objp, JSBool preserveVal = JS_FALSE);
JSBool preserveVal, JSObject *innerObj,
jsval id, uintN flags, JSObject **objp);
/**
* Resolve a native property named id from innerObj onto wrapperObj. The

View File

@ -2406,6 +2406,9 @@ nsXPConnect::GetWrapperForObject(JSContext* aJSContext,
return NS_ERROR_FAILURE;
*_retval = OBJECT_TO_JSVAL(wrappedObj);
if(wrapper->NeedsChromeWrapper() &&
!XPC_SOW_WrapObject(aJSContext, aScope, *_retval, _retval))
return NS_ERROR_FAILURE;
return NS_OK;
}

View File

@ -1281,8 +1281,23 @@ XPCConvert::NativeInterface2JSObject(XPCCallContext& ccx,
}
if(triedWrapping)
return destObj &&
CreateHolderIfNeeded(ccx, destObj, d, dest);
{
if(!destObj)
return JS_FALSE;
jsval wrappedObjVal = OBJECT_TO_JSVAL(destObj);
AUTO_MARK_JSVAL(ccx, &wrappedObjVal);
if(wrapper->NeedsChromeWrapper())
{
if(!XPC_SOW_WrapObject(ccx, xpcscope->GetGlobalJSObject(),
OBJECT_TO_JSVAL(destObj),
&wrappedObjVal))
return JS_FALSE;
}
return CreateHolderIfNeeded(ccx, JSVAL_TO_OBJECT(wrappedObjVal),
d, dest);
}
}
}
@ -1297,11 +1312,23 @@ XPCConvert::NativeInterface2JSObject(XPCCallContext& ccx,
if(!strongWrapper)
strongWrapper = wrapper;
AUTO_MARK_JSVAL(ccx, &v);
return XPC_XOW_WrapObject(ccx, scope, &v) &&
(!wrapper->NeedsChromeWrapper() ||
XPC_SOW_WrapObject(ccx, xpcscope->GetGlobalJSObject(),
v, &v)) &&
CreateHolderIfNeeded(ccx, JSVAL_TO_OBJECT(v), d, dest);
}
*d = v;
if(allowNativeWrapper && wrapper->NeedsChromeWrapper())
{
if(!XPC_SOW_WrapObject(ccx, xpcscope->GetGlobalJSObject(), v, d))
return JS_FALSE;
}
else
{
*d = v;
}
if(dest)
*dest = strongWrapper.forget().get();
return JS_TRUE;

View File

@ -2346,8 +2346,9 @@ public:
if(mScriptableInfo && JS_IsGCMarkingTracer(trc))
mScriptableInfo->Mark();
if(HasProto()) GetProto()->TraceJS(trc);
if(mWrapper)
JS_CALL_OBJECT_TRACER(trc, mWrapper, "XPCWrappedNative::mWrapper");
JSObject* wrapper = GetWrapper();
if(wrapper)
JS_CALL_OBJECT_TRACER(trc, wrapper, "XPCWrappedNative::mWrapper");
TraceOtherWrapper(trc);
}
@ -2387,8 +2388,17 @@ public:
JSBool HasExternalReference() const {return mRefCnt > 1;}
JSObject* GetWrapper() { return mWrapper; }
void SetWrapper(JSObject *obj) { mWrapper = obj; }
JSBool NeedsChromeWrapper() { return !!(mWrapper & 1); }
void SetNeedsChromeWrapper() { mWrapper |= 1; }
JSObject* GetWrapper()
{
return (JSObject *)(mWrapper & ~1);
}
void SetWrapper(JSObject *obj)
{
JSBool reset = NeedsChromeWrapper();
mWrapper = PRWord(obj) | reset;
}
void NoteTearoffs(nsCycleCollectionTraversalCallback& cb);
@ -2454,7 +2464,7 @@ private:
JSObject* mFlatJSObject;
XPCNativeScriptableInfo* mScriptableInfo;
XPCWrappedNativeTearOffChunk mFirstChunk;
JSObject* mWrapper;
PRWord mWrapper;
#ifdef XPC_CHECK_WRAPPER_THREADSAFETY
public:
@ -4082,6 +4092,10 @@ JSBool
XPC_XOW_WrapObject(JSContext *cx, JSObject *parent, jsval *vp,
XPCWrappedNative *wn = nsnull);
JSBool
XPC_SOW_WrapObject(JSContext *cx, JSObject *parent, jsval v,
jsval *vp);
#ifdef XPC_IDISPATCH_SUPPORT
// IDispatch specific classes
#include "XPCDispPrivate.h"

View File

@ -829,7 +829,7 @@ xpc_qsUnwrapThisImpl(JSContext *cx,
wrapper = (XPCWrappedNative*) xpc_GetJSPrivate(STOBJ_GET_PARENT(cur));
NS_ASSERTION(wrapper, "XPCWN wrapping nothing");
}
else if(clazz == &sXPC_XOW_JSClass.base)
else
{
JSObject *unsafeObj = XPCWrapper::Unwrap(cx, cur);
if(unsafeObj)
@ -842,21 +842,6 @@ xpc_qsUnwrapThisImpl(JSContext *cx,
// XPCWrappedNative::GetWrappedNativeOfJSObject.
goto next;
}
else if(XPCNativeWrapper::IsNativeWrapperClass(clazz))
{
if(!XPCNativeWrapper::GetWrappedNative(cx, cur, &wrapper) ||
!wrapper)
goto next;
}
else if(IsXPCSafeJSObjectWrapperClass(clazz))
{
cur = STOBJ_GET_PARENT(cur);
NS_ASSERTION(cur, "SJOW wrapping nothing");
continue;
}
else {
goto next;
}
rv = getNativeFromWrapper(wrapper, iid, ppThis, pThisRef, vp);
if(NS_SUCCEEDED(rv))

View File

@ -44,6 +44,7 @@
#include "xpcprivate.h"
#include "nsArrayEnumerator.h"
#include "nsWrapperCache.h"
#include "XPCWrapper.h"
NS_IMPL_THREADSAFE_ISUPPORTS1(nsXPCWrappedJSClass, nsIXPCWrappedJSClass)
@ -736,7 +737,12 @@ nsXPCWrappedJSClass::GetRootJSObject(XPCCallContext& ccx, JSObject* aJSObj)
{
JSObject* result = CallQueryInterfaceOnJSObject(ccx, aJSObj,
NS_GET_IID(nsISupports));
return result ? result : aJSObj;
if(!result)
return aJSObj;
JSObject* inner = XPCWrapper::Unwrap(ccx, result);
if (inner)
return inner;
return result;
}
void

View File

@ -419,6 +419,7 @@ XPCWrappedNative::GetNewOrUsed(XPCCallContext& ccx,
jsval newParentVal = JSVAL_NULL;
XPCMarkableJSVal newParentVal_markable(&newParentVal);
AutoMarkingJSVal newParentVal_automarker(ccx, &newParentVal_markable);
JSBool chromeOnly = JS_FALSE;
if(sciWrapper.GetFlags().WantPreCreate())
{
@ -428,6 +429,9 @@ XPCWrappedNative::GetNewOrUsed(XPCCallContext& ccx,
if(NS_FAILED(rv))
return rv;
chromeOnly = (rv == NS_SUCCESS_CHROME_ACCESS_ONLY);
rv = NS_OK;
NS_ASSERTION(!XPCNativeWrapper::IsNativeWrapper(parent),
"Parent should never be an XPCNativeWrapper here");
@ -519,7 +523,7 @@ XPCWrappedNative::GetNewOrUsed(XPCCallContext& ccx,
NS_ASSERTION(!XPCNativeWrapper::IsNativeWrapper(parent),
"XPCNativeWrapper being used to parent XPCWrappedNative?");
if(!wrapper->Init(ccx, parent, isGlobal, &sciWrapper))
{
NS_RELEASE(wrapper);
@ -534,6 +538,10 @@ XPCWrappedNative::GetNewOrUsed(XPCCallContext& ccx,
return rv;
}
if(chromeOnly)
wrapper->SetNeedsChromeWrapper();
#if DEBUG_xpc_leaks
{
char* s = wrapper->ToString(ccx);
@ -1491,23 +1499,9 @@ return_tearoff:
return wrapper;
}
// Unwrap any XPCCrossOriginWrappers and SafeJSObjectWrappers.
// Unwrap any wrapper wrappers.
JSObject *unsafeObj;
if(clazz == &sXPC_XOW_JSClass.base &&
(unsafeObj = XPCWrapper::Unwrap(cx, cur)))
return GetWrappedNativeOfJSObject(cx, unsafeObj, funobj, pobj2,
pTearOff);
if(XPCNativeWrapper::IsNativeWrapperClass(clazz))
{
XPCWrappedNative* wrapper;
if(XPCNativeWrapper::GetWrappedNative(cx, cur, &wrapper) && wrapper)
return GetWrappedNativeOfJSObject(cx, wrapper->GetFlatJSObject(),
funobj, pobj2, pTearOff);
}
if(IsXPCSafeJSObjectWrapperClass(clazz) &&
(unsafeObj = STOBJ_GET_PARENT(cur)))
if((unsafeObj = XPCWrapper::Unwrap(cx, cur)))
return GetWrappedNativeOfJSObject(cx, unsafeObj, funobj, pobj2,
pTearOff);
}
@ -1526,7 +1520,7 @@ return_tearoff:
JSObject *unsafeObj;
clazz = STOBJ_GET_CLASS(outer);
if(clazz == &sXPC_XOW_JSClass.base &&
(unsafeObj = XPCWrapper::Unwrap(cx, outer)))
(unsafeObj = XPCWrapper::UnwrapXOW(cx, outer)))
{
outer = unsafeObj;
}

View File

@ -742,11 +742,14 @@ MochiKit.Base.update(MochiKit.Base, {
}
return MochiKit.Base.reprRegistry.match(o);
} catch (e) {
if (typeof(o.NAME) == 'string' && (
o.toString == Function.prototype.toString ||
o.toString == Object.prototype.toString
)) {
return o.NAME;
try {
if (typeof(o.NAME) == 'string' && (
o.toString == Function.prototype.toString ||
o.toString == Object.prototype.toString
)) {
return o.NAME;
}
} catch (e) {
}
}
try {