diff options
| author | Xinchen Hui <laruence@php.net> | 2012-08-22 18:32:03 +0800 |
|---|---|---|
| committer | Xinchen Hui <laruence@php.net> | 2012-08-22 18:32:03 +0800 |
| commit | 60a29791e4b66844e5dfff698141074d48fc3da8 (patch) | |
| tree | 7b2df724455d4d152d2870161c8249b18b0b5f05 | |
| parent | 3d4f91da4b6e1c4e918fa330782b9cae98334b11 (diff) | |
| download | php-git-60a29791e4b66844e5dfff698141074d48fc3da8.tar.gz | |
Fixed bug that jmp in try block jmp over finally block
Refactor the implemention, make codes clear
| -rw-r--r-- | Zend/tests/catch_finally_001.phpt | 2 | ||||
| -rw-r--r-- | Zend/tests/catch_finally_002.phpt | 2 | ||||
| -rw-r--r-- | Zend/tests/catch_finally_003.phpt | 2 | ||||
| -rw-r--r-- | Zend/tests/catch_finally_004.phpt | 2 | ||||
| -rw-r--r-- | Zend/tests/catch_finally_005.phpt | 2 | ||||
| -rw-r--r-- | Zend/tests/catch_finally_006.phpt | 2 | ||||
| -rw-r--r-- | Zend/tests/try_catch_finally_005.phpt | 52 | ||||
| -rw-r--r-- | Zend/tests/try_catch_finally_006.phpt | 39 | ||||
| -rw-r--r-- | Zend/tests/try_catch_finally_007.phpt | 46 | ||||
| -rw-r--r-- | Zend/tests/try_finally_001.phpt | 3 | ||||
| -rw-r--r-- | Zend/tests/try_finally_002.phpt | 2 | ||||
| -rw-r--r-- | Zend/tests/try_finally_003.phpt | 2 | ||||
| -rw-r--r-- | Zend/tests/try_finally_004.phpt | 2 | ||||
| -rw-r--r-- | Zend/tests/try_finally_005.phpt | 2 | ||||
| -rw-r--r-- | Zend/tests/try_finally_006.phpt | 2 | ||||
| -rw-r--r-- | Zend/tests/try_finally_007.phpt | 2 | ||||
| -rw-r--r-- | Zend/tests/try_finally_008.phpt | 2 | ||||
| -rw-r--r-- | Zend/tests/try_finally_009.phpt | 2 | ||||
| -rw-r--r-- | Zend/zend_compile.c | 24 | ||||
| -rw-r--r-- | Zend/zend_compile.h | 6 | ||||
| -rw-r--r-- | Zend/zend_opcode.c | 6 | ||||
| -rw-r--r-- | Zend/zend_vm_def.h | 865 | ||||
| -rw-r--r-- | Zend/zend_vm_execute.h | 363 |
23 files changed, 751 insertions, 681 deletions
diff --git a/Zend/tests/catch_finally_001.phpt b/Zend/tests/catch_finally_001.phpt index 2b58fa7132..0c3f597a0a 100644 --- a/Zend/tests/catch_finally_001.phpt +++ b/Zend/tests/catch_finally_001.phpt @@ -1,5 +1,5 @@ --TEST-- -Try catch finally +Try catch finally (basic test) --FILE-- <?php function foo ($throw = FALSE) { diff --git a/Zend/tests/catch_finally_002.phpt b/Zend/tests/catch_finally_002.phpt index 5f36ae2aa8..c54477ff8c 100644 --- a/Zend/tests/catch_finally_002.phpt +++ b/Zend/tests/catch_finally_002.phpt @@ -1,5 +1,5 @@ --TEST-- -Try catch finally return +Try catch finally (basic test with return) --FILE-- <?php function foo () { diff --git a/Zend/tests/catch_finally_003.phpt b/Zend/tests/catch_finally_003.phpt index a47c6f0f2c..24e468d335 100644 --- a/Zend/tests/catch_finally_003.phpt +++ b/Zend/tests/catch_finally_003.phpt @@ -1,5 +1,5 @@ --TEST-- -Try catch finally multi-return +Try catch finally (with multi-returns) --FILE-- <?php function dummy($msg) { diff --git a/Zend/tests/catch_finally_004.phpt b/Zend/tests/catch_finally_004.phpt index be32a435c3..a2c22beab1 100644 --- a/Zend/tests/catch_finally_004.phpt +++ b/Zend/tests/catch_finally_004.phpt @@ -1,5 +1,5 @@ --TEST-- -Nesting try catch finally +Try catch finally (nesting try-catch-finally) --FILE-- <?php diff --git a/Zend/tests/catch_finally_005.phpt b/Zend/tests/catch_finally_005.phpt index d8573bd4e2..c2fd55df27 100644 --- a/Zend/tests/catch_finally_005.phpt +++ b/Zend/tests/catch_finally_005.phpt @@ -1,5 +1,5 @@ --TEST-- -Try catch finally with return +Try catch finally (with multi-returns and exception) --FILE-- <?php function foo ($a) { diff --git a/Zend/tests/catch_finally_006.phpt b/Zend/tests/catch_finally_006.phpt index 48937c40d4..9759eab37e 100644 --- a/Zend/tests/catch_finally_006.phpt +++ b/Zend/tests/catch_finally_006.phpt @@ -1,5 +1,5 @@ --TEST-- -Try catch finally: re-throw exception in catch block +Try catch finally (re-throw exception in catch block) --FILE-- <?php function foo ($a) { diff --git a/Zend/tests/try_catch_finally_005.phpt b/Zend/tests/try_catch_finally_005.phpt new file mode 100644 index 0000000000..dafeb6bbe0 --- /dev/null +++ b/Zend/tests/try_catch_finally_005.phpt @@ -0,0 +1,52 @@ +--TEST-- +Try catch finally (break / cont in try block) +--CREDITS-- +adoy +--FILE-- +<?php +for ($i = 0; $i < 100 ; $i ++) { + try { + break; + } finally { + var_dump("break"); + } +} + + +for ($i = 0; $i < 2; $i ++) { + try { + continue; + } finally { + var_dump("continue1"); + } +} + +for ($i = 0; $i < 3; $i ++) { + try { + try { + continue; + } finally { + var_dump("continue2"); + if ($i == 1) { + throw new Exception("continue exception"); + } + } + } catch (Exception $e) { + var_dump("cactched"); + } finally { + var_dump("finally"); + } +} + +?> +--EXPECTF-- +string(5) "break" +string(9) "continue1" +string(9) "continue1" +string(9) "continue2" +string(7) "finally" +string(9) "continue2" +string(8) "cactched" +string(7) "finally" +string(9) "continue2" +string(7) "finally" diff --git a/Zend/tests/try_catch_finally_006.phpt b/Zend/tests/try_catch_finally_006.phpt new file mode 100644 index 0000000000..dab6af6a58 --- /dev/null +++ b/Zend/tests/try_catch_finally_006.phpt @@ -0,0 +1,39 @@ +--TEST-- +Try catch finally (goto in try/catch block) +--CREDITS-- +adoy +--FILE-- +<?php +function foo($ex = NULL) { + try { + try { + goto label; + } finally { + var_dump("finally1"); + if ($ex) throw $ex; + } + } catch (Exception $e) { + var_dump("catched"); + if ($ex) return "return1"; + } finally { + var_dump("finally2"); + } + +label: + var_dump("label"); + return "return2"; +} + +var_dump(foo()); +var_dump(foo(new Exception())); + +?> +--EXPECTF-- +string(8) "finally1" +string(8) "finally2" +string(5) "label" +string(7) "return2" +string(8) "finally1" +string(7) "catched" +string(8) "finally2" +string(7) "return1" diff --git a/Zend/tests/try_catch_finally_007.phpt b/Zend/tests/try_catch_finally_007.phpt new file mode 100644 index 0000000000..ad33c68131 --- /dev/null +++ b/Zend/tests/try_catch_finally_007.phpt @@ -0,0 +1,46 @@ +--TEST-- +Try catch finally (goto in try/catch block) +--CREDITS-- +adoy +--FILE-- +<?php +function foo($ret = FALSE) { + try { + try { + do { + goto label; + } while(0); + foreach (array() as $val) { + continue; + } + } finally { + var_dump("finally1"); + throw new Exception("exception"); + } + } catch (Exception $e) { + goto local; +local: + var_dump("catched"); + if ($ret) return "return"; + } finally { + var_dump("finally2"); + } + +label: + var_dump("label"); +} + +var_dump(foo()); +var_dump(foo(true)); + +?> +--EXPECTF-- +string(8) "finally1" +string(7) "catched" +string(8) "finally2" +string(5) "label" +NULL +string(8) "finally1" +string(7) "catched" +string(8) "finally2" +string(6) "return" diff --git a/Zend/tests/try_finally_001.phpt b/Zend/tests/try_finally_001.phpt index 1c168da275..0f740872c2 100644 --- a/Zend/tests/try_finally_001.phpt +++ b/Zend/tests/try_finally_001.phpt @@ -1,5 +1,5 @@ --TEST-- -Try finally +Try finally (basic test) --FILE-- <?php function foo ($a) { @@ -20,4 +20,3 @@ Stack trace: #0 %stry_finally_001.php(%d): foo('finally') #1 {main} thrown in %stry_finally_001.php on line %d - diff --git a/Zend/tests/try_finally_002.phpt b/Zend/tests/try_finally_002.phpt index 44676966fe..99a34f62fb 100644 --- a/Zend/tests/try_finally_002.phpt +++ b/Zend/tests/try_finally_002.phpt @@ -1,5 +1,5 @@ --TEST-- -Try finally +Try finally (re-throw exception in finally block) --FILE-- <?php function foo () { diff --git a/Zend/tests/try_finally_003.phpt b/Zend/tests/try_finally_003.phpt index c5a380995a..c1294911bd 100644 --- a/Zend/tests/try_finally_003.phpt +++ b/Zend/tests/try_finally_003.phpt @@ -1,5 +1,5 @@ --TEST-- -Try finally +Try finally (call sequence test) --FILE-- <?php function foo () { diff --git a/Zend/tests/try_finally_004.phpt b/Zend/tests/try_finally_004.phpt index 8caa8fb18f..08930a40c5 100644 --- a/Zend/tests/try_finally_004.phpt +++ b/Zend/tests/try_finally_004.phpt @@ -1,5 +1,5 @@ --TEST-- -Try without catch/finally block +Try finally (without catch/finally block) --FILE-- <?php function foo () { diff --git a/Zend/tests/try_finally_005.phpt b/Zend/tests/try_finally_005.phpt index 2c6c2c9e6c..8664d6b1bf 100644 --- a/Zend/tests/try_finally_005.phpt +++ b/Zend/tests/try_finally_005.phpt @@ -1,5 +1,5 @@ --TEST-- -Finally with long goto +Try finally (with long goto) --FILE-- <?php function foo () { diff --git a/Zend/tests/try_finally_006.phpt b/Zend/tests/try_finally_006.phpt index 2bfa4caea9..f53e6b5bc1 100644 --- a/Zend/tests/try_finally_006.phpt +++ b/Zend/tests/try_finally_006.phpt @@ -1,5 +1,5 @@ --TEST-- -Finally with near goto +Try finally (with near goto) --FILE-- <?php function foo () { diff --git a/Zend/tests/try_finally_007.phpt b/Zend/tests/try_finally_007.phpt index b13bd59e50..634937495c 100644 --- a/Zend/tests/try_finally_007.phpt +++ b/Zend/tests/try_finally_007.phpt @@ -1,5 +1,5 @@ --TEST-- -Finally with goto previous label +Try finally (with goto previous label) --FILE-- <?php function foo () { diff --git a/Zend/tests/try_finally_008.phpt b/Zend/tests/try_finally_008.phpt index 9025d8824d..cee37aedab 100644 --- a/Zend/tests/try_finally_008.phpt +++ b/Zend/tests/try_finally_008.phpt @@ -1,5 +1,5 @@ --TEST-- -Finally with jmp (do while) +Try finally (with break in do...while) --FILE-- <?php function foo () { diff --git a/Zend/tests/try_finally_009.phpt b/Zend/tests/try_finally_009.phpt index 7c3da6760b..b29930a75e 100644 --- a/Zend/tests/try_finally_009.phpt +++ b/Zend/tests/try_finally_009.phpt @@ -1,5 +1,5 @@ --TEST-- -Finally with jmp (for continue) +Try finally (with for continue) --FILE-- <?php function foo () { diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 2ae8cc510f..cb0be0890a 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -2696,7 +2696,7 @@ void zend_initialize_try_catch_element(znode *catch_token TSRMLS_DC) /* {{{ */ zend_stack_top(&CG(bp_stack), (void **) &jmp_list_ptr); zend_llist_add_element(jmp_list_ptr, &jmp_op_number); - catch_token->EA = get_next_op_number(CG(active_op_array)); + catch_token->EA = get_next_op_number(CG(active_op_array)); } /* }}} */ @@ -2792,7 +2792,7 @@ void zend_do_end_finally(znode *try_token, znode* catch_token, znode *finally_to zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); CG(active_op_array)->try_catch_array[try_token->u.op.opline_num].finally_op = finally_token->u.op.opline_num; CG(active_op_array)->try_catch_array[try_token->u.op.opline_num].finally_end = get_next_op_number(CG(active_op_array)); - CG(active_op_array)->has_finally_block = 1; + CG(active_op_array)->has_finally_block = 1; opline->opcode = ZEND_LEAVE; SET_UNUSED(opline->op1); @@ -4059,9 +4059,9 @@ static void zend_traits_init_trait_structures(zend_class_entry *ce TSRMLS_DC) /* /** And, ensure that the referenced method is resolvable, too. */ lcname = zend_str_tolower_dup(cur_method_ref->method_name, - cur_method_ref->mname_len); + cur_method_ref->mname_len); method_exists = zend_hash_exists(&cur_method_ref->ce->function_table, - lcname, cur_method_ref->mname_len + 1); + lcname, cur_method_ref->mname_len + 1); efree(lcname); if (!method_exists) { @@ -5043,11 +5043,11 @@ void zend_do_begin_class_declaration(const znode *class_token, znode *class_name opline->op2_type = IS_CONST; if (doing_inheritance) { - /* Make sure a trait does not try to extend a class */ - if ((new_class_entry->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) { - zend_error(E_COMPILE_ERROR, "A trait (%s) cannot extend a class. Traits can only be composed from other traits with the 'use' keyword. Error", new_class_entry->name); - } - + /* Make sure a trait does not try to extend a class */ + if ((new_class_entry->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) { + zend_error(E_COMPILE_ERROR, "A trait (%s) cannot extend a class. Traits can only be composed from other traits with the 'use' keyword. Error", new_class_entry->name); + } + opline->extended_value = parent_class_name->u.op.var; opline->opcode = ZEND_DECLARE_INHERITED_CLASS; } else { @@ -6998,9 +6998,9 @@ void zend_do_use(znode *ns_name, znode *new_name, int is_global TSRMLS_DC) /* {{ lcname = zend_str_tolower_dup(Z_STRVAL_P(name), Z_STRLEN_P(name)); if (((Z_STRLEN_P(name) == sizeof("self")-1) && - !memcmp(lcname, "self", sizeof("self")-1)) || - ((Z_STRLEN_P(name) == sizeof("parent")-1) && - !memcmp(lcname, "parent", sizeof("parent")-1))) { + !memcmp(lcname, "self", sizeof("self")-1)) || + ((Z_STRLEN_P(name) == sizeof("parent")-1) && + !memcmp(lcname, "parent", sizeof("parent")-1))) { zend_error(E_COMPILE_ERROR, "Cannot use %s as %s because '%s' is a special class name", Z_STRVAL_P(ns), Z_STRVAL_P(name), Z_STRVAL_P(name)); } diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 80e02ab309..971860602e 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -281,7 +281,7 @@ struct _zend_op_array { zend_try_catch_element *try_catch_array; int last_try_catch; - zend_bool has_finally_block; + zend_bool has_finally_block; /* static variables support */ HashTable *static_variables; @@ -384,8 +384,8 @@ struct _zend_execute_data { zend_class_entry *current_called_scope; zval *current_this; zval *current_object; - zend_uint leaving; - zend_uint leaving_dest; + zend_uint leaving; + zend_uint leaving_dest; }; #define EX(element) execute_data.element diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 2552d2ebd6..6c15829100 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -87,7 +87,7 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz op_array->static_variables = NULL; op_array->last_try_catch = 0; - op_array->has_finally_block = 0; + op_array->has_finally_block = 0; op_array->this_var = -1; @@ -552,8 +552,8 @@ ZEND_API int pass_two(zend_op_array *op_array TSRMLS_DC) } opline->op1.jmp_addr = &op_array->opcodes[opline->op1.opline_num]; break; - case ZEND_BRK: - case ZEND_CONT: + case ZEND_BRK: + case ZEND_CONT: if (op_array->last_try_catch) { int nest_levels, array_offset; zend_brk_cont_element *jmp_to; diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index d921f81efc..ce1674e4f3 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1840,6 +1840,392 @@ ZEND_VM_HANDLER(39, ZEND_ASSIGN_REF, VAR|CV, VAR|CV) ZEND_VM_NEXT_OPCODE(); } +ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) +{ + zend_bool nested; + zend_op_array *op_array = EX(op_array); + + EG(current_execute_data) = EX(prev_execute_data); + EG(opline_ptr) = NULL; + if (!EG(active_symbol_table)) { + zval ***cv = EX_CVs(); + zval ***end = cv + op_array->last_var; + while (cv != end) { + if (*cv) { + zval_ptr_dtor(*cv); + } + cv++; + } + } + + if ((op_array->fn_flags & ZEND_ACC_CLOSURE) && op_array->prototype) { + zval_ptr_dtor((zval**)&op_array->prototype); + } + + nested = EX(nested); + + zend_vm_stack_free(execute_data TSRMLS_CC); + + if (nested) { + execute_data = EG(current_execute_data); + } + if (nested) { + USE_OPLINE + + LOAD_REGS(); + LOAD_OPLINE(); + if (UNEXPECTED(opline->opcode == ZEND_INCLUDE_OR_EVAL)) { + + EX(function_state).function = (zend_function *) EX(op_array); + EX(function_state).arguments = NULL; + EX(object) = EX(current_object); + + EG(opline_ptr) = &EX(opline); + EG(active_op_array) = EX(op_array); + EG(return_value_ptr_ptr) = EX(original_return_value); + destroy_op_array(op_array TSRMLS_CC); + efree(op_array); + if (UNEXPECTED(EG(exception) != NULL)) { + zend_throw_exception_internal(NULL TSRMLS_CC); + HANDLE_EXCEPTION_LEAVE(); + } else if (RETURN_VALUE_USED(opline)) { + if (!EX_T(opline->result.var).var.ptr) { /* there was no return statement */ + zval *retval; + + ALLOC_ZVAL(retval); + ZVAL_BOOL(retval, 1); + INIT_PZVAL(retval); + EX_T(opline->result.var).var.ptr = retval; + } + } + + ZEND_VM_INC_OPCODE(); + ZEND_VM_LEAVE(); + } else { + + EG(opline_ptr) = &EX(opline); + EG(active_op_array) = EX(op_array); + EG(return_value_ptr_ptr) = EX(original_return_value); + if (EG(active_symbol_table)) { + if (EG(symtable_cache_ptr)>=EG(symtable_cache_limit)) { + zend_hash_destroy(EG(active_symbol_table)); + FREE_HASHTABLE(EG(active_symbol_table)); + } else { + /* clean before putting into the cache, since clean + could call dtors, which could use cached hash */ + zend_hash_clean(EG(active_symbol_table)); + *(++EG(symtable_cache_ptr)) = EG(active_symbol_table); + } + } + EG(active_symbol_table) = EX(symbol_table); + + EX(function_state).function = (zend_function *) EX(op_array); + EX(function_state).arguments = NULL; + + if (EG(This)) { + if (UNEXPECTED(EG(exception) != NULL) && IS_CTOR_CALL(EX(called_scope))) { + if (IS_CTOR_USED(EX(called_scope))) { + Z_DELREF_P(EG(This)); + } + if (Z_REFCOUNT_P(EG(This)) == 1) { + zend_object_store_ctor_failed(EG(This) TSRMLS_CC); + } + } + zval_ptr_dtor(&EG(This)); + } + EG(This) = EX(current_this); + EG(scope) = EX(current_scope); + EG(called_scope) = EX(current_called_scope); + + EX(object) = EX(current_object); + EX(called_scope) = DECODE_CTOR(EX(called_scope)); + + zend_vm_stack_clear_multiple(TSRMLS_C); + + if (UNEXPECTED(EG(exception) != NULL)) { + zend_throw_exception_internal(NULL TSRMLS_CC); + if (RETURN_VALUE_USED(opline) && EX_T(opline->result.var).var.ptr) { + zval_ptr_dtor(&EX_T(opline->result.var).var.ptr); + } + HANDLE_EXCEPTION_LEAVE(); + } + + ZEND_VM_INC_OPCODE(); + ZEND_VM_LEAVE(); + } + } + ZEND_VM_RETURN(); +} + +ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY) +{ + USE_OPLINE + zend_bool should_change_scope = 0; + zend_function *fbc = EX(function_state).function; + + SAVE_OPLINE(); + if (UNEXPECTED((fbc->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) != 0)) { + if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_ABSTRACT) != 0)) { + zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", fbc->common.scope->name, fbc->common.function_name); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); /* Never reached */ + } + if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) { + zend_error(E_DEPRECATED, "Function %s%s%s() is deprecated", + fbc->common.scope ? fbc->common.scope->name : "", + fbc->common.scope ? "::" : "", + fbc->common.function_name); + } + } + if (fbc->common.scope && + !(fbc->common.fn_flags & ZEND_ACC_STATIC) && + !EX(object)) { + + if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + /* FIXME: output identifiers properly */ + zend_error(E_STRICT, "Non-static method %s::%s() should not be called statically", fbc->common.scope->name, fbc->common.function_name); + } else { + /* FIXME: output identifiers properly */ + /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ + zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically", fbc->common.scope->name, fbc->common.function_name); + } + } + + if (fbc->type == ZEND_USER_FUNCTION || fbc->common.scope) { + should_change_scope = 1; + EX(current_this) = EG(This); + EX(current_scope) = EG(scope); + EX(current_called_scope) = EG(called_scope); + EG(This) = EX(object); + EG(scope) = (fbc->type == ZEND_USER_FUNCTION || !EX(object)) ? fbc->common.scope : NULL; + EG(called_scope) = EX(called_scope); + } + + zend_arg_types_stack_3_pop(&EG(arg_types_stack), &EX(called_scope), &EX(current_object), &EX(fbc)); + EX(function_state).arguments = zend_vm_stack_push_args(opline->extended_value TSRMLS_CC); + LOAD_OPLINE(); + + if (fbc->type == ZEND_INTERNAL_FUNCTION) { + temp_variable *ret = &EX_T(opline->result.var); + + MAKE_STD_ZVAL(ret->var.ptr); + ZVAL_NULL(ret->var.ptr); + ret->var.ptr_ptr = &ret->var.ptr; + ret->var.fcall_returned_reference = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0; + + if (fbc->common.arg_info) { + zend_uint i=0; + zval **p = (zval**)EX(function_state).arguments; + ulong arg_count = opline->extended_value; + + while (arg_count>0) { + zend_verify_arg_type(fbc, ++i, *(p-arg_count), 0 TSRMLS_CC); + arg_count--; + } + } + + if (!zend_execute_internal) { + /* saves one function call if zend_execute_internal is not used */ + fbc->internal_function.handler(opline->extended_value, ret->var.ptr, (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) ? &ret->var.ptr : NULL, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC); + } else { + zend_execute_internal(EXECUTE_DATA, RETURN_VALUE_USED(opline) TSRMLS_CC); + } + + if (!RETURN_VALUE_USED(opline)) { + zval_ptr_dtor(&ret->var.ptr); + } + } else if (fbc->type == ZEND_USER_FUNCTION) { + EX(original_return_value) = EG(return_value_ptr_ptr); + EG(active_symbol_table) = NULL; + EG(active_op_array) = &fbc->op_array; + EG(return_value_ptr_ptr) = NULL; + if (RETURN_VALUE_USED(opline)) { + temp_variable *ret = &EX_T(opline->result.var); + + ret->var.ptr = NULL; + EG(return_value_ptr_ptr) = &ret->var.ptr; + ret->var.ptr_ptr = &ret->var.ptr; + ret->var.fcall_returned_reference = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0; + } + + if (EXPECTED(zend_execute == execute)) { + if (EXPECTED(EG(exception) == NULL)) { + ZEND_VM_ENTER(); + } + } else { + zend_execute(EG(active_op_array) TSRMLS_CC); + } + + EG(opline_ptr) = &EX(opline); + EG(active_op_array) = EX(op_array); + EG(return_value_ptr_ptr) = EX(original_return_value); + if (EG(active_symbol_table)) { + if (EG(symtable_cache_ptr)>=EG(symtable_cache_limit)) { + zend_hash_destroy(EG(active_symbol_table)); + FREE_HASHTABLE(EG(active_symbol_table)); + } else { + /* clean before putting into the cache, since clean + could call dtors, which could use cached hash */ + zend_hash_clean(EG(active_symbol_table)); + *(++EG(symtable_cache_ptr)) = EG(active_symbol_table); + } + } + EG(active_symbol_table) = EX(symbol_table); + } else { /* ZEND_OVERLOADED_FUNCTION */ + MAKE_STD_ZVAL(EX_T(opline->result.var).var.ptr); + ZVAL_NULL(EX_T(opline->result.var).var.ptr); + + /* Not sure what should be done here if it's a static method */ + if (EXPECTED(EX(object) != NULL)) { + Z_OBJ_HT_P(EX(object))->call_method(fbc->common.function_name, opline->extended_value, EX_T(opline->result.var).var.ptr, &EX_T(opline->result.var).var.ptr, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC); + } else { + zend_error_noreturn(E_ERROR, "Cannot call overloaded function for non-object"); + } + + if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) { + efree((char*)fbc->common.function_name); + } + efree(fbc); + + if (!RETURN_VALUE_USED(opline)) { + zval_ptr_dtor(&EX_T(opline->result.var).var.ptr); + } else { + Z_UNSET_ISREF_P(EX_T(opline->result.var).var.ptr); + Z_SET_REFCOUNT_P(EX_T(opline->result.var).var.ptr, 1); + EX_T(opline->result.var).var.fcall_returned_reference = 0; + EX_T(opline->result.var).var.ptr_ptr = &EX_T(opline->result.var).var.ptr; + } + } + + EX(function_state).function = (zend_function *) EX(op_array); + EX(function_state).arguments = NULL; + + if (should_change_scope) { + if (EG(This)) { + if (UNEXPECTED(EG(exception) != NULL) && IS_CTOR_CALL(EX(called_scope))) { + if (IS_CTOR_USED(EX(called_scope))) { + Z_DELREF_P(EG(This)); + } + if (Z_REFCOUNT_P(EG(This)) == 1) { + zend_object_store_ctor_failed(EG(This) TSRMLS_CC); + } + } + zval_ptr_dtor(&EG(This)); + } + EG(This) = EX(current_this); + EG(scope) = EX(current_scope); + EG(called_scope) = EX(current_called_scope); + } + + EX(object) = EX(current_object); + EX(called_scope) = DECODE_CTOR(EX(called_scope)); + + zend_vm_stack_clear_multiple(TSRMLS_C); + + if (UNEXPECTED(EG(exception) != NULL)) { + zend_throw_exception_internal(NULL TSRMLS_CC); + if (RETURN_VALUE_USED(opline) && EX_T(opline->result.var).var.ptr) { + zval_ptr_dtor(&EX_T(opline->result.var).var.ptr); + } + HANDLE_EXCEPTION(); + } + + ZEND_VM_NEXT_OPCODE(); +} + +ZEND_VM_HELPER_EX(zend_finally_handler_leaving, ANY, ANY, int type) +{ + USE_OPLINE + zend_uint i, op_num = opline - EX(op_array)->opcodes; + zend_uint catch_op_num = 0, finally_op_num = 0; + + SAVE_OPLINE(); + + switch (type) { + case ZEND_THROW: + case ZEND_RETURN: + case ZEND_RETURN_BY_REF: + case ZEND_LEAVE: + { + if (EG(prev_exception) || (type == ZEND_LEAVE && EG(exception))) { + for (i=0; i<EX(op_array)->last_try_catch; i++) { + if (EX(op_array)->try_catch_array[i].try_op > op_num) { + break; + } + if (op_num < EX(op_array)->try_catch_array[i].finally_op) { + finally_op_num = EX(op_array)->try_catch_array[i].finally_op; + } + if (op_num < EX(op_array)->try_catch_array[i].catch_op) { + catch_op_num = EX(op_array)->try_catch_array[i].catch_op; + } + } + } else { + for (i=0; i<EX(op_array)->last_try_catch; i++) { + if (EX(op_array)->try_catch_array[i].try_op > op_num) { + break; + } + if (op_num < EX(op_array)->try_catch_array[i].finally_op) { + finally_op_num = EX(op_array)->try_catch_array[i].finally_op; + } + } + } + + if (catch_op_num && finally_op_num) { + /* EG(exception) || EG(prev_exception) */ + if (catch_op_num > finally_op_num) { + EX(leaving) = ZEND_THROW; + ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]); + } else { + EX(leaving) = 0; + ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]); + } + } else if (catch_op_num) { + EX(leaving) = 0; + ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]); + } else if (finally_op_num) { + if (type != ZEND_LEAVE) { + EX(leaving) = type; + } + ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]); + } else if (EX(leaving) && type != ZEND_LEAVE) { + /* leave it to ZEND_LEAVE */ + EX(leaving) = type; + ZEND_VM_NEXT_OPCODE(); + } else { + ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper); + } + } + break; + case ZEND_JMP: + case ZEND_BRK: + case ZEND_CONT: + case ZEND_GOTO: + { + /* these can not occurred in exception context */ + for (i=0; i<EG(active_op_array)->last_try_catch; i++) { + if (EG(active_op_array)->try_catch_array[i].try_op > op_num) { + break; + } + if (op_num < EG(active_op_array)->try_catch_array[i].finally_op + && (EX(leaving_dest) < EG(active_op_array)->try_catch_array[i].try_op + || EX(leaving_dest) >= EG(active_op_array)->try_catch_array[i].finally_end)) { + finally_op_num = EG(active_op_array)->try_catch_array[i].finally_op; + } + } + + if (finally_op_num) { + EX(leaving) = type; + ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]); + } else { + EX(leaving) = 0; + ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[EX(leaving_dest)]); + } + } + break; + } + ZEND_VM_CONTINUE(); +} + ZEND_VM_HANDLER(42, ZEND_JMP, ANY, ANY) { USE_OPLINE @@ -1847,6 +2233,10 @@ ZEND_VM_HANDLER(42, ZEND_JMP, ANY, ANY) #if DEBUG_ZEND>=2 printf("Jumping to %d\n", opline->op1.opline_num); #endif + if (EX(op_array)->has_finally_block) { + EX(leaving_dest) = opline->op1.jmp_addr - EX(op_array)->opcodes; + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_finally_handler_leaving, type, ZEND_JMP); + } ZEND_VM_SET_OPCODE(opline->op1.jmp_addr); ZEND_VM_CONTINUE(); /* CHECK_ME */ } @@ -2508,299 +2898,6 @@ ZEND_VM_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) -{ - zend_bool nested; - zend_op_array *op_array = EX(op_array); - - EG(current_execute_data) = EX(prev_execute_data); - EG(opline_ptr) = NULL; - if (!EG(active_symbol_table)) { - zval ***cv = EX_CVs(); - zval ***end = cv + op_array->last_var; - while (cv != end) { - if (*cv) { - zval_ptr_dtor(*cv); - } - cv++; - } - } - - if ((op_array->fn_flags & ZEND_ACC_CLOSURE) && op_array->prototype) { - zval_ptr_dtor((zval**)&op_array->prototype); - } - - nested = EX(nested); - - zend_vm_stack_free(execute_data TSRMLS_CC); - - if (nested) { - execute_data = EG(current_execute_data); - } - if (nested) { - USE_OPLINE - - LOAD_REGS(); - LOAD_OPLINE(); - if (UNEXPECTED(opline->opcode == ZEND_INCLUDE_OR_EVAL)) { - - EX(function_state).function = (zend_function *) EX(op_array); - EX(function_state).arguments = NULL; - EX(object) = EX(current_object); - - EG(opline_ptr) = &EX(opline); - EG(active_op_array) = EX(op_array); - EG(return_value_ptr_ptr) = EX(original_return_value); - destroy_op_array(op_array TSRMLS_CC); - efree(op_array); - if (UNEXPECTED(EG(exception) != NULL)) { - zend_throw_exception_internal(NULL TSRMLS_CC); - HANDLE_EXCEPTION_LEAVE(); - } else if (RETURN_VALUE_USED(opline)) { - if (!EX_T(opline->result.var).var.ptr) { /* there was no return statement */ - zval *retval; - - ALLOC_ZVAL(retval); - ZVAL_BOOL(retval, 1); - INIT_PZVAL(retval); - EX_T(opline->result.var).var.ptr = retval; - } - } - - ZEND_VM_INC_OPCODE(); - ZEND_VM_LEAVE(); - } else { - - EG(opline_ptr) = &EX(opline); - EG(active_op_array) = EX(op_array); - EG(return_value_ptr_ptr) = EX(original_return_value); - if (EG(active_symbol_table)) { - if (EG(symtable_cache_ptr)>=EG(symtable_cache_limit)) { - zend_hash_destroy(EG(active_symbol_table)); - FREE_HASHTABLE(EG(active_symbol_table)); - } else { - /* clean before putting into the cache, since clean - could call dtors, which could use cached hash */ - zend_hash_clean(EG(active_symbol_table)); - *(++EG(symtable_cache_ptr)) = EG(active_symbol_table); - } - } - EG(active_symbol_table) = EX(symbol_table); - - EX(function_state).function = (zend_function *) EX(op_array); - EX(function_state).arguments = NULL; - - if (EG(This)) { - if (UNEXPECTED(EG(exception) != NULL) && IS_CTOR_CALL(EX(called_scope))) { - if (IS_CTOR_USED(EX(called_scope))) { - Z_DELREF_P(EG(This)); - } - if (Z_REFCOUNT_P(EG(This)) == 1) { - zend_object_store_ctor_failed(EG(This) TSRMLS_CC); - } - } - zval_ptr_dtor(&EG(This)); - } - EG(This) = EX(current_this); - EG(scope) = EX(current_scope); - EG(called_scope) = EX(current_called_scope); - - EX(object) = EX(current_object); - EX(called_scope) = DECODE_CTOR(EX(called_scope)); - - zend_vm_stack_clear_multiple(TSRMLS_C); - - if (UNEXPECTED(EG(exception) != NULL)) { - zend_throw_exception_internal(NULL TSRMLS_CC); - if (RETURN_VALUE_USED(opline) && EX_T(opline->result.var).var.ptr) { - zval_ptr_dtor(&EX_T(opline->result.var).var.ptr); - } - HANDLE_EXCEPTION_LEAVE(); - } - - ZEND_VM_INC_OPCODE(); - ZEND_VM_LEAVE(); - } - } - ZEND_VM_RETURN(); -} - -ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY) -{ - USE_OPLINE - zend_bool should_change_scope = 0; - zend_function *fbc = EX(function_state).function; - - SAVE_OPLINE(); - if (UNEXPECTED((fbc->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) != 0)) { - if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_ABSTRACT) != 0)) { - zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", fbc->common.scope->name, fbc->common.function_name); - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); /* Never reached */ - } - if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) { - zend_error(E_DEPRECATED, "Function %s%s%s() is deprecated", - fbc->common.scope ? fbc->common.scope->name : "", - fbc->common.scope ? "::" : "", - fbc->common.function_name); - } - } - if (fbc->common.scope && - !(fbc->common.fn_flags & ZEND_ACC_STATIC) && - !EX(object)) { - - if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - /* FIXME: output identifiers properly */ - zend_error(E_STRICT, "Non-static method %s::%s() should not be called statically", fbc->common.scope->name, fbc->common.function_name); - } else { - /* FIXME: output identifiers properly */ - /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically", fbc->common.scope->name, fbc->common.function_name); - } - } - - if (fbc->type == ZEND_USER_FUNCTION || fbc->common.scope) { - should_change_scope = 1; - EX(current_this) = EG(This); - EX(current_scope) = EG(scope); - EX(current_called_scope) = EG(called_scope); - EG(This) = EX(object); - EG(scope) = (fbc->type == ZEND_USER_FUNCTION || !EX(object)) ? fbc->common.scope : NULL; - EG(called_scope) = EX(called_scope); - } - - zend_arg_types_stack_3_pop(&EG(arg_types_stack), &EX(called_scope), &EX(current_object), &EX(fbc)); - EX(function_state).arguments = zend_vm_stack_push_args(opline->extended_value TSRMLS_CC); - LOAD_OPLINE(); - - if (fbc->type == ZEND_INTERNAL_FUNCTION) { - temp_variable *ret = &EX_T(opline->result.var); - - MAKE_STD_ZVAL(ret->var.ptr); - ZVAL_NULL(ret->var.ptr); - ret->var.ptr_ptr = &ret->var.ptr; - ret->var.fcall_returned_reference = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0; - - if (fbc->common.arg_info) { - zend_uint i=0; - zval **p = (zval**)EX(function_state).arguments; - ulong arg_count = opline->extended_value; - - while (arg_count>0) { - zend_verify_arg_type(fbc, ++i, *(p-arg_count), 0 TSRMLS_CC); - arg_count--; - } - } - - if (!zend_execute_internal) { - /* saves one function call if zend_execute_internal is not used */ - fbc->internal_function.handler(opline->extended_value, ret->var.ptr, (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) ? &ret->var.ptr : NULL, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC); - } else { - zend_execute_internal(EXECUTE_DATA, RETURN_VALUE_USED(opline) TSRMLS_CC); - } - - if (!RETURN_VALUE_USED(opline)) { - zval_ptr_dtor(&ret->var.ptr); - } - } else if (fbc->type == ZEND_USER_FUNCTION) { - EX(original_return_value) = EG(return_value_ptr_ptr); - EG(active_symbol_table) = NULL; - EG(active_op_array) = &fbc->op_array; - EG(return_value_ptr_ptr) = NULL; - if (RETURN_VALUE_USED(opline)) { - temp_variable *ret = &EX_T(opline->result.var); - - ret->var.ptr = NULL; - EG(return_value_ptr_ptr) = &ret->var.ptr; - ret->var.ptr_ptr = &ret->var.ptr; - ret->var.fcall_returned_reference = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0; - } - - if (EXPECTED(zend_execute == execute)) { - if (EXPECTED(EG(exception) == NULL)) { - ZEND_VM_ENTER(); - } - } else { - zend_execute(EG(active_op_array) TSRMLS_CC); - } - - EG(opline_ptr) = &EX(opline); - EG(active_op_array) = EX(op_array); - EG(return_value_ptr_ptr) = EX(original_return_value); - if (EG(active_symbol_table)) { - if (EG(symtable_cache_ptr)>=EG(symtable_cache_limit)) { - zend_hash_destroy(EG(active_symbol_table)); - FREE_HASHTABLE(EG(active_symbol_table)); - } else { - /* clean before putting into the cache, since clean - could call dtors, which could use cached hash */ - zend_hash_clean(EG(active_symbol_table)); - *(++EG(symtable_cache_ptr)) = EG(active_symbol_table); - } - } - EG(active_symbol_table) = EX(symbol_table); - } else { /* ZEND_OVERLOADED_FUNCTION */ - MAKE_STD_ZVAL(EX_T(opline->result.var).var.ptr); - ZVAL_NULL(EX_T(opline->result.var).var.ptr); - - /* Not sure what should be done here if it's a static method */ - if (EXPECTED(EX(object) != NULL)) { - Z_OBJ_HT_P(EX(object))->call_method(fbc->common.function_name, opline->extended_value, EX_T(opline->result.var).var.ptr, &EX_T(opline->result.var).var.ptr, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC); - } else { - zend_error_noreturn(E_ERROR, "Cannot call overloaded function for non-object"); - } - - if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) { - efree((char*)fbc->common.function_name); - } - efree(fbc); - - if (!RETURN_VALUE_USED(opline)) { - zval_ptr_dtor(&EX_T(opline->result.var).var.ptr); - } else { - Z_UNSET_ISREF_P(EX_T(opline->result.var).var.ptr); - Z_SET_REFCOUNT_P(EX_T(opline->result.var).var.ptr, 1); - EX_T(opline->result.var).var.fcall_returned_reference = 0; - EX_T(opline->result.var).var.ptr_ptr = &EX_T(opline->result.var).var.ptr; - } - } - - EX(function_state).function = (zend_function *) EX(op_array); - EX(function_state).arguments = NULL; - - if (should_change_scope) { - if (EG(This)) { - if (UNEXPECTED(EG(exception) != NULL) && IS_CTOR_CALL(EX(called_scope))) { - if (IS_CTOR_USED(EX(called_scope))) { - Z_DELREF_P(EG(This)); - } - if (Z_REFCOUNT_P(EG(This)) == 1) { - zend_object_store_ctor_failed(EG(This) TSRMLS_CC); - } - } - zval_ptr_dtor(&EG(This)); - } - EG(This) = EX(current_this); - EG(scope) = EX(current_scope); - EG(called_scope) = EX(current_called_scope); - } - - EX(object) = EX(current_object); - EX(called_scope) = DECODE_CTOR(EX(called_scope)); - - zend_vm_stack_clear_multiple(TSRMLS_C); - - if (UNEXPECTED(EG(exception) != NULL)) { - zend_throw_exception_internal(NULL TSRMLS_CC); - if (RETURN_VALUE_USED(opline) && EX_T(opline->result.var).var.ptr) { - zval_ptr_dtor(&EX_T(opline->result.var).var.ptr); - } - HANDLE_EXCEPTION(); - } - - ZEND_VM_NEXT_OPCODE(); -} - ZEND_VM_HANDLER(61, ZEND_DO_FCALL_BY_NAME, ANY, ANY) { EX(function_state).function = EX(fbc); @@ -2878,10 +2975,10 @@ ZEND_VM_HANDLER(62, ZEND_RETURN, CONST|TMP|VAR|CV, ANY) } FREE_OP1_IF_VAR(); - if (EG(active_op_array)->has_finally_block) { - ZEND_VM_DISPATCH_TO_HELPER_EX(zend_finally_handler_leaving, type, ZEND_RETURN); - } - ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper); + if (EX(op_array)->has_finally_block) { + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_finally_handler_leaving, type, ZEND_RETURN); + } + ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper); } ZEND_VM_HANDLER(111, ZEND_RETURN_BY_REF, CONST|TMP|VAR|CV, ANY) @@ -2954,10 +3051,10 @@ ZEND_VM_HANDLER(111, ZEND_RETURN_BY_REF, CONST|TMP|VAR|CV, ANY) FREE_OP1_IF_VAR(); - if (EG(active_op_array)->has_finally_block) { - ZEND_VM_DISPATCH_TO_HELPER_EX(zend_finally_handler_leaving, type, ZEND_RETURN_BY_REF); - } - ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper); + if (EX(op_array)->has_finally_block) { + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_finally_handler_leaving, type, ZEND_RETURN_BY_REF); + } + ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper); } ZEND_VM_HANDLER(108, ZEND_THROW, CONST|TMP|VAR|CV, ANY) @@ -3292,93 +3389,6 @@ ZEND_VM_HANDLER(52, ZEND_BOOL, CONST|TMP|VAR|CV, ANY) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HELPER_EX(zend_finally_handler_leaving, ANY, ANY, int type) -{ - USE_OPLINE - zend_uint i, op_num = opline - EX(op_array)->opcodes; - zend_uint catch_op_num = 0, finally_op_num = 0; - - SAVE_OPLINE(); - - switch (type) { - case ZEND_THROW: - case ZEND_RETURN: - case ZEND_RETURN_BY_REF: - { - if (EG(prev_exception)) { - for (i=0; i<EG(active_op_array)->last_try_catch; i++) { - if (EG(active_op_array)->try_catch_array[i].try_op > op_num) { - break; - } - if (op_num < EG(active_op_array)->try_catch_array[i].finally_op) { - finally_op_num = EG(active_op_array)->try_catch_array[i].finally_op; - } - if (op_num < EG(active_op_array)->try_catch_array[i].catch_op) { - catch_op_num = EG(active_op_array)->try_catch_array[i].catch_op; - } - } - } else { - for (i=0; i<EG(active_op_array)->last_try_catch; i++) { - if (EG(active_op_array)->try_catch_array[i].try_op > op_num) { - break; - } - if (op_num < EG(active_op_array)->try_catch_array[i].finally_op) { - finally_op_num = EG(active_op_array)->try_catch_array[i].finally_op; - } - } - } - - if (catch_op_num && finally_op_num) { - /* EG(exception) || EG(prev_exception) */ - if (catch_op_num > finally_op_num) { - EX(leaving) = ZEND_THROW; - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]); - } else { - EX(leaving) = 0; - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]); - } - } else if (catch_op_num) { - EX(leaving) = 0; - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]); - } else if (finally_op_num) { - EX(leaving) = type; - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]); - } else if (EX(leaving)) { - /* leave it to ZEND_LEAVE */ - ZEND_VM_NEXT_OPCODE(); - } else { - ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper); - } - } - break; - case ZEND_BRK: - case ZEND_CONT: - case ZEND_GOTO: - { - for (i=0; i<EG(active_op_array)->last_try_catch; i++) { - if (EG(active_op_array)->try_catch_array[i].try_op > op_num) { - break; - } - if (op_num < EG(active_op_array)->try_catch_array[i].finally_op - && (EX(leaving_dest) < EG(active_op_array)->try_catch_array[i].try_op - || EX(leaving_dest) >= EG(active_op_array)->try_catch_array[i].finally_end)) { - finally_op_num = EG(active_op_array)->try_catch_array[i].finally_op; - } - } - - if (finally_op_num) { - EX(leaving) = type; - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]); - } else { - EX(leaving) = 0; - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[EX(leaving_dest)]); - } - } - break; - } - ZEND_VM_CONTINUE(); -} - ZEND_VM_HANDLER(50, ZEND_BRK, ANY, CONST) { USE_OPLINE @@ -3388,10 +3398,10 @@ ZEND_VM_HANDLER(50, ZEND_BRK, ANY, CONST) el = zend_brk_cont(Z_LVAL_P(opline->op2.zv), opline->op1.opline_num, EX(op_array), EX_Ts() TSRMLS_CC); FREE_OP2(); - if (EG(active_op_array)->has_finally_block) { - EX(leaving_dest) = el->brk; - ZEND_VM_DISPATCH_TO_HELPER_EX(zend_finally_handler_leaving, type, ZEND_BRK); - } + if (EX(op_array)->has_finally_block) { + EX(leaving_dest) = el->brk; + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_finally_handler_leaving, type, ZEND_BRK); + } ZEND_VM_JMP(EX(op_array)->opcodes + el->brk); } @@ -3404,10 +3414,10 @@ ZEND_VM_HANDLER(51, ZEND_CONT, ANY, CONST) el = zend_brk_cont(Z_LVAL_P(opline->op2.zv), opline->op1.opline_num, EX(op_array), EX_Ts() TSRMLS_CC); FREE_OP2(); - if (EG(active_op_array)->has_finally_block) { - EX(leaving_dest) = el->cont; - ZEND_VM_DISPATCH_TO_HELPER_EX(zend_finally_handler_leaving, type, ZEND_CONT); - } + if (EG(active_op_array)->has_finally_block) { + EX(leaving_dest) = el->cont; + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_finally_handler_leaving, type, ZEND_CONT); + } ZEND_VM_JMP(EX(op_array)->opcodes + el->cont); } @@ -3435,10 +3445,10 @@ ZEND_VM_HANDLER(100, ZEND_GOTO, ANY, CONST) } break; } - if ((EG(active_op_array)->has_finally_block)) { - EX(leaving_dest) = opline->op1.jmp_addr - EG(active_op_array)->opcodes; - ZEND_VM_DISPATCH_TO_HELPER_EX(zend_finally_handler_leaving, type, ZEND_GOTO); - } + if (EX(op_array)->has_finally_block) { + EX(leaving_dest) = opline->op1.jmp_addr - EX(op_array)->opcodes; + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_finally_handler_leaving, type, ZEND_GOTO); + } ZEND_VM_JMP(opline->op1.jmp_addr); } @@ -5305,7 +5315,7 @@ ZEND_VM_HANDLER(153, ZEND_DECLARE_LAMBDA_FUNCTION, CONST, UNUSED) zend_function *op_array; SAVE_OPLINE(); - + if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), Z_HASH_P(opline->op1.zv), (void *) &op_array) == FAILURE) || UNEXPECTED(op_array->type != ZEND_USER_FUNCTION)) { zend_error_noreturn(E_ERROR, "Base lambda function for closure not found"); @@ -5340,64 +5350,21 @@ ZEND_VM_HANDLER(156, ZEND_SEPARATE, VAR, UNUSED) ZEND_VM_HANDLER(159, ZEND_LEAVE, ANY, ANY) { - USE_OPLINE zend_exception_restore(TSRMLS_C); - if (!EX(leaving)) { ZEND_VM_NEXT_OPCODE(); } else { - zend_uint i, op_num = opline - EX(op_array)->opcodes; - zend_uint catch_op_num = 0, finally_op_num = 0; - switch (EX(leaving)) { + zend_uint leaving = EX(leaving); + switch (leaving) { case ZEND_RETURN: case ZEND_RETURN_BY_REF: case ZEND_THROW: - { - if (EG(exception)) { - for (i = 0; i < EX(leaving); i++) { - if (EG(active_op_array)->try_catch_array[i].try_op > op_num) { - break; - } - if (op_num < EG(active_op_array)->try_catch_array[i].finally_op) { - finally_op_num = EG(active_op_array)->try_catch_array[i].finally_op; - } - if (op_num < EG(active_op_array)->try_catch_array[i].catch_op) { - catch_op_num = EG(active_op_array)->try_catch_array[i].catch_op; - } - } - } else { - for (i = 0; i < EX(leaving); i++) { - if (EG(active_op_array)->try_catch_array[i].try_op > op_num) { - break; - } - if (op_num < EG(active_op_array)->try_catch_array[i].finally_op) { - finally_op_num = EG(active_op_array)->try_catch_array[i].finally_op; - } - } - } - - if (catch_op_num && finally_op_num) { - if (catch_op_num > finally_op_num) { - EX(leaving) = ZEND_THROW; - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]); - } else { - EX(leaving) = 0; - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]); - } - } else if (catch_op_num) { - EX(leaving) = 0; - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]); - } else if (finally_op_num) { - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]); - } else { - ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper); - } - } - break; + leaving = ZEND_LEAVE; + case ZEND_JMP: case ZEND_BRK: case ZEND_CONT: case ZEND_GOTO: - ZEND_VM_DISPATCH_TO_HELPER_EX(zend_finally_handler_leaving, type, EX(leaving)); + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_finally_handler_leaving, type, leaving); break; } } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 9818583334..bd19124574 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -427,33 +427,6 @@ zend_vm_enter: zend_error_noreturn(E_ERROR, "Arrived at end of main loop which shouldn't happen"); } -static int ZEND_FASTCALL ZEND_JMP_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - -#if DEBUG_ZEND>=2 - printf("Jumping to %d\n", opline->op1.opline_num); -#endif - ZEND_VM_SET_OPCODE(opline->op1.jmp_addr); - ZEND_VM_CONTINUE(); /* CHECK_ME */ -} - -static int ZEND_FASTCALL ZEND_INIT_STRING_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - zval *tmp = &EX_T(opline->result.var).tmp_var; - - SAVE_OPLINE(); - tmp->value.str.val = emalloc(1); - tmp->value.str.val[0] = 0; - tmp->value.str.len = 0; - Z_SET_REFCOUNT_P(tmp, 1); - tmp->type = IS_STRING; - Z_UNSET_ISREF_P(tmp); - /*CHECK_EXCEPTION();*/ - ZEND_VM_NEXT_OPCODE(); -} - static int ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) { zend_bool nested; @@ -747,53 +720,6 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR ZEND_VM_NEXT_OPCODE(); } -static int ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - EX(function_state).function = EX(fbc); - return zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); -} - -static int ZEND_FASTCALL ZEND_RECV_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - zend_uint arg_num = opline->op1.num; - zval **param = zend_vm_stack_get_arg(arg_num TSRMLS_CC); - - SAVE_OPLINE(); - if (UNEXPECTED(param == NULL)) { - if (zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, NULL, opline->extended_value TSRMLS_CC)) { - const char *space; - const char *class_name; - zend_execute_data *ptr; - - if (EG(active_op_array)->scope) { - class_name = EG(active_op_array)->scope->name; - space = "::"; - } else { - class_name = space = ""; - } - ptr = EX(prev_execute_data); - - if(ptr && ptr->op_array) { - zend_error(E_WARNING, "Missing argument %u for %s%s%s(), called in %s on line %d and defined", opline->op1.num, class_name, space, get_active_function_name(TSRMLS_C), ptr->op_array->filename, ptr->opline->lineno); - } else { - zend_error(E_WARNING, "Missing argument %u for %s%s%s()", opline->op1.num, class_name, space, get_active_function_name(TSRMLS_C)); - } - } - } else { - zval **var_ptr; - - zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, *param, opline->extended_value TSRMLS_CC); - var_ptr = _get_zval_ptr_ptr_cv_BP_VAR_W(EX_CVs(), opline->result.var TSRMLS_CC); - Z_DELREF_PP(var_ptr); - *var_ptr = *param; - Z_ADDREF_PP(var_ptr); - } - - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); -} - static int ZEND_FASTCALL zend_finally_handler_leaving_SPEC(int type, ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -806,26 +732,27 @@ static int ZEND_FASTCALL zend_finally_handler_leaving_SPEC(int type, ZEND_OPCODE case ZEND_THROW: case ZEND_RETURN: case ZEND_RETURN_BY_REF: + case ZEND_LEAVE: { - if (EG(prev_exception)) { - for (i=0; i<EG(active_op_array)->last_try_catch; i++) { - if (EG(active_op_array)->try_catch_array[i].try_op > op_num) { + if (EG(prev_exception) || (type == ZEND_LEAVE && EG(exception))) { + for (i=0; i<EX(op_array)->last_try_catch; i++) { + if (EX(op_array)->try_catch_array[i].try_op > op_num) { break; } - if (op_num < EG(active_op_array)->try_catch_array[i].finally_op) { - finally_op_num = EG(active_op_array)->try_catch_array[i].finally_op; + if (op_num < EX(op_array)->try_catch_array[i].finally_op) { + finally_op_num = EX(op_array)->try_catch_array[i].finally_op; } - if (op_num < EG(active_op_array)->try_catch_array[i].catch_op) { - catch_op_num = EG(active_op_array)->try_catch_array[i].catch_op; + if (op_num < EX(op_array)->try_catch_array[i].catch_op) { + catch_op_num = EX(op_array)->try_catch_array[i].catch_op; } } } else { - for (i=0; i<EG(active_op_array)->last_try_catch; i++) { - if (EG(active_op_array)->try_catch_array[i].try_op > op_num) { + for (i=0; i<EX(op_array)->last_try_catch; i++) { + if (EX(op_array)->try_catch_array[i].try_op > op_num) { break; } - if (op_num < EG(active_op_array)->try_catch_array[i].finally_op) { - finally_op_num = EG(active_op_array)->try_catch_array[i].finally_op; + if (op_num < EX(op_array)->try_catch_array[i].finally_op) { + finally_op_num = EX(op_array)->try_catch_array[i].finally_op; } } } @@ -843,44 +770,127 @@ static int ZEND_FASTCALL zend_finally_handler_leaving_SPEC(int type, ZEND_OPCODE EX(leaving) = 0; ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]); } else if (finally_op_num) { - EX(leaving) = type; + if (type != ZEND_LEAVE) { + EX(leaving) = type; + } ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]); - } else if (EX(leaving)) { + } else if (EX(leaving) && type != ZEND_LEAVE) { /* leave it to ZEND_LEAVE */ + EX(leaving) = type; ZEND_VM_NEXT_OPCODE(); } else { return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } } break; + case ZEND_JMP: case ZEND_BRK: case ZEND_CONT: case ZEND_GOTO: { - for (i=0; i<EG(active_op_array)->last_try_catch; i++) { - if (EG(active_op_array)->try_catch_array[i].try_op > op_num) { - break; - } - if (op_num < EG(active_op_array)->try_catch_array[i].finally_op - && (EX(leaving_dest) < EG(active_op_array)->try_catch_array[i].try_op - || EX(leaving_dest) >= EG(active_op_array)->try_catch_array[i].finally_end)) { - finally_op_num = EG(active_op_array)->try_catch_array[i].finally_op; - } - } - - if (finally_op_num) { - EX(leaving) = type; - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]); - } else { - EX(leaving) = 0; - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[EX(leaving_dest)]); - } - } + /* these can not occurred in exception context */ + for (i=0; i<EG(active_op_array)->last_try_catch; i++) { + if (EG(active_op_array)->try_catch_array[i].try_op > op_num) { + break; + } + if (op_num < EG(active_op_array)->try_catch_array[i].finally_op + && (EX(leaving_dest) < EG(active_op_array)->try_catch_array[i].try_op + || EX(leaving_dest) >= EG(active_op_array)->try_catch_array[i].finally_end)) { + finally_op_num = EG(active_op_array)->try_catch_array[i].finally_op; + } + } + + if (finally_op_num) { + EX(leaving) = type; + ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]); + } else { + EX(leaving) = 0; + ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[EX(leaving_dest)]); + } + } break; } ZEND_VM_CONTINUE(); } +static int ZEND_FASTCALL ZEND_JMP_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + +#if DEBUG_ZEND>=2 + printf("Jumping to %d\n", opline->op1.opline_num); +#endif + if (EX(op_array)->has_finally_block) { + EX(leaving_dest) = opline->op1.jmp_addr - EX(op_array)->opcodes; + return zend_finally_handler_leaving_SPEC(ZEND_JMP, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } + ZEND_VM_SET_OPCODE(opline->op1.jmp_addr); + ZEND_VM_CONTINUE(); /* CHECK_ME */ +} + +static int ZEND_FASTCALL ZEND_INIT_STRING_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *tmp = &EX_T(opline->result.var).tmp_var; + + SAVE_OPLINE(); + tmp->value.str.val = emalloc(1); + tmp->value.str.val[0] = 0; + tmp->value.str.len = 0; + Z_SET_REFCOUNT_P(tmp, 1); + tmp->type = IS_STRING; + Z_UNSET_ISREF_P(tmp); + /*CHECK_EXCEPTION();*/ + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + EX(function_state).function = EX(fbc); + return zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); +} + +static int ZEND_FASTCALL ZEND_RECV_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_uint arg_num = opline->op1.num; + zval **param = zend_vm_stack_get_arg(arg_num TSRMLS_CC); + + SAVE_OPLINE(); + if (UNEXPECTED(param == NULL)) { + if (zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, NULL, opline->extended_value TSRMLS_CC)) { + const char *space; + const char *class_name; + zend_execute_data *ptr; + + if (EG(active_op_array)->scope) { + class_name = EG(active_op_array)->scope->name; + space = "::"; + } else { + class_name = space = ""; + } + ptr = EX(prev_execute_data); + + if(ptr && ptr->op_array) { + zend_error(E_WARNING, "Missing argument %u for %s%s%s(), called in %s on line %d and defined", opline->op1.num, class_name, space, get_active_function_name(TSRMLS_C), ptr->op_array->filename, ptr->opline->lineno); + } else { + zend_error(E_WARNING, "Missing argument %u for %s%s%s()", opline->op1.num, class_name, space, get_active_function_name(TSRMLS_C)); + } + } + } else { + zval **var_ptr; + + zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, *param, opline->extended_value TSRMLS_CC); + var_ptr = _get_zval_ptr_ptr_cv_BP_VAR_W(EX_CVs(), opline->result.var TSRMLS_CC); + Z_DELREF_PP(var_ptr); + *var_ptr = *param; + Z_ADDREF_PP(var_ptr); + } + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_NEW_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -1264,64 +1274,21 @@ static int ZEND_FASTCALL ZEND_USER_OPCODE_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS static int ZEND_FASTCALL ZEND_LEAVE_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - USE_OPLINE zend_exception_restore(TSRMLS_C); - if (!EX(leaving)) { ZEND_VM_NEXT_OPCODE(); } else { - zend_uint i, op_num = opline - EX(op_array)->opcodes; - zend_uint catch_op_num = 0, finally_op_num = 0; - switch (EX(leaving)) { + zend_uint leaving = EX(leaving); + switch (leaving) { case ZEND_RETURN: case ZEND_RETURN_BY_REF: case ZEND_THROW: - { - if (EG(exception)) { - for (i = 0; i < EX(leaving); i++) { - if (EG(active_op_array)->try_catch_array[i].try_op > op_num) { - break; - } - if (op_num < EG(active_op_array)->try_catch_array[i].finally_op) { - finally_op_num = EG(active_op_array)->try_catch_array[i].finally_op; - } - if (op_num < EG(active_op_array)->try_catch_array[i].catch_op) { - catch_op_num = EG(active_op_array)->try_catch_array[i].catch_op; - } - } - } else { - for (i = 0; i < EX(leaving); i++) { - if (EG(active_op_array)->try_catch_array[i].try_op > op_num) { - break; - } - if (op_num < EG(active_op_array)->try_catch_array[i].finally_op) { - finally_op_num = EG(active_op_array)->try_catch_array[i].finally_op; - } - } - } - - if (catch_op_num && finally_op_num) { - if (catch_op_num > finally_op_num) { - EX(leaving) = ZEND_THROW; - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]); - } else { - EX(leaving) = 0; - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]); - } - } else if (catch_op_num) { - EX(leaving) = 0; - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]); - } else if (finally_op_num) { - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]); - } else { - return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } - } - break; + leaving = ZEND_LEAVE; + case ZEND_JMP: case ZEND_BRK: case ZEND_CONT: case ZEND_GOTO: - return zend_finally_handler_leaving_SPEC(EX(leaving), ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return zend_finally_handler_leaving_SPEC(leaving, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); break; } } @@ -1563,10 +1530,10 @@ static int ZEND_FASTCALL ZEND_BRK_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) el = zend_brk_cont(Z_LVAL_P(opline->op2.zv), opline->op1.opline_num, EX(op_array), EX_Ts() TSRMLS_CC); - if (EG(active_op_array)->has_finally_block) { - EX(leaving_dest) = el->brk; - return zend_finally_handler_leaving_SPEC(ZEND_BRK, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } + if (EX(op_array)->has_finally_block) { + EX(leaving_dest) = el->brk; + return zend_finally_handler_leaving_SPEC(ZEND_BRK, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } ZEND_VM_JMP(EX(op_array)->opcodes + el->brk); } @@ -1579,10 +1546,10 @@ static int ZEND_FASTCALL ZEND_CONT_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) el = zend_brk_cont(Z_LVAL_P(opline->op2.zv), opline->op1.opline_num, EX(op_array), EX_Ts() TSRMLS_CC); - if (EG(active_op_array)->has_finally_block) { - EX(leaving_dest) = el->cont; - return zend_finally_handler_leaving_SPEC(ZEND_CONT, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } + if (EG(active_op_array)->has_finally_block) { + EX(leaving_dest) = el->cont; + return zend_finally_handler_leaving_SPEC(ZEND_CONT, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } ZEND_VM_JMP(EX(op_array)->opcodes + el->cont); } @@ -1610,10 +1577,10 @@ static int ZEND_FASTCALL ZEND_GOTO_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } break; } - if ((EG(active_op_array)->has_finally_block)) { - EX(leaving_dest) = opline->op1.jmp_addr - EG(active_op_array)->opcodes; - return zend_finally_handler_leaving_SPEC(ZEND_CONT, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } + if (EX(op_array)->has_finally_block) { + EX(leaving_dest) = opline->op1.jmp_addr - EX(op_array)->opcodes; + return zend_finally_handler_leaving_SPEC(ZEND_GOTO, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } ZEND_VM_JMP(opline->op1.jmp_addr); } @@ -2465,10 +2432,10 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARG *EG(return_value_ptr_ptr) = ret; } - if (EG(active_op_array)->has_finally_block) { - return zend_finally_handler_leaving_SPEC(ZEND_RETURN, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } - return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + if (EX(op_array)->has_finally_block) { + return zend_finally_handler_leaving_SPEC(ZEND_RETURN, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } + return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_RETURN_BY_REF_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -2539,10 +2506,10 @@ static int ZEND_FASTCALL ZEND_RETURN_BY_REF_SPEC_CONST_HANDLER(ZEND_OPCODE_HAND } } while (0); - if (EG(active_op_array)->has_finally_block) { - return zend_finally_handler_leaving_SPEC(ZEND_RETURN_BY_REF, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } - return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + if (EX(op_array)->has_finally_block) { + return zend_finally_handler_leaving_SPEC(ZEND_RETURN_BY_REF, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } + return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_THROW_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -7015,10 +6982,10 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) *EG(return_value_ptr_ptr) = ret; } - if (EG(active_op_array)->has_finally_block) { - return zend_finally_handler_leaving_SPEC(ZEND_RETURN, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } - return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + if (EX(op_array)->has_finally_block) { + return zend_finally_handler_leaving_SPEC(ZEND_RETURN, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } + return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_RETURN_BY_REF_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -7089,10 +7056,10 @@ static int ZEND_FASTCALL ZEND_RETURN_BY_REF_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLE } } while (0); - if (EG(active_op_array)->has_finally_block) { - return zend_finally_handler_leaving_SPEC(ZEND_RETURN_BY_REF, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } - return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + if (EX(op_array)->has_finally_block) { + return zend_finally_handler_leaving_SPEC(ZEND_RETURN_BY_REF, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } + return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_THROW_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -11471,10 +11438,10 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; - if (EG(active_op_array)->has_finally_block) { - return zend_finally_handler_leaving_SPEC(ZEND_RETURN, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } - return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + if (EX(op_array)->has_finally_block) { + return zend_finally_handler_leaving_SPEC(ZEND_RETURN, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } + return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_RETURN_BY_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -11547,10 +11514,10 @@ static int ZEND_FASTCALL ZEND_RETURN_BY_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLE if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; - if (EG(active_op_array)->has_finally_block) { - return zend_finally_handler_leaving_SPEC(ZEND_RETURN_BY_REF, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } - return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + if (EX(op_array)->has_finally_block) { + return zend_finally_handler_leaving_SPEC(ZEND_RETURN_BY_REF, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } + return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_THROW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -27490,10 +27457,10 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) *EG(return_value_ptr_ptr) = ret; } - if (EG(active_op_array)->has_finally_block) { - return zend_finally_handler_leaving_SPEC(ZEND_RETURN, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } - return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + if (EX(op_array)->has_finally_block) { + return zend_finally_handler_leaving_SPEC(ZEND_RETURN, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } + return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_RETURN_BY_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -27564,10 +27531,10 @@ static int ZEND_FASTCALL ZEND_RETURN_BY_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER } } while (0); - if (EG(active_op_array)->has_finally_block) { - return zend_finally_handler_leaving_SPEC(ZEND_RETURN_BY_REF, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } - return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + if (EX(op_array)->has_finally_block) { + return zend_finally_handler_leaving_SPEC(ZEND_RETURN_BY_REF, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } + return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_THROW_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) |
