]> granicus.if.org Git - php/commitdiff
Fixed Bug #72213 (Finally leaks on nested exceptions)
authorXinchen Hui <laruence@gmail.com>
Tue, 17 May 2016 07:32:43 +0000 (15:32 +0800)
committerXinchen Hui <laruence@gmail.com>
Tue, 17 May 2016 07:32:43 +0000 (15:32 +0800)
Zend/tests/try/bug72213.phpt [new file with mode: 0644]
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

diff --git a/Zend/tests/try/bug72213.phpt b/Zend/tests/try/bug72213.phpt
new file mode 100644 (file)
index 0000000..6240502
--- /dev/null
@@ -0,0 +1,25 @@
+--TEST--
+Bug #72213 (Finally leaks on nested exceptions)
+--FILE--
+<?php
+function test() {
+       try {
+               throw new Exception('a');
+       } finally {
+               try {
+                       throw new Exception('b');
+               } finally {
+               }
+       }
+}
+
+try {
+       test();
+} catch (Exception $e) {
+       var_dump($e->getMessage());
+       var_dump($e->getPrevious()->getMessage());
+}
+?>
+--EXPECT--
+string(1) "b"
+string(1) "a"
index c02b27a953804b902bdedd47e0c2831eed3cdbe7..cb568faa4307af437d0b65a41a1154a126f521b7 100644 (file)
@@ -7087,7 +7087,7 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
 {
        uint32_t op_num = EG(opline_before_exception) - EX(func)->op_array.opcodes;
        int i;
-       uint32_t catch_op_num = 0, finally_op_num = 0, finally_op_end = 0;
+       uint32_t catch_op_num = 0, finally_op_num = 0, finally_op_end = 0, prev_finally_op_end = 0;
        int in_finally = 0;
 
        {
@@ -7118,6 +7118,7 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
                if (op_num >= EX(func)->op_array.try_catch_array[i].finally_op &&
                                op_num < EX(func)->op_array.try_catch_array[i].finally_end) {
                        finally_op_end = EX(func)->op_array.try_catch_array[i].finally_end;
+                       prev_finally_op_end = finally_op_end;
                        in_finally = 1;
                }
        }
@@ -7128,8 +7129,13 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
                zval *fast_call = EX_VAR(EX(func)->op_array.opcodes[finally_op_end].op1.var);
 
                cleanup_live_vars(execute_data, op_num, finally_op_num);
-               if (in_finally && Z_OBJ_P(fast_call)) {
-                       zend_exception_set_previous(EG(exception), Z_OBJ_P(fast_call));
+               if (prev_finally_op_end) {
+                       zval *prev_fast_call = EX_VAR(EX(func)->op_array.opcodes[prev_finally_op_end].op1.var);
+
+                       if (Z_OBJ_P(prev_fast_call)) {
+                               zend_exception_set_previous(EG(exception), Z_OBJ_P(prev_fast_call));
+                               Z_OBJ_P(prev_fast_call) = NULL;
+                       }
                }
                Z_OBJ_P(fast_call) = EG(exception);
                EG(exception) = NULL;
index 8572451a293b70db951021b9ad7d7f8d399e65e0..3518508c3503ef6aafe5fb4741a615a4d9848ce0 100644 (file)
@@ -1693,7 +1693,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(
 {
        uint32_t op_num = EG(opline_before_exception) - EX(func)->op_array.opcodes;
        int i;
-       uint32_t catch_op_num = 0, finally_op_num = 0, finally_op_end = 0;
+       uint32_t catch_op_num = 0, finally_op_num = 0, finally_op_end = 0, prev_finally_op_end = 0;
        int in_finally = 0;
 
        {
@@ -1724,6 +1724,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(
                if (op_num >= EX(func)->op_array.try_catch_array[i].finally_op &&
                                op_num < EX(func)->op_array.try_catch_array[i].finally_end) {
                        finally_op_end = EX(func)->op_array.try_catch_array[i].finally_end;
+                       prev_finally_op_end = finally_op_end;
                        in_finally = 1;
                }
        }
@@ -1734,8 +1735,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(
                zval *fast_call = EX_VAR(EX(func)->op_array.opcodes[finally_op_end].op1.var);
 
                cleanup_live_vars(execute_data, op_num, finally_op_num);
-               if (in_finally && Z_OBJ_P(fast_call)) {
-                       zend_exception_set_previous(EG(exception), Z_OBJ_P(fast_call));
+               if (prev_finally_op_end) {
+                       zval *prev_fast_call = EX_VAR(EX(func)->op_array.opcodes[prev_finally_op_end].op1.var);
+
+                       if (Z_OBJ_P(prev_fast_call)) {
+                               zend_exception_set_previous(EG(exception), Z_OBJ_P(prev_fast_call));
+                               Z_OBJ_P(prev_fast_call) = NULL;
+                       }
                }
                Z_OBJ_P(fast_call) = EG(exception);
                EG(exception) = NULL;