]> granicus.if.org Git - php/commitdiff
- Use ZEND_FREE() opcode instead of ZEND_SWITCH_FREE(IS_TMP_VAR)
authorDmitry Stogov <dmitry@php.net>
Mon, 5 May 2008 11:02:46 +0000 (11:02 +0000)
committerDmitry Stogov <dmitry@php.net>
Mon, 5 May 2008 11:02:46 +0000 (11:02 +0000)
- Fixed bug #44913 (Segfault when using return in combination with nested loops and continue 2)

Zend/tests/bug44913.phpt [new file with mode: 0644]
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_execute.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

diff --git a/Zend/tests/bug44913.phpt b/Zend/tests/bug44913.phpt
new file mode 100644 (file)
index 0000000..0c2551f
--- /dev/null
@@ -0,0 +1,17 @@
+--TEST--
+Bug #44913 (Segfault when using return in combination with nested loops and continue 2)
+--FILE--
+<?php
+function something() {
+        foreach(array(1, 2) as $value) {
+                for($i = 0; $i < 1; $i++) {
+                        continue 2;
+                }
+                return;
+        }
+}
+something();
+echo "ok\n";
+?>
+--EXPECT--
+ok
index 1a0fc5e323d78ef9322d4ea387609d359beb5ba1..fe16738cd52cc1eb7b37f1a7259fdd551d8ccb15 100644 (file)
@@ -2129,7 +2129,7 @@ static int generate_free_switch_expr(zend_switch_entry *switch_entry TSRMLS_DC)
 
        opline = get_next_op(CG(active_op_array) TSRMLS_CC);
 
-       opline->opcode = ZEND_SWITCH_FREE;
+       opline->opcode = (switch_entry->cond.op_type == IS_TMP_VAR) ? ZEND_FREE : ZEND_SWITCH_FREE;
        opline->op1 = switch_entry->cond;
        SET_UNUSED(opline->op2);
        opline->extended_value = 0;
@@ -2148,7 +2148,7 @@ static int generate_free_foreach_copy(zend_op *foreach_copy TSRMLS_DC) /* {{{ */
 
        opline = get_next_op(CG(active_op_array) TSRMLS_CC);
 
-       opline->opcode = ZEND_SWITCH_FREE;
+       opline->opcode = (foreach_copy->result.op_type == IS_TMP_VAR) ? ZEND_FREE : ZEND_SWITCH_FREE;
        opline->op1 = foreach_copy->result;
        SET_UNUSED(opline->op2);
        opline->extended_value = 1;
@@ -2156,7 +2156,7 @@ static int generate_free_foreach_copy(zend_op *foreach_copy TSRMLS_DC) /* {{{ */
        if (foreach_copy->op1.op_type != IS_UNUSED) {
                opline = get_next_op(CG(active_op_array) TSRMLS_CC);
 
-               opline->opcode = ZEND_SWITCH_FREE;
+               opline->opcode = (foreach_copy->op1.op_type == IS_TMP_VAR) ? ZEND_FREE : ZEND_SWITCH_FREE;
                opline->op1 = foreach_copy->op1;
                SET_UNUSED(opline->op2);
                opline->extended_value = 0;
@@ -2169,6 +2169,7 @@ static int generate_free_foreach_copy(zend_op *foreach_copy TSRMLS_DC) /* {{{ */
 void zend_do_return(znode *expr, int do_end_vparse TSRMLS_DC) /* {{{ */
 {
        zend_op *opline;
+       int start_op_number, end_op_number;
 
        if (do_end_vparse) {
                if (CG(active_op_array)->return_reference && !zend_is_function_or_method_call(expr)) {
@@ -2178,6 +2179,8 @@ void zend_do_return(znode *expr, int do_end_vparse TSRMLS_DC) /* {{{ */
                }
        }
 
+       start_op_number = get_next_op_number(CG(active_op_array));
+
 #ifdef ZTS
        zend_stack_apply_with_argument(&CG(switch_cond_stack), ZEND_STACK_APPLY_TOPDOWN, (int (*)(void *element, void *)) generate_free_switch_expr TSRMLS_CC);
        zend_stack_apply_with_argument(&CG(foreach_copy_stack), ZEND_STACK_APPLY_TOPDOWN, (int (*)(void *element, void *)) generate_free_foreach_copy TSRMLS_CC);
@@ -2186,6 +2189,12 @@ void zend_do_return(znode *expr, int do_end_vparse TSRMLS_DC) /* {{{ */
        zend_stack_apply(&CG(foreach_copy_stack), ZEND_STACK_APPLY_TOPDOWN, (int (*)(void *element)) generate_free_foreach_copy);
 #endif
 
+       end_op_number = get_next_op_number(CG(active_op_array));
+       while (start_op_number < end_op_number) {
+               CG(active_op_array)->opcodes[start_op_number].op1.u.EA.type = EXT_TYPE_FREE_ON_RETURN;
+               start_op_number++;
+       }
+
        opline = get_next_op(CG(active_op_array) TSRMLS_CC);
 
        opline->opcode = ZEND_RETURN;
@@ -3225,7 +3234,7 @@ void zend_do_switch_end(znode *case_list TSRMLS_DC) /* {{{ */
        if (switch_entry_ptr->cond.op_type==IS_VAR || switch_entry_ptr->cond.op_type==IS_TMP_VAR) {
                /* emit free for the switch condition*/
                opline = get_next_op(CG(active_op_array) TSRMLS_CC);
-               opline->opcode = ZEND_SWITCH_FREE;
+               opline->opcode = (switch_entry_ptr->cond.op_type == IS_TMP_VAR) ? ZEND_FREE : ZEND_SWITCH_FREE;
                opline->op1 = switch_entry_ptr->cond;
                SET_UNUSED(opline->op2);
        }
index fd6746caeb295976eb640756b8fb2d301f6f0b11..9605002c2ad381e4e17e8490b1875020c7bb001d 100644 (file)
@@ -324,7 +324,8 @@ struct _zend_execute_data {
 #define IS_UNUSED      (1<<3)  /* Unused variable */
 #define IS_CV          (1<<4)  /* Compiled variable */
 
-#define EXT_TYPE_UNUSED                (1<<0)
+#define EXT_TYPE_UNUSED                                (1<<0)
+#define EXT_TYPE_FREE_ON_RETURN                (2<<0)
 
 #include "zend_globals.h"
 
index ce7a511b5cf0e8c76eb6fb1e6689f99dc3290018..29494387a6c05453ed1767df5ecad8a745b2abcb 100644 (file)
@@ -412,22 +412,18 @@ static inline zval *_get_obj_zval_ptr(znode *op, temp_variable *Ts, zend_free_op
 }
 /* }}} */
 
-static inline void zend_switch_free(temp_variable *T, int type, int extended_value TSRMLS_DC) /* {{{ */
+static inline void zend_switch_free(temp_variable *T, int extended_value TSRMLS_DC) /* {{{ */
 {
-       if (type == IS_VAR) {
-               if (T->var.ptr) {
-                       if (extended_value & ZEND_FE_RESET_VARIABLE) { /* foreach() free */
-                               Z_DELREF_P(T->var.ptr);
-                       }
-                       zval_ptr_dtor(&T->var.ptr);
-               } else if (!T->var.ptr_ptr) {
-                       /* perform the equivalent of equivalent of a
-                        * quick & silent get_zval_ptr, and FREE_OP
-                        */
-                       PZVAL_UNLOCK_FREE(T->str_offset.str);
+       if (T->var.ptr) {
+               if (extended_value & ZEND_FE_RESET_VARIABLE) { /* foreach() free */
+                       Z_DELREF_P(T->var.ptr);
                }
-       } else { /* IS_TMP_VAR */
-               zendi_zval_dtor(T->tmp_var);
+               zval_ptr_dtor(&T->var.ptr);
+       } else if (!T->var.ptr_ptr) {
+               /* perform the equivalent of equivalent of a
+                * quick & silent get_zval_ptr, and FREE_OP
+                */
+               PZVAL_UNLOCK_FREE(T->str_offset.str);
        }
 }
 /* }}} */
@@ -1347,10 +1343,14 @@ static inline zend_brk_cont_element* zend_brk_cont(int nest_levels, int array_of
 
                        switch (brk_opline->opcode) {
                                case ZEND_SWITCH_FREE:
-                                       zend_switch_free(&T(brk_opline->op1.u.var), brk_opline->op1.op_type, brk_opline->extended_value TSRMLS_CC);
+                                       if (brk_opline->op1.u.EA.type != EXT_TYPE_FREE_ON_RETURN) {
+                                               zend_switch_free(&T(brk_opline->op1.u.var), brk_opline->extended_value TSRMLS_CC);
+                                       }
                                        break;
                                case ZEND_FREE:
-                                       zendi_zval_dtor(T(brk_opline->op1.u.var).tmp_var);
+                                       if (brk_opline->op1.u.EA.type != EXT_TYPE_FREE_ON_RETURN) {
+                                               zendi_zval_dtor(T(brk_opline->op1.u.var).tmp_var);
+                                       }
                                        break;
                        }
                }
index 424570a167a721b54dfdf23749ae46982b50f5cb..fc04af946860fc0a3199bf9c3a82ff378b704beb 100644 (file)
@@ -2702,10 +2702,14 @@ ZEND_VM_HANDLER(100, ZEND_GOTO, ANY, CONST)
 
        switch (brk_opline->opcode) {
                case ZEND_SWITCH_FREE:
-                       zend_switch_free(&EX_T(brk_opline->op1.u.var), brk_opline->op1.op_type, brk_opline->extended_value TSRMLS_CC);
+                       if (brk_opline->op1.u.EA.type != EXT_TYPE_FREE_ON_RETURN) {
+                               zend_switch_free(&EX_T(brk_opline->op1.u.var), brk_opline->extended_value TSRMLS_CC);
+                       }
                        break;
                case ZEND_FREE:
-                       zendi_zval_dtor(EX_T(brk_opline->op1.u.var).tmp_var);
+                       if (brk_opline->op1.u.EA.type != EXT_TYPE_FREE_ON_RETURN) {
+                               zendi_zval_dtor(EX_T(brk_opline->op1.u.var).tmp_var);
+                       }
                        break;
        }
        ZEND_VM_JMP(opline->op1.u.jmp_addr);
@@ -2743,11 +2747,11 @@ ZEND_VM_HANDLER(48, ZEND_CASE, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV)
        ZEND_VM_NEXT_OPCODE();
 }
 
-ZEND_VM_HANDLER(49, ZEND_SWITCH_FREE, TMP|VAR, ANY)
+ZEND_VM_HANDLER(49, ZEND_SWITCH_FREE, VAR, ANY)
 {
        zend_op *opline = EX(opline);
 
-       zend_switch_free(&EX_T(opline->op1.u.var), OP1_TYPE, opline->extended_value TSRMLS_CC);
+       zend_switch_free(&EX_T(opline->op1.u.var), opline->extended_value TSRMLS_CC);
        ZEND_VM_NEXT_OPCODE();
 }
 
@@ -4287,10 +4291,14 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
 
                                switch (brk_opline->opcode) {
                                        case ZEND_SWITCH_FREE:
-                                               zend_switch_free(&EX_T(brk_opline->op1.u.var), brk_opline->op1.op_type, brk_opline->extended_value TSRMLS_CC);
+                                               if (brk_opline->op1.u.EA.type != EXT_TYPE_FREE_ON_RETURN) {
+                                                       zend_switch_free(&EX_T(brk_opline->op1.u.var), brk_opline->extended_value TSRMLS_CC);
+                                               }
                                                break;
                                        case ZEND_FREE:
-                                               zendi_zval_dtor(EX_T(brk_opline->op1.u.var).tmp_var);
+                                               if (brk_opline->op1.u.EA.type != EXT_TYPE_FREE_ON_RETURN) {
+                                                       zendi_zval_dtor(EX_T(brk_opline->op1.u.var).tmp_var);
+                                               }
                                                break;
                                }
                        }
index cc47d898eadd0dc35e72eaf7305cda2b7828a223..9280fc88ba4dbe13a5d7c93eb107c21ec25512d8 100644 (file)
@@ -523,10 +523,14 @@ static int ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 
                                switch (brk_opline->opcode) {
                                        case ZEND_SWITCH_FREE:
-                                               zend_switch_free(&EX_T(brk_opline->op1.u.var), brk_opline->op1.op_type, brk_opline->extended_value TSRMLS_CC);
+                                               if (brk_opline->op1.u.EA.type != EXT_TYPE_FREE_ON_RETURN) {
+                                                       zend_switch_free(&EX_T(brk_opline->op1.u.var), brk_opline->extended_value TSRMLS_CC);
+                                               }
                                                break;
                                        case ZEND_FREE:
-                                               zendi_zval_dtor(EX_T(brk_opline->op1.u.var).tmp_var);
+                                               if (brk_opline->op1.u.EA.type != EXT_TYPE_FREE_ON_RETURN) {
+                                                       zendi_zval_dtor(EX_T(brk_opline->op1.u.var).tmp_var);
+                                               }
                                                break;
                                }
                        }
@@ -733,10 +737,14 @@ static int ZEND_GOTO_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 
        switch (brk_opline->opcode) {
                case ZEND_SWITCH_FREE:
-                       zend_switch_free(&EX_T(brk_opline->op1.u.var), brk_opline->op1.op_type, brk_opline->extended_value TSRMLS_CC);
+                       if (brk_opline->op1.u.EA.type != EXT_TYPE_FREE_ON_RETURN) {
+                               zend_switch_free(&EX_T(brk_opline->op1.u.var), brk_opline->extended_value TSRMLS_CC);
+                       }
                        break;
                case ZEND_FREE:
-                       zendi_zval_dtor(EX_T(brk_opline->op1.u.var).tmp_var);
+                       if (brk_opline->op1.u.EA.type != EXT_TYPE_FREE_ON_RETURN) {
+                               zendi_zval_dtor(EX_T(brk_opline->op1.u.var).tmp_var);
+                       }
                        break;
        }
        ZEND_VM_JMP(opline->op1.u.jmp_addr);
@@ -4868,14 +4876,6 @@ static int ZEND_BOOL_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        ZEND_VM_NEXT_OPCODE();
 }
 
-static int ZEND_SWITCH_FREE_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
-{
-       zend_op *opline = EX(opline);
-
-       zend_switch_free(&EX_T(opline->op1.u.var), IS_TMP_VAR, opline->extended_value TSRMLS_CC);
-       ZEND_VM_NEXT_OPCODE();
-}
-
 static int ZEND_CLONE_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
        zend_op *opline = EX(opline);
@@ -8266,7 +8266,7 @@ static int ZEND_SWITCH_FREE_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
        zend_op *opline = EX(opline);
 
-       zend_switch_free(&EX_T(opline->op1.u.var), IS_VAR, opline->extended_value TSRMLS_CC);
+       zend_switch_free(&EX_T(opline->op1.u.var), opline->extended_value TSRMLS_CC);
        ZEND_VM_NEXT_OPCODE();
 }
 
@@ -31948,11 +31948,11 @@ void zend_init_opcodes_handlers(void)
        ZEND_NULL_HANDLER,
        ZEND_NULL_HANDLER,
        ZEND_NULL_HANDLER,
-       ZEND_SWITCH_FREE_SPEC_TMP_HANDLER,
-       ZEND_SWITCH_FREE_SPEC_TMP_HANDLER,
-       ZEND_SWITCH_FREE_SPEC_TMP_HANDLER,
-       ZEND_SWITCH_FREE_SPEC_TMP_HANDLER,
-       ZEND_SWITCH_FREE_SPEC_TMP_HANDLER,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
        ZEND_SWITCH_FREE_SPEC_VAR_HANDLER,
        ZEND_SWITCH_FREE_SPEC_VAR_HANDLER,
        ZEND_SWITCH_FREE_SPEC_VAR_HANDLER,