LCOV - code coverage report
Current view: top level - js/xpconnect/src - XPCWrappedNativeJSOps.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 386 572 67.5 %
Date: 2017-07-14 16:53:18 Functions: 27 45 60.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /* vim: set ts=8 sts=4 et sw=4 tw=99: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : /* JavaScript JSClasses and JSOps for our Wrapped Native JS Objects. */
       8             : 
       9             : #include "xpcprivate.h"
      10             : #include "xpc_make_class.h"
      11             : #include "jsprf.h"
      12             : #include "mozilla/dom/BindingUtils.h"
      13             : #include "mozilla/Preferences.h"
      14             : #include "nsIAddonInterposition.h"
      15             : #include "AddonWrapper.h"
      16             : #include "js/Class.h"
      17             : 
      18             : using namespace mozilla;
      19             : using namespace JS;
      20             : 
      21             : /***************************************************************************/
      22             : 
      23             : // All of the exceptions thrown into JS from this file go through here.
      24             : // That makes this a nice place to set a breakpoint.
      25             : 
      26           0 : static bool Throw(nsresult errNum, JSContext* cx)
      27             : {
      28           0 :     XPCThrower::Throw(errNum, cx);
      29           0 :     return false;
      30             : }
      31             : 
      32             : // Handy macro used in many callback stub below.
      33             : 
      34             : #define THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper)                          \
      35             :     PR_BEGIN_MACRO                                                            \
      36             :     if (!wrapper)                                                             \
      37             :         return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);                    \
      38             :     if (!wrapper->IsValid())                                                  \
      39             :         return Throw(NS_ERROR_XPC_HAS_BEEN_SHUTDOWN, cx);                     \
      40             :     PR_END_MACRO
      41             : 
      42             : /***************************************************************************/
      43             : 
      44             : static bool
      45           8 : ToStringGuts(XPCCallContext& ccx)
      46             : {
      47          16 :     UniqueChars sz;
      48           8 :     XPCWrappedNative* wrapper = ccx.GetWrapper();
      49             : 
      50           8 :     if (wrapper)
      51           8 :         sz.reset(wrapper->ToString(ccx.GetTearOff()));
      52             :     else
      53           0 :         sz = JS_smprintf("[xpconnect wrapped native prototype]");
      54             : 
      55           8 :     if (!sz) {
      56           0 :         JS_ReportOutOfMemory(ccx);
      57           0 :         return false;
      58             :     }
      59             : 
      60           8 :     JSString* str = JS_NewStringCopyZ(ccx, sz.get());
      61           8 :     if (!str)
      62           0 :         return false;
      63             : 
      64           8 :     ccx.SetRetVal(JS::StringValue(str));
      65           8 :     return true;
      66             : }
      67             : 
      68             : /***************************************************************************/
      69             : 
      70             : static bool
      71           0 : XPC_WN_Shared_ToString(JSContext* cx, unsigned argc, Value* vp)
      72             : {
      73           0 :     CallArgs args = CallArgsFromVp(argc, vp);
      74           0 :     RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
      75           0 :     if (!obj)
      76           0 :         return false;
      77             : 
      78           0 :     XPCCallContext ccx(cx, obj);
      79           0 :     if (!ccx.IsValid())
      80           0 :         return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);
      81           0 :     ccx.SetName(ccx.GetContext()->GetStringID(XPCJSContext::IDX_TO_STRING));
      82           0 :     ccx.SetArgsAndResultPtr(args.length(), args.array(), vp);
      83           0 :     return ToStringGuts(ccx);
      84             : }
      85             : 
      86             : static bool
      87           0 : XPC_WN_Shared_ToSource(JSContext* cx, unsigned argc, Value* vp)
      88             : {
      89           0 :     CallArgs args = CallArgsFromVp(argc, vp);
      90             :     static const char empty[] = "({})";
      91           0 :     JSString* str = JS_NewStringCopyN(cx, empty, sizeof(empty)-1);
      92           0 :     if (!str)
      93           0 :         return false;
      94           0 :     args.rval().setString(str);
      95             : 
      96           0 :     return true;
      97             : }
      98             : 
      99             : static bool
     100         852 : XPC_WN_Shared_toPrimitive(JSContext* cx, unsigned argc, Value* vp)
     101             : {
     102         852 :     CallArgs args = CallArgsFromVp(argc, vp);
     103             : 
     104        1704 :     RootedObject obj(cx);
     105         852 :     if (!JS_ValueToObject(cx, args.thisv(), &obj))
     106           0 :         return false;
     107        1704 :     XPCCallContext ccx(cx, obj);
     108         852 :     XPCWrappedNative* wrapper = ccx.GetWrapper();
     109         852 :     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
     110             : 
     111             :     JSType hint;
     112         852 :     if (!GetFirstArgumentAsTypeHint(cx, args, &hint))
     113           0 :         return false;
     114             : 
     115         852 :     if (hint == JSTYPE_NUMBER) {
     116           0 :         args.rval().set(JS_GetNaNValue(cx));
     117           0 :         return true;
     118             :     }
     119             : 
     120         852 :     MOZ_ASSERT(hint == JSTYPE_STRING || hint == JSTYPE_UNDEFINED);
     121         852 :     ccx.SetName(ccx.GetContext()->GetStringID(XPCJSContext::IDX_TO_STRING));
     122         852 :     ccx.SetArgsAndResultPtr(0, nullptr, args.rval().address());
     123             : 
     124         852 :     XPCNativeMember* member = ccx.GetMember();
     125         852 :     if (member && member->IsMethod()) {
     126         844 :         if (!XPCWrappedNative::CallMethod(ccx))
     127           0 :             return false;
     128             : 
     129         844 :         if (args.rval().isPrimitive())
     130         844 :             return true;
     131             :     }
     132             : 
     133             :     // else...
     134           8 :     return ToStringGuts(ccx);
     135             : }
     136             : 
     137             : /***************************************************************************/
     138             : 
     139             : // A "double wrapped object" is a user JSObject that has been wrapped as a
     140             : // wrappedJS in order to be used by native code and then re-wrapped by a
     141             : // wrappedNative wrapper to be used by JS code. One might think of it as:
     142             : //    wrappedNative(wrappedJS(underlying_JSObject))
     143             : // This is done (as opposed to just unwrapping the wrapped JS and automatically
     144             : // returning the underlying JSObject) so that JS callers will see what looks
     145             : // Like any other xpcom object - and be limited to use its interfaces.
     146             : //
     147             : // See the comment preceding nsIXPCWrappedJSObjectGetter in nsIXPConnect.idl.
     148             : 
     149             : static JSObject*
     150           6 : GetDoubleWrappedJSObject(XPCCallContext& ccx, XPCWrappedNative* wrapper)
     151             : {
     152          12 :     RootedObject obj(ccx);
     153             :     nsCOMPtr<nsIXPConnectWrappedJS>
     154          12 :         underware = do_QueryInterface(wrapper->GetIdentityObject());
     155           6 :     if (underware) {
     156          12 :         RootedObject mainObj(ccx, underware->GetJSObject());
     157           6 :         if (mainObj) {
     158             :             RootedId id(ccx, ccx.GetContext()->
     159          12 :                             GetStringID(XPCJSContext::IDX_WRAPPED_JSOBJECT));
     160             : 
     161          12 :             JSAutoCompartment ac(ccx, mainObj);
     162             : 
     163          12 :             RootedValue val(ccx);
     164          12 :             if (JS_GetPropertyById(ccx, mainObj, id, &val) &&
     165           6 :                 !val.isPrimitive()) {
     166           6 :                 obj = val.toObjectOrNull();
     167             :             }
     168             :         }
     169             :     }
     170          12 :     return obj;
     171             : }
     172             : 
     173             : // This is the getter native function we use to handle 'wrappedJSObject' for
     174             : // double wrapped JSObjects.
     175             : 
     176             : static bool
     177           3 : XPC_WN_DoubleWrappedGetter(JSContext* cx, unsigned argc, Value* vp)
     178             : {
     179           3 :     CallArgs args = CallArgsFromVp(argc, vp);
     180             : 
     181           6 :     RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
     182           3 :     if (!obj)
     183           0 :         return false;
     184             : 
     185           6 :     XPCCallContext ccx(cx, obj);
     186           3 :     XPCWrappedNative* wrapper = ccx.GetWrapper();
     187           3 :     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
     188             : 
     189           3 :     MOZ_ASSERT(JS_TypeOfValue(cx, args.calleev()) == JSTYPE_FUNCTION, "bad function");
     190             : 
     191           6 :     RootedObject realObject(cx, GetDoubleWrappedJSObject(ccx, wrapper));
     192           3 :     if (!realObject) {
     193             :         // This is pretty unexpected at this point. The object originally
     194             :         // responded to this get property call and now gives no object.
     195             :         // XXX Should this throw something at the caller?
     196           0 :         args.rval().setNull();
     197           0 :         return true;
     198             :     }
     199             : 
     200             :     // It is a double wrapped object. This should really never appear in
     201             :     // content these days, but addons still do it - see bug 965921.
     202           3 :     if (MOZ_UNLIKELY(!nsContentUtils::IsSystemCaller(cx))) {
     203           0 :         JS_ReportErrorASCII(cx, "Attempt to use .wrappedJSObject in untrusted code");
     204           0 :         return false;
     205             :     }
     206           3 :     args.rval().setObject(*realObject);
     207           3 :     return JS_WrapValue(cx, args.rval());
     208             : }
     209             : 
     210             : /***************************************************************************/
     211             : 
     212             : // This is our shared function to define properties on our JSObjects.
     213             : 
     214             : /*
     215             :  * NOTE:
     216             :  * We *never* set the tearoff names (e.g. nsIFoo) as JS_ENUMERATE.
     217             :  * We *never* set toString or toSource as JS_ENUMERATE.
     218             :  */
     219             : 
     220             : static bool
     221        5576 : DefinePropertyIfFound(XPCCallContext& ccx,
     222             :                       HandleObject obj,
     223             :                       HandleId idArg,
     224             :                       XPCNativeSet* set,
     225             :                       XPCNativeInterface* ifaceArg,
     226             :                       XPCNativeMember* member,
     227             :                       XPCWrappedNativeScope* scope,
     228             :                       bool reflectToStringAndToSource,
     229             :                       XPCWrappedNative* wrapperToReflectInterfaceNames,
     230             :                       XPCWrappedNative* wrapperToReflectDoubleWrap,
     231             :                       nsIXPCScriptable* scr,
     232             :                       unsigned propFlags,
     233             :                       bool* resolved)
     234             : {
     235       11152 :     RootedId id(ccx, idArg);
     236       11152 :     RefPtr<XPCNativeInterface> iface = ifaceArg;
     237        5576 :     XPCJSContext* xpccx = ccx.GetContext();
     238             :     bool found;
     239             :     const char* name;
     240             : 
     241        5576 :     propFlags |= JSPROP_RESOLVING;
     242             : 
     243        5576 :     if (set) {
     244        5576 :         if (iface)
     245         298 :             found = true;
     246             :         else
     247        5278 :             found = set->FindMember(id, &member, &iface);
     248             :     } else
     249           0 :         found = (nullptr != (member = iface->FindMember(id)));
     250             : 
     251        5576 :     if (!found) {
     252        2768 :         if (reflectToStringAndToSource) {
     253             :             JSNative call;
     254        2768 :             uint32_t flags = 0;
     255             : 
     256        2768 :             if (scr) {
     257        5396 :                 nsCOMPtr<nsIClassInfo> classInfo = do_QueryInterface(scr);
     258             : 
     259        2698 :                 if (classInfo) {
     260        2686 :                     nsresult rv = classInfo->GetFlags(&flags);
     261        2686 :                     if (NS_FAILED(rv))
     262           0 :                         return Throw(rv, ccx);
     263             :                 }
     264             :             }
     265             : 
     266        2768 :             bool overwriteToString = !(flags & nsIClassInfo::DOM_OBJECT)
     267        2768 :                 || Preferences::GetBool("dom.XPCToStringForDOMClasses", false);
     268             : 
     269        8304 :             if(id == xpccx->GetStringID(XPCJSContext::IDX_TO_STRING)
     270        8304 :                 && overwriteToString)
     271             :             {
     272           0 :                 call = XPC_WN_Shared_ToString;
     273           0 :                 name = xpccx->GetStringName(XPCJSContext::IDX_TO_STRING);
     274        2768 :             } else if (id == xpccx->GetStringID(XPCJSContext::IDX_TO_SOURCE)) {
     275           0 :                 call = XPC_WN_Shared_ToSource;
     276           0 :                 name = xpccx->GetStringName(XPCJSContext::IDX_TO_SOURCE);
     277        2768 :             } else if (id == SYMBOL_TO_JSID(
     278        2768 :                                JS::GetWellKnownSymbol(ccx, JS::SymbolCode::toPrimitive)))
     279             :             {
     280          65 :                 call = XPC_WN_Shared_toPrimitive;
     281          65 :                 name = "[Symbol.toPrimitive]";
     282             :             } else {
     283        2703 :                 call = nullptr;
     284             :             }
     285             : 
     286        2768 :             if (call) {
     287         130 :                 RootedFunction fun(ccx, JS_NewFunction(ccx, call, 0, 0, name));
     288          65 :                 if (!fun) {
     289           0 :                     JS_ReportOutOfMemory(ccx);
     290           0 :                     return false;
     291             :                 }
     292             : 
     293         130 :                 AutoResolveName arn(ccx, id);
     294          65 :                 if (resolved)
     295          65 :                     *resolved = true;
     296         130 :                 RootedObject value(ccx, JS_GetFunctionObject(fun));
     297         130 :                 return JS_DefinePropertyById(ccx, obj, id, value,
     298          65 :                                              propFlags & ~JSPROP_ENUMERATE);
     299             :             }
     300             :         }
     301             :         // This *might* be a tearoff name that is not yet part of our
     302             :         // set. Let's lookup the name and see if it is the name of an
     303             :         // interface. Then we'll see if the object actually *does* this
     304             :         // interface and add a tearoff as necessary.
     305             : 
     306        2703 :         if (wrapperToReflectInterfaceNames) {
     307           6 :             JSAutoByteString name;
     308           6 :             RefPtr<XPCNativeInterface> iface2;
     309             :             XPCWrappedNativeTearOff* to;
     310           6 :             RootedObject jso(ccx);
     311           3 :             nsresult rv = NS_OK;
     312             : 
     313          12 :             if (JSID_IS_STRING(id) &&
     314           9 :                 name.encodeLatin1(ccx, JSID_TO_STRING(id)) &&
     315          12 :                 (iface2 = XPCNativeInterface::GetNewOrUsed(name.ptr())) &&
     316             :                 nullptr != (to = wrapperToReflectInterfaceNames->
     317           6 :                            FindTearOff(iface2, true, &rv)) &&
     318           3 :                 nullptr != (jso = to->GetJSObject()))
     319             : 
     320             :             {
     321           0 :                 AutoResolveName arn(ccx, id);
     322           0 :                 if (resolved)
     323           0 :                     *resolved = true;
     324           0 :                 return JS_DefinePropertyById(ccx, obj, id, jso,
     325           0 :                                              propFlags & ~JSPROP_ENUMERATE);
     326           3 :             } else if (NS_FAILED(rv) && rv != NS_ERROR_NO_INTERFACE) {
     327           0 :                 return Throw(rv, ccx);
     328             :             }
     329             :         }
     330             : 
     331             :         // This *might* be a double wrapped JSObject
     332        8112 :         if (wrapperToReflectDoubleWrap &&
     333        5415 :             id == xpccx->GetStringID(XPCJSContext::IDX_WRAPPED_JSOBJECT) &&
     334           3 :             GetDoubleWrappedJSObject(ccx, wrapperToReflectDoubleWrap)) {
     335             :             // We build and add a getter function.
     336             :             // A security check is done on a per-get basis.
     337             : 
     338             :             JSFunction* fun;
     339             : 
     340           3 :             id = xpccx->GetStringID(XPCJSContext::IDX_WRAPPED_JSOBJECT);
     341           3 :             name = xpccx->GetStringName(XPCJSContext::IDX_WRAPPED_JSOBJECT);
     342             : 
     343           3 :             fun = JS_NewFunction(ccx, XPC_WN_DoubleWrappedGetter,
     344           3 :                                  0, 0, name);
     345             : 
     346           3 :             if (!fun)
     347           0 :                 return false;
     348             : 
     349           6 :             RootedObject funobj(ccx, JS_GetFunctionObject(fun));
     350           3 :             if (!funobj)
     351           0 :                 return false;
     352             : 
     353           3 :             propFlags |= JSPROP_GETTER | JSPROP_SHARED;
     354           3 :             propFlags &= ~JSPROP_ENUMERATE;
     355             : 
     356           6 :             AutoResolveName arn(ccx, id);
     357           3 :             if (resolved)
     358           3 :                 *resolved = true;
     359           6 :             return JS_DefinePropertyById(ccx, obj, id, UndefinedHandleValue, propFlags,
     360           3 :                                          JS_DATA_TO_FUNC_PTR(JSNative, funobj.get()),
     361           3 :                                          nullptr);
     362             :         }
     363             : 
     364        2700 :         if (resolved)
     365        2700 :             *resolved = false;
     366        2700 :         return true;
     367             :     }
     368             : 
     369        2808 :     if (!member) {
     370           0 :         if (wrapperToReflectInterfaceNames) {
     371             :             XPCWrappedNativeTearOff* to =
     372           0 :               wrapperToReflectInterfaceNames->FindTearOff(iface, true);
     373             : 
     374           0 :             if (!to)
     375           0 :                 return false;
     376           0 :             RootedObject jso(ccx, to->GetJSObject());
     377           0 :             if (!jso)
     378           0 :                 return false;
     379             : 
     380           0 :             AutoResolveName arn(ccx, id);
     381           0 :             if (resolved)
     382           0 :                 *resolved = true;
     383           0 :             return JS_DefinePropertyById(ccx, obj, id, jso,
     384           0 :                                          propFlags & ~JSPROP_ENUMERATE);
     385             :         }
     386           0 :         if (resolved)
     387           0 :             *resolved = false;
     388           0 :         return true;
     389             :     }
     390             : 
     391        2808 :     if (member->IsConstant()) {
     392         106 :         RootedValue val(ccx);
     393         106 :         AutoResolveName arn(ccx, id);
     394          53 :         if (resolved)
     395          53 :             *resolved = true;
     396         212 :         return member->GetConstantValue(ccx, iface, val.address()) &&
     397         212 :                JS_DefinePropertyById(ccx, obj, id, val, propFlags);
     398             :     }
     399             : 
     400        2755 :     if (scope->HasInterposition()) {
     401           0 :         Rooted<PropertyDescriptor> desc(ccx);
     402           0 :         if (!xpc::InterposeProperty(ccx, obj, iface->GetIID(), id, &desc))
     403           0 :             return false;
     404             : 
     405           0 :         if (desc.object()) {
     406           0 :             AutoResolveName arn(ccx, id);
     407           0 :             if (resolved)
     408           0 :                 *resolved = true;
     409           0 :             desc.attributesRef() |= JSPROP_RESOLVING;
     410           0 :             return JS_DefinePropertyById(ccx, obj, id, desc);
     411             :         }
     412             :     }
     413             : 
     414       16514 :     if (id == xpccx->GetStringID(XPCJSContext::IDX_TO_STRING) ||
     415       16525 :         id == xpccx->GetStringID(XPCJSContext::IDX_TO_SOURCE) ||
     416        1330 :         (scr &&
     417        1480 :          scr->DontEnumQueryInterface() &&
     418        2905 :          id == xpccx->GetStringID(XPCJSContext::IDX_QUERY_INTERFACE)))
     419          11 :         propFlags &= ~JSPROP_ENUMERATE;
     420             : 
     421        5510 :     RootedValue funval(ccx);
     422        2755 :     if (!member->NewFunctionObject(ccx, iface, obj, funval.address()))
     423           0 :         return false;
     424             : 
     425        2755 :     if (member->IsMethod()) {
     426        2758 :         AutoResolveName arn(ccx, id);
     427        1379 :         if (resolved)
     428        1379 :             *resolved = true;
     429        1379 :         return JS_DefinePropertyById(ccx, obj, id, funval, propFlags);
     430             :     }
     431             : 
     432             :     // else...
     433             : 
     434        1376 :     MOZ_ASSERT(member->IsAttribute(), "way broken!");
     435             : 
     436        1376 :     propFlags |= JSPROP_GETTER | JSPROP_SHARED;
     437        1376 :     propFlags &= ~JSPROP_READONLY;
     438        1376 :     JSObject* funobj = funval.toObjectOrNull();
     439        1376 :     JSNative getter = JS_DATA_TO_FUNC_PTR(JSNative, funobj);
     440             :     JSNative setter;
     441        1376 :     if (member->IsWritableAttribute()) {
     442         216 :         propFlags |= JSPROP_SETTER;
     443         216 :         setter = JS_DATA_TO_FUNC_PTR(JSNative, funobj);
     444             :     } else {
     445        1160 :         setter = nullptr;
     446             :     }
     447             : 
     448        2752 :     AutoResolveName arn(ccx, id);
     449        1376 :     if (resolved)
     450        1376 :         *resolved = true;
     451             : 
     452        1376 :     return JS_DefinePropertyById(ccx, obj, id, UndefinedHandleValue, propFlags, getter, setter);
     453             : }
     454             : 
     455             : /***************************************************************************/
     456             : /***************************************************************************/
     457             : 
     458             : static bool
     459        1387 : XPC_WN_OnlyIWrite_AddPropertyStub(JSContext* cx, HandleObject obj, HandleId id, HandleValue v)
     460             : {
     461        2774 :     XPCCallContext ccx(cx, obj, nullptr, id);
     462        1387 :     XPCWrappedNative* wrapper = ccx.GetWrapper();
     463        1387 :     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
     464             : 
     465             :     // Allow only XPConnect to add/set the property
     466        1387 :     if (ccx.GetResolveName() == id)
     467        1387 :         return true;
     468             : 
     469           0 :     return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx);
     470             : }
     471             : 
     472             : bool
     473           0 : XPC_WN_CannotModifyPropertyStub(JSContext* cx, HandleObject obj, HandleId id,
     474             :                                 HandleValue v)
     475             : {
     476           0 :     return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx);
     477             : }
     478             : 
     479             : bool
     480           0 : XPC_WN_CannotDeletePropertyStub(JSContext* cx, HandleObject obj, HandleId id,
     481             :                                 ObjectOpResult& result)
     482             : {
     483           0 :     return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx);
     484             : }
     485             : 
     486             : bool
     487           0 : XPC_WN_CannotModifySetPropertyStub(JSContext* cx, HandleObject obj, HandleId id,
     488             :                                    MutableHandleValue vp, ObjectOpResult& result)
     489             : {
     490           0 :     return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx);
     491             : }
     492             : 
     493             : bool
     494           6 : XPC_WN_Shared_Enumerate(JSContext* cx, HandleObject obj)
     495             : {
     496          12 :     XPCCallContext ccx(cx, obj);
     497           6 :     XPCWrappedNative* wrapper = ccx.GetWrapper();
     498           6 :     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
     499             : 
     500             :     // Since we aren't going to enumerate tearoff names and the prototype
     501             :     // handles non-mutated members, we can do this potential short-circuit.
     502           6 :     if (!wrapper->HasMutatedSet())
     503           4 :         return true;
     504             : 
     505           2 :     XPCNativeSet* set = wrapper->GetSet();
     506           4 :     XPCNativeSet* protoSet = wrapper->HasProto() ?
     507           4 :                                 wrapper->GetProto()->GetSet() : nullptr;
     508             : 
     509           2 :     uint16_t interface_count = set->GetInterfaceCount();
     510           2 :     XPCNativeInterface** interfaceArray = set->GetInterfaceArray();
     511          10 :     for (uint16_t i = 0; i < interface_count; i++) {
     512           8 :         XPCNativeInterface* iface = interfaceArray[i];
     513           8 :         uint16_t member_count = iface->GetMemberCount();
     514          98 :         for (uint16_t k = 0; k < member_count; k++) {
     515          90 :             XPCNativeMember* member = iface->GetMemberAt(k);
     516          90 :             jsid name = member->GetName();
     517             : 
     518             :             // Skip if this member is going to come from the proto.
     519             :             uint16_t index;
     520         180 :             if (protoSet &&
     521         174 :                 protoSet->FindMember(name, nullptr, &index) && index == i)
     522          78 :                 continue;
     523          12 :             if (!xpc_ForcePropertyResolve(cx, obj, name))
     524           0 :                 return false;
     525             :         }
     526             :     }
     527           2 :     return true;
     528             : }
     529             : 
     530             : /***************************************************************************/
     531             : 
     532             : enum WNHelperType {
     533             :     WN_NOHELPER,
     534             :     WN_HELPER
     535             : };
     536             : 
     537             : static void
     538           0 : WrappedNativeFinalize(js::FreeOp* fop, JSObject* obj, WNHelperType helperType)
     539             : {
     540           0 :     const js::Class* clazz = js::GetObjectClass(obj);
     541           0 :     if (clazz->flags & JSCLASS_DOM_GLOBAL) {
     542           0 :         mozilla::dom::DestroyProtoAndIfaceCache(obj);
     543             :     }
     544           0 :     nsISupports* p = static_cast<nsISupports*>(xpc_GetJSPrivate(obj));
     545           0 :     if (!p)
     546           0 :         return;
     547             : 
     548           0 :     XPCWrappedNative* wrapper = static_cast<XPCWrappedNative*>(p);
     549           0 :     if (helperType == WN_HELPER)
     550           0 :         wrapper->GetScriptable()->Finalize(wrapper, js::CastToJSFreeOp(fop), obj);
     551           0 :     wrapper->FlatJSObjectFinalized();
     552             : }
     553             : 
     554             : static void
     555           0 : WrappedNativeObjectMoved(JSObject* obj, const JSObject* old)
     556             : {
     557           0 :     nsISupports* p = static_cast<nsISupports*>(xpc_GetJSPrivate(obj));
     558           0 :     if (!p)
     559           0 :         return;
     560             : 
     561           0 :     XPCWrappedNative* wrapper = static_cast<XPCWrappedNative*>(p);
     562           0 :     wrapper->FlatJSObjectMoved(obj, old);
     563             : }
     564             : 
     565             : void
     566           0 : XPC_WN_NoHelper_Finalize(js::FreeOp* fop, JSObject* obj)
     567             : {
     568           0 :     WrappedNativeFinalize(fop, obj, WN_NOHELPER);
     569           0 : }
     570             : 
     571             : /*
     572             :  * General comment about XPConnect tracing: Given a C++ object |wrapper| and its
     573             :  * corresponding JS object |obj|, calling |wrapper->TraceSelf| will ask the JS
     574             :  * engine to mark |obj|. Eventually, this will lead to the trace hook being
     575             :  * called for |obj|. The trace hook should call |wrapper->TraceInside|, which
     576             :  * should mark any JS objects held by |wrapper| as members.
     577             :  */
     578             : 
     579             : /* static */ void
     580         183 : XPCWrappedNative::Trace(JSTracer* trc, JSObject* obj)
     581             : {
     582         183 :     const js::Class* clazz = js::GetObjectClass(obj);
     583         183 :     if (clazz->flags & JSCLASS_DOM_GLOBAL) {
     584           0 :         mozilla::dom::TraceProtoAndIfaceCache(trc, obj);
     585             :     }
     586         183 :     MOZ_ASSERT(IS_WN_CLASS(clazz));
     587             : 
     588         183 :     XPCWrappedNative* wrapper = XPCWrappedNative::Get(obj);
     589         183 :     if (wrapper && wrapper->IsValid())
     590         183 :         wrapper->TraceInside(trc);
     591         183 : }
     592             : 
     593             : void
     594         177 : XPCWrappedNative_Trace(JSTracer* trc, JSObject* obj)
     595             : {
     596         177 :     XPCWrappedNative::Trace(trc, obj);
     597         177 : }
     598             : 
     599             : static bool
     600        2528 : XPC_WN_NoHelper_Resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp)
     601             : {
     602        5056 :     XPCCallContext ccx(cx, obj, nullptr, id);
     603        2528 :     XPCWrappedNative* wrapper = ccx.GetWrapper();
     604        2528 :     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
     605             : 
     606        2528 :     XPCNativeSet* set = ccx.GetSet();
     607        2528 :     if (!set)
     608           0 :         return true;
     609             : 
     610             :     // Don't resolve properties that are on our prototype.
     611        2528 :     if (ccx.GetInterface() && !ccx.GetStaticMemberIsLocal())
     612        1141 :         return true;
     613             : 
     614        1387 :     return DefinePropertyIfFound(ccx, obj, id,
     615             :                                  set, nullptr, nullptr, wrapper->GetScope(),
     616             :                                  true, wrapper, wrapper, nullptr,
     617             :                                  JSPROP_ENUMERATE |
     618             :                                  JSPROP_READONLY |
     619             :                                  JSPROP_PERMANENT,
     620        1387 :                                  resolvedp);
     621             : }
     622             : 
     623             : static const js::ClassOps XPC_WN_NoHelper_JSClassOps = {
     624             :     XPC_WN_OnlyIWrite_AddPropertyStub, // addProperty
     625             :     XPC_WN_CannotDeletePropertyStub,   // delProperty
     626             :     nullptr,                           // getProperty
     627             :     nullptr,                           // setProperty
     628             :     XPC_WN_Shared_Enumerate,           // enumerate
     629             :     nullptr,                           // newEnumerate
     630             :     XPC_WN_NoHelper_Resolve,           // resolve
     631             :     nullptr,                           // mayResolve
     632             :     XPC_WN_NoHelper_Finalize,          // finalize
     633             :     nullptr,                           // call
     634             :     nullptr,                           // construct
     635             :     nullptr,                           // hasInstance
     636             :     XPCWrappedNative::Trace,           // trace
     637             : };
     638             : 
     639             : const js::ClassExtension XPC_WN_JSClassExtension = {
     640             :     nullptr, // weakmapKeyDelegateOp
     641             :     WrappedNativeObjectMoved
     642             : };
     643             : 
     644             : const js::Class XPC_WN_NoHelper_JSClass = {
     645             :     "XPCWrappedNative_NoHelper",
     646             :     XPC_WRAPPER_FLAGS |
     647             :     JSCLASS_IS_WRAPPED_NATIVE |
     648             :     JSCLASS_PRIVATE_IS_NSISUPPORTS |
     649             :     JSCLASS_FOREGROUND_FINALIZE,
     650             :     &XPC_WN_NoHelper_JSClassOps,
     651             :     JS_NULL_CLASS_SPEC,
     652             :     &XPC_WN_JSClassExtension,
     653             :     JS_NULL_OBJECT_OPS
     654             : };
     655             : 
     656             : 
     657             : /***************************************************************************/
     658             : 
     659             : bool
     660        1408 : XPC_WN_MaybeResolvingPropertyStub(JSContext* cx, HandleObject obj, HandleId id, HandleValue v)
     661             : {
     662        2816 :     XPCCallContext ccx(cx, obj);
     663        1408 :     XPCWrappedNative* wrapper = ccx.GetWrapper();
     664        1408 :     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
     665             : 
     666        1408 :     if (ccx.GetResolvingWrapper() == wrapper)
     667        1408 :         return true;
     668           0 :     return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx);
     669             : }
     670             : 
     671             : bool
     672           0 : XPC_WN_MaybeResolvingSetPropertyStub(JSContext* cx, HandleObject obj, HandleId id,
     673             :                                      MutableHandleValue vp, ObjectOpResult& result)
     674             : {
     675           0 :     result.succeed();
     676           0 :     return XPC_WN_MaybeResolvingPropertyStub(cx, obj, id, vp);
     677             : }
     678             : 
     679             : bool
     680           0 : XPC_WN_MaybeResolvingDeletePropertyStub(JSContext* cx, HandleObject obj, HandleId id,
     681             :                                         ObjectOpResult& result)
     682             : {
     683           0 :     XPCCallContext ccx(cx, obj);
     684           0 :     XPCWrappedNative* wrapper = ccx.GetWrapper();
     685           0 :     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
     686             : 
     687           0 :     if (ccx.GetResolvingWrapper() == wrapper) {
     688           0 :         return result.succeed();
     689             :     }
     690           0 :     return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx);
     691             : }
     692             : 
     693             : // macro fun!
     694             : #define PRE_HELPER_STUB                                                       \
     695             :     /* It's very important for "unwrapped" to be rooted here.  */             \
     696             :     RootedObject unwrapped(cx, js::CheckedUnwrap(obj, false));                \
     697             :     if (!unwrapped) {                                                         \
     698             :         JS_ReportErrorASCII(cx, "Permission denied to operate on object.");   \
     699             :         return false;                                                         \
     700             :     }                                                                         \
     701             :     if (!IS_WN_REFLECTOR(unwrapped)) {                                        \
     702             :         return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);                    \
     703             :     }                                                                         \
     704             :     XPCWrappedNative* wrapper = XPCWrappedNative::Get(unwrapped);             \
     705             :     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);                             \
     706             :     bool retval = true;                                                       \
     707             :     nsresult rv = wrapper->GetScriptable()->
     708             : 
     709             : #define POST_HELPER_STUB                                                      \
     710             :     if (NS_FAILED(rv))                                                        \
     711             :         return Throw(rv, cx);                                                 \
     712             :     return retval;
     713             : 
     714             : #define POST_HELPER_STUB_WITH_OBJECTOPRESULT(failMethod)                      \
     715             :     if (NS_FAILED(rv))                                                        \
     716             :         return Throw(rv, cx);                                                 \
     717             :     return retval ? result.succeed() : result.failMethod();
     718             : 
     719             : bool
     720           6 : XPC_WN_Helper_GetProperty(JSContext* cx, HandleObject obj, HandleId id,
     721             :                           MutableHandleValue vp)
     722             : {
     723          12 :     PRE_HELPER_STUB
     724           6 :     GetProperty(wrapper, cx, obj, id, vp.address(), &retval);
     725           6 :     POST_HELPER_STUB
     726             : }
     727             : 
     728             : bool
     729           6 : XPC_WN_Helper_SetProperty(JSContext* cx, HandleObject obj, HandleId id,
     730             :                           MutableHandleValue vp, ObjectOpResult& result)
     731             : {
     732          12 :     PRE_HELPER_STUB
     733           6 :     SetProperty(wrapper, cx, obj, id, vp.address(), &retval);
     734           6 :     POST_HELPER_STUB_WITH_OBJECTOPRESULT(failReadOnly)
     735             : }
     736             : 
     737             : bool
     738          93 : XPC_WN_Helper_Call(JSContext* cx, unsigned argc, Value* vp)
     739             : {
     740          93 :     JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
     741             :     // N.B. we want obj to be the callee, not JS_THIS(cx, vp)
     742         186 :     RootedObject obj(cx, &args.callee());
     743             : 
     744             :     XPCCallContext ccx(cx, obj, nullptr, JSID_VOIDHANDLE, args.length(),
     745         186 :                        args.array(), args.rval().address());
     746          93 :     if (!ccx.IsValid())
     747           0 :         return false;
     748             : 
     749         186 :     PRE_HELPER_STUB
     750          93 :     Call(wrapper, cx, obj, args, &retval);
     751          93 :     POST_HELPER_STUB
     752             : }
     753             : 
     754             : bool
     755          41 : XPC_WN_Helper_Construct(JSContext* cx, unsigned argc, Value* vp)
     756             : {
     757          41 :     JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
     758          82 :     RootedObject obj(cx, &args.callee());
     759          41 :     if (!obj)
     760           0 :         return false;
     761             : 
     762             :     XPCCallContext ccx(cx, obj, nullptr, JSID_VOIDHANDLE, args.length(),
     763          82 :                        args.array(), args.rval().address());
     764          41 :     if (!ccx.IsValid())
     765           0 :         return false;
     766             : 
     767          82 :     PRE_HELPER_STUB
     768          41 :     Construct(wrapper, cx, obj, args, &retval);
     769          41 :     POST_HELPER_STUB
     770             : }
     771             : 
     772             : bool
     773         163 : XPC_WN_Helper_HasInstance(JSContext* cx, HandleObject obj, MutableHandleValue valp, bool* bp)
     774             : {
     775             :     bool retval2;
     776         326 :     PRE_HELPER_STUB
     777         163 :     HasInstance(wrapper, cx, obj, valp, &retval2, &retval);
     778         163 :     *bp = retval2;
     779         163 :     POST_HELPER_STUB
     780             : }
     781             : 
     782             : void
     783           0 : XPC_WN_Helper_Finalize(js::FreeOp* fop, JSObject* obj)
     784             : {
     785           0 :     WrappedNativeFinalize(fop, obj, WN_HELPER);
     786           0 : }
     787             : 
     788             : bool
     789       19330 : XPC_WN_Helper_Resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp)
     790             : {
     791       19330 :     nsresult rv = NS_OK;
     792       19330 :     bool retval = true;
     793       19330 :     bool resolved = false;
     794       38660 :     XPCCallContext ccx(cx, obj);
     795       19330 :     XPCWrappedNative* wrapper = ccx.GetWrapper();
     796       19330 :     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
     797             : 
     798       38660 :     RootedId old(cx, ccx.SetResolveName(id));
     799             : 
     800       38660 :     nsCOMPtr<nsIXPCScriptable> scr = wrapper->GetScriptable();
     801       19330 :     if (scr && scr->WantResolve()) {
     802             :         XPCWrappedNative* oldResolvingWrapper;
     803       17213 :         bool allowPropMods = scr->AllowPropModsDuringResolve();
     804             : 
     805       17213 :         if (allowPropMods)
     806        2771 :             oldResolvingWrapper = ccx.SetResolvingWrapper(wrapper);
     807             : 
     808       17213 :         rv = scr->Resolve(wrapper, cx, obj, id, &resolved, &retval);
     809             : 
     810       17213 :         if (allowPropMods)
     811        2771 :             (void)ccx.SetResolvingWrapper(oldResolvingWrapper);
     812             :     }
     813             : 
     814       19330 :     old = ccx.SetResolveName(old);
     815       19330 :     MOZ_ASSERT(old == id, "bad nest");
     816             : 
     817       19330 :     if (NS_FAILED(rv)) {
     818           0 :         return Throw(rv, cx);
     819             :     }
     820             : 
     821       19330 :     if (resolved) {
     822        1371 :         *resolvedp = true;
     823       17959 :     } else if (wrapper->HasMutatedSet()) {
     824             :         // We are here if scriptable did not resolve this property and
     825             :         // it *might* be in the instance set but not the proto set.
     826             : 
     827         298 :         XPCNativeSet* set = wrapper->GetSet();
     828         298 :         XPCNativeSet* protoSet = wrapper->HasProto() ?
     829         298 :                                     wrapper->GetProto()->GetSet() : nullptr;
     830         298 :         XPCNativeMember* member = nullptr;
     831         596 :         RefPtr<XPCNativeInterface> iface;
     832         298 :         bool IsLocal = false;
     833             : 
     834         298 :         if (set->FindMember(id, &member, &iface, protoSet, &IsLocal) &&
     835             :             IsLocal) {
     836             : 
     837             :             XPCWrappedNative* wrapperForInterfaceNames =
     838         298 :                 (scr && scr->DontReflectInterfaceNames()) ? nullptr : wrapper;
     839             : 
     840             :             XPCWrappedNative* oldResolvingWrapper =
     841         298 :                 ccx.SetResolvingWrapper(wrapper);
     842         298 :             retval = DefinePropertyIfFound(ccx, obj, id,
     843             :                                            set, iface, member,
     844             :                                            wrapper->GetScope(),
     845             :                                            false,
     846             :                                            wrapperForInterfaceNames,
     847             :                                            nullptr, scr,
     848             :                                            JSPROP_ENUMERATE, resolvedp);
     849         298 :             (void)ccx.SetResolvingWrapper(oldResolvingWrapper);
     850             :         }
     851             :     }
     852             : 
     853       19330 :     return retval;
     854             : }
     855             : 
     856             : bool
     857           1 : XPC_WN_Helper_Enumerate(JSContext* cx, HandleObject obj)
     858             : {
     859           2 :     XPCCallContext ccx(cx, obj);
     860           1 :     XPCWrappedNative* wrapper = ccx.GetWrapper();
     861           1 :     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
     862             : 
     863           2 :     nsCOMPtr<nsIXPCScriptable> scr = wrapper->GetScriptable();
     864           1 :     if (!scr || !scr->WantEnumerate())
     865           0 :         return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);
     866             : 
     867           1 :     if (!XPC_WN_Shared_Enumerate(cx, obj))
     868           0 :         return false;
     869             : 
     870           1 :     bool retval = true;
     871           1 :     nsresult rv = scr->Enumerate(wrapper, cx, obj, &retval);
     872           1 :     if (NS_FAILED(rv))
     873           0 :         return Throw(rv, cx);
     874           1 :     return retval;
     875             : }
     876             : 
     877             : /***************************************************************************/
     878             : 
     879             : bool
     880           3 : XPC_WN_NewEnumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties,
     881             :                     bool enumerableOnly)
     882             : {
     883           6 :     XPCCallContext ccx(cx, obj);
     884           3 :     XPCWrappedNative* wrapper = ccx.GetWrapper();
     885           3 :     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
     886             : 
     887           6 :     nsCOMPtr<nsIXPCScriptable> scr = wrapper->GetScriptable();
     888           3 :     if (!scr || !scr->WantNewEnumerate())
     889           0 :         return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);
     890             : 
     891           3 :     if (!XPC_WN_Shared_Enumerate(cx, obj))
     892           0 :         return false;
     893             : 
     894           3 :     bool retval = true;
     895           3 :     nsresult rv = scr->NewEnumerate(wrapper, cx, obj, properties, &retval);
     896           3 :     if (NS_FAILED(rv))
     897           0 :         return Throw(rv, cx);
     898           3 :     return retval;
     899             : }
     900             : 
     901             : /***************************************************************************/
     902             : /***************************************************************************/
     903             : 
     904             : // Compatibility hack.
     905             : //
     906             : // XPConnect used to do all sorts of funny tricks to find the "correct"
     907             : // |this| object for a given method (often to the detriment of proper
     908             : // call/apply). When these tricks were removed, a fair amount of chrome
     909             : // code broke, because it was relying on being able to grab methods off
     910             : // some XPCOM object (like the nsITelemetry service) and invoke them without
     911             : // a proper |this|. So, if it's quite clear that we're in this situation and
     912             : // about to use a |this| argument that just won't work, fix things up.
     913             : //
     914             : // This hack is only useful for getters/setters if someone sets an XPCOM object
     915             : // as the prototype for a vanilla JS object and expects the XPCOM attributes to
     916             : // work on the derived object, which we really don't want to support. But we
     917             : // handle it anyway, for now, to minimize regression risk on an already-risky
     918             : // landing.
     919             : //
     920             : // This hack is mainly useful for the NoHelper JSClass. We also fix up
     921             : // Components.utils because it implements nsIXPCScriptable (giving it a custom
     922             : // JSClass) but not nsIClassInfo (which would put the methods on a prototype).
     923             : 
     924             : #define IS_NOHELPER_CLASS(clasp) (clasp == &XPC_WN_NoHelper_JSClass)
     925             : #define IS_CU_CLASS(clasp) (clasp->name[0] == 'n' && !strcmp(clasp->name, "nsXPCComponents_Utils"))
     926             : 
     927             : MOZ_ALWAYS_INLINE JSObject*
     928       11152 : FixUpThisIfBroken(JSObject* obj, JSObject* funobj)
     929             : {
     930       11152 :     if (funobj) {
     931             :         JSObject* parentObj =
     932             :             &js::GetFunctionNativeReserved(funobj,
     933       11152 :                                            XPC_FUNCTION_PARENT_OBJECT_SLOT).toObject();
     934       11152 :         const js::Class* parentClass = js::GetObjectClass(parentObj);
     935       11152 :         if (MOZ_UNLIKELY((IS_NOHELPER_CLASS(parentClass) || IS_CU_CLASS(parentClass)) &&
     936             :                          (js::GetObjectClass(obj) != parentClass)))
     937             :         {
     938          20 :             return parentObj;
     939             :         }
     940             :     }
     941       11132 :     return obj;
     942             : }
     943             : 
     944             : bool
     945        8249 : XPC_WN_CallMethod(JSContext* cx, unsigned argc, Value* vp)
     946             : {
     947        8249 :     JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
     948        8249 :     MOZ_ASSERT(JS_TypeOfValue(cx, args.calleev()) == JSTYPE_FUNCTION, "bad function");
     949       16497 :     RootedObject funobj(cx, &args.callee());
     950             : 
     951       16497 :     RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
     952        8249 :     if (!obj)
     953           0 :         return false;
     954             : 
     955        8249 :     obj = FixUpThisIfBroken(obj, funobj);
     956             :     XPCCallContext ccx(cx, obj, funobj, JSID_VOIDHANDLE, args.length(),
     957       16497 :                        args.array(), vp);
     958        8249 :     XPCWrappedNative* wrapper = ccx.GetWrapper();
     959        8249 :     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
     960             : 
     961       16497 :     RefPtr<XPCNativeInterface> iface;
     962             :     XPCNativeMember*    member;
     963             : 
     964        8249 :     if (!XPCNativeMember::GetCallInfo(funobj, &iface, &member))
     965           0 :         return Throw(NS_ERROR_XPC_CANT_GET_METHOD_INFO, cx);
     966        8249 :     ccx.SetCallInfo(iface, member, false);
     967        8249 :     return XPCWrappedNative::CallMethod(ccx);
     968             : }
     969             : 
     970             : bool
     971        2903 : XPC_WN_GetterSetter(JSContext* cx, unsigned argc, Value* vp)
     972             : {
     973        2903 :     JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
     974        2903 :     MOZ_ASSERT(JS_TypeOfValue(cx, args.calleev()) == JSTYPE_FUNCTION, "bad function");
     975        5806 :     RootedObject funobj(cx, &args.callee());
     976             : 
     977        5806 :     RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
     978        2903 :     if (!obj)
     979           0 :         return false;
     980             : 
     981        2903 :     obj = FixUpThisIfBroken(obj, funobj);
     982             :     XPCCallContext ccx(cx, obj, funobj, JSID_VOIDHANDLE, args.length(),
     983        5806 :                        args.array(), vp);
     984        2903 :     XPCWrappedNative* wrapper = ccx.GetWrapper();
     985        2903 :     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
     986             : 
     987        5806 :     RefPtr<XPCNativeInterface> iface;
     988             :     XPCNativeMember*    member;
     989             : 
     990        2903 :     if (!XPCNativeMember::GetCallInfo(funobj, &iface, &member))
     991           0 :         return Throw(NS_ERROR_XPC_CANT_GET_METHOD_INFO, cx);
     992             : 
     993        2903 :     if (args.length() != 0 && member->IsWritableAttribute()) {
     994          38 :         ccx.SetCallInfo(iface, member, true);
     995          38 :         bool retval = XPCWrappedNative::SetAttribute(ccx);
     996          38 :         if (retval)
     997          38 :             args.rval().set(args[0]);
     998          38 :         return retval;
     999             :     }
    1000             :     // else...
    1001             : 
    1002        2865 :     ccx.SetCallInfo(iface, member, false);
    1003        2865 :     return XPCWrappedNative::GetAttribute(ccx);
    1004             : }
    1005             : 
    1006             : /***************************************************************************/
    1007             : 
    1008             : static bool
    1009           1 : XPC_WN_Shared_Proto_Enumerate(JSContext* cx, HandleObject obj)
    1010             : {
    1011           1 :     MOZ_ASSERT(js::GetObjectClass(obj) == &XPC_WN_ModsAllowed_Proto_JSClass ||
    1012             :                js::GetObjectClass(obj) == &XPC_WN_NoMods_Proto_JSClass,
    1013             :                "bad proto");
    1014             :     XPCWrappedNativeProto* self =
    1015           1 :         (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
    1016           1 :     if (!self)
    1017           0 :         return false;
    1018             : 
    1019           1 :     XPCNativeSet* set = self->GetSet();
    1020           1 :     if (!set)
    1021           0 :         return false;
    1022             : 
    1023           2 :     XPCCallContext ccx(cx);
    1024           1 :     if (!ccx.IsValid())
    1025           0 :         return false;
    1026             : 
    1027           1 :     uint16_t interface_count = set->GetInterfaceCount();
    1028           1 :     XPCNativeInterface** interfaceArray = set->GetInterfaceArray();
    1029           4 :     for (uint16_t i = 0; i < interface_count; i++) {
    1030           3 :         XPCNativeInterface* iface = interfaceArray[i];
    1031           3 :         uint16_t member_count = iface->GetMemberCount();
    1032             : 
    1033          16 :         for (uint16_t k = 0; k < member_count; k++) {
    1034          13 :             if (!xpc_ForcePropertyResolve(cx, obj, iface->GetMemberAt(k)->GetName()))
    1035           0 :                 return false;
    1036             :         }
    1037             :     }
    1038             : 
    1039           1 :     return true;
    1040             : }
    1041             : 
    1042             : static void
    1043           0 : XPC_WN_Shared_Proto_Finalize(js::FreeOp* fop, JSObject* obj)
    1044             : {
    1045             :     // This can be null if xpc shutdown has already happened
    1046           0 :     XPCWrappedNativeProto* p = (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
    1047           0 :     if (p)
    1048           0 :         p->JSProtoObjectFinalized(fop, obj);
    1049           0 : }
    1050             : 
    1051             : static void
    1052           0 : XPC_WN_Shared_Proto_ObjectMoved(JSObject* obj, const JSObject* old)
    1053             : {
    1054             :     // This can be null if xpc shutdown has already happened
    1055           0 :     XPCWrappedNativeProto* p = (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
    1056           0 :     if (p)
    1057           0 :         p->JSProtoObjectMoved(obj, old);
    1058           0 : }
    1059             : 
    1060             : static void
    1061          24 : XPC_WN_Shared_Proto_Trace(JSTracer* trc, JSObject* obj)
    1062             : {
    1063             :     // This can be null if xpc shutdown has already happened
    1064             :     XPCWrappedNativeProto* p =
    1065          24 :         (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
    1066          24 :     if (p)
    1067          24 :         p->TraceInside(trc);
    1068          24 : }
    1069             : 
    1070             : /*****************************************************/
    1071             : 
    1072             : static bool
    1073         121 : XPC_WN_ModsAllowed_Proto_Resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvep)
    1074             : {
    1075         121 :     MOZ_ASSERT(js::GetObjectClass(obj) == &XPC_WN_ModsAllowed_Proto_JSClass,
    1076             :                "bad proto");
    1077             : 
    1078             :     XPCWrappedNativeProto* self =
    1079         121 :         (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
    1080         121 :     if (!self)
    1081           0 :         return false;
    1082             : 
    1083         242 :     XPCCallContext ccx(cx);
    1084         121 :     if (!ccx.IsValid())
    1085           0 :         return false;
    1086             : 
    1087         242 :     nsCOMPtr<nsIXPCScriptable> scr = self->GetScriptable();
    1088         121 :     return DefinePropertyIfFound(ccx, obj, id,
    1089             :                                  self->GetSet(), nullptr, nullptr,
    1090             :                                  self->GetScope(),
    1091             :                                  true, nullptr, nullptr, scr,
    1092         121 :                                  JSPROP_ENUMERATE, resolvep);
    1093             : }
    1094             : 
    1095             : static const js::ClassOps XPC_WN_ModsAllowed_Proto_JSClassOps = {
    1096             :     nullptr,                            // addProperty
    1097             :     nullptr,                            // delProperty
    1098             :     nullptr,                            // getProperty
    1099             :     nullptr,                            // setProperty
    1100             :     XPC_WN_Shared_Proto_Enumerate,      // enumerate
    1101             :     nullptr,                            // newEnumerate
    1102             :     XPC_WN_ModsAllowed_Proto_Resolve,   // resolve
    1103             :     nullptr,                            // mayResolve
    1104             :     XPC_WN_Shared_Proto_Finalize,       // finalize
    1105             :     nullptr,                            // call
    1106             :     nullptr,                            // construct
    1107             :     nullptr,                            // hasInstance
    1108             :     XPC_WN_Shared_Proto_Trace,          // trace
    1109             : };
    1110             : 
    1111             : static const js::ClassExtension XPC_WN_Shared_Proto_ClassExtension = {
    1112             :     nullptr,    /* weakmapKeyDelegateOp */
    1113             :     XPC_WN_Shared_Proto_ObjectMoved
    1114             : };
    1115             : 
    1116             : const js::Class XPC_WN_ModsAllowed_Proto_JSClass = {
    1117             :     "XPC_WN_ModsAllowed_Proto_JSClass",
    1118             :     XPC_WRAPPER_FLAGS,
    1119             :     &XPC_WN_ModsAllowed_Proto_JSClassOps,
    1120             :     JS_NULL_CLASS_SPEC,
    1121             :     &XPC_WN_Shared_Proto_ClassExtension,
    1122             :     JS_NULL_OBJECT_OPS
    1123             : };
    1124             : 
    1125             : /***************************************************************************/
    1126             : 
    1127             : static bool
    1128        1118 : XPC_WN_OnlyIWrite_Proto_AddPropertyStub(JSContext* cx, HandleObject obj, HandleId id,
    1129             :                                         HandleValue v)
    1130             : {
    1131        1118 :     MOZ_ASSERT(js::GetObjectClass(obj) == &XPC_WN_NoMods_Proto_JSClass,
    1132             :                "bad proto");
    1133             : 
    1134             :     XPCWrappedNativeProto* self =
    1135        1118 :         (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
    1136        1118 :     if (!self)
    1137           0 :         return false;
    1138             : 
    1139        2236 :     XPCCallContext ccx(cx);
    1140        1118 :     if (!ccx.IsValid())
    1141           0 :         return false;
    1142             : 
    1143             :     // Allow XPConnect to add the property only
    1144        1118 :     if (ccx.GetResolveName() == id)
    1145        1118 :         return true;
    1146             : 
    1147           0 :     return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);
    1148             : }
    1149             : 
    1150             : static bool
    1151        3770 : XPC_WN_NoMods_Proto_Resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp)
    1152             : {
    1153        3770 :     MOZ_ASSERT(js::GetObjectClass(obj) == &XPC_WN_NoMods_Proto_JSClass,
    1154             :                "bad proto");
    1155             : 
    1156             :     XPCWrappedNativeProto* self =
    1157        3770 :         (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
    1158        3770 :     if (!self)
    1159           0 :         return false;
    1160             : 
    1161        7540 :     XPCCallContext ccx(cx);
    1162        3770 :     if (!ccx.IsValid())
    1163           0 :         return false;
    1164             : 
    1165        7540 :     nsCOMPtr<nsIXPCScriptable> scr = self->GetScriptable();
    1166             : 
    1167        3770 :     return DefinePropertyIfFound(ccx, obj, id,
    1168             :                                  self->GetSet(), nullptr, nullptr,
    1169             :                                  self->GetScope(),
    1170             :                                  true, nullptr, nullptr, scr,
    1171             :                                  JSPROP_READONLY |
    1172             :                                  JSPROP_PERMANENT |
    1173        3770 :                                  JSPROP_ENUMERATE, resolvedp);
    1174             : }
    1175             : 
    1176             : static const js::ClassOps XPC_WN_NoMods_Proto_JSClassOps = {
    1177             :     XPC_WN_OnlyIWrite_Proto_AddPropertyStub,   // addProperty
    1178             :     XPC_WN_CannotDeletePropertyStub,           // delProperty
    1179             :     nullptr,                                   // getProperty
    1180             :     nullptr,                                   // setProperty
    1181             :     XPC_WN_Shared_Proto_Enumerate,             // enumerate
    1182             :     nullptr,                                   // newEnumerate
    1183             :     XPC_WN_NoMods_Proto_Resolve,               // resolve
    1184             :     nullptr,                                   // mayResolve
    1185             :     XPC_WN_Shared_Proto_Finalize,              // finalize
    1186             :     nullptr,                                   // call
    1187             :     nullptr,                                   // construct
    1188             :     nullptr,                                   // hasInstance
    1189             :     XPC_WN_Shared_Proto_Trace,                 // trace
    1190             : };
    1191             : 
    1192             : const js::Class XPC_WN_NoMods_Proto_JSClass = {
    1193             :     "XPC_WN_NoMods_Proto_JSClass",
    1194             :     XPC_WRAPPER_FLAGS,
    1195             :     &XPC_WN_NoMods_Proto_JSClassOps,
    1196             :     JS_NULL_CLASS_SPEC,
    1197             :     &XPC_WN_Shared_Proto_ClassExtension,
    1198             :     JS_NULL_OBJECT_OPS
    1199             : };
    1200             : 
    1201             : /***************************************************************************/
    1202             : 
    1203             : static bool
    1204           0 : XPC_WN_TearOff_Enumerate(JSContext* cx, HandleObject obj)
    1205             : {
    1206           0 :     XPCCallContext ccx(cx, obj);
    1207           0 :     XPCWrappedNative* wrapper = ccx.GetWrapper();
    1208           0 :     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
    1209             : 
    1210           0 :     XPCWrappedNativeTearOff* to = ccx.GetTearOff();
    1211             :     XPCNativeInterface* iface;
    1212             : 
    1213           0 :     if (!to || nullptr == (iface = to->GetInterface()))
    1214           0 :         return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);
    1215             : 
    1216           0 :     uint16_t member_count = iface->GetMemberCount();
    1217           0 :     for (uint16_t k = 0; k < member_count; k++) {
    1218           0 :         if (!xpc_ForcePropertyResolve(cx, obj, iface->GetMemberAt(k)->GetName()))
    1219           0 :             return false;
    1220             :     }
    1221             : 
    1222           0 :     return true;
    1223             : }
    1224             : 
    1225             : static bool
    1226           0 : XPC_WN_TearOff_Resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp)
    1227             : {
    1228           0 :     XPCCallContext ccx(cx, obj);
    1229           0 :     XPCWrappedNative* wrapper = ccx.GetWrapper();
    1230           0 :     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
    1231             : 
    1232           0 :     XPCWrappedNativeTearOff* to = ccx.GetTearOff();
    1233             :     XPCNativeInterface* iface;
    1234             : 
    1235           0 :     if (!to || nullptr == (iface = to->GetInterface()))
    1236           0 :         return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);
    1237             : 
    1238           0 :     return DefinePropertyIfFound(ccx, obj, id, nullptr, iface, nullptr,
    1239             :                                  wrapper->GetScope(),
    1240             :                                  true, nullptr, nullptr, nullptr,
    1241             :                                  JSPROP_READONLY |
    1242             :                                  JSPROP_PERMANENT |
    1243           0 :                                  JSPROP_ENUMERATE, resolvedp);
    1244             : }
    1245             : 
    1246             : static void
    1247           0 : XPC_WN_TearOff_Finalize(js::FreeOp* fop, JSObject* obj)
    1248             : {
    1249             :     XPCWrappedNativeTearOff* p = (XPCWrappedNativeTearOff*)
    1250           0 :         xpc_GetJSPrivate(obj);
    1251           0 :     if (!p)
    1252           0 :         return;
    1253           0 :     p->JSObjectFinalized();
    1254             : }
    1255             : 
    1256             : static void
    1257           0 : XPC_WN_TearOff_ObjectMoved(JSObject* obj, const JSObject* old)
    1258             : {
    1259             :     XPCWrappedNativeTearOff* p = (XPCWrappedNativeTearOff*)
    1260           0 :         xpc_GetJSPrivate(obj);
    1261           0 :     if (!p)
    1262           0 :         return;
    1263           0 :     p->JSObjectMoved(obj, old);
    1264             : }
    1265             : 
    1266             : // Make sure XPC_WRAPPER_FLAGS has no reserved slots, so our
    1267             : // XPC_WN_TEAROFF_RESERVED_SLOTS value is OK.
    1268             : 
    1269             : static_assert(((XPC_WRAPPER_FLAGS >> JSCLASS_RESERVED_SLOTS_SHIFT) &
    1270             :                JSCLASS_RESERVED_SLOTS_MASK) == 0,
    1271             :               "XPC_WRAPPER_FLAGS should not include any reserved slots");
    1272             : 
    1273             : static const js::ClassOps XPC_WN_Tearoff_JSClassOps = {
    1274             :     XPC_WN_OnlyIWrite_AddPropertyStub,  // addProperty
    1275             :     XPC_WN_CannotDeletePropertyStub,    // delProperty
    1276             :     nullptr,                            // getProperty
    1277             :     nullptr,                            // setProperty
    1278             :     XPC_WN_TearOff_Enumerate,           // enumerate
    1279             :     nullptr,                            // newEnumerate
    1280             :     XPC_WN_TearOff_Resolve,             // resolve
    1281             :     nullptr,                            // mayResolve
    1282             :     XPC_WN_TearOff_Finalize,            // finalize
    1283             :     nullptr,                            // call
    1284             :     nullptr,                            // construct
    1285             :     nullptr,                            // hasInstance
    1286             :     nullptr,                            // trace
    1287             : };
    1288             : 
    1289             : static const js::ClassExtension XPC_WN_Tearoff_JSClassExtension = {
    1290             :     nullptr,                            // weakmapKeyDelegateOp
    1291             :     XPC_WN_TearOff_ObjectMoved
    1292             : };
    1293             : 
    1294             : const js::Class XPC_WN_Tearoff_JSClass = {
    1295             :     "WrappedNative_TearOff",
    1296             :     XPC_WRAPPER_FLAGS |
    1297             :     JSCLASS_HAS_RESERVED_SLOTS(XPC_WN_TEAROFF_RESERVED_SLOTS),
    1298             :     &XPC_WN_Tearoff_JSClassOps,
    1299             :     JS_NULL_CLASS_SPEC,
    1300             :     &XPC_WN_Tearoff_JSClassExtension
    1301             : };

Generated by: LCOV version 1.13