]> granicus.if.org Git - php/commitdiff
Fixed bug #72213 (Finally leaks on nested exceptions).
authorDmitry Stogov <dmitry@zend.com>
Tue, 24 May 2016 22:25:12 +0000 (01:25 +0300)
committerDmitry Stogov <dmitry@zend.com>
Tue, 24 May 2016 22:25:12 +0000 (01:25 +0300)
Squashed commit of the following:

commit 8461b0407fc9eab0869d43b84e6a92ba2fe06997
Author: Dmitry Stogov <dmitry@zend.com>
Date:   Wed May 25 00:34:42 2016 +0300

    Rmoved zend_try_catch_element.parent and walk through op_array.try_catch_array backward from the current try_cacth_offset.

commit 0c71e249649bed178bfbef30bb3e63c57f07af05
Author: Dmitry Stogov <dmitry@zend.com>
Date:   Wed May 25 00:04:53 2016 +0300

    Move SAVE_OPLINE() to its original place

commit 111432a4df738fcd65878a42f23194dc3c4983a2
Author: Dmitry Stogov <dmitry@zend.com>
Date:   Wed May 25 00:01:10 2016 +0300

    Separate the common part of ZEND_HANDLE_EXCEPTION and FAST_RET into zend_dispatch_try_catch_finally_helper.

commit 4f21c06c2ec17819a708bc037f318784554a6ecd
Author: Nikita Popov <nikic@php.net>
Date:   Tue May 24 14:55:27 2016 +0200

    Improve finally fix

commit da5c7274997b8308e682b5bf280124e3a1483086
Author: Dmitry Stogov <dmitry@zend.com>
Date:   Tue May 24 10:36:08 2016 +0300

    Fixed Zend/tests/try/bug70228_3.phpt and Zend/tests/try/bug70228_4.phpt

commit cfcedf2fb4f4fc1f7de9f7d53a3037fed7795f19
Author: Dmitry Stogov <dmitry@zend.com>
Date:   Tue May 24 02:59:27 2016 +0300

    Added test

commit 4c6aa93d43da941eb4fda15b48154bfb104bdc04
Author: Dmitry Stogov <dmitry@zend.com>
Date:   Tue May 24 00:38:20 2016 +0300

    Added tests

commit 8a8f4704b0eca2e460d42c1f253a363b0db8e510
Author: Dmitry Stogov <dmitry@zend.com>
Date:   Mon May 23 23:27:34 2016 +0300

    Fixed bug #72213 (Finally leaks on nested exceptions)

24 files changed:
NEWS
Zend/tests/bug65784.phpt
Zend/tests/return_types/029.phpt
Zend/tests/try/bug70228_2.phpt [new file with mode: 0644]
Zend/tests/try/bug70228_3.phpt [new file with mode: 0644]
Zend/tests/try/bug70228_4.phpt [new file with mode: 0644]
Zend/tests/try/bug72213.phpt
Zend/tests/try/try_finally_023.phpt [new file with mode: 0644]
Zend/tests/try/try_finally_024.phpt [new file with mode: 0644]
Zend/tests/try/try_finally_025.phpt [new file with mode: 0644]
Zend/tests/try/try_finally_026.phpt [new file with mode: 0644]
Zend/tests/try/try_finally_027.phpt [new file with mode: 0644]
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_opcode.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
Zend/zend_vm_gen.php
Zend/zend_vm_opcodes.c
Zend/zend_vm_opcodes.h
ext/opcache/Optimizer/block_pass.c
ext/opcache/Optimizer/zend_dump.c
sapi/phpdbg/phpdbg_opcode.c
sapi/phpdbg/tests/exceptions_003.phpt

diff --git a/NEWS b/NEWS
index 150586fe4708c86bd861a721da21c3ae6ad30140..0c65ee803665d790d26c4e07f5810a36e30461c1 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -19,6 +19,7 @@ PHP                                                                        NEWS
   . Fixed bug #71897 (ASCII 0x7F Delete control character permitted in
     identifiers). (Andrea)
   . Fixed bug #72188 (Nested try/finally blocks losing return value). (Dmitry)
+  . Fixed bug #72213 (Finally leaks on nested exceptions). (Dmitry, Nikita)
   . Implemented the RFC `Support Class Constant Visibility`. (Sean DuBois,
     Reeze Xia, Dmitry)
   . Added void return type. (Andrea)
index c079b3d2822b22060b4c2c41cff9a36c71ebcffe..397c52aef9adff8969be5de14ad1fd48671917b1 100644 (file)
@@ -57,8 +57,13 @@ $bar = foo3();
 string(9) "not catch"
 NULL
 
-Fatal error: Uncaught Error: Class 'NotExists' not found in %sbug65784.php:%d
+Fatal error: Uncaught Exception: not catched in %sbug65784.php:42
 Stack trace:
-#0 %s(%d): foo3()
+#0 %sbug65784.php(52): foo3()
 #1 {main}
-  thrown in %sbug65784.php on line %d
+
+Next Error: Class 'NotExists' not found in %s/bug65784.php:46
+Stack trace:
+#0 %sbug65784.php(52): foo3()
+#1 {main}
+  thrown in %sbug65784.php on line 46
index 011182df37795d4ed924fd14b563e1bfd2de4b9e..041b354130fe6d9bb145f4fd7b2fa05e73b32204 100644 (file)
@@ -16,7 +16,12 @@ function foo() : array {
 foo();
 ?>
 --EXPECTF--
-Fatal error: Uncaught TypeError: Return value of foo() must be of the type array, none returned in %s29.php:%d
+Fatal error: Uncaught Exception: xxxx in %s:%d
+Stack trace:
+#0 %s(%d): foo()
+#1 {main}
+
+Next TypeError: Return value of foo() must be of the type array, none returned in %s29.php:%d
 Stack trace:
 #0 %s(%d): foo()
 #1 {main}
diff --git a/Zend/tests/try/bug70228_2.phpt b/Zend/tests/try/bug70228_2.phpt
new file mode 100644 (file)
index 0000000..c988e70
--- /dev/null
@@ -0,0 +1,20 @@
+--TEST--
+Bug #70228 (memleak if return in finally block)
+--FILE--
+<?php
+function test() {
+    try {
+        throw new Exception(1);
+    } finally {
+        try {
+            throw new Exception(2);
+        } finally {
+            return 42;
+        }
+    }
+}
+
+var_dump(test());
+?>
+--EXPECT--
+int(42)
diff --git a/Zend/tests/try/bug70228_3.phpt b/Zend/tests/try/bug70228_3.phpt
new file mode 100644 (file)
index 0000000..55dbe4f
--- /dev/null
@@ -0,0 +1,31 @@
+--TEST--
+Bug #70228 (memleak if return in finally block)
+--FILE--
+<?php
+function test() {
+    try {
+        throw new Exception(1);
+    } finally {
+        try {
+            try {
+            } finally {
+                return 42;
+            }
+        } finally {
+            throw new Exception(2);
+        }
+    }
+}
+
+try {
+    var_dump(test());
+} catch (Exception $e) {
+    do {
+        echo $e->getMessage() . "\n";
+        $e = $e->getPrevious();
+    } while ($e);
+}
+?>
+--EXPECT--
+2
+1
diff --git a/Zend/tests/try/bug70228_4.phpt b/Zend/tests/try/bug70228_4.phpt
new file mode 100644 (file)
index 0000000..f0ab3b0
--- /dev/null
@@ -0,0 +1,32 @@
+--TEST--
+Bug #70228 (memleak if return in finally block)
+--FILE--
+<?php
+function test() {
+    try {
+        throw new Exception(1);
+    } finally {
+        try {
+            try {
+                try {
+                } finally {
+                    return 42;
+                }
+            } finally {
+                throw new Exception(3);
+            }
+        } catch (Exception $e) {}
+    }
+}
+
+try {
+    var_dump(test());
+} catch (Exception $e) {
+    do {
+        echo $e->getMessage() . "\n";
+        $e = $e->getPrevious();
+    } while ($e);
+}
+?>
+--EXPECT--
+1
index aee4c95b20b0fdc4e760d1dd9718ffe63db8bdec..624050295eab7251d1ec821078406514ee26f7c8 100644 (file)
@@ -1,7 +1,5 @@
 --TEST--
 Bug #72213 (Finally leaks on nested exceptions)
---XFAIL--
-See https://bugs.php.net/bug.php?id=72213
 --FILE--
 <?php
 function test() {
diff --git a/Zend/tests/try/try_finally_023.phpt b/Zend/tests/try/try_finally_023.phpt
new file mode 100644 (file)
index 0000000..e88eddb
--- /dev/null
@@ -0,0 +1,37 @@
+--TEST--
+Loop var dtor throwing exception during return inside try/catch inside finally
+--FILE--
+<?php
+
+class Dtor {
+    public function __destruct() {
+        throw new Exception(2);
+    }
+}
+
+function test() {
+    try {
+        throw new Exception(1);
+    } finally {
+        try {
+            foreach ([new Dtor] as $v) {
+                unset($v);
+                return 42;
+            }
+        } catch (Exception $e) {
+        }
+    }
+}
+
+try {
+    test();
+} catch (Exception $e) {
+    echo $e, "\n";
+}
+
+?>
+--EXPECTF--
+Exception: 1 in %s:%d
+Stack trace:
+#0 %s(%d): test()
+#1 {main}
diff --git a/Zend/tests/try/try_finally_024.phpt b/Zend/tests/try/try_finally_024.phpt
new file mode 100644 (file)
index 0000000..eb0b26a
--- /dev/null
@@ -0,0 +1,38 @@
+--TEST--
+Exception in finally inside finally following try/catch containing throwing try/finally
+--FILE--
+<?php
+
+function test() {
+    try {
+        throw new Exception(1);
+    } finally {
+        try {
+            try {
+            } finally {
+                throw new Exception(2);
+            }
+        } catch (Exception $e) {}
+        try {
+        } finally {
+            throw new Exception(3);
+        }
+    }
+}
+
+try {
+    test();
+} catch (Exception $e) {
+    echo $e, "\n";
+}
+?>
+--EXPECTF--
+Exception: 1 in %s:%d
+Stack trace:
+#0 %s(%d): test()
+#1 {main}
+
+Next Exception: 3 in %s:%d
+Stack trace:
+#0 %s(%d): test()
+#1 {main}
diff --git a/Zend/tests/try/try_finally_025.phpt b/Zend/tests/try/try_finally_025.phpt
new file mode 100644 (file)
index 0000000..7ca535b
--- /dev/null
@@ -0,0 +1,28 @@
+--TEST--
+Throw in try of try/finally inside catch
+--FILE--
+<?php
+
+function test() {
+    try {
+        throw new Exception(1);
+    } catch (Exception $e) {
+        try {
+            throw new Exception(2);
+        } finally {
+        }
+    }
+}
+
+try {
+    test();
+} catch (Exception $e) {
+    echo $e, "\n";
+}
+
+?>
+--EXPECTF--
+Exception: 2 in %s:%d
+Stack trace:
+#0 %s(%d): test()
+#1 {main}
diff --git a/Zend/tests/try/try_finally_026.phpt b/Zend/tests/try/try_finally_026.phpt
new file mode 100644 (file)
index 0000000..29a5de3
--- /dev/null
@@ -0,0 +1,37 @@
+--TEST--
+Throw in finally inside catch inside finally
+--FILE--
+<?php
+
+function test() {
+    try {
+        throw new Exception(1);
+    } finally {
+        try {
+            throw new Exception(2);
+        } catch (Exception $e) {
+            try {
+            } finally {
+                throw new Exception(3);
+            }
+        }
+    }
+}
+
+try {
+    test();
+} catch (Exception $e) {
+    echo $e, "\n";
+}
+
+?>
+--EXPECTF--
+Exception: 1 in %s:%d
+Stack trace:
+#0 %s(%d): test()
+#1 {main}
+
+Next Exception: 3 in %s:%d
+Stack trace:
+#0 %s(%d): test()
+#1 {main}
diff --git a/Zend/tests/try/try_finally_027.phpt b/Zend/tests/try/try_finally_027.phpt
new file mode 100644 (file)
index 0000000..1e66479
--- /dev/null
@@ -0,0 +1,34 @@
+--TEST--
+Return in try with throw in finally, inside other finally
+--FILE--
+<?php
+
+function test() {
+    try {
+        throw new Exception(1);
+    } finally {
+        try {
+            return 42;
+        } finally {
+            throw new Exception(2);
+        }
+    }
+}
+
+try {
+    test();
+} catch (Exception $e) {
+    echo $e, "\n";
+}
+
+?>
+--EXPECTF--
+Exception: 1 in %s:%d
+Stack trace:
+#0 %s(%d): test()
+#1 {main}
+
+Next Exception: 2 in %s:%d
+Stack trace:
+#0 %s(%d): test()
+#1 {main}
index 0994681c209bcc160e64a80fdb644116d6f884bc..c6da34732aef70e314057d7fa1dfec3e24cab773 100644 (file)
@@ -234,6 +234,7 @@ void zend_oparray_context_begin(zend_oparray_context *prev_context) /* {{{ */
        CG(context).backpatch_count = 0;
        CG(context).in_finally = 0;
        CG(context).fast_call_var = -1;
+       CG(context).try_catch_offset = -1;
        CG(context).current_brk_cont = -1;
        CG(context).last_brk_cont = 0;
        CG(context).brk_cont_array = NULL;
@@ -4008,6 +4009,12 @@ static int zend_handle_loops_and_finally_ex(zend_long depth) /* {{{ */
                        SET_UNUSED(opline->op1);
                        SET_UNUSED(opline->op2);
                        opline->op1.num = loop_var->u.try_catch_offset;
+               } else if (loop_var->opcode == ZEND_DISCARD_EXCEPTION) {
+                       zend_op *opline = get_next_op(CG(active_op_array));
+                       opline->opcode = ZEND_DISCARD_EXCEPTION;
+                       opline->op1_type = IS_TMP_VAR;
+                       opline->op1.var = loop_var->var_num;
+                       SET_UNUSED(opline->op2);
                } else if (loop_var->opcode == ZEND_RETURN) {
                        /* Stack separator */
                        break;
@@ -4057,12 +4064,6 @@ void zend_compile_return(zend_ast *ast) /* {{{ */
                zend_compile_expr(&expr_node, expr_ast);
        }
 
-       if (CG(context).in_finally) {
-               opline = zend_emit_op(NULL, ZEND_DISCARD_EXCEPTION, NULL, NULL);
-               opline->op1_type = IS_TMP_VAR;
-               opline->op1.var = CG(context).fast_call_var;
-       }
-
        /* Generator return types are handled separately */
        if (!(CG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) && CG(active_op_array)->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
                zend_emit_return_type_check(expr_ast ? &expr_node : NULL, CG(active_op_array)->arg_info - 1);
@@ -4573,6 +4574,7 @@ void zend_compile_try(zend_ast *ast) /* {{{ */
        uint32_t try_catch_offset;
        uint32_t *jmp_opnums = safe_emalloc(sizeof(uint32_t), catches->children, 0);
        uint32_t orig_fast_call_var = CG(context).fast_call_var;
+       uint32_t orig_try_catch_offset = CG(context).try_catch_offset;
 
        if (catches->children == 0 && !finally_ast) {
                zend_error_noreturn(E_COMPILE_ERROR, "Cannot use try without catch or finally");
@@ -4606,6 +4608,8 @@ void zend_compile_try(zend_ast *ast) /* {{{ */
                zend_stack_push(&CG(loop_var_stack), &fast_call);
        }
 
+       CG(context).try_catch_offset = try_catch_offset;
+
        zend_compile_stmt(try_ast);
 
        if (catches->children != 0) {
@@ -4679,11 +4683,18 @@ void zend_compile_try(zend_ast *ast) /* {{{ */
        }
 
        if (finally_ast) {
+               zend_loop_var discard_exception;
                uint32_t opnum_jmp = get_next_op_number(CG(active_op_array)) + 1;
                
                /* Pop FAST_CALL from unwind stack */
                zend_stack_del_top(&CG(loop_var_stack));
 
+               /* Push DISCARD_EXCEPTION on unwind stack */
+               discard_exception.opcode = ZEND_DISCARD_EXCEPTION;
+               discard_exception.var_type = IS_TMP_VAR;
+               discard_exception.var_num = CG(context).fast_call_var;
+               zend_stack_push(&CG(loop_var_stack), &discard_exception);
+
                CG(zend_lineno) = finally_ast->lineno;
 
                opline = zend_emit_op(NULL, ZEND_FAST_CALL, NULL, NULL);
@@ -4704,12 +4715,18 @@ void zend_compile_try(zend_ast *ast) /* {{{ */
                opline = zend_emit_op(NULL, ZEND_FAST_RET, NULL, NULL);
                opline->op1_type = IS_TMP_VAR;
                opline->op1.var = CG(context).fast_call_var;
+               opline->op2.num = orig_try_catch_offset;
 
                zend_update_jump_target_to_next(opnum_jmp);
 
                CG(context).fast_call_var = orig_fast_call_var;
+
+               /* Pop DISCARD_EXCEPTION from unwind stack */
+               zend_stack_del_top(&CG(loop_var_stack));
        }
 
+       CG(context).try_catch_offset = orig_try_catch_offset;
+
        efree(jmp_opnums);
 }
 /* }}} */
index 72215a20d16939da3d83b06089c0d6cc52a65c06..5ab0d0375bdb0118e4901e2b63f1836fea26dba8 100644 (file)
@@ -191,6 +191,7 @@ typedef struct _zend_oparray_context {
        int        backpatch_count;
        int        in_finally;
        uint32_t   fast_call_var;
+       uint32_t   try_catch_offset;
        int        current_brk_cont;
        int        last_brk_cont;
        zend_brk_cont_element *brk_cont_array;
@@ -959,11 +960,6 @@ static zend_always_inline int zend_check_arg_send_type(const zend_function *zf,
 #define ZEND_RETURNS_FUNCTION 1<<0
 #define ZEND_RETURNS_VALUE    1<<1
 
-#define ZEND_FAST_RET_TO_CATCH         1
-#define ZEND_FAST_RET_TO_FINALLY       2
-
-#define ZEND_FAST_CALL_FROM_FINALLY    1
-
 #define ZEND_ARRAY_ELEMENT_REF         (1<<0)
 #define ZEND_ARRAY_NOT_PACKED          (1<<1)
 #define ZEND_ARRAY_SIZE_SHIFT          2
index 34e060fa4aebd740bd0f24bfb88fa3547d0f9593..0b5fe75ff8b06619ee57d2a525bdc626b03ec792 100644 (file)
@@ -534,57 +534,6 @@ static void zend_check_finally_breakout(zend_op_array *op_array, uint32_t op_num
        }
 }
 
-static void zend_resolve_fast_call(zend_op_array *op_array, uint32_t op_num)
-{
-       int i;
-       uint32_t finally_num = (uint32_t)-1;
-
-       for (i = 0; i < op_array->last_try_catch; i++) {
-               if (op_num >= op_array->try_catch_array[i].finally_op
-                               && op_num < op_array->try_catch_array[i].finally_end) {
-                       finally_num = i;
-               }
-       }
-
-       if (finally_num != (uint32_t)-1) {
-               /* Must be ZEND_FAST_CALL */
-               ZEND_ASSERT(op_array->opcodes[op_array->try_catch_array[finally_num].finally_op - 2].opcode == ZEND_FAST_CALL);
-               op_array->opcodes[op_num].extended_value = ZEND_FAST_CALL_FROM_FINALLY;
-       }
-}
-
-static void zend_resolve_finally_ret(zend_op_array *op_array, uint32_t op_num)
-{
-       int i;
-       uint32_t finally_num = (uint32_t)-1;
-       uint32_t catch_num = (uint32_t)-1;
-
-       for (i = 0; i < op_array->last_try_catch; i++) {
-               if (op_array->try_catch_array[i].try_op > op_num) {
-                       break;
-               }
-               if (op_num < op_array->try_catch_array[i].finally_op) {
-                       finally_num = i;
-               }
-               if (op_num < op_array->try_catch_array[i].catch_op) {
-                       catch_num = i;
-               }
-       }
-
-       if (finally_num != (uint32_t)-1 &&
-           (catch_num == (uint32_t)-1 ||
-            op_array->try_catch_array[catch_num].catch_op >=
-            op_array->try_catch_array[finally_num].finally_op)) {
-               /* in case of unhandled exception return to upward finally block */
-               op_array->opcodes[op_num].extended_value = ZEND_FAST_RET_TO_FINALLY;
-               op_array->opcodes[op_num].op2.num = finally_num;
-       } else if (catch_num != (uint32_t)-1) {
-               /* in case of unhandled exception return to upward catch block */
-               op_array->opcodes[op_num].extended_value = ZEND_FAST_RET_TO_CATCH;
-               op_array->opcodes[op_num].op2.num = catch_num;
-       }
-}
-
 static uint32_t zend_get_brk_cont_target(const zend_op_array *op_array, const zend_op *opline) {
        int nest_levels = opline->op2.num;
        int array_offset = opline->op1.num;
@@ -633,12 +582,8 @@ ZEND_API int pass_two(zend_op_array *op_array)
                switch (opline->opcode) {
                        case ZEND_FAST_CALL:
                                opline->op1.opline_num = op_array->try_catch_array[opline->op1.num].finally_op;
-                               zend_resolve_fast_call(op_array, opline - op_array->opcodes);
                                ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op1);
                                break;
-                       case ZEND_FAST_RET:
-                               zend_resolve_finally_ret(op_array, opline - op_array->opcodes);
-                               break;
                        case ZEND_BRK:
                        case ZEND_CONT:
                                {
index 4ac2057d27b4b1eb73dd6a43c3372ffccf2a826c..7c584f38a1eb725ee0042304fec8e3a23a9ec554 100644 (file)
@@ -7105,12 +7105,58 @@ ZEND_VM_HANDLER(155, ZEND_BIND_TRAITS, ANY, ANY)
        ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
 }
 
+ZEND_VM_HELPER(zend_dispatch_try_catch_finally_helper, ANY, ANY, uint32_t try_catch_offset, uint32_t op_num)
+{
+       zend_object *ex = EG(exception);
+
+       /* Walk try/catch/finally structures upwards, performing the necessary actions */
+       while (try_catch_offset != (uint32_t) -1) {
+               zend_try_catch_element *try_catch =
+                       &EX(func)->op_array.try_catch_array[try_catch_offset];
+
+               if (op_num < try_catch->catch_op) {
+                       /* Go to catch block */
+                       cleanup_live_vars(execute_data, op_num, try_catch->catch_op);
+                       ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[try_catch->catch_op]);
+                       ZEND_VM_CONTINUE();
+
+               } else if (op_num < try_catch->finally_op) {
+                       /* Go to finally block */
+                       zval *fast_call = EX_VAR(EX(func)->op_array.opcodes[try_catch->finally_end].op1.var);
+                       cleanup_live_vars(execute_data, op_num, try_catch->finally_op);
+                       Z_OBJ_P(fast_call) = EG(exception);
+                       EG(exception) = NULL;
+                       fast_call->u2.lineno = (uint32_t)-1;
+                       ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[try_catch->finally_op]);
+                       ZEND_VM_CONTINUE();
+
+               } else if (op_num < try_catch->finally_end) {
+                       /* Chain potential exception from wrapping finally block */
+                       zval *fast_call = EX_VAR(EX(func)->op_array.opcodes[try_catch->finally_end].op1.var);
+                       if (Z_OBJ_P(fast_call)) {
+                               zend_exception_set_previous(ex, Z_OBJ_P(fast_call));
+                               ex = Z_OBJ_P(fast_call);
+                       }
+               }
+
+               try_catch_offset--;
+       }
+
+       /* Uncaught exception */
+       cleanup_live_vars(execute_data, op_num, 0);
+       if (UNEXPECTED((EX_CALL_INFO() & ZEND_CALL_GENERATOR) != 0)) {
+               zend_generator *generator = zend_get_running_generator(execute_data);
+               zend_generator_close(generator, 1);
+               ZEND_VM_RETURN();
+       } else {
+               ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
+       }
+}
+
 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;
-       int in_finally = 0;
+       uint32_t throw_op_num = EG(opline_before_exception) - EX(func)->op_array.opcodes;
+       uint32_t i, current_try_catch_offset = (uint32_t) -1;
 
        {
                const zend_op *exc_opline = EG(opline_before_exception);
@@ -7118,68 +7164,27 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
                        && exc_opline->extended_value & ZEND_FREE_ON_RETURN) {
                        /* exceptions thrown because of loop var destruction on return/break/...
                         * are logically thrown at the end of the foreach loop, so adjust the
-                        * op_num.
+                        * throw_op_num.
                         */
-                       op_num = EX(func)->op_array.live_range[exc_opline->op2.num].end;
+                       throw_op_num = EX(func)->op_array.live_range[exc_opline->op2.num].end;
                }
        }
 
+       /* Find the innermost try/catch/finally the exception was thrown in */
        for (i = 0; i < EX(func)->op_array.last_try_catch; i++) {
-               if (EX(func)->op_array.try_catch_array[i].try_op > op_num) {
+               zend_try_catch_element *try_catch = &EX(func)->op_array.try_catch_array[i];
+               if (try_catch->try_op > throw_op_num) {
                        /* further blocks will not be relevant... */
                        break;
                }
-               in_finally = 0;
-               if (op_num < EX(func)->op_array.try_catch_array[i].catch_op) {
-                       catch_op_num = EX(func)->op_array.try_catch_array[i].catch_op;
-               }
-               if (op_num < EX(func)->op_array.try_catch_array[i].finally_op) {
-                       finally_op_num = EX(func)->op_array.try_catch_array[i].finally_op;
-                       finally_op_end = EX(func)->op_array.try_catch_array[i].finally_end;
-               }
-               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;
-                       in_finally = 1;
+               if (throw_op_num < try_catch->catch_op || throw_op_num < try_catch->finally_end) {
+                       current_try_catch_offset = i;
                }
        }
 
-       cleanup_unfinished_calls(execute_data, op_num);
-
-       if (finally_op_num && (!catch_op_num || catch_op_num >= finally_op_num)) {
-               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));
-               }
-               Z_OBJ_P(fast_call) = EG(exception);
-               EG(exception) = NULL;
-               fast_call->u2.lineno = (uint32_t)-1;
-               ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[finally_op_num]);
-               ZEND_VM_CONTINUE();
-       } else {
-               cleanup_live_vars(execute_data, op_num, catch_op_num);
-               if (in_finally) {
-                       /* we are going out of current finally scope */
-                       zval *fast_call = EX_VAR(EX(func)->op_array.opcodes[finally_op_end].op1.var);
+       cleanup_unfinished_calls(execute_data, throw_op_num);
 
-                       if (Z_OBJ_P(fast_call)) {
-                               zend_exception_set_previous(EG(exception), Z_OBJ_P(fast_call));
-                               Z_OBJ_P(fast_call) = NULL;
-                       }
-               }
-               if (catch_op_num) {
-                       ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[catch_op_num]);
-                       ZEND_VM_CONTINUE();
-               } else if (UNEXPECTED((EX_CALL_INFO() & ZEND_CALL_GENERATOR) != 0)) {
-                       zend_generator *generator = zend_get_running_generator(execute_data);
-                       zend_generator_close(generator, 1);
-                       ZEND_VM_RETURN();
-               } else {
-                       ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
-               }
-       }
+       ZEND_VM_DISPATCH_TO_HELPER(zend_dispatch_try_catch_finally_helper, try_catch_offset, current_try_catch_offset, op_num, throw_op_num);
 }
 
 ZEND_VM_HANDLER(146, ZEND_VERIFY_ABSTRACT_CLASS, ANY, ANY)
@@ -7539,71 +7544,43 @@ ZEND_VM_HANDLER(159, ZEND_DISCARD_EXCEPTION, ANY, ANY)
                /* discard the previously thrown exception */
                OBJ_RELEASE(Z_OBJ_P(fast_call));
                Z_OBJ_P(fast_call) = NULL;
+               ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
        }
 
        ZEND_VM_NEXT_OPCODE();
 }
 
-ZEND_VM_HANDLER(162, ZEND_FAST_CALL, JMP_ADDR, ANY, FAST_CALL)
+ZEND_VM_HANDLER(162, ZEND_FAST_CALL, JMP_ADDR, ANY)
 {
        USE_OPLINE
        zval *fast_call = EX_VAR(opline->result.var);
 
-       if (opline->extended_value == ZEND_FAST_CALL_FROM_FINALLY && UNEXPECTED(Z_OBJ_P(fast_call) != NULL)) {
-               fast_call->u2.lineno = (uint32_t)-1;
-       } else {
-               Z_OBJ_P(fast_call) = NULL;
-               /* set return address */
-               fast_call->u2.lineno = opline - EX(func)->op_array.opcodes;
-       }
+       Z_OBJ_P(fast_call) = NULL;
+       /* set return address */
+       fast_call->u2.lineno = opline - EX(func)->op_array.opcodes;
        ZEND_VM_SET_OPCODE(OP_JMP_ADDR(opline, opline->op1));
        ZEND_VM_CONTINUE();
 }
 
-ZEND_VM_HANDLER(163, ZEND_FAST_RET, ANY, TRY_CATCH, FAST_RET)
+ZEND_VM_HANDLER(163, ZEND_FAST_RET, ANY, TRY_CATCH)
 {
        USE_OPLINE
        zval *fast_call = EX_VAR(opline->op1.var);
+       uint32_t current_try_catch_offset, current_op_num;
 
        if (fast_call->u2.lineno != (uint32_t)-1) {
                const zend_op *fast_ret = EX(func)->op_array.opcodes + fast_call->u2.lineno;
+
                ZEND_VM_SET_OPCODE(fast_ret + 1);
                ZEND_VM_CONTINUE();
-       } else {
-               /* special case for unhandled exceptions */
-               USE_OPLINE
-
-               if (opline->extended_value == ZEND_FAST_RET_TO_FINALLY) {
-                       uint32_t finally_op = EX(func)->op_array.try_catch_array[opline->op2.num].finally_op;
-                       uint32_t finally_end = EX(func)->op_array.try_catch_array[opline->op2.num].finally_end;
-                       zval *next_fast_call = EX_VAR(EX(func)->op_array.opcodes[finally_end].op1.var);
-
-                       Z_OBJ_P(next_fast_call) = Z_OBJ_P(fast_call);
-                       next_fast_call->u2.lineno = (uint32_t)-1;
-                       cleanup_live_vars(execute_data, opline - EX(func)->op_array.opcodes, finally_op);
-                       ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[finally_op]);
-                       ZEND_VM_CONTINUE();
-               } else {
-                       EG(exception) = Z_OBJ_P(fast_call);
-                       Z_OBJ_P(fast_call) = NULL;
-                       if (opline->extended_value == ZEND_FAST_RET_TO_CATCH) {
-                               uint32_t catch_op = EX(func)->op_array.try_catch_array[opline->op2.num].catch_op;
-
-                               cleanup_live_vars(execute_data, opline - EX(func)->op_array.opcodes, catch_op);
-                               ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[catch_op]);
-                               ZEND_VM_CONTINUE();
-                       } else {
-                               cleanup_live_vars(execute_data, opline - EX(func)->op_array.opcodes, 0);
-                               if (UNEXPECTED((EX_CALL_INFO() & ZEND_CALL_GENERATOR) != 0)) {
-                                       zend_generator *generator = zend_get_running_generator(execute_data);
-                                       zend_generator_close(generator, 1);
-                                       ZEND_VM_RETURN();
-                               } else {
-                                       ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
-                               }
-                       }
-               }
        }
+
+       /* special case for unhandled exceptions */
+       EG(exception) = Z_OBJ_P(fast_call);
+       Z_OBJ_P(fast_call) = NULL;
+       current_try_catch_offset = opline->op2.num;
+       current_op_num = opline - EX(func)->op_array.opcodes;
+       ZEND_VM_DISPATCH_TO_HELPER(zend_dispatch_try_catch_finally_helper, try_catch_offset, current_try_catch_offset, op_num, current_op_num);
 }
 
 ZEND_VM_HANDLER(168, ZEND_BIND_GLOBAL, CV, CONST)
index 9f6130c0597ec92d94ae606dd1b15a12609a6422..878d280c179fd9255ea911368607f6de28651ef1 100644 (file)
@@ -1690,12 +1690,58 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BIND_TRAITS_SPEC_HANDLER(ZEND_
        ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
 }
 
+static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_dispatch_try_catch_finally_helper_SPEC(uint32_t try_catch_offset, uint32_t op_num ZEND_OPCODE_HANDLER_ARGS_DC)
+{
+       zend_object *ex = EG(exception);
+
+       /* Walk try/catch/finally structures upwards, performing the necessary actions */
+       while (try_catch_offset != (uint32_t) -1) {
+               zend_try_catch_element *try_catch =
+                       &EX(func)->op_array.try_catch_array[try_catch_offset];
+
+               if (op_num < try_catch->catch_op) {
+                       /* Go to catch block */
+                       cleanup_live_vars(execute_data, op_num, try_catch->catch_op);
+                       ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[try_catch->catch_op]);
+                       ZEND_VM_CONTINUE();
+
+               } else if (op_num < try_catch->finally_op) {
+                       /* Go to finally block */
+                       zval *fast_call = EX_VAR(EX(func)->op_array.opcodes[try_catch->finally_end].op1.var);
+                       cleanup_live_vars(execute_data, op_num, try_catch->finally_op);
+                       Z_OBJ_P(fast_call) = EG(exception);
+                       EG(exception) = NULL;
+                       fast_call->u2.lineno = (uint32_t)-1;
+                       ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[try_catch->finally_op]);
+                       ZEND_VM_CONTINUE();
+
+               } else if (op_num < try_catch->finally_end) {
+                       /* Chain potential exception from wrapping finally block */
+                       zval *fast_call = EX_VAR(EX(func)->op_array.opcodes[try_catch->finally_end].op1.var);
+                       if (Z_OBJ_P(fast_call)) {
+                               zend_exception_set_previous(ex, Z_OBJ_P(fast_call));
+                               ex = Z_OBJ_P(fast_call);
+                       }
+               }
+
+               try_catch_offset--;
+       }
+
+       /* Uncaught exception */
+       cleanup_live_vars(execute_data, op_num, 0);
+       if (UNEXPECTED((EX_CALL_INFO() & ZEND_CALL_GENERATOR) != 0)) {
+               zend_generator *generator = zend_get_running_generator(execute_data);
+               zend_generator_close(generator, 1);
+               ZEND_VM_RETURN();
+       } else {
+               ZEND_VM_TAIL_CALL(zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU));
+       }
+}
+
 static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
-       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;
-       int in_finally = 0;
+       uint32_t throw_op_num = EG(opline_before_exception) - EX(func)->op_array.opcodes;
+       uint32_t i, current_try_catch_offset = (uint32_t) -1;
 
        {
                const zend_op *exc_opline = EG(opline_before_exception);
@@ -1703,68 +1749,27 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(
                        && exc_opline->extended_value & ZEND_FREE_ON_RETURN) {
                        /* exceptions thrown because of loop var destruction on return/break/...
                         * are logically thrown at the end of the foreach loop, so adjust the
-                        * op_num.
+                        * throw_op_num.
                         */
-                       op_num = EX(func)->op_array.live_range[exc_opline->op2.num].end;
+                       throw_op_num = EX(func)->op_array.live_range[exc_opline->op2.num].end;
                }
        }
 
+       /* Find the innermost try/catch/finally the exception was thrown in */
        for (i = 0; i < EX(func)->op_array.last_try_catch; i++) {
-               if (EX(func)->op_array.try_catch_array[i].try_op > op_num) {
+               zend_try_catch_element *try_catch = &EX(func)->op_array.try_catch_array[i];
+               if (try_catch->try_op > throw_op_num) {
                        /* further blocks will not be relevant... */
                        break;
                }
-               in_finally = 0;
-               if (op_num < EX(func)->op_array.try_catch_array[i].catch_op) {
-                       catch_op_num = EX(func)->op_array.try_catch_array[i].catch_op;
-               }
-               if (op_num < EX(func)->op_array.try_catch_array[i].finally_op) {
-                       finally_op_num = EX(func)->op_array.try_catch_array[i].finally_op;
-                       finally_op_end = EX(func)->op_array.try_catch_array[i].finally_end;
-               }
-               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;
-                       in_finally = 1;
+               if (throw_op_num < try_catch->catch_op || throw_op_num < try_catch->finally_end) {
+                       current_try_catch_offset = i;
                }
        }
 
-       cleanup_unfinished_calls(execute_data, op_num);
-
-       if (finally_op_num && (!catch_op_num || catch_op_num >= finally_op_num)) {
-               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));
-               }
-               Z_OBJ_P(fast_call) = EG(exception);
-               EG(exception) = NULL;
-               fast_call->u2.lineno = (uint32_t)-1;
-               ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[finally_op_num]);
-               ZEND_VM_CONTINUE();
-       } else {
-               cleanup_live_vars(execute_data, op_num, catch_op_num);
-               if (in_finally) {
-                       /* we are going out of current finally scope */
-                       zval *fast_call = EX_VAR(EX(func)->op_array.opcodes[finally_op_end].op1.var);
+       cleanup_unfinished_calls(execute_data, throw_op_num);
 
-                       if (Z_OBJ_P(fast_call)) {
-                               zend_exception_set_previous(EG(exception), Z_OBJ_P(fast_call));
-                               Z_OBJ_P(fast_call) = NULL;
-                       }
-               }
-               if (catch_op_num) {
-                       ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[catch_op_num]);
-                       ZEND_VM_CONTINUE();
-               } else if (UNEXPECTED((EX_CALL_INFO() & ZEND_CALL_GENERATOR) != 0)) {
-                       zend_generator *generator = zend_get_running_generator(execute_data);
-                       zend_generator_close(generator, 1);
-                       ZEND_VM_RETURN();
-               } else {
-                       ZEND_VM_TAIL_CALL(zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU));
-               }
-       }
+       ZEND_VM_TAIL_CALL(zend_dispatch_try_catch_finally_helper_SPEC(current_try_catch_offset, throw_op_num ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC));
 }
 
 static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_ABSTRACT_CLASS_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
@@ -1818,6 +1823,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DISCARD_EXCEPTION_SPEC_HANDLER
                /* discard the previously thrown exception */
                OBJ_RELEASE(Z_OBJ_P(fast_call));
                Z_OBJ_P(fast_call) = NULL;
+               ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
        }
 
        ZEND_VM_NEXT_OPCODE();
@@ -1828,13 +1834,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CALL_SPEC_HANDLER(ZEND_OP
        USE_OPLINE
        zval *fast_call = EX_VAR(opline->result.var);
 
-       if (opline->extended_value == ZEND_FAST_CALL_FROM_FINALLY && UNEXPECTED(Z_OBJ_P(fast_call) != NULL)) {
-               fast_call->u2.lineno = (uint32_t)-1;
-       } else {
-               Z_OBJ_P(fast_call) = NULL;
-               /* set return address */
-               fast_call->u2.lineno = opline - EX(func)->op_array.opcodes;
-       }
+       Z_OBJ_P(fast_call) = NULL;
+       /* set return address */
+       fast_call->u2.lineno = opline - EX(func)->op_array.opcodes;
        ZEND_VM_SET_OPCODE(OP_JMP_ADDR(opline, opline->op1));
        ZEND_VM_CONTINUE();
 }
@@ -1843,46 +1845,21 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_RET_SPEC_HANDLER(ZEND_OPC
 {
        USE_OPLINE
        zval *fast_call = EX_VAR(opline->op1.var);
+       uint32_t current_try_catch_offset, current_op_num;
 
        if (fast_call->u2.lineno != (uint32_t)-1) {
                const zend_op *fast_ret = EX(func)->op_array.opcodes + fast_call->u2.lineno;
+
                ZEND_VM_SET_OPCODE(fast_ret + 1);
                ZEND_VM_CONTINUE();
-       } else {
-               /* special case for unhandled exceptions */
-               USE_OPLINE
-
-               if (opline->extended_value == ZEND_FAST_RET_TO_FINALLY) {
-                       uint32_t finally_op = EX(func)->op_array.try_catch_array[opline->op2.num].finally_op;
-                       uint32_t finally_end = EX(func)->op_array.try_catch_array[opline->op2.num].finally_end;
-                       zval *next_fast_call = EX_VAR(EX(func)->op_array.opcodes[finally_end].op1.var);
-
-                       Z_OBJ_P(next_fast_call) = Z_OBJ_P(fast_call);
-                       next_fast_call->u2.lineno = (uint32_t)-1;
-                       cleanup_live_vars(execute_data, opline - EX(func)->op_array.opcodes, finally_op);
-                       ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[finally_op]);
-                       ZEND_VM_CONTINUE();
-               } else {
-                       EG(exception) = Z_OBJ_P(fast_call);
-                       Z_OBJ_P(fast_call) = NULL;
-                       if (opline->extended_value == ZEND_FAST_RET_TO_CATCH) {
-                               uint32_t catch_op = EX(func)->op_array.try_catch_array[opline->op2.num].catch_op;
-
-                               cleanup_live_vars(execute_data, opline - EX(func)->op_array.opcodes, catch_op);
-                               ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[catch_op]);
-                               ZEND_VM_CONTINUE();
-                       } else {
-                               cleanup_live_vars(execute_data, opline - EX(func)->op_array.opcodes, 0);
-                               if (UNEXPECTED((EX_CALL_INFO() & ZEND_CALL_GENERATOR) != 0)) {
-                                       zend_generator *generator = zend_get_running_generator(execute_data);
-                                       zend_generator_close(generator, 1);
-                                       ZEND_VM_RETURN();
-                               } else {
-                                       ZEND_VM_TAIL_CALL(zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU));
-                               }
-                       }
-               }
        }
+
+       /* special case for unhandled exceptions */
+       EG(exception) = Z_OBJ_P(fast_call);
+       Z_OBJ_P(fast_call) = NULL;
+       current_try_catch_offset = opline->op2.num;
+       current_op_num = opline - EX(func)->op_array.opcodes;
+       ZEND_VM_TAIL_CALL(zend_dispatch_try_catch_finally_helper_SPEC(current_try_catch_offset, current_op_num ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC));
 }
 
 static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSERT_CHECK_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
index 88fe287b55d95afd9dd40131558c70a3473fc0c5..03d9817c6be4c0e39fb982370846cfa38609d3f5 100644 (file)
@@ -83,8 +83,8 @@ $vm_op_flags = array(
        "ZEND_VM_EXT_CONST_FETCH" => 0x06000000,
        "ZEND_VM_EXT_TYPE"        => 0x07000000,
        "ZEND_VM_EXT_EVAL"        => 0x08000000,
-       "ZEND_VM_EXT_FAST_CALL"   => 0x09000000,
-       "ZEND_VM_EXT_FAST_RET"    => 0x0a000000,
+       // unused 0x09000000,
+       // unused 0x0a000000,
        "ZEND_VM_EXT_SRC"         => 0x0b000000,
        "ZEND_VM_EXT_SEND"        => 0x0c000000,
        "ZEND_VM_NO_CONST_CONST"  => 0x40000000,
@@ -124,8 +124,6 @@ $vm_ext_decode = array(
        "ARRAY_INIT"           => ZEND_VM_EXT_ARRAY_INIT,
        "TYPE"                 => ZEND_VM_EXT_TYPE,
        "EVAL"                 => ZEND_VM_EXT_EVAL,
-       "FAST_CALL"            => ZEND_VM_EXT_FAST_CALL,
-       "FAST_RET"             => ZEND_VM_EXT_FAST_RET,
        "ISSET"                => ZEND_VM_EXT_ISSET,
        "ARG_NUM"              => ZEND_VM_EXT_ARG_NUM,
        "REF"                  => ZEND_VM_EXT_REF,
index 180b745fb25797433094315ca43f37b26bf1d041..5463f9c498863ba94dc0eb24a70c4ef61c39a681 100644 (file)
@@ -371,8 +371,8 @@ static uint32_t zend_vm_opcodes_flags[184] = {
        0x00000000,
        0x0b000303,
        0x00000003,
-       0x09000020,
-       0x0a003000,
+       0x00000020,
+       0x00003000,
        0x00000010,
        0x00000000,
        0x00000707,
index 00aa20ea37bfdcb0cfb9bdf09cb84f15008d2838..4f5a0d615a27dcd3b847bbf2718543b7d6a47946 100644 (file)
@@ -54,8 +54,6 @@
 #define ZEND_VM_EXT_CONST_FETCH  0x06000000
 #define ZEND_VM_EXT_TYPE         0x07000000
 #define ZEND_VM_EXT_EVAL         0x08000000
-#define ZEND_VM_EXT_FAST_CALL    0x09000000
-#define ZEND_VM_EXT_FAST_RET     0x0a000000
 #define ZEND_VM_EXT_SRC          0x0b000000
 #define ZEND_VM_EXT_SEND         0x0c000000
 #define ZEND_VM_NO_CONST_CONST   0x40000000
index 2e84b73252f509c31dfb6b0a8e2b67578d695fbc..02fb8192a66ee2963b730af41b07cb99a1b1f331 100644 (file)
@@ -898,9 +898,8 @@ static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array)
                                zend_op *opline = new_opcodes;
                                zend_op *end = opline + len;
                                while (opline < end) {
-                                       if ((opline->opcode == ZEND_FAST_CALL ||
-                                            opline->opcode == ZEND_FAST_RET) &&
-                                           opline->extended_value &&
+                                       if (opline->opcode == ZEND_FAST_RET &&
+                                           opline->op2.num != (uint32_t)-1 &&
                                            opline->op2.num < (uint32_t)j) {
                                                opline->op2.num = map[opline->op2.num];
                                        }
index d85fb82d8394ec6e901be820da5aa1de94a19e66..c306c7ac1e3fc1f6d79bee3565307d2895a0fc37 100644 (file)
@@ -92,7 +92,7 @@ static void zend_dump_unused_op(const zend_op *opline, znode_op op, uint32_t fla
        if (ZEND_VM_OP_NUM == (flags & ZEND_VM_OP_MASK)) {
                fprintf(stderr, " %u", op.num);
        } else if (ZEND_VM_OP_TRY_CATCH == (flags & ZEND_VM_OP_MASK)) {
-               if (opline->opcode != ZEND_FAST_RET || opline->extended_value) {
+               if (op.num != (uint32_t)-1) {
                        fprintf(stderr, " try-catch(%u)", op.num);
                }
        } else if (ZEND_VM_OP_LIVE_RANGE == (flags & ZEND_VM_OP_MASK)) {
@@ -498,16 +498,6 @@ static void zend_dump_op(const zend_op_array *op_array, const zend_basic_block *
                                fprintf(stderr, " (\?\?\?)");
                                break;
                }
-       } else if (ZEND_VM_EXT_FAST_CALL == (flags & ZEND_VM_EXT_MASK)) {
-               if (opline->extended_value == ZEND_FAST_CALL_FROM_FINALLY) {
-                       fprintf(stderr, " (from-finally)");
-               }
-       } else if (ZEND_VM_EXT_FAST_RET == (flags & ZEND_VM_EXT_MASK)) {
-               if (opline->extended_value == ZEND_FAST_RET_TO_CATCH) {
-                       fprintf(stderr, " (to-catch)");
-               } else if (opline->extended_value == ZEND_FAST_RET_TO_FINALLY) {
-                       fprintf(stderr, " (to-finally)");
-               }
        } else if (ZEND_VM_EXT_SRC == (flags & ZEND_VM_EXT_MASK)) {
                if (opline->extended_value == ZEND_RETURNS_VALUE) {
                        fprintf(stderr, " (value)");
index 8bd7c4e50e398c09068921c930f044c63f46d915..44119c9e5116aaff77694dc618d43d72464115bf 100644 (file)
@@ -74,7 +74,7 @@ char *phpdbg_decode_input_op(
        } else if (ZEND_VM_OP_NUM == (flags & ZEND_VM_OP_MASK)) {
                spprintf(&result, 0, "%" PRIu32, op.num);
        } else if (ZEND_VM_OP_TRY_CATCH == (flags & ZEND_VM_OP_MASK)) {
-               if (opline->opcode != ZEND_FAST_RET || opline->extended_value) {
+               if (op.num != (uint32_t)-1) {
                        spprintf(&result, 0, "try-catch(%" PRIu32 ")", op.num);
                }
        } else if (ZEND_VM_OP_LIVE_RANGE == (flags & ZEND_VM_OP_MASK)) {
@@ -99,21 +99,6 @@ char *phpdbg_decode_opline(zend_op_array *ops, zend_op *opline) /*{{{ */
        uint32_t flags = zend_get_opcode_flags(opline->opcode);
        char *result, *decode[4] = {NULL, NULL, NULL, NULL};
 
-       /* EX */
-       switch (opline->opcode) {
-       case ZEND_FAST_CALL:
-               if (opline->extended_value == ZEND_FAST_CALL_FROM_FINALLY) {
-                       decode[0] = estrdup("FAST_CALL<FROM_FINALLY>");
-               }
-               break;
-       case ZEND_FAST_RET:
-               if (opline->extended_value != 0) {
-                       spprintf(&decode[0], 0, "FAST_RET<%s>",
-                               opline->extended_value == ZEND_FAST_RET_TO_CATCH ? "TO_CATCH" : "TO_FINALLY");
-               }
-               break;
-       }
-
        /* OP1 */
        decode[1] = phpdbg_decode_input_op(
                ops, opline, opline->op1, opline->op1_type, ZEND_VM_OP1_FLAGS(flags));
index 37e7289092fa15db975da5475e6cc4171103579c..2a982bcbe306f2c732775efed17bf2306520a5e3 100644 (file)
@@ -25,7 +25,7 @@ prompt> [L7 %s ECHO                    "ok "
  00008:        }
  00009: } catch (Error $e) {
 prompt> ok
-[L7 %s FAST_RET<TO_CATCH>      ~%d                   try-catch(0)                             %s]
+[L7 %s FAST_RET                ~%d                   try-catch(0)                             %s]
 [L9 %s CATCH                   "Error"              $e                   1                    %s]
 >00005:                x();
  00006:        } finally {