From: Dmitry Stogov Date: Tue, 19 Sep 2006 21:36:54 +0000 (+0000) Subject: Fixed bugs #34065 and #38623 (throw in foreach/switch causes memory leaks) X-Git-Tag: php-5.2.0RC5~125 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=cd6537ed6d9d3bf957d70281731406196fba484d;p=php Fixed bugs #34065 and #38623 (throw in foreach/switch causes memory leaks) --- diff --git a/NEWS b/NEWS index d401e9ec4c..bcd6362133 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,8 @@ PHP NEWS (Dmitry) - Fixed bug #38844 (curl_easy_strerror() is defined only since cURL 7.12.0). (Tony) +- Fixed bug #38623 (leaks in a tricky code with switch() and exceptions). + (Dmitry) - Fixed bug #38574 (missing curl constants and improper constant detection). (Ilia) - Fixed bug #37870 (pgo_pgsql tries to de-allocate unused statements). @@ -13,6 +15,7 @@ PHP NEWS - Fixed bug #36681 (pdo_pgsql driver incorrectly ignored some errors). (Wez, Ilia) - Fixed bug #34066 (recursive array_walk causes segfault). (Tony) +- Fixed bug #34065 (throw in foreach causes memory leaks). (Dmitry) 14 Sep 2006, PHP 5.2.0RC4 - Added DSA key generation support to openssl_pkey_new(), FR #38731 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 bb04271e2e..191d8dfe94 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -649,6 +649,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 3525198d91..fb3bafa737 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 79bf603408..13204e692c 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -3718,7 +3718,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; @@ -3737,7 +3738,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; + catch_op_num = EX(op_array)->try_catch_array[i].catch_op; + catched = 1; } } @@ -3753,6 +3755,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; @@ -3763,12 +3787,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 f3039acaab..277cd3cf37 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -528,7 +528,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; @@ -547,7 +548,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; + catch_op_num = EX(op_array)->try_catch_array[i].catch_op; + catched = 1; } } @@ -563,6 +565,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; @@ -573,12 +597,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)