]> granicus.if.org Git - php/commitdiff
Fixed bugs #34065 and #38623 (throw in foreach/switch causes memory leaks)
authorDmitry Stogov <dmitry@php.net>
Tue, 19 Sep 2006 21:36:00 +0000 (21:36 +0000)
committerDmitry Stogov <dmitry@php.net>
Tue, 19 Sep 2006 21:36:00 +0000 (21:36 +0000)
Zend/tests/bug34065.phpt [new file with mode: 0755]
Zend/tests/bug38623.phpt [new file with mode: 0755]
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

diff --git a/Zend/tests/bug34065.phpt b/Zend/tests/bug34065.phpt
new file mode 100755 (executable)
index 0000000..9d76fca
--- /dev/null
@@ -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 (executable)
index 0000000..9b042a9
--- /dev/null
@@ -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
index 6552602812e51eb81211ead220324d96c5332ea4..c7472e8444322d29e2262ddcf9124f9636443626 100644 (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;
 }
 
index 71f156006486293867371ae53cd149ecb3ee76c1..6dc24704ef955c2afb8def758e284dbcc58dc386 100644 (file)
@@ -89,6 +89,7 @@ struct _zend_op {
 
 
 typedef struct _zend_brk_cont_element {
+       int start;
        int cont;
        int brk;
        int parent;
index 01f481da16ac3af97f0c146d77af3dcb19301a1a..9fcd1284aa92b04f37cf2c21a360fae96b0f8fd0 100644 (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,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)
index 0755c04ae4bc8d18791eb06d2f20dbcee057c9a6..d2afe00271937b8fdc4d32dfbecaae56de30b7bd 100644 (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,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)