summaryrefslogtreecommitdiffstats
path: root/js/xpconnect/wrappers
diff options
context:
space:
mode:
authorwolfbeast <mcwerewolf@wolfbeast.com>2019-02-07 10:39:40 +0100
committerwolfbeast <mcwerewolf@wolfbeast.com>2019-02-07 10:39:40 +0100
commit88db0108b14d58cf5d82ed7346f48f010feaaf0d (patch)
tree1d78ae8cd21d7d17293f66c166ca44718501d4aa /js/xpconnect/wrappers
parent8db772d2ca44ff44f32d434e7f62acba289b4155 (diff)
downloadUXP-88db0108b14d58cf5d82ed7346f48f010feaaf0d.tar
UXP-88db0108b14d58cf5d82ed7346f48f010feaaf0d.tar.gz
UXP-88db0108b14d58cf5d82ed7346f48f010feaaf0d.tar.lz
UXP-88db0108b14d58cf5d82ed7346f48f010feaaf0d.tar.xz
UXP-88db0108b14d58cf5d82ed7346f48f010feaaf0d.zip
Align `instanceof` with the final ES6 spec.
Diffstat (limited to 'js/xpconnect/wrappers')
-rw-r--r--js/xpconnect/wrappers/WaiveXrayWrapper.cpp31
-rw-r--r--js/xpconnect/wrappers/WaiveXrayWrapper.h2
-rw-r--r--js/xpconnect/wrappers/XrayWrapper.cpp14
-rw-r--r--js/xpconnect/wrappers/XrayWrapper.h2
4 files changed, 49 insertions, 0 deletions
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
@@ -88,6 +88,37 @@ WaiveXrayWrapper::nativeCall(JSContext* cx, JS::IsAcceptableThis test,
}
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
{
return CrossCompartmentWrapper::getPrototype(cx, wrapper, protop) &&
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<JSObject*> 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<JSObject*> wrapper,
JS::Handle<jsid> id,
JS::MutableHandle<JS::PropertyDescriptor> 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
@@ -2309,6 +2309,20 @@ XrayWrapper<Base, Traits>::getBuiltinClass(JSContext* cx, JS::HandleObject wrapp
}
template <typename Base, typename Traits>
+bool
+XrayWrapper<Base, Traits>::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 <typename Base, typename Traits>
const char*
XrayWrapper<Base, Traits>::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;