]> granicus.if.org Git - php/commitdiff
Fixed bug #72508 (strange references after recursive function call and "switch" state...
authorXinchen Hui <laruence@gmail.com>
Tue, 28 Jun 2016 07:36:50 +0000 (15:36 +0800)
committerXinchen Hui <laruence@gmail.com>
Tue, 28 Jun 2016 07:36:50 +0000 (15:36 +0800)
NEWS
Zend/tests/bug72508.phpt [new file with mode: 0644]
Zend/zend_compile.c

diff --git a/NEWS b/NEWS
index 816a20f451cf8a83a5525d40f14859243fbb197e..33e4f5f0153b45151f5bb7cc218ac1b19dd59dec 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,10 @@ PHP                                                                        NEWS
 |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
 ?? ??? 2016 PHP 7.0.9
 
+- Core:
+  . Fixed bug #72508 (strange references after recursive function call and
+    "switch" statement). (Laruence)
+
 - CLI:
   . Fixed bug #72484 (SCRIPT_FILENAME shows wrong path if the user specify
     router.php). (Laruence)
diff --git a/Zend/tests/bug72508.phpt b/Zend/tests/bug72508.phpt
new file mode 100644 (file)
index 0000000..60196bf
--- /dev/null
@@ -0,0 +1,30 @@
+--TEST--
+Bug #72508 (strange references after recursive function call and "switch" statement)
+--FILE--
+<?php
+function a ($option) {
+       b($option['bla']);
+       c($option);
+       var_dump($option);
+}
+function b (&$string) {
+       $string = 'changed';
+}
+function c ($option) {
+       switch ($option['bla']) {
+       default:
+               $copy = $option;
+               $copy['bla'] = 'copy';
+               break;
+       case NULL:
+               break;
+       }
+}
+a(array('bla' => 'fasel'));
+
+?>
+--EXPECT--
+array(1) {
+  ["bla"]=>
+  string(7) "changed"
+}
index 593c19e01519d12f611d1fccd7b250e306f4568e..3af1fb3861a4a0ab3b0d2e058f22f7b83a2d3f39 100644 (file)
@@ -4035,16 +4035,32 @@ void zend_compile_switch(zend_ast *ast) /* {{{ */
 
        znode expr_node, case_node;
        zend_op *opline;
-       uint32_t *jmpnz_opnums = safe_emalloc(sizeof(uint32_t), cases->children, 0);
-       uint32_t opnum_default_jmp;
+       uint32_t *jmpnz_opnums, opnum_default_jmp;
 
        zend_compile_expr(&expr_node, expr_ast);
 
+       if (cases->children == 1 && cases->child[0]->child[0] == NULL) {
+               /* we have to take care about the case that only have one default branch,
+                * expr result will not be unrefed in this case, but it should be like in ZEND_CASE */
+               zend_ast *stmt_ast = cases->child[0]->child[1];
+               if (expr_node.op_type == IS_VAR || expr_node.op_type == IS_TMP_VAR) {
+                       zend_emit_op(NULL, ZEND_FREE, &expr_node, NULL);
+               } else if (expr_node.op_type == IS_CONST) {
+                       zval_dtor(&expr_node.u.constant);
+               }
+
+               zend_begin_loop(ZEND_NOP, NULL);
+               zend_compile_stmt(stmt_ast);
+               zend_end_loop(get_next_op_number(CG(active_op_array)));
+               return;
+       }
+
        zend_begin_loop(ZEND_FREE, &expr_node);
 
        case_node.op_type = IS_TMP_VAR;
        case_node.u.op.var = get_temporary_variable(CG(active_op_array));
 
+       jmpnz_opnums = safe_emalloc(sizeof(uint32_t), cases->children, 0);
        for (i = 0; i < cases->children; ++i) {
                zend_ast *case_ast = cases->child[i];
                zend_ast *cond_ast = case_ast->child[0];