LCOV - code coverage report
Current view: top level - js/src - jswrapper.h (source / functions) Hit Total Coverage
Test: output.info Lines: 11 21 52.4 %
Date: 2017-07-14 16:53:18 Functions: 6 10 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             : #ifndef jswrapper_h
       8             : #define jswrapper_h
       9             : 
      10             : #include "mozilla/Attributes.h"
      11             : 
      12             : #include "js/Proxy.h"
      13             : 
      14             : namespace js {
      15             : 
      16             : /*
      17             :  * Helper for Wrapper::New default options.
      18             :  *
      19             :  * Callers of Wrapper::New() who wish to specify a prototype for the created
      20             :  * Wrapper, *MUST* construct a WrapperOptions with a JSContext.
      21             :  */
      22        9308 : class MOZ_STACK_CLASS WrapperOptions : public ProxyOptions {
      23             :   public:
      24        9308 :     WrapperOptions() : ProxyOptions(false),
      25        9308 :                        proto_()
      26        9308 :     {}
      27             : 
      28             :     explicit WrapperOptions(JSContext* cx) : ProxyOptions(false),
      29             :                                              proto_()
      30             :     {
      31             :         proto_.emplace(cx);
      32             :     }
      33             : 
      34             :     inline JSObject* proto() const;
      35             :     WrapperOptions& setProto(JSObject* protoArg) {
      36             :         MOZ_ASSERT(proto_);
      37             :         *proto_ = protoArg;
      38             :         return *this;
      39             :     }
      40             : 
      41             :   private:
      42             :     mozilla::Maybe<JS::RootedObject> proto_;
      43             : };
      44             : 
      45             : /*
      46             :  * A wrapper is a proxy with a target object to which it generally forwards
      47             :  * operations, but may restrict access to certain operations or augment those
      48             :  * operations in various ways.
      49             :  *
      50             :  * A wrapper can be "unwrapped" in C++, exposing the underlying object.
      51             :  * Callers should be careful to avoid unwrapping security wrappers in the wrong
      52             :  * context.
      53             :  *
      54             :  * Important: If you add a method implementation here, you probably also need
      55             :  * to add an override in CrossCompartmentWrapper. If you don't, you risk
      56             :  * compartment mismatches. See bug 945826 comment 0.
      57             :  */
      58             : class JS_FRIEND_API(Wrapper) : public BaseProxyHandler
      59             : {
      60             :     unsigned mFlags;
      61             : 
      62             :   public:
      63           0 :     explicit constexpr Wrapper(unsigned aFlags, bool aHasPrototype = false,
      64             :                                    bool aHasSecurityPolicy = false)
      65           0 :       : BaseProxyHandler(&family, aHasPrototype, aHasSecurityPolicy),
      66           0 :         mFlags(aFlags)
      67           0 :     { }
      68             : 
      69             :     virtual bool finalizeInBackground(const Value& priv) const override;
      70             : 
      71             :     /* Standard internal methods. */
      72             :     virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
      73             :                                           MutableHandle<PropertyDescriptor> desc) const override;
      74             :     virtual bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id,
      75             :                                 Handle<PropertyDescriptor> desc,
      76             :                                 ObjectOpResult& result) const override;
      77             :     virtual bool ownPropertyKeys(JSContext* cx, HandleObject proxy,
      78             :                                  AutoIdVector& props) const override;
      79             :     virtual bool delete_(JSContext* cx, HandleObject proxy, HandleId id,
      80             :                          ObjectOpResult& result) const override;
      81             :     virtual JSObject* enumerate(JSContext* cx, HandleObject proxy) const override;
      82             :     virtual bool getPrototype(JSContext* cx, HandleObject proxy,
      83             :                               MutableHandleObject protop) const override;
      84             :     virtual bool setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto,
      85             :                               ObjectOpResult& result) const override;
      86             :     virtual bool getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary,
      87             :                                         MutableHandleObject protop) const override;
      88             :     virtual bool setImmutablePrototype(JSContext* cx, HandleObject proxy,
      89             :                                        bool* succeeded) const override;
      90             :     virtual bool preventExtensions(JSContext* cx, HandleObject proxy,
      91             :                                    ObjectOpResult& result) const override;
      92             :     virtual bool isExtensible(JSContext* cx, HandleObject proxy, bool* extensible) const override;
      93             :     virtual bool has(JSContext* cx, HandleObject proxy, HandleId id,
      94             :                      bool* bp) const override;
      95             :     virtual bool get(JSContext* cx, HandleObject proxy, HandleValue receiver,
      96             :                      HandleId id, MutableHandleValue vp) const override;
      97             :     virtual bool set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v,
      98             :                      HandleValue receiver, ObjectOpResult& result) const override;
      99             :     virtual bool call(JSContext* cx, HandleObject proxy, const CallArgs& args) const override;
     100             :     virtual bool construct(JSContext* cx, HandleObject proxy, const CallArgs& args) const override;
     101             : 
     102             :     /* SpiderMonkey extensions. */
     103             :     virtual bool getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
     104             :                                        MutableHandle<PropertyDescriptor> desc) const override;
     105             :     virtual bool hasOwn(JSContext* cx, HandleObject proxy, HandleId id,
     106             :                         bool* bp) const override;
     107             :     virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy,
     108             :                                               AutoIdVector& props) const override;
     109             :     virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
     110             :                             const CallArgs& args) const override;
     111             :     virtual bool hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v,
     112             :                              bool* bp) const override;
     113             :     virtual bool getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls) const override;
     114             :     virtual bool isArray(JSContext* cx, HandleObject proxy,
     115             :                          JS::IsArrayAnswer* answer) const override;
     116             :     virtual const char* className(JSContext* cx, HandleObject proxy) const override;
     117             :     virtual JSString* fun_toString(JSContext* cx, HandleObject proxy,
     118             :                                    unsigned indent) const override;
     119             :     virtual RegExpShared* regexp_toShared(JSContext* cx, HandleObject proxy) const override;
     120             :     virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy,
     121             :                                   MutableHandleValue vp) const override;
     122             :     virtual bool isCallable(JSObject* obj) const override;
     123             :     virtual bool isConstructor(JSObject* obj) const override;
     124             :     virtual JSObject* weakmapKeyDelegate(JSObject* proxy) const override;
     125             : 
     126             :   public:
     127             :     using BaseProxyHandler::Action;
     128             : 
     129             :     enum Flags {
     130             :         CROSS_COMPARTMENT = 1 << 0,
     131             :         LAST_USED_FLAG = CROSS_COMPARTMENT
     132             :     };
     133             : 
     134             :     static JSObject* New(JSContext* cx, JSObject* obj, const Wrapper* handler,
     135             :                          const WrapperOptions& options = WrapperOptions());
     136             : 
     137             :     static JSObject* Renew(JSObject* existing, JSObject* obj, const Wrapper* handler);
     138             : 
     139             :     static const Wrapper* wrapperHandler(JSObject* wrapper);
     140             : 
     141             :     static JSObject* wrappedObject(JSObject* wrapper);
     142             : 
     143       38635 :     unsigned flags() const {
     144       38635 :         return mFlags;
     145             :     }
     146             : 
     147             :     static const char family;
     148             :     static const Wrapper singleton;
     149             :     static const Wrapper singletonWithPrototype;
     150             : 
     151             :     static JSObject* defaultProto;
     152             : };
     153             : 
     154             : inline JSObject*
     155        9264 : WrapperOptions::proto() const
     156             : {
     157        9264 :     return proto_ ? *proto_ : Wrapper::defaultProto;
     158             : }
     159             : 
     160             : /* Base class for all cross compartment wrapper handlers. */
     161             : class JS_FRIEND_API(CrossCompartmentWrapper) : public Wrapper
     162             : {
     163             :   public:
     164           0 :     explicit constexpr CrossCompartmentWrapper(unsigned aFlags, bool aHasPrototype = false,
     165             :                                                    bool aHasSecurityPolicy = false)
     166           0 :       : Wrapper(CROSS_COMPARTMENT | aFlags, aHasPrototype, aHasSecurityPolicy)
     167           0 :     { }
     168             : 
     169             :     /* Standard internal methods. */
     170             :     virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id,
     171             :                                           MutableHandle<PropertyDescriptor> desc) const override;
     172             :     virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id,
     173             :                                 Handle<PropertyDescriptor> desc,
     174             :                                 ObjectOpResult& result) const override;
     175             :     virtual bool ownPropertyKeys(JSContext* cx, HandleObject wrapper,
     176             :                                  AutoIdVector& props) const override;
     177             :     virtual bool delete_(JSContext* cx, HandleObject wrapper, HandleId id,
     178             :                          ObjectOpResult& result) const override;
     179             :     virtual JSObject* enumerate(JSContext* cx, HandleObject wrapper) const override;
     180             :     virtual bool getPrototype(JSContext* cx, HandleObject proxy,
     181             :                               MutableHandleObject protop) const override;
     182             :     virtual bool setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto,
     183             :                               ObjectOpResult& result) const override;
     184             : 
     185             :     virtual bool getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary,
     186             :                                         MutableHandleObject protop) const override;
     187             :     virtual bool setImmutablePrototype(JSContext* cx, HandleObject proxy,
     188             :                                        bool* succeeded) const override;
     189             :     virtual bool preventExtensions(JSContext* cx, HandleObject wrapper,
     190             :                                    ObjectOpResult& result) const override;
     191             :     virtual bool isExtensible(JSContext* cx, HandleObject wrapper, bool* extensible) const override;
     192             :     virtual bool has(JSContext* cx, HandleObject wrapper, HandleId id, bool* bp) const override;
     193             :     virtual bool get(JSContext* cx, HandleObject wrapper, HandleValue receiver,
     194             :                      HandleId id, MutableHandleValue vp) const override;
     195             :     virtual bool set(JSContext* cx, HandleObject wrapper, HandleId id, HandleValue v,
     196             :                      HandleValue receiver, ObjectOpResult& result) const override;
     197             :     virtual bool call(JSContext* cx, HandleObject wrapper, const CallArgs& args) const override;
     198             :     virtual bool construct(JSContext* cx, HandleObject wrapper, const CallArgs& args) const override;
     199             : 
     200             :     /* SpiderMonkey extensions. */
     201             :     virtual bool getPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id,
     202             :                                        MutableHandle<PropertyDescriptor> desc) const override;
     203             :     virtual bool hasOwn(JSContext* cx, HandleObject wrapper, HandleId id, bool* bp) const override;
     204             :     virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject wrapper,
     205             :                                               AutoIdVector& props) const override;
     206             :     virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
     207             :                             const CallArgs& args) const override;
     208             :     virtual bool hasInstance(JSContext* cx, HandleObject wrapper, MutableHandleValue v,
     209             :                              bool* bp) const override;
     210             :     virtual const char* className(JSContext* cx, HandleObject proxy) const override;
     211             :     virtual JSString* fun_toString(JSContext* cx, HandleObject wrapper,
     212             :                                    unsigned indent) const override;
     213             :     virtual RegExpShared* regexp_toShared(JSContext* cx, HandleObject proxy) const override;
     214             :     virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const override;
     215             : 
     216             :     // Allocate CrossCompartmentWrappers in the nursery.
     217        3409 :     virtual bool canNurseryAllocate() const override { return true; }
     218             : 
     219             :     static const CrossCompartmentWrapper singleton;
     220             :     static const CrossCompartmentWrapper singletonWithPrototype;
     221             : };
     222             : 
     223             : class JS_FRIEND_API(OpaqueCrossCompartmentWrapper) : public CrossCompartmentWrapper
     224             : {
     225             :   public:
     226             :     explicit constexpr OpaqueCrossCompartmentWrapper() : CrossCompartmentWrapper(0)
     227             :     { }
     228             : 
     229             :     /* Standard internal methods. */
     230             :     virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id,
     231             :                                           MutableHandle<PropertyDescriptor> desc) const override;
     232             :     virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id,
     233             :                                 Handle<PropertyDescriptor> desc,
     234             :                                 ObjectOpResult& result) const override;
     235             :     virtual bool ownPropertyKeys(JSContext* cx, HandleObject wrapper,
     236             :                                  AutoIdVector& props) const override;
     237             :     virtual bool delete_(JSContext* cx, HandleObject wrapper, HandleId id,
     238             :                          ObjectOpResult& result) const override;
     239             :     virtual JSObject* enumerate(JSContext* cx, HandleObject wrapper) const override;
     240             :     virtual bool getPrototype(JSContext* cx, HandleObject wrapper,
     241             :                               MutableHandleObject protop) const override;
     242             :     virtual bool setPrototype(JSContext* cx, HandleObject wrapper, HandleObject proto,
     243             :                               ObjectOpResult& result) const override;
     244             :     virtual bool getPrototypeIfOrdinary(JSContext* cx, HandleObject wrapper, bool* isOrdinary,
     245             :                                         MutableHandleObject protop) const override;
     246             :     virtual bool setImmutablePrototype(JSContext* cx, HandleObject wrapper,
     247             :                                        bool* succeeded) const override;
     248             :     virtual bool preventExtensions(JSContext* cx, HandleObject wrapper,
     249             :                                    ObjectOpResult& result) const override;
     250             :     virtual bool isExtensible(JSContext* cx, HandleObject wrapper, bool* extensible) const override;
     251             :     virtual bool has(JSContext* cx, HandleObject wrapper, HandleId id,
     252             :                      bool* bp) const override;
     253             :     virtual bool get(JSContext* cx, HandleObject wrapper, HandleValue receiver,
     254             :                      HandleId id, MutableHandleValue vp) const override;
     255             :     virtual bool set(JSContext* cx, HandleObject wrapper, HandleId id, HandleValue v,
     256             :                      HandleValue receiver, ObjectOpResult& result) const override;
     257             :     virtual bool call(JSContext* cx, HandleObject wrapper, const CallArgs& args) const override;
     258             :     virtual bool construct(JSContext* cx, HandleObject wrapper, const CallArgs& args) const override;
     259             : 
     260             :     /* SpiderMonkey extensions. */
     261             :     virtual bool getPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id,
     262             :                                        MutableHandle<PropertyDescriptor> desc) const override;
     263             :     virtual bool hasOwn(JSContext* cx, HandleObject wrapper, HandleId id,
     264             :                         bool* bp) const override;
     265             :     virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject wrapper,
     266             :                                               AutoIdVector& props) const override;
     267             :     virtual bool getBuiltinClass(JSContext* cx, HandleObject wrapper, ESClass* cls) const override;
     268             :     virtual bool isArray(JSContext* cx, HandleObject obj,
     269             :                          JS::IsArrayAnswer* answer) const override;
     270             :     virtual const char* className(JSContext* cx, HandleObject wrapper) const override;
     271             :     virtual JSString* fun_toString(JSContext* cx, HandleObject proxy, unsigned indent) const override;
     272             : 
     273             :     static const OpaqueCrossCompartmentWrapper singleton;
     274             : };
     275             : 
     276             : /*
     277             :  * Base class for security wrappers. A security wrapper is potentially hiding
     278             :  * all or part of some wrapped object thus SecurityWrapper defaults to denying
     279             :  * access to the wrappee. This is the opposite of Wrapper which tries to be
     280             :  * completely transparent.
     281             :  *
     282             :  * NB: Currently, only a few ProxyHandler operations are overridden to deny
     283             :  * access, relying on derived SecurityWrapper to block access when necessary.
     284             :  */
     285             : template <class Base>
     286             : class JS_FRIEND_API(SecurityWrapper) : public Base
     287             : {
     288             :   public:
     289           0 :     explicit constexpr SecurityWrapper(unsigned flags, bool hasPrototype = false)
     290           0 :       : Base(flags, hasPrototype, /* hasSecurityPolicy = */ true)
     291           0 :     { }
     292             : 
     293             :     virtual bool enter(JSContext* cx, HandleObject wrapper, HandleId id, Wrapper::Action act,
     294             :                        bool mayThrow, bool* bp) const override;
     295             : 
     296             :     virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id,
     297             :                                 Handle<PropertyDescriptor> desc,
     298             :                                 ObjectOpResult& result) const override;
     299             :     virtual bool isExtensible(JSContext* cx, HandleObject wrapper, bool* extensible) const override;
     300             :     virtual bool preventExtensions(JSContext* cx, HandleObject wrapper,
     301             :                                    ObjectOpResult& result) const override;
     302             :     virtual bool setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto,
     303             :                               ObjectOpResult& result) const override;
     304             :     virtual bool setImmutablePrototype(JSContext* cx, HandleObject proxy, bool* succeeded) const override;
     305             : 
     306             :     virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
     307             :                             const CallArgs& args) const override;
     308             :     virtual bool getBuiltinClass(JSContext* cx, HandleObject wrapper, ESClass* cls) const override;
     309             :     virtual bool isArray(JSContext* cx, HandleObject wrapper, JS::IsArrayAnswer* answer) const override;
     310             :     virtual RegExpShared* regexp_toShared(JSContext* cx, HandleObject proxy) const override;
     311             :     virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const override;
     312             : 
     313             :     // Allow isCallable and isConstructor. They used to be class-level, and so could not be guarded
     314             :     // against.
     315             : 
     316             :     virtual bool watch(JSContext* cx, JS::HandleObject proxy, JS::HandleId id,
     317             :                        JS::HandleObject callable) const override;
     318             :     virtual bool unwatch(JSContext* cx, JS::HandleObject proxy, JS::HandleId id) const override;
     319             : 
     320             :     /*
     321             :      * Allow our subclasses to select the superclass behavior they want without
     322             :      * needing to specify an exact superclass.
     323             :      */
     324             :     typedef Base Permissive;
     325             :     typedef SecurityWrapper<Base> Restrictive;
     326             : };
     327             : 
     328             : typedef SecurityWrapper<CrossCompartmentWrapper> CrossCompartmentSecurityWrapper;
     329             : 
     330             : extern JSObject*
     331             : TransparentObjectWrapper(JSContext* cx, HandleObject existing, HandleObject obj);
     332             : 
     333             : inline bool
     334      419207 : IsWrapper(JSObject* obj)
     335             : {
     336      419207 :     return IsProxy(obj) && GetProxyHandler(obj)->family() == &Wrapper::family;
     337             : }
     338             : 
     339             : // Given a JSObject, returns that object stripped of wrappers. If
     340             : // stopAtWindowProxy is true, then this returns the WindowProxy if it was
     341             : // previously wrapped. Otherwise, this returns the first object for which
     342             : // JSObject::isWrapper returns false.
     343             : //
     344             : // ExposeToActiveJS is called on wrapper targets to allow gray marking
     345             : // assertions to work while an incremental GC is in progress, but this means
     346             : // that this cannot be called from the GC or off the main thread.
     347             : JS_FRIEND_API(JSObject*)
     348             : UncheckedUnwrap(JSObject* obj, bool stopAtWindowProxy = true, unsigned* flagsp = nullptr);
     349             : 
     350             : // Given a JSObject, returns that object stripped of wrappers. At each stage,
     351             : // the security wrapper has the opportunity to veto the unwrap. If
     352             : // stopAtWindowProxy is true, then this returns the WindowProxy if it was
     353             : // previously wrapped.
     354             : //
     355             : // ExposeToActiveJS is called on wrapper targets to allow gray marking
     356             : // assertions to work while an incremental GC is in progress, but this means
     357             : // that this cannot be called from the GC or off the main thread.
     358             : JS_FRIEND_API(JSObject*)
     359             : CheckedUnwrap(JSObject* obj, bool stopAtWindowProxy = true);
     360             : 
     361             : // Unwrap only the outermost security wrapper, with the same semantics as
     362             : // above. This is the checked version of Wrapper::wrappedObject.
     363             : JS_FRIEND_API(JSObject*)
     364             : UnwrapOneChecked(JSObject* obj, bool stopAtWindowProxy = true);
     365             : 
     366             : // Given a JSObject, returns that object stripped of wrappers. This returns the
     367             : // WindowProxy if it was previously wrapped.
     368             : //
     369             : // ExposeToActiveJS is not called on wrapper targets so this can be called from
     370             : // the GC or off the main thread.
     371             : JS_FRIEND_API(JSObject*)
     372             : UncheckedUnwrapWithoutExpose(JSObject* obj);
     373             : 
     374             : void
     375             : ReportAccessDenied(JSContext* cx);
     376             : 
     377             : JS_FRIEND_API(bool)
     378             : IsCrossCompartmentWrapper(JSObject* obj);
     379             : 
     380             : JS_FRIEND_API(void)
     381             : NukeCrossCompartmentWrapper(JSContext* cx, JSObject* wrapper);
     382             : 
     383             : void
     384             : RemapWrapper(JSContext* cx, JSObject* wobj, JSObject* newTarget);
     385             : 
     386             : JS_FRIEND_API(bool)
     387             : RemapAllWrappersForObject(JSContext* cx, JSObject* oldTarget,
     388             :                           JSObject* newTarget);
     389             : 
     390             : // API to recompute all cross-compartment wrappers whose source and target
     391             : // match the given filters.
     392             : JS_FRIEND_API(bool)
     393             : RecomputeWrappers(JSContext* cx, const CompartmentFilter& sourceFilter,
     394             :                   const CompartmentFilter& targetFilter);
     395             : 
     396             : } /* namespace js */
     397             : 
     398             : #endif /* jswrapper_h */

Generated by: LCOV version 1.13