Permalink
Browse files

Fixed bugs #34065 and #38623 (throw in foreach/switch causes memory l…

…eaks)
  • Loading branch information...
1 parent 7d14dad commit cd6537ed6d9d3bf957d70281731406196fba484d Dmitry Stogov committed Sep 19, 2006
Showing with 100 additions and 16 deletions.
  1. +3 −0 NEWS
  2. +15 −0 Zend/tests/bug34065.phpt
  3. +16 −0 Zend/tests/bug38623.phpt
  4. +1 −0 Zend/zend_compile.c
  5. +1 −0 Zend/zend_compile.h
  6. +32 −8 Zend/zend_vm_def.h
  7. +32 −8 Zend/zend_vm_execute.h
View
3 NEWS
@@ -6,13 +6,16 @@ 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).
(Ilia, ce at netage dot bg)
- 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
View
@@ -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
View
@@ -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
@@ -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;
}
View
@@ -89,6 +89,7 @@ struct _zend_op {
typedef struct _zend_brk_cont_element {
+ int start;
int cont;
int brk;
int parent;
View
@@ -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; 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;
@@ -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)
View
@@ -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; 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;
@@ -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)

0 comments on commit cd6537e

Please sign in to comment.