Null pointer dereference in WTF::RefPtr<WTF::StringImpl>::operator!() under slow_path_get_direct_pname
https://bugs.webkit.org/show_bug.cgi?id=171801

Reviewed by Michael Saboff.
        
JSTests:

These tests used to crash. The prefix and postfix tests cover different paths, except
postfix-ignored goes down the same path as prefix due to an optimization.

* stress/for-in-postfix-ignored-index.js: Added.
(foo):
* stress/for-in-postfix-index.js: Added.
(foo):
* stress/for-in-prefix-index.js: Added.
(foo):

Source/JavaScriptCore:

This was a goofy oversight. The for-in optimization relies on the bytecode generator
to detect when the loop's index variable gets mutated. We forgot to have the hooks for
detecting this in prefix and postfix operations (++i and i++).

* bytecompiler/NodesCodegen.cpp:
(JSC::PostfixNode::emitResolve):
(JSC::PrefixNode::emitResolve):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@216593 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/JSTests/ChangeLog b/JSTests/ChangeLog
index c149918..860e829 100644
--- a/JSTests/ChangeLog
+++ b/JSTests/ChangeLog
@@ -1,3 +1,20 @@
+2017-05-10  Filip Pizlo  <fpizlo@apple.com>
+
+        Null pointer dereference in WTF::RefPtr<WTF::StringImpl>::operator!() under slow_path_get_direct_pname
+        https://bugs.webkit.org/show_bug.cgi?id=171801
+
+        Reviewed by Michael Saboff.
+        
+        These tests used to crash. The prefix and postfix tests cover different paths, except
+        postfix-ignored goes down the same path as prefix due to an optimization.
+
+        * stress/for-in-postfix-ignored-index.js: Added.
+        (foo):
+        * stress/for-in-postfix-index.js: Added.
+        (foo):
+        * stress/for-in-prefix-index.js: Added.
+        (foo):
+
 2017-05-08  Mark Lam  <mark.lam@apple.com>
 
         op_throw_static_error's use of its first operand should be reflected in DFG BytecodeUseDef as well.
diff --git a/JSTests/stress/for-in-postfix-ignored-index.js b/JSTests/stress/for-in-postfix-ignored-index.js
new file mode 100644
index 0000000..b7947ea
--- /dev/null
+++ b/JSTests/stress/for-in-postfix-ignored-index.js
@@ -0,0 +1,14 @@
+//@ runDefault
+
+function foo(o) {
+    var result = 0;
+    for (var s in o) {
+        s++;
+        result += o[s];
+    }
+    return result;
+}
+
+var result = foo({f:42});
+if ("" + result != "NaN")
+    throw "Error: bad result: " + result;
diff --git a/JSTests/stress/for-in-postfix-index.js b/JSTests/stress/for-in-postfix-index.js
new file mode 100644
index 0000000..0d59240
--- /dev/null
+++ b/JSTests/stress/for-in-postfix-index.js
@@ -0,0 +1,15 @@
+//@ runDefault
+
+function foo(o) {
+    var result = 0;
+    for (var s in o) {
+        var tmp = s++;
+        result += o[s];
+        result += tmp;
+    }
+    return result;
+}
+
+var result = foo({f:42});
+if ("" + result != "NaN")
+    throw "Error: bad result: " + result;
diff --git a/JSTests/stress/for-in-prefix-index.js b/JSTests/stress/for-in-prefix-index.js
new file mode 100644
index 0000000..4f700fd
--- /dev/null
+++ b/JSTests/stress/for-in-prefix-index.js
@@ -0,0 +1,12 @@
+//@ runDefault
+
+function foo(o) {
+    var result = 0;
+    for (var s in o)
+        result += o[--s];
+    return result;
+}
+
+var result = foo({f:42});
+if ("" + result != "NaN")
+    throw "Error: bad result: " + result;
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index ada621e..d1c9f50 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,18 @@
+2017-05-10  Filip Pizlo  <fpizlo@apple.com>
+
+        Null pointer dereference in WTF::RefPtr<WTF::StringImpl>::operator!() under slow_path_get_direct_pname
+        https://bugs.webkit.org/show_bug.cgi?id=171801
+
+        Reviewed by Michael Saboff.
+        
+        This was a goofy oversight. The for-in optimization relies on the bytecode generator
+        to detect when the loop's index variable gets mutated. We forgot to have the hooks for
+        detecting this in prefix and postfix operations (++i and i++).
+
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::PostfixNode::emitResolve):
+        (JSC::PrefixNode::emitResolve):
+
 2017-05-10  Michael Catanzaro  <mcatanzaro@igalia.com>
 
         [GTK] -Wmissing-field-initializers triggered by RemoteInspectorServer.cpp:128
diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
index f3e5557..6ad5794 100644
--- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
+++ b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
@@ -1412,6 +1412,7 @@
             generator.emitReadOnlyExceptionIfNeeded(var);
             localReg = generator.emitMove(generator.tempDestination(dst), local);
         }
+        generator.invalidateForInContextForLocal(local);
         RefPtr<RegisterID> oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), localReg.get(), m_operator);
         generator.emitProfileType(localReg.get(), var, divotStart(), divotEnd());
         return oldValue.get();
@@ -1624,6 +1625,7 @@
             generator.emitReadOnlyExceptionIfNeeded(var);
             localReg = generator.emitMove(generator.tempDestination(dst), localReg.get());
         } else if (generator.vm()->typeProfiler()) {
+            generator.invalidateForInContextForLocal(local);
             RefPtr<RegisterID> tempDst = generator.tempDestination(dst);
             generator.emitMove(tempDst.get(), localReg.get());
             emitIncOrDec(generator, tempDst.get(), m_operator);
@@ -1631,6 +1633,7 @@
             generator.emitProfileType(localReg.get(), var, divotStart(), divotEnd());
             return generator.moveToDestinationIfNeeded(dst, tempDst.get());
         }
+        generator.invalidateForInContextForLocal(local);
         emitIncOrDec(generator, localReg.get(), m_operator);
         return generator.moveToDestinationIfNeeded(dst, localReg.get());
     }