From 88db0108b14d58cf5d82ed7346f48f010feaaf0d Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 7 Feb 2019 10:39:40 +0100 Subject: Align `instanceof` with the final ES6 spec. --- js/xpconnect/wrappers/WaiveXrayWrapper.cpp | 31 ++++++++++++++++++++++++++++++ js/xpconnect/wrappers/WaiveXrayWrapper.h | 2 ++ js/xpconnect/wrappers/XrayWrapper.cpp | 14 ++++++++++++++ js/xpconnect/wrappers/XrayWrapper.h | 2 ++ 4 files changed, 49 insertions(+) (limited to 'js/xpconnect/wrappers') diff --git a/js/xpconnect/wrappers/WaiveXrayWrapper.cpp b/js/xpconnect/wrappers/WaiveXrayWrapper.cpp index 27c010d34..dca3daa58 100644 --- a/js/xpconnect/wrappers/WaiveXrayWrapper.cpp +++ b/js/xpconnect/wrappers/WaiveXrayWrapper.cpp @@ -87,6 +87,37 @@ WaiveXrayWrapper::nativeCall(JSContext* cx, JS::IsAcceptableThis test, WrapperFactory::WaiveXrayAndWrap(cx, args.rval()); } +bool +WaiveXrayWrapper::hasInstance(JSContext* cx, HandleObject wrapper, + MutableHandleValue v, bool* bp) const { + if (v.isObject() && WrapperFactory::IsXrayWrapper(&v.toObject())) { + // If |v| is an XrayWrapper and in the same compartment as the value + // wrapped by |wrapper|, then the Xrays of |v| would be waived upon + // calling CrossCompartmentWrapper::hasInstance. This may trigger + // getters and proxy traps of unwrapped |v|. To prevent that from + // happening, we exit early. + + // |wrapper| is the right operand of "instanceof", and must either be + // a function or an object with a @@hasInstance method. We are not going + // to call @@hasInstance, so only check whether it is a function. + // This check is here for consistency with usual "instanceof" behavior, + // which throws if the right operand is not a function. Without this + // check, the "instanceof" operator would return false and potentially + // hide errors in the code that uses the "instanceof" operator. + if (!JS::IsCallable(wrapper)) { + RootedValue wrapperv(cx, JS::ObjectValue(*wrapper)); + js::ReportIsNotFunction(cx, wrapperv); + return false; + } + + *bp = false; + return true; + } + + // Both |wrapper| and |v| have no Xrays here. + return CrossCompartmentWrapper::hasInstance(cx, wrapper, v, bp); +} + bool WaiveXrayWrapper::getPrototype(JSContext* cx, HandleObject wrapper, MutableHandleObject protop) const { diff --git a/js/xpconnect/wrappers/WaiveXrayWrapper.h b/js/xpconnect/wrappers/WaiveXrayWrapper.h index b0b447796..0f9675c17 100644 --- a/js/xpconnect/wrappers/WaiveXrayWrapper.h +++ b/js/xpconnect/wrappers/WaiveXrayWrapper.h @@ -36,6 +36,8 @@ class WaiveXrayWrapper : public js::CrossCompartmentWrapper { JS::MutableHandle objp) const override; virtual bool nativeCall(JSContext* cx, JS::IsAcceptableThis test, JS::NativeImpl impl, const JS::CallArgs& args) const override; + virtual bool hasInstance(JSContext* cx, JS::HandleObject wrapper, + JS::MutableHandleValue v, bool* bp) const override; virtual bool getPropertyDescriptor(JSContext* cx, JS::Handle wrapper, JS::Handle id, JS::MutableHandle desc) const override; diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index 48a9fdc68..6e5a2f5e5 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -2308,6 +2308,20 @@ XrayWrapper::getBuiltinClass(JSContext* cx, JS::HandleObject wrapp return Traits::getBuiltinClass(cx, wrapper, Base::singleton, cls); } +template +bool +XrayWrapper::hasInstance(JSContext* cx, + JS::HandleObject wrapper, + JS::MutableHandleValue v, + bool* bp) const { + assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::GET); + + // CrossCompartmentWrapper::hasInstance unwraps |wrapper|'s Xrays and enters + // its compartment. Any present XrayWrappers should be preserved, so the + // standard "instanceof" implementation is called without unwrapping first. + return JS::InstanceofOperator(cx, wrapper, v, bp); +} + template const char* XrayWrapper::className(JSContext* cx, HandleObject wrapper) const diff --git a/js/xpconnect/wrappers/XrayWrapper.h b/js/xpconnect/wrappers/XrayWrapper.h index 5630982c2..038d82390 100644 --- a/js/xpconnect/wrappers/XrayWrapper.h +++ b/js/xpconnect/wrappers/XrayWrapper.h @@ -482,6 +482,8 @@ class XrayWrapper : public Base { JS::AutoIdVector& props) const override; virtual bool getBuiltinClass(JSContext* cx, JS::HandleObject wapper, js::ESClass* cls) const override; + virtual bool hasInstance(JSContext* cx, JS::HandleObject wrapper, + JS::MutableHandleValue v, bool* bp) const override; virtual const char* className(JSContext* cx, JS::HandleObject proxy) const override; static const XrayWrapper singleton; -- cgit v1.2.3