js/src/jswrapper.h

Thu, 15 Jan 2015 15:55:04 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:55:04 +0100
branch
TOR_BUG_9701
changeset 9
a63d609f5ebe
permissions
-rw-r--r--

Back out 97036ab72558 which inappropriately compared turds to third parties.

     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/. */
     7 #ifndef jswrapper_h
     8 #define jswrapper_h
    10 #include "mozilla/Attributes.h"
    12 #include "jsproxy.h"
    14 namespace js {
    16 class DummyFrameGuard;
    18 /*
    19  * Helper for Wrapper::New default options.
    20  *
    21  * Callers of Wrapper::New() who wish to specify a prototype for the created
    22  * Wrapper, *MUST* construct a WrapperOptions with a JSContext.
    23  */
    24 class MOZ_STACK_CLASS WrapperOptions : public ProxyOptions {
    25   public:
    26     WrapperOptions() : ProxyOptions(false, nullptr),
    27                        proto_()
    28     {}
    30     WrapperOptions(JSContext *cx) : ProxyOptions(false, nullptr),
    31                                     proto_()
    32     {
    33         proto_.construct(cx);
    34     }
    36     inline JSObject *proto() const;
    37     WrapperOptions &setProto(JSObject *protoArg) {
    38         JS_ASSERT(!proto_.empty());
    39         proto_.ref() = protoArg;
    40         return *this;
    41     }
    43   private:
    44     mozilla::Maybe<JS::RootedObject> proto_;
    45 };
    47 /*
    48  * A wrapper is a proxy with a target object to which it generally forwards
    49  * operations, but may restrict access to certain operations or instrument
    50  * the trap operations in various ways. A wrapper is distinct from a Direct Proxy
    51  * Handler in the sense that it can be "unwrapped" in C++, exposing the underlying
    52  * object (Direct Proxy Handlers have an underlying target object, but don't
    53  * expect to expose this object via any kind of unwrapping operation). Callers
    54  * should be careful to avoid unwrapping security wrappers in the wrong context.
    55  */
    56 class JS_FRIEND_API(Wrapper) : public DirectProxyHandler
    57 {
    58     unsigned mFlags;
    60   public:
    61     using BaseProxyHandler::Action;
    63     enum Flags {
    64         CROSS_COMPARTMENT = 1 << 0,
    65         LAST_USED_FLAG = CROSS_COMPARTMENT
    66     };
    68     virtual bool defaultValue(JSContext *cx, HandleObject obj, JSType hint,
    69                               MutableHandleValue vp) MOZ_OVERRIDE;
    71     static JSObject *New(JSContext *cx, JSObject *obj, JSObject *parent, Wrapper *handler,
    72                          const WrapperOptions *options = nullptr);
    74     static JSObject *Renew(JSContext *cx, JSObject *existing, JSObject *obj, Wrapper *handler);
    76     static Wrapper *wrapperHandler(JSObject *wrapper);
    78     static JSObject *wrappedObject(JSObject *wrapper);
    80     unsigned flags() const {
    81         return mFlags;
    82     }
    84     explicit Wrapper(unsigned flags, bool hasPrototype = false);
    86     virtual ~Wrapper();
    88     virtual bool finalizeInBackground(Value priv) MOZ_OVERRIDE;
    90     static Wrapper singleton;
    91     static Wrapper singletonWithPrototype;
    93     static JSObject *defaultProto;
    94 };
    96 inline JSObject *
    97 WrapperOptions::proto() const
    98 {
    99     return proto_.empty() ? Wrapper::defaultProto : proto_.ref();
   100 }
   102 /* Base class for all cross compartment wrapper handlers. */
   103 class JS_FRIEND_API(CrossCompartmentWrapper) : public Wrapper
   104 {
   105   public:
   106     CrossCompartmentWrapper(unsigned flags, bool hasPrototype = false);
   108     virtual ~CrossCompartmentWrapper();
   110     /* ES5 Harmony fundamental wrapper traps. */
   111     virtual bool preventExtensions(JSContext *cx, HandleObject wrapper) MOZ_OVERRIDE;
   112     virtual bool getPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
   113                                        MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
   114     virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
   115                                           MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
   116     virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
   117                                 MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
   118     virtual bool getOwnPropertyNames(JSContext *cx, HandleObject wrapper,
   119                                      AutoIdVector &props) MOZ_OVERRIDE;
   120     virtual bool delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) MOZ_OVERRIDE;
   121     virtual bool enumerate(JSContext *cx, HandleObject wrapper, AutoIdVector &props) MOZ_OVERRIDE;
   123     /* ES5 Harmony derived wrapper traps. */
   124     virtual bool has(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) MOZ_OVERRIDE;
   125     virtual bool hasOwn(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) MOZ_OVERRIDE;
   126     virtual bool get(JSContext *cx, HandleObject wrapper, HandleObject receiver,
   127                      HandleId id, MutableHandleValue vp) MOZ_OVERRIDE;
   128     virtual bool set(JSContext *cx, HandleObject wrapper, HandleObject receiver,
   129                      HandleId id, bool strict, MutableHandleValue vp) MOZ_OVERRIDE;
   130     virtual bool keys(JSContext *cx, HandleObject wrapper, AutoIdVector &props) MOZ_OVERRIDE;
   131     virtual bool iterate(JSContext *cx, HandleObject wrapper, unsigned flags,
   132                          MutableHandleValue vp) MOZ_OVERRIDE;
   134     /* Spidermonkey extensions. */
   135     virtual bool isExtensible(JSContext *cx, HandleObject wrapper, bool *extensible) MOZ_OVERRIDE;
   136     virtual bool call(JSContext *cx, HandleObject wrapper, const CallArgs &args) MOZ_OVERRIDE;
   137     virtual bool construct(JSContext *cx, HandleObject wrapper, const CallArgs &args) MOZ_OVERRIDE;
   138     virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
   139                             CallArgs args) MOZ_OVERRIDE;
   140     virtual bool hasInstance(JSContext *cx, HandleObject wrapper, MutableHandleValue v,
   141                              bool *bp) MOZ_OVERRIDE;
   142     virtual const char *className(JSContext *cx, HandleObject proxy) MOZ_OVERRIDE;
   143     virtual JSString *fun_toString(JSContext *cx, HandleObject wrapper,
   144                                    unsigned indent) MOZ_OVERRIDE;
   145     virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) MOZ_OVERRIDE;
   146     virtual bool defaultValue(JSContext *cx, HandleObject wrapper, JSType hint,
   147                               MutableHandleValue vp) MOZ_OVERRIDE;
   148     virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy,
   149                                 MutableHandleObject protop) MOZ_OVERRIDE;
   150     virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto,
   151                                 bool *bp) MOZ_OVERRIDE;
   153     static CrossCompartmentWrapper singleton;
   154     static CrossCompartmentWrapper singletonWithPrototype;
   155 };
   157 /*
   158  * Base class for security wrappers. A security wrapper is potentially hiding
   159  * all or part of some wrapped object thus SecurityWrapper defaults to denying
   160  * access to the wrappee. This is the opposite of Wrapper which tries to be
   161  * completely transparent.
   162  *
   163  * NB: Currently, only a few ProxyHandler operations are overridden to deny
   164  * access, relying on derived SecurityWrapper to block access when necessary.
   165  */
   166 template <class Base>
   167 class JS_FRIEND_API(SecurityWrapper) : public Base
   168 {
   169   public:
   170     SecurityWrapper(unsigned flags);
   172     virtual bool isExtensible(JSContext *cx, HandleObject wrapper, bool *extensible) MOZ_OVERRIDE;
   173     virtual bool preventExtensions(JSContext *cx, HandleObject wrapper) MOZ_OVERRIDE;
   174     virtual bool enter(JSContext *cx, HandleObject wrapper, HandleId id, Wrapper::Action act,
   175                        bool *bp) MOZ_OVERRIDE;
   176     virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
   177                             CallArgs args) MOZ_OVERRIDE;
   178     virtual bool defaultValue(JSContext *cx, HandleObject wrapper, JSType hint,
   179                               MutableHandleValue vp) MOZ_OVERRIDE;
   180     virtual bool objectClassIs(HandleObject obj, ESClassValue classValue,
   181                                JSContext *cx) MOZ_OVERRIDE;
   182     virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) MOZ_OVERRIDE;
   183     virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
   184                                 MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
   186     virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto,
   187                                 bool *bp) MOZ_OVERRIDE;
   189     virtual bool watch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
   190                        JS::HandleObject callable) MOZ_OVERRIDE;
   191     virtual bool unwatch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id) MOZ_OVERRIDE;
   193     /*
   194      * Allow our subclasses to select the superclass behavior they want without
   195      * needing to specify an exact superclass.
   196      */
   197     typedef Base Permissive;
   198     typedef SecurityWrapper<Base> Restrictive;
   199 };
   201 typedef SecurityWrapper<Wrapper> SameCompartmentSecurityWrapper;
   202 typedef SecurityWrapper<CrossCompartmentWrapper> CrossCompartmentSecurityWrapper;
   204 class JS_FRIEND_API(DeadObjectProxy) : public BaseProxyHandler
   205 {
   206   public:
   207     // This variable exists solely to provide a unique address for use as an identifier.
   208     static const char sDeadObjectFamily;
   210     explicit DeadObjectProxy();
   212     /* ES5 Harmony fundamental wrapper traps. */
   213     virtual bool preventExtensions(JSContext *cx, HandleObject proxy) MOZ_OVERRIDE;
   214     virtual bool getPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
   215                                        MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
   216     virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
   217                                           MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
   218     virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
   219                                 MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
   220     virtual bool getOwnPropertyNames(JSContext *cx, HandleObject wrapper,
   221                                      AutoIdVector &props) MOZ_OVERRIDE;
   222     virtual bool delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) MOZ_OVERRIDE;
   223     virtual bool enumerate(JSContext *cx, HandleObject wrapper, AutoIdVector &props) MOZ_OVERRIDE;
   225     /* Spidermonkey extensions. */
   226     virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) MOZ_OVERRIDE;
   227     virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) MOZ_OVERRIDE;
   228     virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) MOZ_OVERRIDE;
   229     virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
   230                             CallArgs args) MOZ_OVERRIDE;
   231     virtual bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v,
   232                              bool *bp) MOZ_OVERRIDE;
   233     virtual bool objectClassIs(HandleObject obj, ESClassValue classValue,
   234                                JSContext *cx) MOZ_OVERRIDE;
   235     virtual const char *className(JSContext *cx, HandleObject proxy) MOZ_OVERRIDE;
   236     virtual JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent) MOZ_OVERRIDE;
   237     virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) MOZ_OVERRIDE;
   238     virtual bool defaultValue(JSContext *cx, HandleObject obj, JSType hint,
   239                               MutableHandleValue vp) MOZ_OVERRIDE;
   240     virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy,
   241                                 MutableHandleObject protop) MOZ_OVERRIDE;
   243     static DeadObjectProxy singleton;
   244 };
   246 extern JSObject *
   247 TransparentObjectWrapper(JSContext *cx, HandleObject existing, HandleObject obj,
   248                          HandleObject wrappedProto, HandleObject parent,
   249                          unsigned flags);
   251 // Proxy family for wrappers. Public so that IsWrapper() can be fully inlined by
   252 // jsfriendapi users.
   253 // This variable exists solely to provide a unique address for use as an identifier.
   254 extern JS_FRIEND_DATA(const char) sWrapperFamily;
   256 inline bool
   257 IsWrapper(JSObject *obj)
   258 {
   259     return IsProxy(obj) && GetProxyHandler(obj)->family() == &sWrapperFamily;
   260 }
   262 // Given a JSObject, returns that object stripped of wrappers. If
   263 // stopAtOuter is true, then this returns the outer window if it was
   264 // previously wrapped. Otherwise, this returns the first object for
   265 // which JSObject::isWrapper returns false.
   266 JS_FRIEND_API(JSObject *)
   267 UncheckedUnwrap(JSObject *obj, bool stopAtOuter = true, unsigned *flagsp = nullptr);
   269 // Given a JSObject, returns that object stripped of wrappers. At each stage,
   270 // the security wrapper has the opportunity to veto the unwrap. Since checked
   271 // code should never be unwrapping outer window wrappers, we always stop at
   272 // outer windows.
   273 JS_FRIEND_API(JSObject *)
   274 CheckedUnwrap(JSObject *obj, bool stopAtOuter = true);
   276 // Unwrap only the outermost security wrapper, with the same semantics as
   277 // above. This is the checked version of Wrapper::wrappedObject.
   278 JS_FRIEND_API(JSObject *)
   279 UnwrapOneChecked(JSObject *obj, bool stopAtOuter = true);
   281 JS_FRIEND_API(bool)
   282 IsCrossCompartmentWrapper(JSObject *obj);
   284 bool
   285 IsDeadProxyObject(JSObject *obj);
   287 JSObject *
   288 NewDeadProxyObject(JSContext *cx, JSObject *parent,
   289                    const ProxyOptions &options = ProxyOptions());
   291 void
   292 NukeCrossCompartmentWrapper(JSContext *cx, JSObject *wrapper);
   294 bool
   295 RemapWrapper(JSContext *cx, JSObject *wobj, JSObject *newTarget);
   297 JS_FRIEND_API(bool)
   298 RemapAllWrappersForObject(JSContext *cx, JSObject *oldTarget,
   299                           JSObject *newTarget);
   301 // API to recompute all cross-compartment wrappers whose source and target
   302 // match the given filters.
   303 JS_FRIEND_API(bool)
   304 RecomputeWrappers(JSContext *cx, const CompartmentFilter &sourceFilter,
   305                   const CompartmentFilter &targetFilter);
   307 /*
   308  * This auto class should be used around any code, such as brain transplants,
   309  * that may touch dead zones. Brain transplants can cause problems
   310  * because they operate on all compartments, whether live or dead. A brain
   311  * transplant can cause a formerly dead object to be "reanimated" by causing a
   312  * read or write barrier to be invoked on it during the transplant. In this way,
   313  * a zone becomes a zombie, kept alive by repeatedly consuming
   314  * (transplanted) brains.
   315  *
   316  * To work around this issue, we observe when mark bits are set on objects in
   317  * dead zones. If this happens during a brain transplant, we do a full,
   318  * non-incremental GC at the end of the brain transplant. This will clean up any
   319  * objects that were improperly marked.
   320  */
   321 struct JS_FRIEND_API(AutoMaybeTouchDeadZones)
   322 {
   323     // The version that takes an object just uses it for its runtime.
   324     AutoMaybeTouchDeadZones(JSContext *cx);
   325     AutoMaybeTouchDeadZones(JSObject *obj);
   326     ~AutoMaybeTouchDeadZones();
   328   private:
   329     JSRuntime *runtime;
   330     unsigned markCount;
   331     bool inIncremental;
   332     bool manipulatingDeadZones;
   333 };
   335 } /* namespace js */
   337 #endif /* jswrapper_h */

mercurial