From: Dmitry Stogov Date: Tue, 19 Sep 2006 21:36:00 +0000 (+0000) Subject: Fixed bugs #34065 and #38623 (throw in foreach/switch causes memory leaks) X-Git-Tag: RELEASE_1_0_0RC1~1616 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7aeb4421b736f845999ca2423249bad5eb51babe;p=php Fixed bugs #34065 and #38623 (throw in foreach/switch causes memory leaks) --- diff --git a/Zend/tests/bug34065.phpt b/Zend/tests/bug34065.phpt new file mode 100755 index 0000000000..9d76fca643 --- /dev/null +++ b/Zend/tests/bug34065.phpt @@ -0,0 +1,15 @@ +--TEST-- +Bug #34065 (throw in foreach causes memory leaks) +--FILE-- + +--EXPECT-- +ok diff --git a/Zend/tests/bug38623.phpt b/Zend/tests/bug38623.phpt new file mode 100755 index 0000000000..9b042a9141 --- /dev/null +++ b/Zend/tests/bug38623.phpt @@ -0,0 +1,16 @@ +--TEST-- +Bug #38623 (leaks in a tricky code with switch() and exceptions) +--FILE-- + +--EXPECT-- +ok diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 6552602812..c7472e8444 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -688,6 +688,7 @@ static inline void do_begin_loop(TSRMLS_D) parent = CG(active_op_array)->current_brk_cont; CG(active_op_array)->current_brk_cont = CG(active_op_array)->last_brk_cont; brk_cont_element = get_next_brk_cont_element(CG(active_op_array)); + brk_cont_element->start = get_next_op_number(CG(active_op_array)); brk_cont_element->parent = parent; } diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 71f1560064..6dc24704ef 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -89,6 +89,7 @@ struct _zend_op { typedef struct _zend_brk_cont_element { + int start; int cont; int brk; int parent; diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 01f481da16..9fcd1284aa 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -3841,7 +3841,8 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) { zend_uint op_num = EG(opline_before_exception)-EG(active_op_array)->opcodes; int i; - int encapsulating_block=-1; + zend_uint catch_op_num; + int catched = 0; zval **stack_zval_pp; zval restored_error_reporting; @@ -3860,7 +3861,8 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) } if (op_num >= EG(active_op_array)->try_catch_array[i].try_op && op_num < EG(active_op_array)->try_catch_array[i].catch_op) { - encapsulating_block = i; + catched = 1; + catch_op_num = EX(op_array)->try_catch_array[i].catch_op; } } @@ -3876,6 +3878,28 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) zend_ptr_stack_2_pop(&EG(arg_types_stack), (void**)&EX(object), (void**)&EX(fbc)); } + for (i=0; ilast_brk_cont; i++) { + if (EX(op_array)->brk_cont_array[i].start > op_num) { + /* further blocks will not be relevant... */ + break; + } + if (op_num < EX(op_array)->brk_cont_array[i].brk) { + if (!catched || + catch_op_num >= EX(op_array)->brk_cont_array[i].brk) { + zend_op *brk_opline = &EX(op_array)->opcodes[EX(op_array)->brk_cont_array[i].brk]; + + switch (brk_opline->opcode) { + case ZEND_SWITCH_FREE: + zend_switch_free(brk_opline, EX(Ts) TSRMLS_CC); + break; + case ZEND_FREE: + zendi_zval_dtor(EX_T(brk_opline->op1.u.var).tmp_var); + break; + } + } + } + } + /* restore previous error_reporting value */ if (!EG(error_reporting) && EX(old_error_reporting) != NULL && Z_LVAL_P(EX(old_error_reporting)) != 0) { Z_TYPE(restored_error_reporting) = IS_LONG; @@ -3886,12 +3910,12 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) } EX(old_error_reporting) = NULL; - if (encapsulating_block == -1) { - ZEND_VM_RETURN_FROM_EXECUTE_LOOP(); - } else { - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[EG(active_op_array)->try_catch_array[encapsulating_block].catch_op]); - ZEND_VM_CONTINUE(); - } + if (!catched) { + ZEND_VM_RETURN_FROM_EXECUTE_LOOP(); + } else { + ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]); + ZEND_VM_CONTINUE(); + } } ZEND_VM_HANDLER(146, ZEND_VERIFY_ABSTRACT_CLASS, ANY, ANY) diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 0755c04ae4..d2afe00271 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -538,7 +538,8 @@ static int ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_uint op_num = EG(opline_before_exception)-EG(active_op_array)->opcodes; int i; - int encapsulating_block=-1; + zend_uint catch_op_num; + int catched = 0; zval **stack_zval_pp; zval restored_error_reporting; @@ -557,7 +558,8 @@ static int ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } if (op_num >= EG(active_op_array)->try_catch_array[i].try_op && op_num < EG(active_op_array)->try_catch_array[i].catch_op) { - encapsulating_block = i; + catched = 1; + catch_op_num = EX(op_array)->try_catch_array[i].catch_op; } } @@ -573,6 +575,28 @@ static int ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_ptr_stack_2_pop(&EG(arg_types_stack), (void**)&EX(object), (void**)&EX(fbc)); } + for (i=0; ilast_brk_cont; i++) { + if (EX(op_array)->brk_cont_array[i].start > op_num) { + /* further blocks will not be relevant... */ + break; + } + if (op_num < EX(op_array)->brk_cont_array[i].brk) { + if (!catched || + catch_op_num >= EX(op_array)->brk_cont_array[i].brk) { + zend_op *brk_opline = &EX(op_array)->opcodes[EX(op_array)->brk_cont_array[i].brk]; + + switch (brk_opline->opcode) { + case ZEND_SWITCH_FREE: + zend_switch_free(brk_opline, EX(Ts) TSRMLS_CC); + break; + case ZEND_FREE: + zendi_zval_dtor(EX_T(brk_opline->op1.u.var).tmp_var); + break; + } + } + } + } + /* restore previous error_reporting value */ if (!EG(error_reporting) && EX(old_error_reporting) != NULL && Z_LVAL_P(EX(old_error_reporting)) != 0) { Z_TYPE(restored_error_reporting) = IS_LONG; @@ -583,12 +607,12 @@ static int ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } EX(old_error_reporting) = NULL; - if (encapsulating_block == -1) { - ZEND_VM_RETURN_FROM_EXECUTE_LOOP(); - } else { - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[EG(active_op_array)->try_catch_array[encapsulating_block].catch_op]); - ZEND_VM_CONTINUE(); - } + if (!catched) { + ZEND_VM_RETURN_FROM_EXECUTE_LOOP(); + } else { + ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]); + ZEND_VM_CONTINUE(); + } } static int ZEND_VERIFY_ABSTRACT_CLASS_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)