summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@php.net>2006-09-19 21:36:54 +0000
committerDmitry Stogov <dmitry@php.net>2006-09-19 21:36:54 +0000
commitcd6537ed6d9d3bf957d70281731406196fba484d (patch)
tree3d92037f3b3422def57cbcbab33f4c51f0642b29
parent7d14dad02ea58db34594e91f759424c51071c5a8 (diff)
downloadphp-git-cd6537ed6d9d3bf957d70281731406196fba484d.tar.gz
Fixed bugs #34065 and #38623 (throw in foreach/switch causes memory leaks)
-rw-r--r--NEWS3
-rwxr-xr-xZend/tests/bug34065.phpt15
-rwxr-xr-xZend/tests/bug38623.phpt16
-rw-r--r--Zend/zend_compile.c1
-rw-r--r--Zend/zend_compile.h1
-rw-r--r--Zend/zend_vm_def.h40
-rw-r--r--Zend/zend_vm_execute.h40
7 files changed, 100 insertions, 16 deletions
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--
+<?php
+$data = file(__FILE__);
+try {
+ foreach ($data as $line) {
+ throw new Exception("error");
+ }
+} catch (Exception $e) {
+ echo "ok\n";
+}
+?>
+--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--
+<?php
+try {
+ switch(strtolower("apache")) {
+ case "apache":
+ throw new Exception("test");
+ break;
+ }
+} catch (Exception $e) {
+ echo "ok\n";
+}
+?>
+--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; 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)
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; 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)