Bug 1530687 - Check for recursion when delegating `instanceof` to a bound function target. r=anba
authorJason Orendorff <jorendorff@mozilla.com>
Thu, 04 Apr 2019 02:34:52 +0000
changeset 467915 78745e4537faac3932ae7cf944ceecc73288aa95
parent 467914 e875e0c671bf9d49dc518909eaafdb9b35580d80
child 467916 5e7dea1ca822eaca4e56534d90c29e12df3fd471
push id112667
push useraiakab@mozilla.com
push dateThu, 04 Apr 2019 16:12:45 +0000
treeherdermozilla-inbound@230bb363f2f3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersanba
bugs1530687
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1530687 - Check for recursion when delegating `instanceof` to a bound function target. r=anba Differential Revision: https://phabricator.services.mozilla.com/D25409
js/src/tests/non262/operators/instanceof-bound-function-recursion.js
js/src/vm/JSFunction.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/tests/non262/operators/instanceof-bound-function-recursion.js
@@ -0,0 +1,23 @@
+function f() {}
+
+var fn = f;
+for (var i = 0; i < 100000; ++i) {
+  fn = fn.bind();
+
+  // Ensure we don't fallback to @@hasInstance from %FunctionPrototype%.
+  Object.defineProperty(fn, Symbol.hasInstance, {
+    value: undefined, writable: true, enumerable: true, writable: true
+  });
+
+  // Prevent generating overlong names of the form "bound bound bound [...] f".
+  Object.defineProperty(fn, "name", {
+    value: "", writable: true, enumerable: true, writable: true
+  });
+}
+
+assertThrowsInstanceOf(
+  () => ({}) instanceof fn,
+  Error,
+  "detect runaway recursion delegating instanceof to bound function target");
+
+reportCompare(0, 0);
--- a/js/src/vm/JSFunction.cpp
+++ b/js/src/vm/JSFunction.cpp
@@ -715,16 +715,19 @@ bool JS::OrdinaryHasInstance(JSContext* 
   if (!obj->isCallable()) {
     *bp = false;
     return true;
   }
 
   /* Step 2. */
   if (obj->is<JSFunction>() && obj->isBoundFunction()) {
     /* Steps 2a-b. */
+    if (!CheckRecursionLimit(cx)) {
+      return false;
+    }
     obj = obj->as<JSFunction>().getBoundFunctionTarget();
     return InstanceofOperator(cx, obj, v, bp);
   }
 
   /* Step 3. */
   if (!v.isObject()) {
     *bp = false;
     return true;