js/src/jswrapper.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/jswrapper.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,337 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99:
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#ifndef jswrapper_h
    1.11 +#define jswrapper_h
    1.12 +
    1.13 +#include "mozilla/Attributes.h"
    1.14 +
    1.15 +#include "jsproxy.h"
    1.16 +
    1.17 +namespace js {
    1.18 +
    1.19 +class DummyFrameGuard;
    1.20 +
    1.21 +/*
    1.22 + * Helper for Wrapper::New default options.
    1.23 + *
    1.24 + * Callers of Wrapper::New() who wish to specify a prototype for the created
    1.25 + * Wrapper, *MUST* construct a WrapperOptions with a JSContext.
    1.26 + */
    1.27 +class MOZ_STACK_CLASS WrapperOptions : public ProxyOptions {
    1.28 +  public:
    1.29 +    WrapperOptions() : ProxyOptions(false, nullptr),
    1.30 +                       proto_()
    1.31 +    {}
    1.32 +
    1.33 +    WrapperOptions(JSContext *cx) : ProxyOptions(false, nullptr),
    1.34 +                                    proto_()
    1.35 +    {
    1.36 +        proto_.construct(cx);
    1.37 +    }
    1.38 +
    1.39 +    inline JSObject *proto() const;
    1.40 +    WrapperOptions &setProto(JSObject *protoArg) {
    1.41 +        JS_ASSERT(!proto_.empty());
    1.42 +        proto_.ref() = protoArg;
    1.43 +        return *this;
    1.44 +    }
    1.45 +
    1.46 +  private:
    1.47 +    mozilla::Maybe<JS::RootedObject> proto_;
    1.48 +};
    1.49 +
    1.50 +/*
    1.51 + * A wrapper is a proxy with a target object to which it generally forwards
    1.52 + * operations, but may restrict access to certain operations or instrument
    1.53 + * the trap operations in various ways. A wrapper is distinct from a Direct Proxy
    1.54 + * Handler in the sense that it can be "unwrapped" in C++, exposing the underlying
    1.55 + * object (Direct Proxy Handlers have an underlying target object, but don't
    1.56 + * expect to expose this object via any kind of unwrapping operation). Callers
    1.57 + * should be careful to avoid unwrapping security wrappers in the wrong context.
    1.58 + */
    1.59 +class JS_FRIEND_API(Wrapper) : public DirectProxyHandler
    1.60 +{
    1.61 +    unsigned mFlags;
    1.62 +
    1.63 +  public:
    1.64 +    using BaseProxyHandler::Action;
    1.65 +
    1.66 +    enum Flags {
    1.67 +        CROSS_COMPARTMENT = 1 << 0,
    1.68 +        LAST_USED_FLAG = CROSS_COMPARTMENT
    1.69 +    };
    1.70 +
    1.71 +    virtual bool defaultValue(JSContext *cx, HandleObject obj, JSType hint,
    1.72 +                              MutableHandleValue vp) MOZ_OVERRIDE;
    1.73 +
    1.74 +    static JSObject *New(JSContext *cx, JSObject *obj, JSObject *parent, Wrapper *handler,
    1.75 +                         const WrapperOptions *options = nullptr);
    1.76 +
    1.77 +    static JSObject *Renew(JSContext *cx, JSObject *existing, JSObject *obj, Wrapper *handler);
    1.78 +
    1.79 +    static Wrapper *wrapperHandler(JSObject *wrapper);
    1.80 +
    1.81 +    static JSObject *wrappedObject(JSObject *wrapper);
    1.82 +
    1.83 +    unsigned flags() const {
    1.84 +        return mFlags;
    1.85 +    }
    1.86 +
    1.87 +    explicit Wrapper(unsigned flags, bool hasPrototype = false);
    1.88 +
    1.89 +    virtual ~Wrapper();
    1.90 +
    1.91 +    virtual bool finalizeInBackground(Value priv) MOZ_OVERRIDE;
    1.92 +
    1.93 +    static Wrapper singleton;
    1.94 +    static Wrapper singletonWithPrototype;
    1.95 +
    1.96 +    static JSObject *defaultProto;
    1.97 +};
    1.98 +
    1.99 +inline JSObject *
   1.100 +WrapperOptions::proto() const
   1.101 +{
   1.102 +    return proto_.empty() ? Wrapper::defaultProto : proto_.ref();
   1.103 +}
   1.104 +
   1.105 +/* Base class for all cross compartment wrapper handlers. */
   1.106 +class JS_FRIEND_API(CrossCompartmentWrapper) : public Wrapper
   1.107 +{
   1.108 +  public:
   1.109 +    CrossCompartmentWrapper(unsigned flags, bool hasPrototype = false);
   1.110 +
   1.111 +    virtual ~CrossCompartmentWrapper();
   1.112 +
   1.113 +    /* ES5 Harmony fundamental wrapper traps. */
   1.114 +    virtual bool preventExtensions(JSContext *cx, HandleObject wrapper) MOZ_OVERRIDE;
   1.115 +    virtual bool getPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
   1.116 +                                       MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
   1.117 +    virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
   1.118 +                                          MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
   1.119 +    virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
   1.120 +                                MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
   1.121 +    virtual bool getOwnPropertyNames(JSContext *cx, HandleObject wrapper,
   1.122 +                                     AutoIdVector &props) MOZ_OVERRIDE;
   1.123 +    virtual bool delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) MOZ_OVERRIDE;
   1.124 +    virtual bool enumerate(JSContext *cx, HandleObject wrapper, AutoIdVector &props) MOZ_OVERRIDE;
   1.125 +
   1.126 +    /* ES5 Harmony derived wrapper traps. */
   1.127 +    virtual bool has(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) MOZ_OVERRIDE;
   1.128 +    virtual bool hasOwn(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) MOZ_OVERRIDE;
   1.129 +    virtual bool get(JSContext *cx, HandleObject wrapper, HandleObject receiver,
   1.130 +                     HandleId id, MutableHandleValue vp) MOZ_OVERRIDE;
   1.131 +    virtual bool set(JSContext *cx, HandleObject wrapper, HandleObject receiver,
   1.132 +                     HandleId id, bool strict, MutableHandleValue vp) MOZ_OVERRIDE;
   1.133 +    virtual bool keys(JSContext *cx, HandleObject wrapper, AutoIdVector &props) MOZ_OVERRIDE;
   1.134 +    virtual bool iterate(JSContext *cx, HandleObject wrapper, unsigned flags,
   1.135 +                         MutableHandleValue vp) MOZ_OVERRIDE;
   1.136 +
   1.137 +    /* Spidermonkey extensions. */
   1.138 +    virtual bool isExtensible(JSContext *cx, HandleObject wrapper, bool *extensible) MOZ_OVERRIDE;
   1.139 +    virtual bool call(JSContext *cx, HandleObject wrapper, const CallArgs &args) MOZ_OVERRIDE;
   1.140 +    virtual bool construct(JSContext *cx, HandleObject wrapper, const CallArgs &args) MOZ_OVERRIDE;
   1.141 +    virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
   1.142 +                            CallArgs args) MOZ_OVERRIDE;
   1.143 +    virtual bool hasInstance(JSContext *cx, HandleObject wrapper, MutableHandleValue v,
   1.144 +                             bool *bp) MOZ_OVERRIDE;
   1.145 +    virtual const char *className(JSContext *cx, HandleObject proxy) MOZ_OVERRIDE;
   1.146 +    virtual JSString *fun_toString(JSContext *cx, HandleObject wrapper,
   1.147 +                                   unsigned indent) MOZ_OVERRIDE;
   1.148 +    virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) MOZ_OVERRIDE;
   1.149 +    virtual bool defaultValue(JSContext *cx, HandleObject wrapper, JSType hint,
   1.150 +                              MutableHandleValue vp) MOZ_OVERRIDE;
   1.151 +    virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy,
   1.152 +                                MutableHandleObject protop) MOZ_OVERRIDE;
   1.153 +    virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto,
   1.154 +                                bool *bp) MOZ_OVERRIDE;
   1.155 +
   1.156 +    static CrossCompartmentWrapper singleton;
   1.157 +    static CrossCompartmentWrapper singletonWithPrototype;
   1.158 +};
   1.159 +
   1.160 +/*
   1.161 + * Base class for security wrappers. A security wrapper is potentially hiding
   1.162 + * all or part of some wrapped object thus SecurityWrapper defaults to denying
   1.163 + * access to the wrappee. This is the opposite of Wrapper which tries to be
   1.164 + * completely transparent.
   1.165 + *
   1.166 + * NB: Currently, only a few ProxyHandler operations are overridden to deny
   1.167 + * access, relying on derived SecurityWrapper to block access when necessary.
   1.168 + */
   1.169 +template <class Base>
   1.170 +class JS_FRIEND_API(SecurityWrapper) : public Base
   1.171 +{
   1.172 +  public:
   1.173 +    SecurityWrapper(unsigned flags);
   1.174 +
   1.175 +    virtual bool isExtensible(JSContext *cx, HandleObject wrapper, bool *extensible) MOZ_OVERRIDE;
   1.176 +    virtual bool preventExtensions(JSContext *cx, HandleObject wrapper) MOZ_OVERRIDE;
   1.177 +    virtual bool enter(JSContext *cx, HandleObject wrapper, HandleId id, Wrapper::Action act,
   1.178 +                       bool *bp) MOZ_OVERRIDE;
   1.179 +    virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
   1.180 +                            CallArgs args) MOZ_OVERRIDE;
   1.181 +    virtual bool defaultValue(JSContext *cx, HandleObject wrapper, JSType hint,
   1.182 +                              MutableHandleValue vp) MOZ_OVERRIDE;
   1.183 +    virtual bool objectClassIs(HandleObject obj, ESClassValue classValue,
   1.184 +                               JSContext *cx) MOZ_OVERRIDE;
   1.185 +    virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) MOZ_OVERRIDE;
   1.186 +    virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
   1.187 +                                MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
   1.188 +
   1.189 +    virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto,
   1.190 +                                bool *bp) MOZ_OVERRIDE;
   1.191 +
   1.192 +    virtual bool watch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
   1.193 +                       JS::HandleObject callable) MOZ_OVERRIDE;
   1.194 +    virtual bool unwatch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id) MOZ_OVERRIDE;
   1.195 +
   1.196 +    /*
   1.197 +     * Allow our subclasses to select the superclass behavior they want without
   1.198 +     * needing to specify an exact superclass.
   1.199 +     */
   1.200 +    typedef Base Permissive;
   1.201 +    typedef SecurityWrapper<Base> Restrictive;
   1.202 +};
   1.203 +
   1.204 +typedef SecurityWrapper<Wrapper> SameCompartmentSecurityWrapper;
   1.205 +typedef SecurityWrapper<CrossCompartmentWrapper> CrossCompartmentSecurityWrapper;
   1.206 +
   1.207 +class JS_FRIEND_API(DeadObjectProxy) : public BaseProxyHandler
   1.208 +{
   1.209 +  public:
   1.210 +    // This variable exists solely to provide a unique address for use as an identifier.
   1.211 +    static const char sDeadObjectFamily;
   1.212 +
   1.213 +    explicit DeadObjectProxy();
   1.214 +
   1.215 +    /* ES5 Harmony fundamental wrapper traps. */
   1.216 +    virtual bool preventExtensions(JSContext *cx, HandleObject proxy) MOZ_OVERRIDE;
   1.217 +    virtual bool getPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
   1.218 +                                       MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
   1.219 +    virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
   1.220 +                                          MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
   1.221 +    virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
   1.222 +                                MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
   1.223 +    virtual bool getOwnPropertyNames(JSContext *cx, HandleObject wrapper,
   1.224 +                                     AutoIdVector &props) MOZ_OVERRIDE;
   1.225 +    virtual bool delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) MOZ_OVERRIDE;
   1.226 +    virtual bool enumerate(JSContext *cx, HandleObject wrapper, AutoIdVector &props) MOZ_OVERRIDE;
   1.227 +
   1.228 +    /* Spidermonkey extensions. */
   1.229 +    virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) MOZ_OVERRIDE;
   1.230 +    virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) MOZ_OVERRIDE;
   1.231 +    virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) MOZ_OVERRIDE;
   1.232 +    virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
   1.233 +                            CallArgs args) MOZ_OVERRIDE;
   1.234 +    virtual bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v,
   1.235 +                             bool *bp) MOZ_OVERRIDE;
   1.236 +    virtual bool objectClassIs(HandleObject obj, ESClassValue classValue,
   1.237 +                               JSContext *cx) MOZ_OVERRIDE;
   1.238 +    virtual const char *className(JSContext *cx, HandleObject proxy) MOZ_OVERRIDE;
   1.239 +    virtual JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent) MOZ_OVERRIDE;
   1.240 +    virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) MOZ_OVERRIDE;
   1.241 +    virtual bool defaultValue(JSContext *cx, HandleObject obj, JSType hint,
   1.242 +                              MutableHandleValue vp) MOZ_OVERRIDE;
   1.243 +    virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy,
   1.244 +                                MutableHandleObject protop) MOZ_OVERRIDE;
   1.245 +
   1.246 +    static DeadObjectProxy singleton;
   1.247 +};
   1.248 +
   1.249 +extern JSObject *
   1.250 +TransparentObjectWrapper(JSContext *cx, HandleObject existing, HandleObject obj,
   1.251 +                         HandleObject wrappedProto, HandleObject parent,
   1.252 +                         unsigned flags);
   1.253 +
   1.254 +// Proxy family for wrappers. Public so that IsWrapper() can be fully inlined by
   1.255 +// jsfriendapi users.
   1.256 +// This variable exists solely to provide a unique address for use as an identifier.
   1.257 +extern JS_FRIEND_DATA(const char) sWrapperFamily;
   1.258 +
   1.259 +inline bool
   1.260 +IsWrapper(JSObject *obj)
   1.261 +{
   1.262 +    return IsProxy(obj) && GetProxyHandler(obj)->family() == &sWrapperFamily;
   1.263 +}
   1.264 +
   1.265 +// Given a JSObject, returns that object stripped of wrappers. If
   1.266 +// stopAtOuter is true, then this returns the outer window if it was
   1.267 +// previously wrapped. Otherwise, this returns the first object for
   1.268 +// which JSObject::isWrapper returns false.
   1.269 +JS_FRIEND_API(JSObject *)
   1.270 +UncheckedUnwrap(JSObject *obj, bool stopAtOuter = true, unsigned *flagsp = nullptr);
   1.271 +
   1.272 +// Given a JSObject, returns that object stripped of wrappers. At each stage,
   1.273 +// the security wrapper has the opportunity to veto the unwrap. Since checked
   1.274 +// code should never be unwrapping outer window wrappers, we always stop at
   1.275 +// outer windows.
   1.276 +JS_FRIEND_API(JSObject *)
   1.277 +CheckedUnwrap(JSObject *obj, bool stopAtOuter = true);
   1.278 +
   1.279 +// Unwrap only the outermost security wrapper, with the same semantics as
   1.280 +// above. This is the checked version of Wrapper::wrappedObject.
   1.281 +JS_FRIEND_API(JSObject *)
   1.282 +UnwrapOneChecked(JSObject *obj, bool stopAtOuter = true);
   1.283 +
   1.284 +JS_FRIEND_API(bool)
   1.285 +IsCrossCompartmentWrapper(JSObject *obj);
   1.286 +
   1.287 +bool
   1.288 +IsDeadProxyObject(JSObject *obj);
   1.289 +
   1.290 +JSObject *
   1.291 +NewDeadProxyObject(JSContext *cx, JSObject *parent,
   1.292 +                   const ProxyOptions &options = ProxyOptions());
   1.293 +
   1.294 +void
   1.295 +NukeCrossCompartmentWrapper(JSContext *cx, JSObject *wrapper);
   1.296 +
   1.297 +bool
   1.298 +RemapWrapper(JSContext *cx, JSObject *wobj, JSObject *newTarget);
   1.299 +
   1.300 +JS_FRIEND_API(bool)
   1.301 +RemapAllWrappersForObject(JSContext *cx, JSObject *oldTarget,
   1.302 +                          JSObject *newTarget);
   1.303 +
   1.304 +// API to recompute all cross-compartment wrappers whose source and target
   1.305 +// match the given filters.
   1.306 +JS_FRIEND_API(bool)
   1.307 +RecomputeWrappers(JSContext *cx, const CompartmentFilter &sourceFilter,
   1.308 +                  const CompartmentFilter &targetFilter);
   1.309 +
   1.310 +/*
   1.311 + * This auto class should be used around any code, such as brain transplants,
   1.312 + * that may touch dead zones. Brain transplants can cause problems
   1.313 + * because they operate on all compartments, whether live or dead. A brain
   1.314 + * transplant can cause a formerly dead object to be "reanimated" by causing a
   1.315 + * read or write barrier to be invoked on it during the transplant. In this way,
   1.316 + * a zone becomes a zombie, kept alive by repeatedly consuming
   1.317 + * (transplanted) brains.
   1.318 + *
   1.319 + * To work around this issue, we observe when mark bits are set on objects in
   1.320 + * dead zones. If this happens during a brain transplant, we do a full,
   1.321 + * non-incremental GC at the end of the brain transplant. This will clean up any
   1.322 + * objects that were improperly marked.
   1.323 + */
   1.324 +struct JS_FRIEND_API(AutoMaybeTouchDeadZones)
   1.325 +{
   1.326 +    // The version that takes an object just uses it for its runtime.
   1.327 +    AutoMaybeTouchDeadZones(JSContext *cx);
   1.328 +    AutoMaybeTouchDeadZones(JSObject *obj);
   1.329 +    ~AutoMaybeTouchDeadZones();
   1.330 +
   1.331 +  private:
   1.332 +    JSRuntime *runtime;
   1.333 +    unsigned markCount;
   1.334 +    bool inIncremental;
   1.335 +    bool manipulatingDeadZones;
   1.336 +};
   1.337 +
   1.338 +} /* namespace js */
   1.339 +
   1.340 +#endif /* jswrapper_h */

mercurial