]> granicus.if.org Git - php/commitdiff
Fixed bug #69038 (switch(SOMECONSTANT) misbehaves) for master
authorXinchen Hui <laruence@php.net>
Tue, 17 Feb 2015 14:03:50 +0000 (22:03 +0800)
committerXinchen Hui <laruence@php.net>
Tue, 17 Feb 2015 14:05:57 +0000 (22:05 +0800)
ext/opcache/Optimizer/zend_optimizer.c
ext/opcache/tests/bug69038.phpt [new file with mode: 0644]

index a8506fb0789a893cc24e1f4dd419712bcd90a3e3..191e13ca1dd32d2a2ecac18c595dd509b16e8ad4 100644 (file)
@@ -310,13 +310,35 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array,
                                 * usually terminated by ZEND_FREE that finally kills the value.
                                 */
                                case ZEND_CASE: {
-                                       zval old_val;
-                                       ZVAL_COPY_VALUE(&old_val, val);
-                                       zval_copy_ctor(val);
-                                       zend_optimizer_update_op1_const(op_array, opline, val);
-                                       ZVAL_COPY_VALUE(val, &old_val);
-                                       opline++;
-                                       continue;
+                                       zend_op *m, *n;
+                                       int brk = op_array->last_brk_cont;
+                                       while (brk--) {
+                                               if (op_array->brk_cont_array[brk].start <= (opline - op_array->opcodes) &&
+                                                               op_array->brk_cont_array[brk].brk > (opline - op_array->opcodes)) {
+                                                       break;
+                                               }
+                                       }
+                                       m = opline;
+                                       n = op_array->opcodes + op_array->brk_cont_array[brk].brk + 1;
+                                       while (m < n) {
+                                               if (ZEND_OP1_TYPE(m) == type &&
+                                                               ZEND_OP1(m).var == var) {
+                                                       if (m->opcode == ZEND_CASE) {
+                                                               zval old_val;
+                                                               ZVAL_COPY_VALUE(&old_val, val);
+                                                               zval_copy_ctor(val);
+                                                               zend_optimizer_update_op1_const(op_array, m, val);
+                                                               ZVAL_COPY_VALUE(val, &old_val);
+                                                       } else if (m->opcode == ZEND_FREE) {
+                                                               MAKE_NOP(m);
+                                                       } else {
+                                                               ZEND_ASSERT(0);
+                                                       }
+                                               }
+                                               m++;
+                                       }
+                                       zval_dtor(val);
+                                       return 1;
                                }
                                case ZEND_FREE:
                                        MAKE_NOP(opline);
diff --git a/ext/opcache/tests/bug69038.phpt b/ext/opcache/tests/bug69038.phpt
new file mode 100644 (file)
index 0000000..f0c5491
--- /dev/null
@@ -0,0 +1,56 @@
+--TEST--
+Bug #69038 (switch(SOMECONSTANT) misbehaves)
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.optimization_level=-1
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function a($a = "bad") {
+       
+       switch (PHP_OS) {
+       case "LALALALA" : return "LALALAL";
+       case PHP_OS: return "okey";
+       default:   break;
+       }
+
+       return $a;
+}
+
+var_dump(a());
+
+
+function b($b = "bad") {
+       switch (PHP_OS) {
+       case "LALALAL": return "bad";
+       case PHP_OS:
+               switch (PHP_OS) {
+               case "FOO": break;
+               case PHP_OS: return "okey";
+               default :
+                       break;
+               }
+               break;
+       default:
+               break;
+       }
+       return $b;
+}
+var_dump(b());
+
+function c($b = "bad") {
+       switch (extension_loaded("standard")) {
+       case 0 : return "LALALAL";
+       case 1 : return "okey";
+       default : return "bad";
+       }
+}
+var_dump(c());
+
+?>
+--EXPECT--
+string(4) "okey"
+string(4) "okey"
+string(4) "okey"