Bug 1454285 - Part 3: Add test. r=jwalden
authorTooru Fujisawa <arai_a@mac.com>
Thu, 23 Aug 2018 15:48:13 +0900
changeset 488087 ac3e5dee7c57d25faebadbea06c57c2b4b216878
parent 488086 d17c68d95b1630adf72fe81ff214b0acdf4cd590
child 488088 32c6c1848f149454182911c6635b42956cf719de
child 488128 a5f23c113987a3e682b2445016709bebca8eb264
push id9719
push userffxbld-merge
push dateFri, 24 Aug 2018 17:49:46 +0000
treeherdermozilla-beta@719ec98fba77 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwalden
bugs1454285
milestone63.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 1454285 - Part 3: Add test. r=jwalden
js/src/frontend/ForOfLoopControl.cpp
js/src/jit-test/tests/auto-regress/bug1454285.js
--- a/js/src/frontend/ForOfLoopControl.cpp
+++ b/js/src/frontend/ForOfLoopControl.cpp
@@ -119,16 +119,25 @@ ForOfLoopControl::emitIteratorCloseInSco
                                        allowSelfHosted_))
     {
         return false;
     }
     ptrdiff_t end = bce->offset();
     return bce->tryNoteList.append(JSTRY_FOR_OF_ITERCLOSE, 0, start, end);
 }
 
+// Since we're in the middle of emitting code that will leave
+// |bce->innermostEmitterScope()|, passing the innermost emitter scope to
+// emitIteratorCloseInScope and looking up .generator there would be very,
+// very wrong.  We'd find .generator in the function environment, and we'd
+// compute a NameLocation with the correct slot, but we'd compute a
+// hop-count to the function environment that was too big.  At runtime we'd
+// either crash, or we'd find a user-controllable value in that slot, and
+// Very Bad Things would ensue as we reinterpreted that value as an
+// iterator.
 bool
 ForOfLoopControl::emitPrepareForNonLocalJumpFromScope(BytecodeEmitter* bce,
                                                       EmitterScope& currentScope,
                                                       bool isTarget)
 {
     // Pop unnecessary value from the stack.  Effectively this means
     // leaving try-catch block.  However, the performing IteratorClose can
     // reach the depth for try-catch, and effectively re-enter the
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/auto-regress/bug1454285.js
@@ -0,0 +1,86 @@
+// IteratorClose in for-await-of with block-scoped function.
+
+// Non-local-jump without target.
+
+(async function() {
+    for await (let c of []) {
+        function f() {};
+        return;
+    }
+})();
+(async function() {
+    for await (let c of []) {
+        function f() {};
+        break;
+    }
+})();
+(async function() {
+    for await (let c of []) {
+        function f() {};
+        continue;
+    }
+})();
+
+// Non-local-jump with target.
+
+(async function() {
+    for (let x of []) {
+        x: for (let y of []) {
+            for await (let c of []) {
+                function f() {};
+                return;
+            }
+        }
+    }
+})();
+(async function() {
+    for (let x of []) {
+        x: for (let y of []) {
+            for await (let c of []) {
+                function f() {};
+                break x;
+            }
+        }
+    }
+})();
+(async function() {
+    for (let x of []) {
+        x: for (let y of []) {
+            for await (let c of []) {
+                function f() {};
+                continue x;
+            }
+        }
+    }
+})();
+
+(async function() {
+    for await (let x of []) {
+        x: for await (let y of []) {
+            for await (let c of []) {
+                function f() {};
+                return;
+            }
+        }
+    }
+})();
+(async function() {
+    for await (let x of []) {
+        x: for await (let y of []) {
+            for await (let c of []) {
+                function f() {};
+                break x;
+            }
+        }
+    }
+})();
+(async function() {
+    for await (let x of []) {
+        x: for await (let y of []) {
+            for await (let c of []) {
+                function f() {};
+                continue x;
+            }
+        }
+    }
+})();