Last active
May 23, 2016 11:23
-
-
Save dstogov/0a809891c6a3ac3fac4bd0d9711dd330 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/Zend/tests/bug65784.phpt b/Zend/tests/bug65784.phpt | |
index c079b3d..397c52a 100644 | |
--- a/Zend/tests/bug65784.phpt | |
+++ b/Zend/tests/bug65784.phpt | |
@@ -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 | |
diff --git a/Zend/tests/try/bug72213.phpt b/Zend/tests/try/bug72213.phpt | |
index aee4c95..6240502 100644 | |
--- a/Zend/tests/try/bug72213.phpt | |
+++ b/Zend/tests/try/bug72213.phpt | |
@@ -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/zend_compile.c b/Zend/zend_compile.c | |
index 0994681..2ace159 100644 | |
--- a/Zend/zend_compile.c | |
+++ b/Zend/zend_compile.c | |
@@ -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; | |
@@ -4061,6 +4062,7 @@ void zend_compile_return(zend_ast *ast) /* {{{ */ | |
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 */ | |
@@ -4573,6 +4575,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 +4609,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) { | |
@@ -4704,12 +4709,15 @@ 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; | |
} | |
+ CG(context).try_catch_offset = try_catch_offset; | |
+ | |
efree(jmp_opnums); | |
} | |
/* }}} */ | |
diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h | |
index 0de475d..ef341c5 100644 | |
--- a/Zend/zend_compile.h | |
+++ b/Zend/zend_compile.h | |
@@ -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; | |
@@ -958,11 +959,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 | |
diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c | |
index 34e060f..0b5fe75 100644 | |
--- a/Zend/zend_opcode.c | |
+++ b/Zend/zend_opcode.c | |
@@ -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: | |
{ | |
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h | |
index 93ff58e..11340db 100644 | |
--- a/Zend/zend_vm_def.h | |
+++ b/Zend/zend_vm_def.h | |
@@ -7129,7 +7129,6 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) | |
/* 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; | |
} | |
@@ -7150,9 +7149,6 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) | |
zval *fast_call = EX_VAR(EX(func)->op_array.opcodes[finally_op_end].op1.var); | |
cleanup_live_vars(execute_data, op_num, finally_op_num); | |
- if (in_finally && Z_OBJ_P(fast_call)) { | |
- zend_exception_set_previous(EG(exception), Z_OBJ_P(fast_call)); | |
- } | |
Z_OBJ_P(fast_call) = EG(exception); | |
EG(exception) = NULL; | |
fast_call->u2.lineno = (uint32_t)-1; | |
@@ -7162,12 +7158,25 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) | |
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); | |
+ zval *fast_call; | |
+ uint32_t try_catch_offset; | |
+ zend_object *obj = EG(exception); | |
- if (Z_OBJ_P(fast_call)) { | |
- zend_exception_set_previous(EG(exception), Z_OBJ_P(fast_call)); | |
- Z_OBJ_P(fast_call) = NULL; | |
- } | |
+ 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]); | |
@@ -7528,39 +7537,48 @@ ZEND_VM_HANDLER(142, ZEND_YIELD_FROM, CONST|TMP|VAR|CV, ANY) | |
ZEND_VM_RETURN(); | |
} | |
-ZEND_VM_HANDLER(159, ZEND_DISCARD_EXCEPTION, ANY, ANY) | |
+ZEND_VM_HANDLER(159, ZEND_DISCARD_EXCEPTION, ANY, TRY_CATCH) | |
{ | |
USE_OPLINE | |
zval *fast_call = EX_VAR(opline->op1.var); | |
+ uint32_t try_catch_offset; | |
+ SAVE_OPLINE(); | |
/* check for delayed exception */ | |
if (Z_OBJ_P(fast_call) != NULL) { | |
- SAVE_OPLINE(); | |
/* 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[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 (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(); | |
} | |
-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); | |
@@ -7571,36 +7589,43 @@ ZEND_VM_HANDLER(163, ZEND_FAST_RET, ANY, TRY_CATCH, FAST_RET) | |
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]); | |
+ 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; | |
+ | |
+ 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 { | |
- 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(); | |
+ 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]) { | |
+ target = try_catch->finally_op; | |
} else { | |
- ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper); | |
+ target = try_catch->finally_end; | |
+ if (Z_OBJ_P(next_fast_call)) { | |
+ zend_exception_set_previous(Z_OBJ_P(fast_call), Z_OBJ_P(next_fast_call)); | |
+ } | |
} | |
+ 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, target); | |
+ ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[target]); | |
+ ZEND_VM_CONTINUE(); | |
+ } | |
+ } 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); | |
} | |
} | |
} | |
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h | |
index 1b673b8..672ad36 100644 | |
--- a/Zend/zend_vm_execute.h | |
+++ b/Zend/zend_vm_execute.h | |
@@ -1714,7 +1714,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER( | |
/* 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; | |
} | |
@@ -1735,9 +1734,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER( | |
zval *fast_call = EX_VAR(EX(func)->op_array.opcodes[finally_op_end].op1.var); | |
cleanup_live_vars(execute_data, op_num, finally_op_num); | |
- if (in_finally && Z_OBJ_P(fast_call)) { | |
- zend_exception_set_previous(EG(exception), Z_OBJ_P(fast_call)); | |
- } | |
Z_OBJ_P(fast_call) = EG(exception); | |
EG(exception) = NULL; | |
fast_call->u2.lineno = (uint32_t)-1; | |
@@ -1747,12 +1743,25 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER( | |
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); | |
+ zval *fast_call; | |
+ uint32_t try_catch_offset; | |
+ zend_object *obj = EG(exception); | |
- if (Z_OBJ_P(fast_call)) { | |
- zend_exception_set_previous(EG(exception), Z_OBJ_P(fast_call)); | |
- Z_OBJ_P(fast_call) = NULL; | |
- } | |
+ 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]); | |
@@ -1811,14 +1820,27 @@ 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 */ | |
if (Z_OBJ_P(fast_call) != NULL) { | |
- SAVE_OPLINE(); | |
/* 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[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 (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(); | |
} | |
@@ -1828,13 +1850,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(); | |
} | |
@@ -1850,36 +1868,43 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_RET_SPEC_HANDLER(ZEND_OPC | |
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]); | |
+ 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; | |
+ | |
+ 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 { | |
- 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(); | |
+ 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]) { | |
+ target = try_catch->finally_op; | |
} else { | |
- ZEND_VM_TAIL_CALL(zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); | |
+ target = try_catch->finally_end; | |
+ if (Z_OBJ_P(next_fast_call)) { | |
+ zend_exception_set_previous(Z_OBJ_P(fast_call), Z_OBJ_P(next_fast_call)); | |
+ } | |
} | |
+ 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, target); | |
+ ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[target]); | |
+ ZEND_VM_CONTINUE(); | |
+ } | |
+ } 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)); | |
} | |
} | |
} | |
diff --git a/Zend/zend_vm_gen.php b/Zend/zend_vm_gen.php | |
index 88fe287..03d9817 100644 | |
--- a/Zend/zend_vm_gen.php | |
+++ b/Zend/zend_vm_gen.php | |
@@ -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, | |
diff --git a/Zend/zend_vm_opcodes.c b/Zend/zend_vm_opcodes.c | |
index 180b745..a1713ef 100644 | |
--- a/Zend/zend_vm_opcodes.c | |
+++ b/Zend/zend_vm_opcodes.c | |
@@ -368,11 +368,11 @@ static uint32_t zend_vm_opcodes_flags[184] = { | |
0x00000101, | |
0x05000000, | |
0x00000000, | |
- 0x00000000, | |
+ 0x00003000, | |
0x0b000303, | |
0x00000003, | |
- 0x09000020, | |
- 0x0a003000, | |
+ 0x00000020, | |
+ 0x00003000, | |
0x00000010, | |
0x00000000, | |
0x00000707, | |
diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h | |
index 00aa20e..4f5a0d6 100644 | |
--- a/Zend/zend_vm_opcodes.h | |
+++ b/Zend/zend_vm_opcodes.h | |
@@ -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 | |
diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c | |
index 6ad5110..674f27f 100644 | |
--- a/ext/opcache/Optimizer/block_pass.c | |
+++ b/ext/opcache/Optimizer/block_pass.c | |
@@ -904,9 +904,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]; | |
} | |
diff --git a/ext/opcache/Optimizer/zend_dump.c b/ext/opcache/Optimizer/zend_dump.c | |
index 70abe4d..edf7c3d 100644 | |
--- a/ext/opcache/Optimizer/zend_dump.c | |
+++ b/ext/opcache/Optimizer/zend_dump.c | |
@@ -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)"); | |
diff --git a/sapi/phpdbg/phpdbg_opcode.c b/sapi/phpdbg/phpdbg_opcode.c | |
index 8bd7c4e..44119c9 100644 | |
--- a/sapi/phpdbg/phpdbg_opcode.c | |
+++ b/sapi/phpdbg/phpdbg_opcode.c | |
@@ -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)); | |
diff --git a/sapi/phpdbg/tests/exceptions_003.phpt b/sapi/phpdbg/tests/exceptions_003.phpt | |
index 37e7289..2a982bc 100644 | |
--- a/sapi/phpdbg/tests/exceptions_003.phpt | |
+++ b/sapi/phpdbg/tests/exceptions_003.phpt | |
@@ -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 { |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment