com php-src: Exception thrown by "return" statement (from TMP destructors) shouldn't be caught in the same function: Zend/tests/try_fina lly_012.phpt
Zend/zend_compile.c Zend/zend_ compile.h Zend/zend_vm_def.h Zend/zend_vm_execu te.h

From: Date: Fri, 10 Jul 2015 01:13:34 +0000
Subject: com php-src: Exception thrown by "return" statement (from TMP destructors) shouldn't be caught in the same function: Zend/tests/try_fina lly_012.phpt
Zend/zend_compile.c Zend/zend_ compile.h Zend/zend_vm_def.h Zend/zend_vm_execu te.h
Groups: php.cvs 
Request: Send a blank email to php-cvs+get-87896@lists.php.net to get a copy of this message
Commit: 44f7348caa188d6c2b6228eaa622d0ef86b2647e Author: Dmitry Stogov <dmitry@zend.com> Fri, 10 Jul 2015 04:13:34 +0300 Parents: 3bb70fe2903acf2caf2600345f07943f34a3b23c Branches: master Link: http://git.php.net/?p=php-src.git;a=commitdiff;h=44f7348caa188d6c2b6228eaa622d0ef86b2647e Log: Exception thrown by "return" statement (from TMP destructors) shouldn't be caught in the same function Changed paths: A Zend/tests/try_finally_012.phpt M Zend/zend_compile.c M Zend/zend_compile.h M Zend/zend_vm_def.h M Zend/zend_vm_execute.h Diff: diff --git a/Zend/tests/try_finally_012.phpt b/Zend/tests/try_finally_012.phpt new file mode 100644 index 0000000..32fec7a --- /dev/null +++ b/Zend/tests/try_finally_012.phpt @@ -0,0 +1,32 @@ +--TEST-- +Try finally (exception in "return" statement) +--FILE-- +<?php +class A { + public $x = 1; + public $y = 2; + function __destruct() { + throw new Exception(); + } +} +function foo() { + foreach(new A() as $a) { + try { + return $a; + } catch (Exception $e) { + echo "exception in foo\n"; + } finally { + echo "finally\n"; + } + } +} +try { + foo(); +} catch (Exception $e) { + echo "exception in main\n"; +} +?> +--EXPECT-- +finally +exception in main + diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 0927f0c..44807d3 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -3514,9 +3514,20 @@ void zend_compile_unset(zend_ast *ast) /* {{{ */ } /* }}} */ -static void zend_free_foreach_and_switch_variables(void) /* {{{ */ +static void zend_free_foreach_and_switch_variables(uint32_t flags) /* {{{ */ { + uint32_t start_op_number = get_next_op_number(CG(active_op_array)); + zend_stack_apply(&CG(loop_var_stack), ZEND_STACK_APPLY_TOPDOWN, (int (*)(void *element)) generate_free_loop_var); + + if (flags) { + uint32_t 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].extended_value |= flags; + start_op_number++; + } + } } /* }}} */ @@ -3538,7 +3549,7 @@ void zend_compile_return(zend_ast *ast) /* {{{ */ zend_compile_expr(&expr_node, expr_ast); } - zend_free_foreach_and_switch_variables(); + zend_free_foreach_and_switch_variables(ZEND_FREE_ON_RETURN); if (CG(context).in_finally) { opline = zend_emit_op(NULL, ZEND_DISCARD_EXCEPTION, NULL, NULL); diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index a3bc17f...8e9cfe7 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -875,7 +875,9 @@ ZEND_API void zend_assert_valid_class_name(const zend_string *const_name); #define ZEND_FETCH_ARG_MASK 0x000fffff -#define ZEND_MEMBER_FUNC_CALL 1<<0 +#define ZEND_FREE_ON_RETURN (1<<0) + +#define ZEND_MEMBER_FUNC_CALL (1<<0) #define ZEND_ARG_SEND_BY_REF (1<<0) #define ZEND_ARG_COMPILE_TIME_BOUND (1<<1) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index b94614e..5ea7b8a 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2610,10 +2610,13 @@ ZEND_VM_HANDLER(47, ZEND_JMPNZ_EX, CONST|TMPVAR|CV, ANY) ZEND_VM_HANDLER(70, ZEND_FREE, TMPVAR, ANY) { + zval *var; USE_OPLINE SAVE_OPLINE(); - zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + var = EX_VAR(opline->op1.var); + zval_ptr_dtor_nogc(var); + ZVAL_NULL(var); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -2626,8 +2629,10 @@ ZEND_VM_HANDLER(127, ZEND_FE_FREE, TMPVAR, ANY) var = EX_VAR(opline->op1.var); if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) { zend_hash_iterator_del(Z_FE_ITER_P(var)); + Z_FE_ITER_P(var) = (uint32_t)-1; } zval_ptr_dtor_nogc(var); + ZVAL_NULL(var); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -7099,6 +7104,18 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) } } + if (catch_op_num) { + if ((EX(func)->op_array.opcodes[op_num].opcode == ZEND_FREE && (EX(func)->op_array.opcodes[op_num].extended_value & ZEND_FREE_ON_RETURN)) + || (EX(func)->op_array.opcodes[op_num].opcode == ZEND_FE_FREE && (EX(func)->op_array.opcodes[op_num].extended_value & ZEND_FREE_ON_RETURN)) + ) { + /* exceptions thrown because of TMP variable destruction on "return" + * statement should't be caught in the same function. + * See: Zend/tests/try_finally_012.phpt + */ + catch_op_num = 0; + } + } + i_cleanup_unfinished_execution(execute_data, op_num, catch_op_num); if (finally_op_num && (!catch_op_num || catch_op_num >= finally_op_num)) { diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 828babb..8a6918e 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1500,6 +1500,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER( } } + if (catch_op_num) { + if ((EX(func)->op_array.opcodes[op_num].opcode == ZEND_FREE && (EX(func)->op_array.opcodes[op_num].extended_value & ZEND_FREE_ON_RETURN)) + || (EX(func)->op_array.opcodes[op_num].opcode == ZEND_FE_FREE && (EX(func)->op_array.opcodes[op_num].extended_value & ZEND_FREE_ON_RETURN)) + ) { + /* exceptions thrown because of TMP variable destruction on "return" + * statement should't be caught in the same function. + * See: Zend/tests/try_finally_012.phpt + */ + catch_op_num = 0; + } + } + i_cleanup_unfinished_execution(execute_data, op_num, catch_op_num); if (finally_op_num && (!catch_op_num || catch_op_num >= finally_op_num)) { @@ -40189,10 +40201,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_JMPNZ_EX_SPEC_TMPVAR_HANDLER(Z static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FREE_SPEC_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { + zval *var; USE_OPLINE SAVE_OPLINE(); - zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + var = EX_VAR(opline->op1.var); + zval_ptr_dtor_nogc(var); + ZVAL_NULL(var); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -40205,8 +40220,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_FREE_SPEC_TMPVAR_HANDLER(ZE var = EX_VAR(opline->op1.var); if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) { zend_hash_iterator_del(Z_FE_ITER_P(var)); + Z_FE_ITER_P(var) = (uint32_t)-1; } zval_ptr_dtor_nogc(var); + ZVAL_NULL(var); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); }

« previous php.cvs (#87896) next »