]> granicus.if.org Git - php/commitdiff
Fixed bug #77691
authorNikita Popov <nikita.ppv@gmail.com>
Mon, 4 Mar 2019 12:11:12 +0000 (13:11 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Mon, 4 Mar 2019 12:11:12 +0000 (13:11 +0100)
We cannot replace an op1_def opcode with an ASSIGN, if it also has
a used res_def. Usually this doesn't happen because the res_def use
can be eliminated first. The example is a case where operand replacement
on the res_def use fails.

NEWS
ext/opcache/Optimizer/sccp.c
ext/opcache/tests/bug77691.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index f7a1246567962b90ec21b62eb6b306904faf24ed..324f95aa95f8e2f831ea194dfd13da128bb4dc3f 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -21,6 +21,10 @@ PHP                                                                        NEWS
 - MySQLi:
   . Fixed bug #77597 (mysqli_fetch_field hangs scripts). (Nikita)
 
+- Opcache:
+  . Fixed bug #77691 (Opcache passes wrong value for inline array push
+    assignments). (Nikita)
+
 - sodium:
   . Fixed bug #77646 (sign_detached() strings not terminated). (Frank)
 
index 78ce8e7e253b8702ec4b5579953023886a2d908a..8e0b6bf6aba5ec7e5ab66bcef6226e1a38b421f4 100644 (file)
@@ -1581,7 +1581,10 @@ static int replace_constant_operands(sccp_ctx *ctx) {
                                        zend_ssa_remove_instr(ssa, opline, ssa_op);
                                        removed_ops++;
                                }
-                       } else if (ssa_op->op1_def == i) {
+                       } else if (ssa_op->op1_def == i &&
+                                       (ssa_op->result_def < 0 ||
+                                        (ssa->vars[ssa_op->result_def].use_chain < 0 &&
+                                         ssa->vars[ssa_op->result_def].phi_use_chain == NULL))) {
                                /* Compound assign or incdec -> convert to direct ASSIGN */
 
                                /* Destroy previous op2 */
@@ -1595,10 +1598,8 @@ static int replace_constant_operands(sccp_ctx *ctx) {
                                        ssa_op->op2_use_chain = -1;
                                }
 
-                               /* Mark result unused, if possible */
-                               if (ssa_op->result_def >= 0
-                                               && ssa->vars[ssa_op->result_def].use_chain < 0
-                                               && ssa->vars[ssa_op->result_def].phi_use_chain == NULL) {
+                               /* We checked that result has no uses, mark unused */
+                               if (ssa_op->result_def >= 0) {
                                        if (opline->result_type & (IS_TMP_VAR|IS_VAR)) {
                                                zend_optimizer_remove_live_range_ex(op_array, opline->result.var, var->definition);
                                        }
diff --git a/ext/opcache/tests/bug77691.phpt b/ext/opcache/tests/bug77691.phpt
new file mode 100644 (file)
index 0000000..998a348
--- /dev/null
@@ -0,0 +1,26 @@
+--TEST--
+Bug #77691: Opcache passes wrong value for inline array push assignments
+--FILE--
+<?php
+
+if (true) {
+    function dump($str) {
+        var_dump($str);
+    }
+}
+
+function test() {
+    $array = [];
+    dump($array[] = 'test');
+    dump($array);
+}
+
+test();
+
+?>
+--EXPECT--
+string(4) "test"
+array(1) {
+  [0]=>
+  string(4) "test"
+}