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 */