Fixed bugs #34065 and #38623 (throw in foreach/switch causes memory leaks)

This commit is contained in:
Dmitry Stogov 2006-09-19 21:36:00 +00:00
parent 1efe216585
commit 7aeb4421b7
6 changed files with 97 additions and 16 deletions

15
Zend/tests/bug34065.phpt Executable file
View File

@ -0,0 +1,15 @@
--TEST--
Bug #34065 (throw in foreach causes memory leaks)
--FILE--
<?php
$data = file(__FILE__);
try {
foreach ($data as $line) {
throw new Exception("error");
}
} catch (Exception $e) {
echo "ok\n";
}
?>
--EXPECT--
ok

16
Zend/tests/bug38623.phpt Executable file
View File

@ -0,0 +1,16 @@
--TEST--
Bug #38623 (leaks in a tricky code with switch() and exceptions)
--FILE--
<?php
try {
switch(strtolower("apache")) {
case "apache":
throw new Exception("test");
break;
}
} catch (Exception $e) {
echo "ok\n";
}
?>
--EXPECT--
ok

View File

@ -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;
}

View File

@ -89,6 +89,7 @@ struct _zend_op {
typedef struct _zend_brk_cont_element {
int start;
int cont;
int brk;
int parent;

View File

@ -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; i<EX(op_array)->last_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,10 +3910,10 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
}
EX(old_error_reporting) = NULL;
if (encapsulating_block == -1) {
if (!catched) {
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_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]);
ZEND_VM_CONTINUE();
}
}

View File

@ -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; i<EX(op_array)->last_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,10 +607,10 @@ static int ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
}
EX(old_error_reporting) = NULL;
if (encapsulating_block == -1) {
if (!catched) {
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_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]);
ZEND_VM_CONTINUE();
}
}