mirror of
https://github.com/php/php-src.git
synced 2024-11-27 20:03:40 +08:00
Fixed bug #72213 (Finally leaks on nested exceptions).
Squashed commit of the following: commit8461b0407f
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. commit0c71e24964
Author: Dmitry Stogov <dmitry@zend.com> Date: Wed May 25 00:04:53 2016 +0300 Move SAVE_OPLINE() to its original place commit111432a4df
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. commit4f21c06c2e
Author: Nikita Popov <nikic@php.net> Date: Tue May 24 14:55:27 2016 +0200 Improve finally fix commitda5c727499
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 commitcfcedf2fb4
Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 02:59:27 2016 +0300 Added test commit4c6aa93d43
Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 00:38:20 2016 +0300 Added tests commit8a8f4704b0
Author: Dmitry Stogov <dmitry@zend.com> Date: Mon May 23 23:27:34 2016 +0300 Fixed bug #72213 (Finally leaks on nested exceptions)
This commit is contained in:
parent
91f5940329
commit
2ae21abdf7
1
NEWS
1
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)
|
||||
|
@ -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
|
||||
|
@ -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}
|
||||
|
20
Zend/tests/try/bug70228_2.phpt
Normal file
20
Zend/tests/try/bug70228_2.phpt
Normal file
@ -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)
|
31
Zend/tests/try/bug70228_3.phpt
Normal file
31
Zend/tests/try/bug70228_3.phpt
Normal file
@ -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
|
32
Zend/tests/try/bug70228_4.phpt
Normal file
32
Zend/tests/try/bug70228_4.phpt
Normal file
@ -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
|
@ -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() {
|
||||
|
37
Zend/tests/try/try_finally_023.phpt
Normal file
37
Zend/tests/try/try_finally_023.phpt
Normal file
@ -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}
|
38
Zend/tests/try/try_finally_024.phpt
Normal file
38
Zend/tests/try/try_finally_024.phpt
Normal file
@ -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}
|
28
Zend/tests/try/try_finally_025.phpt
Normal file
28
Zend/tests/try/try_finally_025.phpt
Normal file
@ -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}
|
37
Zend/tests/try/try_finally_026.phpt
Normal file
37
Zend/tests/try/try_finally_026.phpt
Normal file
@ -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}
|
34
Zend/tests/try/try_finally_027.phpt
Normal file
34
Zend/tests/try/try_finally_027.phpt
Normal file
@ -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}
|
@ -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);
|
||||
}
|
||||
/* }}} */
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
{
|
||||
|
@ -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);
|
||||
cleanup_unfinished_calls(execute_data, throw_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);
|
||||
|
||||
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)
|
||||
|
@ -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);
|
||||
cleanup_unfinished_calls(execute_data, throw_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);
|
||||
|
||||
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)
|
||||
|
@ -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,
|
||||
|
@ -371,8 +371,8 @@ static uint32_t zend_vm_opcodes_flags[184] = {
|
||||
0x00000000,
|
||||
0x0b000303,
|
||||
0x00000003,
|
||||
0x09000020,
|
||||
0x0a003000,
|
||||
0x00000020,
|
||||
0x00003000,
|
||||
0x00000010,
|
||||
0x00000000,
|
||||
0x00000707,
|
||||
|
@ -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
|
||||
|
@ -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];
|
||||
}
|
||||
|
@ -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)");
|
||||
|
@ -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));
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user