]> granicus.if.org Git - php/commitdiff
Fixed bug #73789 (Strange behavior of class constants in switch/case block)
authorXinchen Hui <laruence@gmail.com>
Tue, 20 Dec 2016 13:01:21 +0000 (21:01 +0800)
committerXinchen Hui <laruence@gmail.com>
Tue, 20 Dec 2016 13:01:21 +0000 (21:01 +0800)
NEWS
ext/opcache/Optimizer/dfa_pass.c
ext/opcache/tests/bug73789.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 9e1cbf2b110b1617c9381a58af08ad03ee3225e9..f94dd9aa9cd9c5a0b1b33449aa1dd7c8d4102d08 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -26,6 +26,8 @@ PHP                                                                        NEWS
     usage. (Andrey)
 
 - Opcache:
+  . Fixed bug #73789 (Strange behavior of class constants in switch/case block).
+    (Laruence)
   . Fixed bug #73746 (Method that returns string returns UNKNOWN:0 instead).
     (Laruence)
   . Fixed bug #73654 (Segmentation fault in zend_call_function). (Nikita)
index b7a0f065f736056abfe2132644560fbdca366669..2780a4cc54d569c1dc51141ce24dc03ba73b98d4 100644 (file)
@@ -569,19 +569,23 @@ void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx
 // op_1: VERIFY_RETURN_TYPE #orig_var.CV [T] -> #v.CV [T] => NOP
 
                                int orig_var = ssa->ops[op_1].op1_use;
-                               int ret = ssa->vars[v].use_chain;
+                               if (zend_ssa_unlink_use_chain(ssa, op_1, orig_var)) {
 
-                               ssa->vars[orig_var].use_chain = ret;
-                               ssa->ops[ret].op1_use = orig_var;
+                                       int ret = ssa->vars[v].use_chain;
 
-                               ssa->vars[v].definition = -1;
-                               ssa->vars[v].use_chain = -1;
+                                       ssa->ops[ret].op1_use = orig_var;
+                                       ssa->ops[ret].op1_use_chain = ssa->vars[orig_var].use_chain;
+                                       ssa->vars[orig_var].use_chain = ret;
 
-                               ssa->ops[op_1].op1_def = -1;
-                               ssa->ops[op_1].op1_use = -1;
+                                       ssa->vars[v].definition = -1;
+                                       ssa->vars[v].use_chain = -1;
+
+                                       ssa->ops[op_1].op1_def = -1;
+                                       ssa->ops[op_1].op1_use = -1;
 
-                               MAKE_NOP(opline);
-                               remove_nops = 1;
+                                       MAKE_NOP(opline);
+                                       remove_nops = 1;
+                               }
 
                        } else if (ssa->ops[op_1].op1_def == v
                         && !RETURN_VALUE_USED(opline)
diff --git a/ext/opcache/tests/bug73789.phpt b/ext/opcache/tests/bug73789.phpt
new file mode 100644 (file)
index 0000000..142d522
--- /dev/null
@@ -0,0 +1,30 @@
+--TEST--
+Bug #73789 (Strange behavior of class constants in switch/case block)
+--FILE--
+<?php
+class Lexer
+{
+       const T_NONE = 1;
+       const T_STRING = 2;
+       const T_DOT = 8;
+       public function getType($value): int
+       {
+               $type = self::T_NONE;
+               switch (true) {
+               case ctype_alpha($value[0]):
+                       $name = 'Lexer::T_' . strtoupper($value);
+                       $type = constant($name);
+                       if ($type > 100) {
+                               return $type;
+                       }
+                       return self::T_STRING;
+               case $value === '.':
+                       return self::T_DOT;
+               default:
+               }
+               return $type;
+       }
+}
+var_dump((new Lexer())->getType("dot"));
+--EXPECT--
+int(2)