LCOV - code coverage report
Current view: directory - js/xpconnect/wrappers - XrayWrapper.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 647 16 2.5 %
Date: 2012-06-02 Functions: 86 8 9.3 %

       1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  * vim: set ts=4 sw=4 et tw=99 ft=cpp:
       3                 :  *
       4                 :  * ***** BEGIN LICENSE BLOCK *****
       5                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       6                 :  *
       7                 :  * The contents of this file are subject to the Mozilla Public License Version
       8                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       9                 :  * the License. You may obtain a copy of the License at
      10                 :  * http://www.mozilla.org/MPL/
      11                 :  *
      12                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      13                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      14                 :  * for the specific language governing rights and limitations under the
      15                 :  * License.
      16                 :  *
      17                 :  * The Original Code is mozilla.org code, released
      18                 :  * June 24, 2010.
      19                 :  *
      20                 :  * The Initial Developer of the Original Code is
      21                 :  *    The Mozilla Foundation
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *    Andreas Gal <gal@mozilla.com>
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      28                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : 
      40                 : #include "XrayWrapper.h"
      41                 : #include "AccessCheck.h"
      42                 : #include "FilteringWrapper.h"
      43                 : #include "CrossOriginWrapper.h"
      44                 : #include "WrapperFactory.h"
      45                 : 
      46                 : #include "nsINode.h"
      47                 : #include "nsIDocument.h"
      48                 : 
      49                 : #include "XPCWrapper.h"
      50                 : #include "xpcprivate.h"
      51                 : 
      52                 : #include "jsapi.h"
      53                 : 
      54                 : namespace xpc {
      55                 : 
      56                 : using namespace js;
      57                 : 
      58                 : static const uint32_t JSSLOT_WN = 0;
      59                 : static const uint32_t JSSLOT_RESOLVING = 1;
      60                 : static const uint32_t JSSLOT_EXPANDO = 2;
      61                 : 
      62                 : class ResolvingId
      63                 : {
      64                 :   public:
      65               0 :     ResolvingId(JSObject *holder, jsid id)
      66                 :       : mId(id),
      67               0 :         mPrev(getResolvingId(holder)),
      68               0 :         mHolder(holder)
      69                 :     {
      70               0 :         js::SetReservedSlot(holder, JSSLOT_RESOLVING, PrivateValue(this));
      71               0 :     }
      72                 : 
      73               0 :     ~ResolvingId() {
      74               0 :         NS_ASSERTION(getResolvingId(mHolder) == this, "unbalanced ResolvingIds");
      75               0 :         js::SetReservedSlot(mHolder, JSSLOT_RESOLVING, PrivateValue(mPrev));
      76               0 :     }
      77                 : 
      78               0 :     static ResolvingId *getResolvingId(JSObject *holder) {
      79               0 :         return (ResolvingId *)js::GetReservedSlot(holder, JSSLOT_RESOLVING).toPrivate();
      80                 :     }
      81                 : 
      82                 :     jsid mId;
      83                 :     ResolvingId *mPrev;
      84                 : 
      85                 :   private:
      86                 :     JSObject *mHolder;
      87                 : };
      88                 : 
      89                 : static bool
      90               0 : IsResolving(JSObject *holder, jsid id)
      91                 : {
      92               0 :     for (ResolvingId *cur = ResolvingId::getResolvingId(holder); cur; cur = cur->mPrev) {
      93               0 :         if (cur->mId == id)
      94               0 :             return true;
      95                 :     }
      96                 : 
      97               0 :     return false;
      98                 : }
      99                 : 
     100                 : static JSBool
     101                 : holder_get(JSContext *cx, JSObject *holder, jsid id, jsval *vp);
     102                 : 
     103                 : static JSBool
     104                 : holder_set(JSContext *cx, JSObject *holder, jsid id, JSBool strict, jsval *vp);
     105                 : 
     106                 : namespace XrayUtils {
     107                 : 
     108                 : JSClass HolderClass = {
     109                 :     "NativePropertyHolder",
     110                 :     JSCLASS_HAS_RESERVED_SLOTS(3),
     111                 :     JS_PropertyStub,        JS_PropertyStub, holder_get,      holder_set,
     112                 :     JS_EnumerateStub,       JS_ResolveStub,  JS_ConvertStub,  NULL,
     113                 :     JSCLASS_NO_OPTIONAL_MEMBERS
     114                 : };
     115                 : 
     116                 : }
     117                 : 
     118                 : using namespace XrayUtils;
     119                 : 
     120                 : static JSObject *
     121               0 : GetHolder(JSObject *obj)
     122                 : {
     123               0 :     return &js::GetProxyExtra(obj, 0).toObject();
     124                 : }
     125                 : 
     126                 : static XPCWrappedNative *
     127               0 : GetWrappedNative(JSObject *obj)
     128                 : {
     129               0 :     NS_ASSERTION(IS_WN_WRAPPER_OBJECT(obj), "expected a wrapped native here");
     130               0 :     return static_cast<XPCWrappedNative *>(js::GetObjectPrivate(obj));
     131                 : }
     132                 : 
     133                 : static XPCWrappedNative *
     134               0 : GetWrappedNativeFromHolder(JSObject *holder)
     135                 : {
     136               0 :     NS_ASSERTION(js::GetObjectJSClass(holder) == &HolderClass, "expected a native property holder object");
     137               0 :     return static_cast<XPCWrappedNative *>(js::GetReservedSlot(holder, JSSLOT_WN).toPrivate());
     138                 : }
     139                 : 
     140                 : static JSObject *
     141               0 : GetWrappedNativeObjectFromHolder(JSObject *holder)
     142                 : {
     143               0 :     NS_ASSERTION(js::GetObjectJSClass(holder) == &HolderClass, "expected a native property holder object");
     144               0 :     return GetWrappedNativeFromHolder(holder)->GetFlatJSObject();
     145                 : }
     146                 : 
     147                 : static JSObject *
     148               0 : GetExpandoObject(JSObject *holder)
     149                 : {
     150               0 :     NS_ASSERTION(js::GetObjectJSClass(holder) == &HolderClass, "expected a native property holder object");
     151               0 :     return js::GetReservedSlot(holder, JSSLOT_EXPANDO).toObjectOrNull();
     152                 : }
     153                 : 
     154                 : static JSObject *
     155               0 : EnsureExpandoObject(JSContext *cx, JSObject *holder)
     156                 : {
     157               0 :     NS_ASSERTION(js::GetObjectJSClass(holder) == &HolderClass, "expected a native property holder object");
     158               0 :     JSObject *expando = GetExpandoObject(holder);
     159               0 :     if (expando)
     160               0 :         return expando;
     161                 :     CompartmentPrivate *priv =
     162               0 :         (CompartmentPrivate *)JS_GetCompartmentPrivate(js::GetObjectCompartment(holder));
     163               0 :     XPCWrappedNative *wn = GetWrappedNativeFromHolder(holder);
     164               0 :     expando = priv->LookupExpandoObject(wn);
     165               0 :     if (!expando) {
     166               0 :         expando = JS_NewObjectWithGivenProto(cx, nsnull, nsnull, js::GetObjectParent(holder));
     167               0 :         if (!expando)
     168               0 :             return NULL;
     169                 :         // Add the expando object to the expando map to keep it alive.
     170               0 :         if (!priv->RegisterExpandoObject(wn, expando)) {
     171               0 :             JS_ReportOutOfMemory(cx);
     172               0 :             return NULL;
     173                 :         }
     174                 :         // Make sure the wn stays alive so it keeps the expando object alive.
     175               0 :         nsRefPtr<nsXPCClassInfo> ci;
     176               0 :         CallQueryInterface(wn->Native(), getter_AddRefs(ci));
     177               0 :         if (ci)
     178               0 :             ci->PreserveWrapper(wn->Native());
     179                 :     }
     180               0 :     js::SetReservedSlot(holder, JSSLOT_EXPANDO, ObjectValue(*expando));
     181               0 :     return expando;
     182                 : }
     183                 : 
     184                 : static inline JSObject *
     185               0 : FindWrapper(JSObject *wrapper)
     186                 : {
     187               0 :     while (!js::IsWrapper(wrapper) ||
     188               0 :            !(Wrapper::wrapperHandler(wrapper)->flags() & WrapperFactory::IS_XRAY_WRAPPER_FLAG)) {
     189               0 :         wrapper = js::GetObjectProto(wrapper);
     190                 :         // NB: we must eventually hit our wrapper.
     191                 :     }
     192                 : 
     193               0 :     return wrapper;
     194                 : }
     195                 : 
     196                 : // Some DOM objects have shared properties that don't have an explicit
     197                 : // getter/setter and rely on the class getter/setter. We install a
     198                 : // class getter/setter on the holder object to trigger them.
     199                 : static JSBool
     200               0 : holder_get(JSContext *cx, JSObject *wrapper, jsid id, jsval *vp)
     201                 : {
     202               0 :     wrapper = FindWrapper(wrapper);
     203                 : 
     204               0 :     JSObject *holder = GetHolder(wrapper);
     205                 : 
     206               0 :     XPCWrappedNative *wn = GetWrappedNativeFromHolder(holder);
     207               0 :     if (NATIVE_HAS_FLAG(wn, WantGetProperty)) {
     208               0 :         JSAutoEnterCompartment ac;
     209               0 :         if (!ac.enter(cx, holder))
     210               0 :             return false;
     211               0 :         bool retval = true;
     212               0 :         nsresult rv = wn->GetScriptableCallback()->GetProperty(wn, cx, wrapper, id, vp, &retval);
     213               0 :         if (NS_FAILED(rv) || !retval) {
     214               0 :             if (retval)
     215               0 :                 XPCThrower::Throw(rv, cx);
     216               0 :             return false;
     217                 :         }
     218                 :     }
     219               0 :     return true;
     220                 : }
     221                 : 
     222                 : static JSBool
     223               0 : holder_set(JSContext *cx, JSObject *wrapper, jsid id, JSBool strict, jsval *vp)
     224                 : {
     225               0 :     wrapper = FindWrapper(wrapper);
     226                 : 
     227               0 :     JSObject *holder = GetHolder(wrapper);
     228               0 :     if (IsResolving(holder, id)) {
     229               0 :         return true;
     230                 :     }
     231                 : 
     232               0 :     XPCWrappedNative *wn = GetWrappedNativeFromHolder(holder);
     233               0 :     if (NATIVE_HAS_FLAG(wn, WantSetProperty)) {
     234               0 :         JSAutoEnterCompartment ac;
     235               0 :         if (!ac.enter(cx, holder))
     236               0 :             return false;
     237               0 :         bool retval = true;
     238               0 :         nsresult rv = wn->GetScriptableCallback()->SetProperty(wn, cx, wrapper, id, vp, &retval);
     239               0 :         if (NS_FAILED(rv) || !retval) {
     240               0 :             if (retval)
     241               0 :                 XPCThrower::Throw(rv, cx);
     242               0 :             return false;
     243                 :         }
     244                 :     }
     245               0 :     return true;
     246                 : }
     247                 : 
     248                 : static bool
     249               0 : ResolveNativeProperty(JSContext *cx, JSObject *wrapper, JSObject *holder, jsid id, bool set,
     250                 :                       JSPropertyDescriptor *desc)
     251                 : {
     252               0 :     desc->obj = NULL;
     253                 : 
     254               0 :     NS_ASSERTION(js::GetObjectJSClass(holder) == &HolderClass, "expected a native property holder object");
     255               0 :     JSObject *wnObject = GetWrappedNativeObjectFromHolder(holder);
     256               0 :     XPCWrappedNative *wn = GetWrappedNative(wnObject);
     257                 : 
     258                 :     // This will do verification and the method lookup for us.
     259               0 :     XPCCallContext ccx(JS_CALLER, cx, wnObject, nsnull, id);
     260                 : 
     261                 :     // There are no native numeric properties, so we can shortcut here. We will not
     262                 :     // find the property.
     263               0 :     if (!JSID_IS_STRING(id)) {
     264                 :         /* Not found */
     265               0 :         return true;
     266                 :     }
     267                 : 
     268                 :     XPCNativeInterface *iface;
     269                 :     XPCNativeMember *member;
     270               0 :     if (ccx.GetWrapper() != wn ||
     271               0 :         !wn->IsValid()  ||
     272                 :         !(iface = ccx.GetInterface()) ||
     273                 :         !(member = ccx.GetMember())) {
     274                 :         /* Not found */
     275               0 :         return true;
     276                 :     }
     277                 : 
     278               0 :     desc->obj = holder;
     279               0 :     desc->attrs = JSPROP_ENUMERATE;
     280               0 :     desc->getter = NULL;
     281               0 :     desc->setter = NULL;
     282               0 :     desc->shortid = 0;
     283               0 :     desc->value = JSVAL_VOID;
     284                 : 
     285               0 :     jsval fval = JSVAL_VOID;
     286               0 :     if (member->IsConstant()) {
     287               0 :         if (!member->GetConstantValue(ccx, iface, &desc->value)) {
     288               0 :             JS_ReportError(cx, "Failed to convert constant native property to JS value");
     289               0 :             return false;
     290                 :         }
     291               0 :     } else if (member->IsAttribute()) {
     292                 :         // This is a getter/setter. Clone a function for it.
     293               0 :         if (!member->NewFunctionObject(ccx, iface, wrapper, &fval)) {
     294               0 :             JS_ReportError(cx, "Failed to clone function object for native getter/setter");
     295               0 :             return false;
     296                 :         }
     297                 : 
     298               0 :         desc->attrs |= JSPROP_GETTER;
     299               0 :         if (member->IsWritableAttribute())
     300               0 :             desc->attrs |= JSPROP_SETTER;
     301                 : 
     302                 :         // Make the property shared on the holder so no slot is allocated
     303                 :         // for it. This avoids keeping garbage alive through that slot.
     304               0 :         desc->attrs |= JSPROP_SHARED;
     305                 :     } else {
     306                 :         // This is a method. Clone a function for it.
     307               0 :         if (!member->NewFunctionObject(ccx, iface, wrapper, &desc->value)) {
     308               0 :             JS_ReportError(cx, "Failed to clone function object for native function");
     309               0 :             return false;
     310                 :         }
     311                 : 
     312                 :         // Without a wrapper the function would live on the prototype. Since we
     313                 :         // don't have one, we have to avoid calling the scriptable helper's
     314                 :         // GetProperty method for this property, so stub out the getter and
     315                 :         // setter here explicitly.
     316               0 :         desc->getter = JS_PropertyStub;
     317               0 :         desc->setter = JS_StrictPropertyStub;
     318                 :     }
     319                 : 
     320               0 :     if (!JS_WrapValue(cx, &desc->value) || !JS_WrapValue(cx, &fval))
     321               0 :         return false;
     322                 : 
     323               0 :     if (desc->attrs & JSPROP_GETTER)
     324               0 :         desc->getter = js::CastAsJSPropertyOp(JSVAL_TO_OBJECT(fval));
     325               0 :     if (desc->attrs & JSPROP_SETTER)
     326               0 :         desc->setter = js::CastAsJSStrictPropertyOp(JSVAL_TO_OBJECT(fval));
     327                 : 
     328                 :     // Define the property.
     329                 :     return JS_DefinePropertyById(cx, holder, id, desc->value,
     330               0 :                                  desc->getter, desc->setter, desc->attrs);
     331                 : }
     332                 : 
     333                 : static JSBool
     334               0 : wrappedJSObject_getter(JSContext *cx, JSObject *wrapper, jsid id, jsval *vp)
     335                 : {
     336               0 :     if (!IsWrapper(wrapper) || !WrapperFactory::IsXrayWrapper(wrapper)) {
     337               0 :         JS_ReportError(cx, "Unexpected object");
     338               0 :         return false;
     339                 :     }
     340                 : 
     341               0 :     *vp = OBJECT_TO_JSVAL(wrapper);
     342                 : 
     343               0 :     return WrapperFactory::WaiveXrayAndWrap(cx, vp);
     344                 : }
     345                 : 
     346                 : template <typename T>
     347                 : static bool
     348               0 : Is(JSObject *wrapper)
     349                 : {
     350               0 :     JSObject *holder = GetHolder(wrapper);
     351               0 :     XPCWrappedNative *wn = GetWrappedNativeFromHolder(holder);
     352               0 :     nsCOMPtr<T> native = do_QueryWrappedNative(wn);
     353               0 :     return !!native;
     354                 : }
     355                 : 
     356                 : static JSBool
     357               0 : WrapURI(JSContext *cx, nsIURI *uri, jsval *vp)
     358                 : {
     359               0 :     JSObject *scope = JS_GetGlobalForScopeChain(cx);
     360                 :     nsresult rv =
     361               0 :         nsXPConnect::FastGetXPConnect()->WrapNativeToJSVal(cx, scope, uri, nsnull,
     362                 :                                                            &NS_GET_IID(nsIURI), true,
     363               0 :                                                            vp, nsnull);
     364               0 :     if (NS_FAILED(rv)) {
     365               0 :         XPCThrower::Throw(rv, cx);
     366               0 :         return false;
     367                 :     }
     368               0 :     return true;
     369                 : }
     370                 : 
     371                 : static JSBool
     372               0 : documentURIObject_getter(JSContext *cx, JSObject *wrapper, jsid id, jsval *vp)
     373                 : {
     374               0 :     if (!IsWrapper(wrapper) || !WrapperFactory::IsXrayWrapper(wrapper)) {
     375               0 :         JS_ReportError(cx, "Unexpected object");
     376               0 :         return false;
     377                 :     }
     378                 : 
     379               0 :     JSObject *holder = GetHolder(wrapper);
     380               0 :     XPCWrappedNative *wn = GetWrappedNativeFromHolder(holder);
     381               0 :     nsCOMPtr<nsIDocument> native = do_QueryWrappedNative(wn);
     382               0 :     if (!native) {
     383               0 :         JS_ReportError(cx, "Unexpected object");
     384               0 :         return false;
     385                 :     }
     386                 : 
     387               0 :     nsCOMPtr<nsIURI> uri = native->GetDocumentURI();
     388               0 :     if (!uri) {
     389               0 :         JS_ReportOutOfMemory(cx);
     390               0 :         return false;
     391                 :     }
     392                 : 
     393               0 :     return WrapURI(cx, uri, vp);
     394                 : }
     395                 : 
     396                 : static JSBool
     397               0 : baseURIObject_getter(JSContext *cx, JSObject *wrapper, jsid id, jsval *vp)
     398                 : {
     399               0 :     if (!IsWrapper(wrapper) || !WrapperFactory::IsXrayWrapper(wrapper)) {
     400               0 :         JS_ReportError(cx, "Unexpected object");
     401               0 :         return false;
     402                 :     }
     403                 : 
     404               0 :     JSObject *holder = GetHolder(wrapper);
     405               0 :     XPCWrappedNative *wn = GetWrappedNativeFromHolder(holder);
     406               0 :     nsCOMPtr<nsINode> native = do_QueryWrappedNative(wn);
     407               0 :     if (!native) {
     408               0 :         JS_ReportError(cx, "Unexpected object");
     409               0 :         return false;
     410                 :     }
     411               0 :     nsCOMPtr<nsIURI> uri = native->GetBaseURI();
     412               0 :     if (!uri) {
     413               0 :         JS_ReportOutOfMemory(cx);
     414               0 :         return false;
     415                 :     }
     416                 : 
     417               0 :     return WrapURI(cx, uri, vp);
     418                 : }
     419                 : 
     420                 : static JSBool
     421               0 : nodePrincipal_getter(JSContext *cx, JSObject *wrapper, jsid id, jsval *vp)
     422                 : {
     423               0 :     if (!IsWrapper(wrapper) || !WrapperFactory::IsXrayWrapper(wrapper)) {
     424               0 :         JS_ReportError(cx, "Unexpected object");
     425               0 :         return false;
     426                 :     }
     427                 : 
     428               0 :     JSObject *holder = GetHolder(wrapper);
     429               0 :     XPCWrappedNative *wn = GetWrappedNativeFromHolder(holder);
     430               0 :     nsCOMPtr<nsINode> node = do_QueryWrappedNative(wn);
     431               0 :     if (!node) {
     432               0 :         JS_ReportError(cx, "Unexpected object");
     433               0 :         return false;
     434                 :     }
     435                 : 
     436               0 :     JSObject *scope = JS_GetGlobalForScopeChain(cx);
     437                 :     nsresult rv =
     438               0 :         nsXPConnect::FastGetXPConnect()->WrapNativeToJSVal(cx, scope, node->NodePrincipal(), nsnull,
     439                 :                                                            &NS_GET_IID(nsIPrincipal), true,
     440               0 :                                                            vp, nsnull);
     441               0 :     if (NS_FAILED(rv)) {
     442               0 :         XPCThrower::Throw(rv, cx);
     443               0 :         return false;
     444                 :     }
     445               0 :     return true;
     446                 : }
     447                 : 
     448                 : static JSBool
     449               0 : XrayToString(JSContext *cx, unsigned argc, jsval *vp)
     450                 : {
     451               0 :     JSObject *wrapper = JS_THIS_OBJECT(cx, vp);
     452               0 :     if (!wrapper || !IsWrapper(wrapper) || !WrapperFactory::IsXrayWrapper(wrapper)) {
     453               0 :         JS_ReportError(cx, "XrayToString called on an incompatible object");
     454               0 :         return false;
     455                 :     }
     456                 : 
     457               0 :     nsAutoString result(NS_LITERAL_STRING("[object XrayWrapper "));
     458               0 :     if (mozilla::dom::binding::instanceIsProxy(&js::GetProxyPrivate(wrapper).toObject())) {
     459               0 :         JSString *wrapperStr = js::GetProxyHandler(wrapper)->obj_toString(cx, wrapper);
     460                 :         size_t length;
     461               0 :         const jschar* chars = JS_GetStringCharsAndLength(cx, wrapperStr, &length);
     462               0 :         if (!chars) {
     463               0 :             JS_ReportOutOfMemory(cx);
     464               0 :             return false;
     465                 :         }
     466               0 :         result.Append(chars, length);
     467                 :     } else {
     468               0 :         JSObject *holder = GetHolder(wrapper);
     469               0 :         XPCWrappedNative *wn = GetWrappedNativeFromHolder(holder);
     470               0 :         JSObject *wrappednative = wn->GetFlatJSObject();
     471                 : 
     472               0 :         XPCCallContext ccx(JS_CALLER, cx, wrappednative);
     473               0 :         char *wrapperStr = wn->ToString(ccx);
     474               0 :         if (!wrapperStr) {
     475               0 :             JS_ReportOutOfMemory(cx);
     476               0 :             return false;
     477                 :         }
     478               0 :         result.AppendASCII(wrapperStr);
     479               0 :         JS_smprintf_free(wrapperStr);
     480                 :     }
     481                 : 
     482               0 :     result.Append(']');
     483                 : 
     484               0 :     JSString *str = JS_NewUCStringCopyN(cx, reinterpret_cast<const jschar *>(result.get()),
     485               0 :                                         result.Length());
     486               0 :     if (!str)
     487               0 :         return false;
     488                 : 
     489               0 :     *vp = STRING_TO_JSVAL(str);
     490               0 :     return true;
     491                 : }
     492                 : 
     493                 : template <typename Base>
     494            7320 : XrayWrapper<Base>::XrayWrapper(unsigned flags)
     495           11712 :   : Base(flags | WrapperFactory::IS_XRAY_WRAPPER_FLAG)
     496                 : {
     497           11712 : }
     498                 : 
     499                 : template <typename Base>
     500            7435 : XrayWrapper<Base>::~XrayWrapper()
     501           11896 : {
     502           23792 : }
     503                 : 
     504                 : template <typename Base>
     505                 : class AutoLeaveHelper
     506                 : {
     507                 :   public:
     508               0 :     AutoLeaveHelper(XrayWrapper<Base> &xray, JSContext *cx, JSObject *wrapper)
     509               0 :       : xray(xray), cx(cx), wrapper(wrapper)
     510                 :     {
     511               0 :     }
     512               0 :     ~AutoLeaveHelper()
     513                 :     {
     514               0 :         xray.leave(cx, wrapper);
     515               0 :     }
     516                 : 
     517                 :   private:
     518                 :     XrayWrapper<Base> &xray;
     519                 :     JSContext *cx;
     520                 :     JSObject *wrapper;
     521                 : };
     522                 : 
     523                 : static bool
     524               0 : IsPrivilegedScript()
     525                 : {
     526                 :     // Redirect access straight to the wrapper if UniversalXPConnect is enabled.
     527               0 :     nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
     528               0 :     if (ssm) {
     529                 :         bool privileged;
     530               0 :         if (NS_SUCCEEDED(ssm->IsCapabilityEnabled("UniversalXPConnect", &privileged)) && privileged)
     531               0 :             return true;
     532                 :     }
     533               0 :     return false;
     534                 : }
     535                 : 
     536                 : namespace XrayUtils {
     537                 : 
     538                 : bool
     539               0 : IsTransparent(JSContext *cx, JSObject *wrapper)
     540                 : {
     541               0 :     if (WrapperFactory::HasWaiveXrayFlag(wrapper))
     542               0 :         return true;
     543                 : 
     544               0 :     if (!WrapperFactory::IsPartiallyTransparent(wrapper))
     545               0 :         return false;
     546                 : 
     547                 :     // Redirect access straight to the wrapper if UniversalXPConnect is enabled.
     548               0 :     if (IsPrivilegedScript())
     549               0 :         return true;
     550                 : 
     551               0 :     return AccessCheck::documentDomainMakesSameOrigin(cx, UnwrapObject(wrapper));
     552                 : }
     553                 : 
     554                 : JSObject *
     555               0 : GetNativePropertiesObject(JSContext *cx, JSObject *wrapper)
     556                 : {
     557               0 :     NS_ASSERTION(js::IsWrapper(wrapper) && WrapperFactory::IsXrayWrapper(wrapper),
     558                 :                  "bad object passed in");
     559                 : 
     560               0 :     JSObject *holder = GetHolder(wrapper);
     561               0 :     NS_ASSERTION(holder, "uninitialized wrapper being used?");
     562               0 :     return holder;
     563                 : }
     564                 : 
     565                 : }
     566                 : 
     567                 : template <typename Base>
     568                 : bool
     569               0 : XrayWrapper<Base>::resolveOwnProperty(JSContext *cx, JSObject *wrapper, jsid id, bool set,
     570                 :                                       PropertyDescriptor *desc)
     571                 : {
     572                 :     // Partially transparent wrappers (which used to be known as XOWs) don't
     573                 :     // have a .wrappedJSObject property.
     574               0 :     XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
     575               0 :     if (!WrapperFactory::IsPartiallyTransparent(wrapper) &&
     576                 :         (id == rt->GetStringID(XPCJSRuntime::IDX_WRAPPED_JSOBJECT) ||
     577                 :          // Check for baseURIObject and nodePrincipal no nodes and
     578                 :          // documentURIObject on documents, but only from privileged scripts.
     579                 :          // Do the id checks before the QIs and IsPrivilegedScript() checks,
     580                 :          // since they're cheaper and will tend to fail most of the time
     581                 :          // anyway.
     582                 :          ((((id == rt->GetStringID(XPCJSRuntime::IDX_BASEURIOBJECT) ||
     583                 :              id == rt->GetStringID(XPCJSRuntime::IDX_NODEPRINCIPAL)) &&
     584                 :             Is<nsINode>(wrapper)) ||
     585                 :            (id == rt->GetStringID(XPCJSRuntime::IDX_DOCUMENTURIOBJECT) &&
     586                 :             Is<nsIDocument>(wrapper))) &&
     587                 :           IsPrivilegedScript()))) {
     588                 :         bool status;
     589               0 :         Wrapper::Action action = set ? Wrapper::SET : Wrapper::GET;
     590               0 :         desc->obj = NULL; // default value
     591               0 :         if (!this->enter(cx, wrapper, id, action, &status))
     592               0 :             return status;
     593                 : 
     594               0 :         AutoLeaveHelper<Base> helper(*this, cx, wrapper);
     595                 : 
     596               0 :         desc->obj = wrapper;
     597               0 :         desc->attrs = JSPROP_ENUMERATE|JSPROP_SHARED;
     598               0 :         if (id == rt->GetStringID(XPCJSRuntime::IDX_WRAPPED_JSOBJECT))
     599               0 :             desc->getter = wrappedJSObject_getter;
     600               0 :         else if (id == rt->GetStringID(XPCJSRuntime::IDX_BASEURIOBJECT))
     601               0 :             desc->getter = baseURIObject_getter;
     602               0 :         else if (id == rt->GetStringID(XPCJSRuntime::IDX_DOCUMENTURIOBJECT))
     603               0 :             desc->getter = documentURIObject_getter;
     604                 :         else
     605               0 :             desc->getter = nodePrincipal_getter;
     606               0 :         desc->setter = NULL;
     607               0 :         desc->shortid = 0;
     608               0 :         desc->value = JSVAL_VOID;
     609               0 :         return true;
     610                 :     }
     611                 : 
     612               0 :     desc->obj = NULL;
     613                 : 
     614               0 :     unsigned flags = (set ? JSRESOLVE_ASSIGNING : 0) | JSRESOLVE_QUALIFIED;
     615               0 :     JSObject *holder = GetHolder(wrapper);
     616               0 :     JSObject *expando = GetExpandoObject(holder);
     617                 : 
     618                 :     // Check for expando properties first.
     619               0 :     if (expando && !JS_GetPropertyDescriptorById(cx, expando, id, flags, desc)) {
     620               0 :         return false;
     621                 :     }
     622               0 :     if (desc->obj) {
     623                 :         // Pretend the property lives on the wrapper.
     624               0 :         desc->obj = wrapper;
     625               0 :         return true;
     626                 :     }
     627                 : 
     628                 :     JSBool hasProp;
     629               0 :     if (!JS_HasPropertyById(cx, holder, id, &hasProp)) {
     630               0 :         return false;
     631                 :     }
     632               0 :     if (!hasProp) {
     633               0 :         XPCWrappedNative *wn = GetWrappedNativeFromHolder(holder);
     634                 : 
     635                 :         // Run the resolve hook of the wrapped native.
     636               0 :         if (!NATIVE_HAS_FLAG(wn, WantNewResolve)) {
     637               0 :             desc->obj = nsnull;
     638               0 :             return true;
     639                 :         }
     640                 : 
     641               0 :         bool retval = true;
     642               0 :         JSObject *pobj = NULL;
     643                 :         nsresult rv = wn->GetScriptableInfo()->GetCallback()->NewResolve(wn, cx, wrapper, id,
     644               0 :                                                                          flags, &pobj, &retval);
     645               0 :         if (NS_FAILED(rv)) {
     646               0 :             if (retval)
     647               0 :                 XPCThrower::Throw(rv, cx);
     648               0 :             return false;
     649                 :         }
     650                 : 
     651               0 :         if (!pobj) {
     652               0 :             desc->obj = nsnull;
     653               0 :             return true;
     654                 :         }
     655                 : 
     656                 : #ifdef DEBUG
     657               0 :         NS_ASSERTION(JS_HasPropertyById(cx, holder, id, &hasProp) &&
     658                 :                      hasProp, "id got defined somewhere else?");
     659                 : #endif
     660                 :     }
     661                 : 
     662               0 :     if (!JS_GetPropertyDescriptorById(cx, holder, id, flags, desc))
     663               0 :         return false;
     664                 : 
     665                 :     // Pretend we found the property on the wrapper, not the holder.
     666               0 :     desc->obj = wrapper;
     667                 : 
     668               0 :     return true;
     669                 : }
     670                 : 
     671                 : template <typename Base>
     672                 : bool
     673               0 : XrayWrapper<Base>::getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id,
     674                 :                                          bool set, PropertyDescriptor *desc)
     675                 : {
     676               0 :     JSObject *holder = GetHolder(wrapper);
     677               0 :     if (IsResolving(holder, id)) {
     678               0 :         desc->obj = NULL;
     679               0 :         return true;
     680                 :     }
     681                 : 
     682                 :     bool status;
     683               0 :     Wrapper::Action action = set ? Wrapper::SET : Wrapper::GET;
     684               0 :     desc->obj = NULL; // default value
     685               0 :     if (!this->enter(cx, wrapper, id, action, &status))
     686               0 :         return status;
     687                 : 
     688               0 :     AutoLeaveHelper<Base> helper(*this, cx, wrapper);
     689                 : 
     690               0 :     ResolvingId resolving(holder, id);
     691                 : 
     692                 :     // Redirect access straight to the wrapper if we should be transparent.
     693               0 :     if (XrayUtils::IsTransparent(cx, wrapper)) {
     694               0 :         JSObject *wnObject = GetWrappedNativeObjectFromHolder(holder);
     695                 : 
     696                 :         {
     697               0 :             JSAutoEnterCompartment ac;
     698               0 :             if (!ac.enter(cx, wnObject))
     699               0 :                 return false;
     700                 : 
     701               0 :             if (!JS_GetPropertyDescriptorById(cx, wnObject, id,
     702                 :                                               (set ? JSRESOLVE_ASSIGNING : 0) | JSRESOLVE_QUALIFIED,
     703                 :                                               desc))
     704               0 :                 return false;
     705                 :         }
     706                 : 
     707               0 :         if (desc->obj)
     708               0 :             desc->obj = wrapper;
     709               0 :         return JS_WrapPropertyDescriptor(cx, desc);
     710                 :     }
     711                 : 
     712               0 :     if (!this->resolveOwnProperty(cx, wrapper, id, set, desc))
     713               0 :         return false;
     714                 : 
     715               0 :     if (desc->obj)
     716               0 :         return true;
     717                 : 
     718               0 :     bool ok = ResolveNativeProperty(cx, wrapper, holder, id, set, desc);
     719               0 :     if (!ok || desc->obj)
     720               0 :         return ok;
     721                 : 
     722               0 :     if (id == nsXPConnect::GetRuntimeInstance()->GetStringID(XPCJSRuntime::IDX_TO_STRING)) {
     723               0 :         desc->obj = wrapper;
     724               0 :         desc->attrs = 0;
     725               0 :         desc->getter = NULL;
     726               0 :         desc->setter = NULL;
     727               0 :         desc->shortid = 0;
     728                 : 
     729               0 :         JSObject *toString = JS_GetFunctionObject(JS_NewFunction(cx, XrayToString, 0, 0, holder, "toString"));
     730               0 :         if (!toString)
     731               0 :             return false;
     732               0 :         desc->value = OBJECT_TO_JSVAL(toString);
     733               0 :         return true;
     734                 :     }
     735                 : 
     736               0 :     return true;
     737                 : }
     738                 : 
     739                 : template <typename Base>
     740                 : bool
     741               0 : XrayWrapper<Base>::getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id,
     742                 :                                             bool set, PropertyDescriptor *desc)
     743                 : {
     744               0 :     JSObject *holder = GetHolder(wrapper);
     745               0 :     if (IsResolving(holder, id)) {
     746               0 :         desc->obj = NULL;
     747               0 :         return true;
     748                 :     }
     749                 : 
     750                 :     bool status;
     751               0 :     Wrapper::Action action = set ? Wrapper::SET : Wrapper::GET;
     752               0 :     desc->obj = NULL; // default value
     753               0 :     if (!this->enter(cx, wrapper, id, action, &status))
     754               0 :         return status;
     755                 : 
     756               0 :     AutoLeaveHelper<Base> helper(*this, cx, wrapper);
     757                 : 
     758               0 :     ResolvingId resolving(holder, id);
     759                 : 
     760                 :     // NB: Nothing we do here acts on the wrapped native itself, so we don't
     761                 :     // enter our policy.
     762                 :     // Redirect access straight to the wrapper if we should be transparent.
     763               0 :     if (XrayUtils::IsTransparent(cx, wrapper)) {
     764               0 :         JSObject *wnObject = GetWrappedNativeObjectFromHolder(holder);
     765                 : 
     766                 :         {
     767               0 :             JSAutoEnterCompartment ac;
     768               0 :             if (!ac.enter(cx, wnObject))
     769               0 :                 return false;
     770                 : 
     771               0 :             if (!JS_GetPropertyDescriptorById(cx, wnObject, id,
     772                 :                                               (set ? JSRESOLVE_ASSIGNING : 0) | JSRESOLVE_QUALIFIED,
     773                 :                                               desc)) {
     774               0 :                 return false;
     775                 :             }
     776                 :         }
     777                 : 
     778               0 :         desc->obj = (desc->obj == wnObject) ? wrapper : nsnull;
     779               0 :         return JS_WrapPropertyDescriptor(cx, desc);
     780                 :     }
     781                 : 
     782               0 :     return this->resolveOwnProperty(cx, wrapper, id, set, desc);
     783                 : }
     784                 : 
     785                 : template <typename Base>
     786                 : bool
     787               0 : XrayWrapper<Base>::defineProperty(JSContext *cx, JSObject *wrapper, jsid id,
     788                 :                                   js::PropertyDescriptor *desc)
     789                 : {
     790               0 :     JSObject *holder = GetHolder(wrapper);
     791               0 :     JSPropertyDescriptor *jsdesc = desc;
     792                 : 
     793                 :     // If shadowing is forbidden, see if the id corresponds to an underlying
     794                 :     // native property.
     795               0 :     if (WrapperFactory::IsShadowingForbidden(wrapper)) {
     796                 :         js::PropertyDescriptor nativeProp;
     797               0 :         if (!ResolveNativeProperty(cx, wrapper, holder, id, false, &nativeProp))
     798               0 :             return false;
     799               0 :         if (nativeProp.obj) {
     800               0 :             JS_ReportError(cx, "Permission denied to shadow native property");
     801               0 :             return false;
     802                 :         }
     803                 :     }
     804                 : 
     805                 :     // Redirect access straight to the wrapper if we should be transparent.
     806               0 :     if (XrayUtils::IsTransparent(cx, wrapper)) {
     807               0 :         JSObject *wnObject = GetWrappedNativeObjectFromHolder(holder);
     808                 : 
     809               0 :         JSAutoEnterCompartment ac;
     810               0 :         if (!ac.enter(cx, wnObject))
     811               0 :             return false;
     812                 : 
     813               0 :         if (!JS_WrapPropertyDescriptor(cx, desc))
     814               0 :             return false;
     815                 : 
     816                 :         return JS_DefinePropertyById(cx, wnObject, id, jsdesc->value, jsdesc->getter, jsdesc->setter,
     817               0 :                                      jsdesc->attrs);
     818                 :     }
     819                 : 
     820                 :     PropertyDescriptor existing_desc;
     821               0 :     if (!getOwnPropertyDescriptor(cx, wrapper, id, true, &existing_desc))
     822               0 :         return false;
     823                 : 
     824               0 :     if (existing_desc.obj && (existing_desc.attrs & JSPROP_PERMANENT))
     825               0 :         return true; // silently ignore attempt to overwrite native property
     826                 : 
     827               0 :     if (IsResolving(holder, id)) {
     828               0 :         if (!(jsdesc->attrs & (JSPROP_GETTER | JSPROP_SETTER))) {
     829               0 :             if (!desc->getter)
     830               0 :                 jsdesc->getter = holder_get;
     831               0 :             if (!desc->setter)
     832               0 :                 jsdesc->setter = holder_set;
     833                 :         }
     834                 : 
     835                 :         return JS_DefinePropertyById(cx, holder, id, jsdesc->value, jsdesc->getter, jsdesc->setter,
     836               0 :                                      jsdesc->attrs);
     837                 :     }
     838                 : 
     839               0 :     JSObject *expando = EnsureExpandoObject(cx, holder);
     840               0 :     if (!expando)
     841               0 :         return false;
     842                 : 
     843                 :     return JS_DefinePropertyById(cx, expando, id, jsdesc->value, jsdesc->getter, jsdesc->setter,
     844               0 :                                  jsdesc->attrs);
     845                 : }
     846                 : 
     847                 : static bool
     848               0 : EnumerateNames(JSContext *cx, JSObject *wrapper, unsigned flags, JS::AutoIdVector &props)
     849                 : {
     850               0 :     JSObject *holder = GetHolder(wrapper);
     851                 : 
     852               0 :     JSObject *wnObject = GetWrappedNativeObjectFromHolder(holder);
     853                 : 
     854                 :     // Redirect access straight to the wrapper if we should be transparent.
     855               0 :     if (XrayUtils::IsTransparent(cx, wrapper)) {
     856               0 :         JSAutoEnterCompartment ac;
     857               0 :         if (!ac.enter(cx, wnObject))
     858               0 :             return false;
     859                 : 
     860               0 :         return js::GetPropertyNames(cx, wnObject, flags, &props);
     861                 :     }
     862                 : 
     863               0 :     if (WrapperFactory::IsPartiallyTransparent(wrapper)) {
     864               0 :         JS_ReportError(cx, "Not allowed to enumerate cross origin objects");
     865               0 :         return false;
     866                 :     }
     867                 : 
     868                 :     // Enumerate expando properties first.
     869               0 :     JSObject *expando = GetExpandoObject(holder);
     870               0 :     if (expando && !js::GetPropertyNames(cx, expando, flags, &props))
     871               0 :         return false;
     872                 : 
     873                 :     // Force all native properties to be materialized onto the wrapped native.
     874               0 :     JS::AutoIdVector wnProps(cx);
     875                 :     {
     876               0 :         JSAutoEnterCompartment ac;
     877               0 :         if (!ac.enter(cx, wnObject))
     878               0 :             return false;
     879               0 :         if (!js::GetPropertyNames(cx, wnObject, flags, &wnProps))
     880               0 :             return false;
     881                 :     }
     882                 : 
     883                 :     // Go through the properties we got and enumerate all native ones.
     884               0 :     for (size_t n = 0; n < wnProps.length(); ++n) {
     885               0 :         jsid id = wnProps[n];
     886                 :         JSBool hasProp;
     887               0 :         if (!JS_HasPropertyById(cx, wrapper, id, &hasProp))
     888               0 :             return false;
     889               0 :         if (hasProp)
     890               0 :             props.append(id);
     891                 :     }
     892               0 :     return true;
     893                 : }
     894                 : 
     895                 : template <typename Base>
     896                 : bool
     897               0 : XrayWrapper<Base>::getOwnPropertyNames(JSContext *cx, JSObject *wrapper,
     898                 :                                        JS::AutoIdVector &props)
     899                 : {
     900               0 :     return EnumerateNames(cx, wrapper, JSITER_OWNONLY | JSITER_HIDDEN, props);
     901                 : }
     902                 : 
     903                 : template <typename Base>
     904                 : bool
     905               0 : XrayWrapper<Base>::delete_(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
     906                 : {
     907               0 :     JSObject *holder = GetHolder(wrapper);
     908                 :     jsval v;
     909                 :     JSBool b;
     910                 : 
     911                 :     // Redirect access straight to the wrapper if we should be transparent.
     912               0 :     if (XrayUtils::IsTransparent(cx, wrapper)) {
     913               0 :         JSObject *wnObject = GetWrappedNativeObjectFromHolder(holder);
     914                 : 
     915               0 :         JSAutoEnterCompartment ac;
     916               0 :         if (!ac.enter(cx, wnObject))
     917               0 :             return false;
     918                 : 
     919               0 :         if (!JS_DeletePropertyById2(cx, wnObject, id, &v) || !JS_ValueToBoolean(cx, v, &b))
     920               0 :             return false;
     921               0 :         *bp = !!b;
     922               0 :         return true;
     923                 :     }
     924                 : 
     925               0 :     JSObject *expando = GetExpandoObject(holder);
     926               0 :     b = true;
     927               0 :     if (expando &&
     928                 :         (!JS_DeletePropertyById2(cx, expando, id, &v) ||
     929                 :          !JS_ValueToBoolean(cx, v, &b))) {
     930               0 :         return false;
     931                 :     }
     932                 : 
     933               0 :     *bp = !!b;
     934               0 :     return true;
     935                 : }
     936                 : 
     937                 : template <typename Base>
     938                 : bool
     939               0 : XrayWrapper<Base>::enumerate(JSContext *cx, JSObject *wrapper, JS::AutoIdVector &props)
     940                 : {
     941               0 :     return EnumerateNames(cx, wrapper, 0, props);
     942                 : }
     943                 : 
     944                 : template <typename Base>
     945                 : bool
     946               0 : XrayWrapper<Base>::fix(JSContext *cx, JSObject *proxy, js::Value *vp)
     947                 : {
     948               0 :     vp->setUndefined();
     949               0 :     return true;
     950                 : }
     951                 : 
     952                 : template <typename Base>
     953                 : bool
     954               0 : XrayWrapper<Base>::get(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id,
     955                 :                        js::Value *vp)
     956                 : {
     957                 :     // Skip our Base if it isn't already ProxyHandler.
     958                 :     // NB: None of the functions we call are prepared for the receiver not
     959                 :     // being the wrapper, so ignore the receiver here.
     960               0 :     return ProxyHandler::get(cx, wrapper, wrapper, id, vp);
     961                 : }
     962                 : 
     963                 : template <typename Base>
     964                 : bool
     965               0 : XrayWrapper<Base>::set(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id,
     966                 :                        bool strict, js::Value *vp)
     967                 : {
     968                 :     // Skip our Base if it isn't already ProxyHandler.
     969                 :     // NB: None of the functions we call are prepared for the receiver not
     970                 :     // being the wrapper, so ignore the receiver here.
     971               0 :     return ProxyHandler::set(cx, wrapper, wrapper, id, strict, vp);
     972                 : }
     973                 : 
     974                 : template <typename Base>
     975                 : bool
     976               0 : XrayWrapper<Base>::has(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
     977                 : {
     978                 :     // Skip our Base if it isn't already ProxyHandler.
     979               0 :     return ProxyHandler::has(cx, wrapper, id, bp);
     980                 : }
     981                 : 
     982                 : template <typename Base>
     983                 : bool
     984               0 : XrayWrapper<Base>::hasOwn(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
     985                 : {
     986                 :     // Skip our Base if it isn't already ProxyHandler.
     987               0 :     return ProxyHandler::hasOwn(cx, wrapper, id, bp);
     988                 : }
     989                 : 
     990                 : template <typename Base>
     991                 : bool
     992               0 : XrayWrapper<Base>::keys(JSContext *cx, JSObject *wrapper, JS::AutoIdVector &props)
     993                 : {
     994                 :     // Skip our Base if it isn't already ProxyHandler.
     995               0 :     return ProxyHandler::keys(cx, wrapper, props);
     996                 : }
     997                 : 
     998                 : template <typename Base>
     999                 : bool
    1000               0 : XrayWrapper<Base>::iterate(JSContext *cx, JSObject *wrapper, unsigned flags, js::Value *vp)
    1001                 : {
    1002                 :     // Skip our Base if it isn't already ProxyHandler.
    1003               0 :     return ProxyHandler::iterate(cx, wrapper, flags, vp);
    1004                 : }
    1005                 : 
    1006                 : template <typename Base>
    1007                 : bool
    1008               0 : XrayWrapper<Base>::call(JSContext *cx, JSObject *wrapper, unsigned argc, js::Value *vp)
    1009                 : {
    1010               0 :     JSObject *holder = GetHolder(wrapper);
    1011               0 :     XPCWrappedNative *wn = GetWrappedNativeFromHolder(holder);
    1012                 : 
    1013                 :     // Run the resolve hook of the wrapped native.
    1014               0 :     if (NATIVE_HAS_FLAG(wn, WantCall)) {
    1015                 :         XPCCallContext ccx(JS_CALLER, cx, wrapper, nsnull, JSID_VOID, argc,
    1016               0 :                            vp + 2, vp);
    1017               0 :         if (!ccx.IsValid())
    1018               0 :             return false;
    1019               0 :         bool ok = true;
    1020                 :         nsresult rv = wn->GetScriptableInfo()->GetCallback()->Call(wn, cx, wrapper,
    1021               0 :                                                                    argc, vp + 2, vp, &ok);
    1022               0 :         if (NS_FAILED(rv)) {
    1023               0 :             if (ok)
    1024               0 :                 XPCThrower::Throw(rv, cx);
    1025               0 :             return false;
    1026                 :         }
    1027                 :     }
    1028                 : 
    1029               0 :     return true;
    1030                 : }
    1031                 : 
    1032                 : template <typename Base>
    1033                 : bool
    1034               0 : XrayWrapper<Base>::construct(JSContext *cx, JSObject *wrapper, unsigned argc,
    1035                 :                              js::Value *argv, js::Value *rval)
    1036                 : {
    1037               0 :     JSObject *holder = GetHolder(wrapper);
    1038               0 :     XPCWrappedNative *wn = GetWrappedNativeFromHolder(holder);
    1039                 : 
    1040                 :     // Run the resolve hook of the wrapped native.
    1041               0 :     if (NATIVE_HAS_FLAG(wn, WantConstruct)) {
    1042               0 :         XPCCallContext ccx(JS_CALLER, cx, wrapper, nsnull, JSID_VOID, argc, argv, rval);
    1043               0 :         if (!ccx.IsValid())
    1044               0 :             return false;
    1045               0 :         bool ok = true;
    1046                 :         nsresult rv = wn->GetScriptableInfo()->GetCallback()->Construct(wn, cx, wrapper,
    1047               0 :                                                                         argc, argv, rval, &ok);
    1048               0 :         if (NS_FAILED(rv)) {
    1049               0 :             if (ok)
    1050               0 :                 XPCThrower::Throw(rv, cx);
    1051               0 :             return false;
    1052                 :         }
    1053                 :     }
    1054                 : 
    1055               0 :     return true;
    1056                 : }
    1057                 : 
    1058                 : template <typename Base>
    1059                 : JSObject *
    1060               0 : XrayWrapper<Base>::createHolder(JSContext *cx, JSObject *wrappedNative, JSObject *parent)
    1061                 : {
    1062               0 :     JSObject *holder = JS_NewObjectWithGivenProto(cx, &HolderClass, nsnull, parent);
    1063               0 :     if (!holder)
    1064               0 :         return nsnull;
    1065                 : 
    1066                 :     CompartmentPrivate *priv =
    1067               0 :         (CompartmentPrivate *)JS_GetCompartmentPrivate(js::GetObjectCompartment(holder));
    1068               0 :     JSObject *inner = JS_ObjectToInnerObject(cx, wrappedNative);
    1069               0 :     XPCWrappedNative *wn = GetWrappedNative(inner);
    1070               0 :     Value expando = ObjectOrNullValue(priv->LookupExpandoObject(wn));
    1071                 : 
    1072                 :     // A note about ownership: the holder has a direct pointer to the wrapped
    1073                 :     // native that we're wrapping. Normally, we'd have to AddRef the pointer
    1074                 :     // so that it doesn't have to be collected, but then we'd have to tell the
    1075                 :     // cycle collector. Fortunately for us, we know that the Xray wrapper
    1076                 :     // itself has a reference to the flat JS object which will hold the
    1077                 :     // wrapped native alive. Furthermore, the reachability of that object and
    1078                 :     // the associated holder are exactly the same, so we can use that for our
    1079                 :     // strong reference.
    1080               0 :     JS_ASSERT(IS_WN_WRAPPER(wrappedNative) ||
    1081                 :               js::GetObjectClass(wrappedNative)->ext.innerObject);
    1082               0 :     js::SetReservedSlot(holder, JSSLOT_WN, PrivateValue(wn));
    1083               0 :     js::SetReservedSlot(holder, JSSLOT_RESOLVING, PrivateValue(NULL));
    1084               0 :     js::SetReservedSlot(holder, JSSLOT_EXPANDO, expando);
    1085               0 :     return holder;
    1086                 : }
    1087                 : 
    1088            2928 : XrayProxy::XrayProxy(unsigned flags)
    1089            2928 :   : XrayWrapper<CrossCompartmentWrapper>(flags)
    1090                 : {
    1091            2928 : }
    1092                 : 
    1093            2974 : XrayProxy::~XrayProxy()
    1094                 : {
    1095            5948 : }
    1096                 : 
    1097                 : // The 'holder' here isn't actually of [[Class]] HolderClass like those used by
    1098                 : // XrayWrapper. Instead, it's a funny hybrid of the 'expando' and 'holder'
    1099                 : // properties. However, we store it in the same slot. Exercise caution.
    1100                 : static JSObject *
    1101               0 : GetHolderObject(JSContext *cx, JSObject *wrapper, bool createHolder = true)
    1102                 : {
    1103               0 :     if (!js::GetProxyExtra(wrapper, 0).isUndefined())
    1104               0 :         return &js::GetProxyExtra(wrapper, 0).toObject();
    1105                 : 
    1106                 :     JSObject *obj = JS_NewObjectWithGivenProto(cx, nsnull, nsnull,
    1107               0 :                                                JS_GetGlobalForObject(cx, wrapper));
    1108               0 :     if (!obj)
    1109               0 :         return nsnull;
    1110               0 :     js::SetProxyExtra(wrapper, 0, ObjectValue(*obj));
    1111               0 :     return obj;
    1112                 : }
    1113                 : 
    1114                 : bool
    1115               0 : XrayProxy::getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id,
    1116                 :                                  bool set, js::PropertyDescriptor *desc)
    1117                 : {
    1118               0 :     JSObject *holder = GetHolderObject(cx, wrapper);
    1119               0 :     if (!holder)
    1120               0 :         return false;
    1121                 : 
    1122                 :     bool status;
    1123               0 :     Wrapper::Action action = set ? Wrapper::SET : Wrapper::GET;
    1124               0 :     desc->obj = NULL; // default value
    1125               0 :     if (!this->enter(cx, wrapper, id, action, &status))
    1126               0 :         return status;
    1127                 : 
    1128               0 :     AutoLeaveHelper<CrossCompartmentWrapper> helper(*this, cx, wrapper);
    1129                 : 
    1130               0 :     JSObject *obj = &js::GetProxyPrivate(wrapper).toObject();
    1131               0 :     if (XrayUtils::IsTransparent(cx, wrapper)) {
    1132                 :         {
    1133               0 :             JSAutoEnterCompartment ac;
    1134               0 :             if (!ac.enter(cx, obj))
    1135               0 :                 return false;
    1136               0 :             if (!JS_GetPropertyDescriptorById(cx, obj, id,
    1137                 :                                               (set ? JSRESOLVE_ASSIGNING : 0) | JSRESOLVE_QUALIFIED,
    1138               0 :                                               desc))
    1139               0 :                 return false;
    1140                 :         }
    1141                 : 
    1142               0 :         if (desc->obj)
    1143               0 :             desc->obj = wrapper;
    1144               0 :         return JS_WrapPropertyDescriptor(cx, desc);
    1145                 :     }
    1146                 : 
    1147                 :     // We don't want to cache own properties on our holder. So we first do this
    1148                 :     // call, and return if we find it (without caching). If we don't find it,
    1149                 :     // we check the cache and do a full resolve (caching any result).
    1150               0 :     if (!js::GetProxyHandler(obj)->getOwnPropertyDescriptor(cx, wrapper, id, set, desc))
    1151               0 :         return false;
    1152               0 :     if (desc->obj) {
    1153               0 :         desc->obj = wrapper;
    1154               0 :         return true;
    1155                 :     }
    1156                 : 
    1157                 :     // Now that we're sure this isn't an own property, look up cached non-own
    1158                 :     // properties before calling all the way through.
    1159               0 :     if (!JS_GetPropertyDescriptorById(cx, holder, id, JSRESOLVE_QUALIFIED, desc))
    1160               0 :         return false;
    1161               0 :     if (desc->obj) {
    1162               0 :         desc->obj = wrapper;
    1163               0 :         return true;
    1164                 :     }
    1165                 : 
    1166                 :     // Nothing in the cache. Call through, and cache the result.
    1167               0 :     if (!js::GetProxyHandler(obj)->getPropertyDescriptor(cx, wrapper, id, set, desc))
    1168               0 :         return false;
    1169                 : 
    1170               0 :     if (!desc->obj) {
    1171               0 :         if (id != nsXPConnect::GetRuntimeInstance()->GetStringID(XPCJSRuntime::IDX_TO_STRING))
    1172               0 :             return true;
    1173                 : 
    1174               0 :         JSFunction *toString = JS_NewFunction(cx, XrayToString, 0, 0, holder, "toString");
    1175               0 :         if (!toString)
    1176               0 :             return false;
    1177                 : 
    1178               0 :         desc->attrs = 0;
    1179               0 :         desc->getter = NULL;
    1180               0 :         desc->setter = NULL;
    1181               0 :         desc->shortid = 0;
    1182               0 :         desc->value.setObject(*JS_GetFunctionObject(toString));
    1183                 :     }
    1184                 : 
    1185               0 :     desc->obj = wrapper;
    1186                 : 
    1187                 :     return JS_DefinePropertyById(cx, holder, id, desc->value, desc->getter, desc->setter,
    1188               0 :                                  desc->attrs);
    1189                 : }
    1190                 : 
    1191                 : bool
    1192               0 : XrayProxy::getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id,
    1193                 :                                     bool set, js::PropertyDescriptor *desc)
    1194                 : {
    1195               0 :     JSObject *holder = GetHolderObject(cx, wrapper);
    1196               0 :     if (!holder)
    1197               0 :         return false;
    1198                 : 
    1199                 :     bool status;
    1200               0 :     Wrapper::Action action = set ? Wrapper::SET : Wrapper::GET;
    1201               0 :     desc->obj = NULL; // default value
    1202               0 :     if (!this->enter(cx, wrapper, id, action, &status))
    1203               0 :         return status;
    1204                 : 
    1205               0 :     AutoLeaveHelper<CrossCompartmentWrapper> helper(*this, cx, wrapper);
    1206                 : 
    1207               0 :     JSObject *obj = &js::GetProxyPrivate(wrapper).toObject();
    1208               0 :     if (XrayUtils::IsTransparent(cx, wrapper)) {
    1209                 :         {
    1210               0 :             JSAutoEnterCompartment ac;
    1211               0 :             if (!ac.enter(cx, obj))
    1212               0 :                 return false;
    1213               0 :             if (!JS_GetPropertyDescriptorById(cx, obj, id,
    1214                 :                                               (set ? JSRESOLVE_ASSIGNING : 0) | JSRESOLVE_QUALIFIED,
    1215               0 :                                               desc))
    1216               0 :                 return false;
    1217                 :         }
    1218                 : 
    1219               0 :         if (desc->obj)
    1220               0 :             desc->obj = desc->obj == obj ? wrapper : NULL;
    1221               0 :         return JS_WrapPropertyDescriptor(cx, desc);
    1222                 :     }
    1223                 : 
    1224               0 :     if (!JS_GetPropertyDescriptorById(cx, holder, id, JSRESOLVE_QUALIFIED, desc))
    1225               0 :         return false;
    1226               0 :     if (desc->obj) {
    1227               0 :         desc->obj = wrapper;
    1228               0 :         return true;
    1229                 :     }
    1230                 : 
    1231               0 :     if (!js::GetProxyHandler(obj)->getOwnPropertyDescriptor(cx, wrapper, id, set, desc))
    1232               0 :         return false;
    1233                 : 
    1234                 :     // The 'not found' property descriptor has obj == NULL.
    1235               0 :     if (desc->obj)
    1236               0 :       desc->obj = wrapper;
    1237                 : 
    1238                 :     // Own properties don't get cached on the holder. Just return.
    1239               0 :     return true;
    1240                 : }
    1241                 : 
    1242                 : bool
    1243               0 : XrayProxy::defineProperty(JSContext *cx, JSObject *wrapper, jsid id,
    1244                 :                           js::PropertyDescriptor *desc)
    1245                 : {
    1246                 :     // This wouldn't be hard to support, but we don't need it right now.
    1247               0 :     MOZ_ASSERT(!WrapperFactory::IsShadowingForbidden(wrapper));
    1248                 : 
    1249               0 :     JSObject *holder = GetHolderObject(cx, wrapper);
    1250               0 :     if (!holder)
    1251               0 :         return false;
    1252                 : 
    1253               0 :     JSObject *obj = &js::GetProxyPrivate(wrapper).toObject();
    1254               0 :     if (XrayUtils::IsTransparent(cx, wrapper)) {
    1255               0 :         JSAutoEnterCompartment ac;
    1256               0 :         if (!ac.enter(cx, obj) || !JS_WrapPropertyDescriptor(cx, desc))
    1257               0 :             return false;
    1258                 : 
    1259                 :         return JS_DefinePropertyById(cx, obj, id, desc->value, desc->getter, desc->setter,
    1260               0 :                                      desc->attrs);
    1261                 :     }
    1262                 : 
    1263                 :     PropertyDescriptor existing_desc;
    1264               0 :     if (!getOwnPropertyDescriptor(cx, wrapper, id, true, &existing_desc))
    1265               0 :         return false;
    1266                 : 
    1267               0 :     if (existing_desc.obj && (existing_desc.attrs & JSPROP_PERMANENT))
    1268               0 :         return true; // silently ignore attempt to overwrite native property
    1269                 : 
    1270                 :     return JS_DefinePropertyById(cx, holder, id, desc->value, desc->getter, desc->setter,
    1271               0 :                                  desc->attrs);
    1272                 : }
    1273                 : 
    1274                 : static bool
    1275               0 : EnumerateProxyNames(JSContext *cx, JSObject *wrapper, unsigned flags, JS::AutoIdVector &props)
    1276                 : {
    1277               0 :     JSObject *obj = &js::GetProxyPrivate(wrapper).toObject();
    1278                 : 
    1279                 :     // Redirect access straight to the wrapper if we should be transparent.
    1280               0 :     if (XrayUtils::IsTransparent(cx, wrapper)) {
    1281               0 :         JSAutoEnterCompartment ac;
    1282               0 :         if (!ac.enter(cx, obj))
    1283               0 :             return false;
    1284                 : 
    1285               0 :         return js::GetPropertyNames(cx, obj, flags, &props);
    1286                 :     }
    1287                 : 
    1288               0 :     if (WrapperFactory::IsPartiallyTransparent(wrapper)) {
    1289               0 :         JS_ReportError(cx, "Not allowed to enumerate cross origin objects");
    1290               0 :         return false;
    1291                 :     }
    1292                 : 
    1293               0 :     if (flags & (JSITER_OWNONLY | JSITER_HIDDEN))
    1294               0 :         return js::GetProxyHandler(obj)->getOwnPropertyNames(cx, wrapper, props);
    1295                 : 
    1296               0 :     return js::GetProxyHandler(obj)->enumerate(cx, wrapper, props);
    1297                 : }
    1298                 : 
    1299                 : bool
    1300               0 : XrayProxy::getOwnPropertyNames(JSContext *cx, JSObject *wrapper, JS::AutoIdVector &props)
    1301                 : {
    1302               0 :     return EnumerateProxyNames(cx, wrapper, JSITER_OWNONLY | JSITER_HIDDEN, props);
    1303                 : }
    1304                 : 
    1305                 : bool
    1306               0 : XrayProxy::delete_(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
    1307                 : {
    1308               0 :     JSObject *obj = &js::GetProxyPrivate(wrapper).toObject();
    1309               0 :     if (XrayUtils::IsTransparent(cx, wrapper)) {
    1310               0 :         JSAutoEnterCompartment ac;
    1311               0 :         if (!ac.enter(cx, obj))
    1312               0 :             return false;
    1313                 : 
    1314                 :         JSBool b;
    1315                 :         jsval v;
    1316               0 :         if (!JS_DeletePropertyById2(cx, obj, id, &v) || !JS_ValueToBoolean(cx, v, &b))
    1317               0 :             return false;
    1318                 : 
    1319               0 :         *bp = b;
    1320                 : 
    1321               0 :         return true;
    1322                 :     }
    1323                 : 
    1324               0 :     if (!js::GetProxyHandler(obj)->delete_(cx, wrapper, id, bp))
    1325               0 :         return false;
    1326                 : 
    1327                 :     JSObject *holder;
    1328               0 :     if (*bp && (holder = GetHolderObject(cx, wrapper, false)))
    1329               0 :         JS_DeletePropertyById(cx, holder, id);
    1330                 : 
    1331               0 :     return true;
    1332                 : }
    1333                 : 
    1334                 : bool
    1335               0 : XrayProxy::enumerate(JSContext *cx, JSObject *wrapper, JS::AutoIdVector &props)
    1336                 : {
    1337               0 :     return EnumerateProxyNames(cx, wrapper, 0, props);
    1338                 : }
    1339                 : 
    1340                 : XrayProxy
    1341            1464 : XrayProxy::singleton(0);
    1342                 : 
    1343                 : 
    1344                 : #define XRAY XrayWrapper<CrossCompartmentSecurityWrapper>
    1345            1464 : template <> XRAY XRAY::singleton(0);
    1346                 : template class XRAY;
    1347                 : #undef XRAY
    1348                 : 
    1349                 : #define XRAY XrayWrapper<SameCompartmentSecurityWrapper>
    1350            1464 : template <> XRAY XRAY::singleton(0);
    1351                 : template class XRAY;
    1352                 : #undef XRAY
    1353                 : 
    1354                 : #define XRAY XrayWrapper<CrossCompartmentWrapper>
    1355            1464 : template <> XRAY XRAY::singleton(0);
    1356                 : template class XRAY;
    1357                 : #undef XRAY
    1358                 : 
    1359            4392 : }

Generated by: LCOV version 1.7