mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
Improve finally fix
This commit is contained in:
parent
da5c727499
commit
4f21c06c2e
11 changed files with 329 additions and 191 deletions
|
@ -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}
|
||||
|
|
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}
|
|
@ -1021,6 +1021,7 @@ static uint32_t zend_add_try_element(uint32_t try_op) /* {{{ */
|
|||
elem->catch_op = 0;
|
||||
elem->finally_op = 0;
|
||||
elem->finally_end = 0;
|
||||
elem->parent = CG(context).try_catch_offset;
|
||||
|
||||
return try_catch_offset;
|
||||
}
|
||||
|
@ -4009,6 +4010,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;
|
||||
|
@ -4058,13 +4065,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;
|
||||
opline->op2.num = CG(context).try_catch_offset;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
@ -4684,11 +4684,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);
|
||||
|
@ -4714,9 +4721,12 @@ void zend_compile_try(zend_ast *ast) /* {{{ */
|
|||
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 = try_catch_offset;
|
||||
CG(context).try_catch_offset = orig_try_catch_offset;
|
||||
|
||||
efree(jmp_opnums);
|
||||
}
|
||||
|
|
|
@ -169,6 +169,7 @@ typedef struct _zend_try_catch_element {
|
|||
uint32_t catch_op; /* ketchup! */
|
||||
uint32_t finally_op;
|
||||
uint32_t finally_end;
|
||||
uint32_t parent;
|
||||
} zend_try_catch_element;
|
||||
|
||||
#define ZEND_LIVE_TMPVAR 0
|
||||
|
|
|
@ -7108,9 +7108,8 @@ ZEND_VM_HANDLER(155, ZEND_BIND_TRAITS, ANY, ANY)
|
|||
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 i, try_catch_offset = (uint32_t) -1;
|
||||
zend_object *ex = EG(exception);
|
||||
|
||||
{
|
||||
const zend_op *exc_opline = EG(opline_before_exception);
|
||||
|
@ -7124,70 +7123,63 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
|
|||
}
|
||||
}
|
||||
|
||||
/* 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 > op_num) {
|
||||
/* further blocks will not be relevant... */
|
||||
break;
|
||||
}
|
||||
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 (op_num < try_catch->catch_op || op_num < try_catch->finally_end) {
|
||||
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);
|
||||
/* 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];
|
||||
|
||||
cleanup_live_vars(execute_data, op_num, finally_op_num);
|
||||
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;
|
||||
uint32_t try_catch_offset;
|
||||
zend_object *obj = EG(exception);
|
||||
|
||||
do {
|
||||
if (catch_op_num && catch_op_num < finally_op_end) {
|
||||
break;
|
||||
}
|
||||
fast_call = EX_VAR(EX(func)->op_array.opcodes[finally_op_end].op1.var);
|
||||
if (Z_OBJ_P(fast_call)) {
|
||||
zend_exception_set_previous(obj, Z_OBJ_P(fast_call));
|
||||
obj = Z_OBJ_P(fast_call);
|
||||
}
|
||||
try_catch_offset = EX(func)->op_array.opcodes[finally_op_end].op2.num;
|
||||
if (try_catch_offset == (uint32_t)-1) {
|
||||
break;
|
||||
}
|
||||
finally_op_end = EX(func)->op_array.try_catch_array[try_catch_offset].finally_end;
|
||||
} while (finally_op_end);
|
||||
}
|
||||
if (catch_op_num) {
|
||||
ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[catch_op_num]);
|
||||
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 (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);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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 = try_catch->parent;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7537,11 +7529,10 @@ ZEND_VM_HANDLER(142, ZEND_YIELD_FROM, CONST|TMP|VAR|CV, ANY)
|
|||
ZEND_VM_RETURN();
|
||||
}
|
||||
|
||||
ZEND_VM_HANDLER(159, ZEND_DISCARD_EXCEPTION, ANY, TRY_CATCH)
|
||||
ZEND_VM_HANDLER(159, ZEND_DISCARD_EXCEPTION, ANY, ANY)
|
||||
{
|
||||
USE_OPLINE
|
||||
zval *fast_call = EX_VAR(opline->op1.var);
|
||||
uint32_t try_catch_offset;
|
||||
SAVE_OPLINE();
|
||||
|
||||
/* check for delayed exception */
|
||||
|
@ -7550,21 +7541,6 @@ ZEND_VM_HANDLER(159, ZEND_DISCARD_EXCEPTION, ANY, TRY_CATCH)
|
|||
OBJ_RELEASE(Z_OBJ_P(fast_call));
|
||||
Z_OBJ_P(fast_call) = NULL;
|
||||
}
|
||||
try_catch_offset = EX(func)->op_array.opcodes[EX(func)->op_array.try_catch_array[opline->op2.num].finally_end].op2.num;
|
||||
while (try_catch_offset != (uint32_t)-1) {
|
||||
zend_try_catch_element *try_catch = EX(func)->op_array.try_catch_array + try_catch_offset;
|
||||
zval *fast_call = EX_VAR(EX(func)->op_array.opcodes[try_catch->finally_end].op1.var);
|
||||
|
||||
if (try_catch->finally_op && try_catch->finally_op > opline - EX(func)->op_array.opcodes) {
|
||||
break;
|
||||
}
|
||||
if (Z_OBJ_P(fast_call) != NULL) {
|
||||
/* discard the previously thrown exception */
|
||||
OBJ_RELEASE(Z_OBJ_P(fast_call));
|
||||
Z_OBJ_P(fast_call) = NULL;
|
||||
}
|
||||
try_catch_offset = EX(func)->op_array.opcodes[try_catch->finally_end].op2.num;
|
||||
}
|
||||
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
}
|
||||
|
@ -7589,28 +7565,25 @@ ZEND_VM_HANDLER(163, ZEND_FAST_RET, ANY, TRY_CATCH)
|
|||
if (fast_call->u2.lineno != (uint32_t)-1) {
|
||||
const zend_op *fast_ret = EX(func)->op_array.opcodes + fast_call->u2.lineno;
|
||||
|
||||
if (Z_OBJ_P(fast_call)) {
|
||||
OBJ_RELEASE(Z_OBJ_P(fast_call));
|
||||
Z_OBJ_P(fast_call) = NULL;
|
||||
}
|
||||
ZEND_VM_SET_OPCODE(fast_ret + 1);
|
||||
ZEND_VM_CONTINUE();
|
||||
} else {
|
||||
/* special case for unhandled exceptions */
|
||||
if (opline->op2.num != (uint32_t)-1) {
|
||||
/* check upper finally block */
|
||||
zend_try_catch_element *try_catch = EX(func)->op_array.try_catch_array + opline->op2.num;
|
||||
uint32_t try_catch_offset = opline->op2.num;
|
||||
while (try_catch_offset != (uint32_t)-1) {
|
||||
/* check upper try block */
|
||||
zend_try_catch_element *try_catch = EX(func)->op_array.try_catch_array + try_catch_offset;
|
||||
|
||||
if (try_catch->catch_op && opline < &EX(func)->op_array.opcodes[try_catch->catch_op]) {
|
||||
EG(exception) = Z_OBJ_P(fast_call);
|
||||
cleanup_live_vars(execute_data, opline - EX(func)->op_array.opcodes, try_catch->catch_op);
|
||||
ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[try_catch->catch_op]);
|
||||
ZEND_VM_CONTINUE();
|
||||
} else {
|
||||
} else if (try_catch->finally_op) {
|
||||
uint32_t target;
|
||||
zval *next_fast_call = EX_VAR(EX(func)->op_array.opcodes[try_catch->finally_end].op1.var);
|
||||
|
||||
if (try_catch->finally_op && opline < &EX(func)->op_array.opcodes[try_catch->finally_op]) {
|
||||
if (opline < &EX(func)->op_array.opcodes[try_catch->finally_op]) {
|
||||
target = try_catch->finally_op;
|
||||
} else {
|
||||
target = try_catch->finally_end;
|
||||
|
@ -7624,17 +7597,18 @@ ZEND_VM_HANDLER(163, ZEND_FAST_RET, ANY, TRY_CATCH)
|
|||
ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[target]);
|
||||
ZEND_VM_CONTINUE();
|
||||
}
|
||||
try_catch_offset = try_catch->parent;
|
||||
}
|
||||
|
||||
/* leave function with exception */
|
||||
EG(exception) = Z_OBJ_P(fast_call);
|
||||
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 {
|
||||
/* leave function with exception */
|
||||
EG(exception) = Z_OBJ_P(fast_call);
|
||||
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);
|
||||
}
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1693,9 +1693,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BIND_TRAITS_SPEC_HANDLER(ZEND_
|
|||
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 i, try_catch_offset = (uint32_t) -1;
|
||||
zend_object *ex = EG(exception);
|
||||
|
||||
{
|
||||
const zend_op *exc_opline = EG(opline_before_exception);
|
||||
|
@ -1709,70 +1708,63 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(
|
|||
}
|
||||
}
|
||||
|
||||
/* 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 > op_num) {
|
||||
/* further blocks will not be relevant... */
|
||||
break;
|
||||
}
|
||||
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 (op_num < try_catch->catch_op || op_num < try_catch->finally_end) {
|
||||
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);
|
||||
/* 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];
|
||||
|
||||
cleanup_live_vars(execute_data, op_num, finally_op_num);
|
||||
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;
|
||||
uint32_t try_catch_offset;
|
||||
zend_object *obj = EG(exception);
|
||||
|
||||
do {
|
||||
if (catch_op_num && catch_op_num < finally_op_end) {
|
||||
break;
|
||||
}
|
||||
fast_call = EX_VAR(EX(func)->op_array.opcodes[finally_op_end].op1.var);
|
||||
if (Z_OBJ_P(fast_call)) {
|
||||
zend_exception_set_previous(obj, Z_OBJ_P(fast_call));
|
||||
obj = Z_OBJ_P(fast_call);
|
||||
}
|
||||
try_catch_offset = EX(func)->op_array.opcodes[finally_op_end].op2.num;
|
||||
if (try_catch_offset == (uint32_t)-1) {
|
||||
break;
|
||||
}
|
||||
finally_op_end = EX(func)->op_array.try_catch_array[try_catch_offset].finally_end;
|
||||
} while (finally_op_end);
|
||||
}
|
||||
if (catch_op_num) {
|
||||
ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[catch_op_num]);
|
||||
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 (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));
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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 = try_catch->parent;
|
||||
}
|
||||
|
||||
/* 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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1820,7 +1812,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DISCARD_EXCEPTION_SPEC_HANDLER
|
|||
{
|
||||
USE_OPLINE
|
||||
zval *fast_call = EX_VAR(opline->op1.var);
|
||||
uint32_t try_catch_offset;
|
||||
SAVE_OPLINE();
|
||||
|
||||
/* check for delayed exception */
|
||||
|
@ -1829,21 +1820,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DISCARD_EXCEPTION_SPEC_HANDLER
|
|||
OBJ_RELEASE(Z_OBJ_P(fast_call));
|
||||
Z_OBJ_P(fast_call) = NULL;
|
||||
}
|
||||
try_catch_offset = EX(func)->op_array.opcodes[EX(func)->op_array.try_catch_array[opline->op2.num].finally_end].op2.num;
|
||||
while (try_catch_offset != (uint32_t)-1) {
|
||||
zend_try_catch_element *try_catch = EX(func)->op_array.try_catch_array + try_catch_offset;
|
||||
zval *fast_call = EX_VAR(EX(func)->op_array.opcodes[try_catch->finally_end].op1.var);
|
||||
|
||||
if (try_catch->finally_op && try_catch->finally_op > opline - EX(func)->op_array.opcodes) {
|
||||
break;
|
||||
}
|
||||
if (Z_OBJ_P(fast_call) != NULL) {
|
||||
/* discard the previously thrown exception */
|
||||
OBJ_RELEASE(Z_OBJ_P(fast_call));
|
||||
Z_OBJ_P(fast_call) = NULL;
|
||||
}
|
||||
try_catch_offset = EX(func)->op_array.opcodes[try_catch->finally_end].op2.num;
|
||||
}
|
||||
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
}
|
||||
|
@ -1868,28 +1844,25 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_RET_SPEC_HANDLER(ZEND_OPC
|
|||
if (fast_call->u2.lineno != (uint32_t)-1) {
|
||||
const zend_op *fast_ret = EX(func)->op_array.opcodes + fast_call->u2.lineno;
|
||||
|
||||
if (Z_OBJ_P(fast_call)) {
|
||||
OBJ_RELEASE(Z_OBJ_P(fast_call));
|
||||
Z_OBJ_P(fast_call) = NULL;
|
||||
}
|
||||
ZEND_VM_SET_OPCODE(fast_ret + 1);
|
||||
ZEND_VM_CONTINUE();
|
||||
} else {
|
||||
/* special case for unhandled exceptions */
|
||||
if (opline->op2.num != (uint32_t)-1) {
|
||||
/* check upper finally block */
|
||||
zend_try_catch_element *try_catch = EX(func)->op_array.try_catch_array + opline->op2.num;
|
||||
uint32_t try_catch_offset = opline->op2.num;
|
||||
while (try_catch_offset != (uint32_t)-1) {
|
||||
/* check upper try block */
|
||||
zend_try_catch_element *try_catch = EX(func)->op_array.try_catch_array + try_catch_offset;
|
||||
|
||||
if (try_catch->catch_op && opline < &EX(func)->op_array.opcodes[try_catch->catch_op]) {
|
||||
EG(exception) = Z_OBJ_P(fast_call);
|
||||
cleanup_live_vars(execute_data, opline - EX(func)->op_array.opcodes, try_catch->catch_op);
|
||||
ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[try_catch->catch_op]);
|
||||
ZEND_VM_CONTINUE();
|
||||
} else {
|
||||
} else if (try_catch->finally_op) {
|
||||
uint32_t target;
|
||||
zval *next_fast_call = EX_VAR(EX(func)->op_array.opcodes[try_catch->finally_end].op1.var);
|
||||
|
||||
if (try_catch->finally_op && opline < &EX(func)->op_array.opcodes[try_catch->finally_op]) {
|
||||
if (opline < &EX(func)->op_array.opcodes[try_catch->finally_op]) {
|
||||
target = try_catch->finally_op;
|
||||
} else {
|
||||
target = try_catch->finally_end;
|
||||
|
@ -1903,17 +1876,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_RET_SPEC_HANDLER(ZEND_OPC
|
|||
ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[target]);
|
||||
ZEND_VM_CONTINUE();
|
||||
}
|
||||
try_catch_offset = try_catch->parent;
|
||||
}
|
||||
|
||||
/* leave function with exception */
|
||||
EG(exception) = Z_OBJ_P(fast_call);
|
||||
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 {
|
||||
/* leave function with exception */
|
||||
EG(exception) = Z_OBJ_P(fast_call);
|
||||
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));
|
||||
}
|
||||
ZEND_VM_TAIL_CALL(zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -368,7 +368,7 @@ static uint32_t zend_vm_opcodes_flags[184] = {
|
|||
0x00000101,
|
||||
0x05000000,
|
||||
0x00000000,
|
||||
0x00003000,
|
||||
0x00000000,
|
||||
0x0b000303,
|
||||
0x00000003,
|
||||
0x00000020,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue