]> granicus.if.org Git - php/commitdiff
Fixed bug #78341
authorNikita Popov <nikita.ppv@gmail.com>
Mon, 29 Jul 2019 11:02:01 +0000 (13:02 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Mon, 29 Jul 2019 11:02:01 +0000 (13:02 +0200)
The smart branch logic assumed b->start refers to the old offsets,
while b->start was already adjusted to the new offsets at this
point. Delay the change until later.

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

diff --git a/NEWS b/NEWS
index 58cc45e10c9bc0cb283eaddae184e4d223463814..b3bdfc87c11daa18c41ebf95c2fa7f78005107bd 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -21,6 +21,9 @@ PHP                                                                        NEWS
 - LiteSpeed:
   . Updated to LiteSpeed SAPI V7.5 (Fixed clean shutdown). (George Wang)
 
+- Opcode:
+  . Fixed bug #78341 (Failure to detect smart branch in DFA pass). (Nikita)
+
 - Standard:
   . Fixed bug #69100 (Bus error from stream_copy_to_stream (file -> SSL stream)
     with invalid length). (Nikita)
index 55b9597850e4366d2acbe08aaf2a2a87c7d6a357..ecf3038b6b9f3ef9f4c147ab979b1d20c7412975 100644 (file)
@@ -181,9 +181,8 @@ static void zend_ssa_remove_nops(zend_op_array *op_array, zend_ssa *ssa, zend_op
 
        for (b = blocks; b < blocks_end; b++) {
                if (b->flags & (ZEND_BB_REACHABLE|ZEND_BB_UNREACHABLE_FREE)) {
-                       uint32_t end;
-
                        if (b->len) {
+                               uint32_t new_start, old_end;
                                while (i < b->start) {
                                        shiftlist[i] = i - target;
                                        i++;
@@ -196,9 +195,9 @@ static void zend_ssa_remove_nops(zend_op_array *op_array, zend_ssa *ssa, zend_op
                                        b->len = 1;
                                }
 
-                               end = b->start + b->len;
-                               b->start = target;
-                               while (i < end) {
+                               new_start = target;
+                               old_end = b->start + b->len;
+                               while (i < old_end) {
                                        shiftlist[i] = i - target;
                                        if (EXPECTED(op_array->opcodes[i].opcode != ZEND_NOP) ||
                                                is_smart_branch_inhibiting_nop(op_array, target, i, b, blocks_end)) {
@@ -211,12 +210,13 @@ static void zend_ssa_remove_nops(zend_op_array *op_array, zend_ssa *ssa, zend_op
                                        }
                                        i++;
                                }
-                               if (target != end) {
+                               b->start = new_start;
+                               if (target != old_end) {
                                        zend_op *opline;
                                        zend_op *new_opline;
 
                                        b->len = target - b->start;
-                                       opline = op_array->opcodes + end - 1;
+                                       opline = op_array->opcodes + old_end - 1;
                                        if (opline->opcode == ZEND_NOP) {
                                                continue;
                                        }
diff --git a/ext/opcache/tests/bug78341.phpt b/ext/opcache/tests/bug78341.phpt
new file mode 100644 (file)
index 0000000..8b10125
--- /dev/null
@@ -0,0 +1,21 @@
+--TEST--
+Bug #78341: Failure to detect smart branch in DFA pass
+--FILE--
+<?php
+
+function test($a) {
+    // Just some dead code...
+    if (strpos("foo", "foo") !== 0) {
+        echo "Foo";
+    }
+
+    $x = $a === null;
+    if ($x) {
+        var_dump($x);
+    }
+}
+test(null);
+
+?>
+--EXPECT--
+bool(true)