diff --git a/Zend/zend_API.c b/Zend/zend_API.c index dc517138073..f028756a937 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -2864,10 +2864,10 @@ static int zend_is_callable_check_class(zend_string *name, zend_fcall_info_cache if (!EG(scope)) { if (error) *error = estrdup("cannot access self:: when no class scope is active"); } else { - fcc->called_scope = EG(current_execute_data) ? EG(current_execute_data)->called_scope : NULL; + fcc->called_scope = zend_get_called_scope(EG(current_execute_data)); fcc->calling_scope = EG(scope); - if (!fcc->object && EG(current_execute_data) && Z_OBJ(EG(current_execute_data)->This)) { - fcc->object = Z_OBJ(EG(current_execute_data)->This); + if (!fcc->object) { + fcc->object = zend_get_this_object(EG(current_execute_data)); } ret = 1; } @@ -2877,22 +2877,24 @@ static int zend_is_callable_check_class(zend_string *name, zend_fcall_info_cache } else if (!EG(scope)->parent) { if (error) *error = estrdup("cannot access parent:: when current class scope has no parent"); } else { - fcc->called_scope = EG(current_execute_data) ? EG(current_execute_data)->called_scope : NULL; + fcc->called_scope = zend_get_called_scope(EG(current_execute_data)); fcc->calling_scope = EG(scope)->parent; - if (!fcc->object && EG(current_execute_data) && Z_OBJ(EG(current_execute_data)->This)) { - fcc->object = Z_OBJ(EG(current_execute_data)->This); + if (!fcc->object) { + fcc->object = zend_get_this_object(EG(current_execute_data)); } *strict_class = 1; ret = 1; } } else if (zend_string_equals_literal(lcname, "static")) { - if (!EG(current_execute_data) || !EG(current_execute_data)->called_scope) { + zend_class_entry *called_scope = zend_get_called_scope(EG(current_execute_data)); + + if (!called_scope) { if (error) *error = estrdup("cannot access static:: when no class scope is active"); } else { - fcc->called_scope = EG(current_execute_data)->called_scope; - fcc->calling_scope = EG(current_execute_data)->called_scope; - if (!fcc->object && Z_OBJ(EG(current_execute_data)->This)) { - fcc->object = Z_OBJ(EG(current_execute_data)->This); + fcc->called_scope = called_scope; + fcc->calling_scope = called_scope; + if (!fcc->object) { + fcc->object = zend_get_this_object(EG(current_execute_data)); } *strict_class = 1; ret = 1; @@ -2906,11 +2908,17 @@ static int zend_is_callable_check_class(zend_string *name, zend_fcall_info_cache } scope = ex ? ex->func->common.scope : NULL; fcc->calling_scope = ce; - if (scope && !fcc->object && EG(current_execute_data) && Z_OBJ(EG(current_execute_data)->This) && - instanceof_function(Z_OBJCE(EG(current_execute_data)->This), scope) && - instanceof_function(scope, fcc->calling_scope)) { - fcc->object = Z_OBJ(EG(current_execute_data)->This); - fcc->called_scope = Z_OBJCE(EG(current_execute_data)->This); + if (scope && !fcc->object) { + zend_object *object = zend_get_this_object(EG(current_execute_data)); + + if (object && + instanceof_function(object->ce, scope) && + instanceof_function(scope, fcc->calling_scope)) { + fcc->object = object; + fcc->called_scope = object->ce; + } else { + fcc->called_scope = fcc->calling_scope; + } } else { fcc->called_scope = fcc->object ? fcc->object->ce : fcc->calling_scope; } @@ -3101,9 +3109,12 @@ get_function_via_handler: if (fcc->function_handler) { retval = 1; call_via_handler = (fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) != 0; - if (call_via_handler && !fcc->object && EG(current_execute_data) && Z_OBJ(EG(current_execute_data)->This) && - instanceof_function(Z_OBJCE(EG(current_execute_data)->This), fcc->calling_scope)) { - fcc->object = Z_OBJ(EG(current_execute_data)->This); + if (call_via_handler && !fcc->object) { + zend_object *object = zend_get_this_object(EG(current_execute_data)); + if (object && + instanceof_function(object->ce, fcc->calling_scope)) { + fcc->object = object; + } } } } diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 996c11b24d8..7313b320658 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -916,12 +916,15 @@ ZEND_FUNCTION(get_class) Retrieves the "Late Static Binding" class name */ ZEND_FUNCTION(get_called_class) { + zend_class_entry *called_scope; + if (zend_parse_parameters_none() == FAILURE) { return; } - if (EX(called_scope)) { - RETURN_STR_COPY(EX(called_scope)->name); + called_scope = zend_get_called_scope(execute_data); + if (called_scope) { + RETURN_STR_COPY(called_scope->name); } else if (!EG(scope)) { zend_error(E_WARNING, "get_called_class() called from outside a class"); } @@ -2304,12 +2307,6 @@ ZEND_FUNCTION(debug_print_backtrace) /* $this may be passed into regular internal functions */ object = Z_OBJ(call->This); - if (object && - call && - call->func->type == ZEND_INTERNAL_FUNCTION && - !call->func->common.scope) { - object = NULL; - } if (call->func) { func = call->func; @@ -2527,12 +2524,6 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int /* $this may be passed into regular internal functions */ object = call ? Z_OBJ(call->This) : NULL; - if (object && - call->func && - call->func->type == ZEND_INTERNAL_FUNCTION && - !call->func->common.scope) { - object = NULL; - } if (call && call->func) { func = call->func; diff --git a/Zend/zend_constants.c b/Zend/zend_constants.c index 32f249ce086..f8205fac0d6 100644 --- a/Zend/zend_constants.c +++ b/Zend/zend_constants.c @@ -349,12 +349,11 @@ ZEND_API zval *zend_get_constant_ex(zend_string *cname, zend_class_entry *scope, } } else if (class_name_len == sizeof("static")-1 && !memcmp(lcname, "static", sizeof("static")-1)) { - if (UNEXPECTED(!EG(current_execute_data)) || - UNEXPECTED(!EG(current_execute_data)->called_scope)) { + ce = zend_get_called_scope(EG(current_execute_data)); + if (UNEXPECTED(!ce)) { zend_error(E_EXCEPTION | E_ERROR, "Cannot access static:: when no class scope is active"); return NULL; } - ce = EG(current_execute_data)->called_scope; } else { ce = zend_fetch_class(class_name, flags); } diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index 67958cf32c9..9e8dde5c3c5 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -42,6 +42,8 @@ ZEND_API void execute_ex(zend_execute_data *execute_data); ZEND_API void execute_internal(zend_execute_data *execute_data, zval *return_value); ZEND_API zend_class_entry *zend_lookup_class(zend_string *name); ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, const zval *key, int use_autoload); +ZEND_API zend_class_entry *zend_get_called_scope(zend_execute_data *ex); +ZEND_API zend_object *zend_get_this_object(zend_execute_data *ex); ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name); ZEND_API int zend_eval_stringl(char *str, size_t str_len, zval *retval_ptr, char *string_name); ZEND_API int zend_eval_string_ex(char *str, zval *retval_ptr, char *string_name, int handle_exceptions); diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 37a27150e5a..61ee1e103eb 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -1055,6 +1055,38 @@ ZEND_API zend_class_entry *zend_lookup_class(zend_string *name) /* {{{ */ } /* }}} */ +ZEND_API zend_class_entry *zend_get_called_scope(zend_execute_data *ex) /* {{{ */ +{ + while (ex) { + if (ex->called_scope) { + return ex->called_scope; + } else if (ex->func) { + if (ex->func->type != ZEND_INTERNAL_FUNCTION || ex->func->common.scope) { + return ex->called_scope; + } + } + ex = ex->prev_execute_data; + } + return NULL; +} +/* }}} */ + +ZEND_API zend_object *zend_get_this_object(zend_execute_data *ex) /* {{{ */ +{ + while (ex) { + if (Z_OBJ(ex->This)) { + return Z_OBJ(ex->This); + } else if (ex->func) { + if (ex->func->type != ZEND_INTERNAL_FUNCTION || ex->func->common.scope) { + return Z_OBJ(ex->This); + } + } + ex = ex->prev_execute_data; + } + return NULL; +} +/* }}} */ + ZEND_API int zend_eval_stringl(char *str, size_t str_len, zval *retval_ptr, char *string_name) /* {{{ */ { zval pv; @@ -1311,13 +1343,14 @@ check_fetch_type: } return EG(scope)->parent; case ZEND_FETCH_CLASS_STATIC: - if (UNEXPECTED(!EG(current_execute_data)) || UNEXPECTED(!EG(current_execute_data)->called_scope)) { + ce = zend_get_called_scope(EG(current_execute_data)); + if (UNEXPECTED(!ce)) { int error_type = (fetch_type & ZEND_FETCH_CLASS_EXCEPTION) ? (E_EXCEPTION | E_ERROR) : E_ERROR; zend_error(error_type, "Cannot access static:: when no class scope is active"); return NULL; } - return EG(current_execute_data)->called_scope; + return ce; case ZEND_FETCH_CLASS_AUTO: { fetch_sub_type = zend_get_class_fetch_type(class_name); if (UNEXPECTED(fetch_sub_type != ZEND_FETCH_CLASS_DEFAULT)) { diff --git a/Zend/zend_interfaces.c b/Zend/zend_interfaces.c index 5cb7024706e..54f8f8c1172 100644 --- a/Zend/zend_interfaces.c +++ b/Zend/zend_interfaces.c @@ -89,13 +89,16 @@ ZEND_API zval* zend_call_method(zval *object, zend_class_entry *obj_ce, zend_fun fcic.calling_scope = obj_ce; if (object) { fcic.called_scope = Z_OBJCE_P(object); - } else if (obj_ce && - !(EG(current_execute_data) && - EG(current_execute_data)->called_scope && - instanceof_function(EG(current_execute_data)->called_scope, obj_ce))) { - fcic.called_scope = obj_ce; } else { - fcic.called_scope = EG(current_execute_data) ? EG(current_execute_data)->called_scope : NULL; + zend_class_entry *called_scope = zend_get_called_scope(EG(current_execute_data)); + + if (obj_ce && + (!called_scope || + !instanceof_function(called_scope, obj_ce))) { + fcic.called_scope = obj_ce; + } else { + fcic.called_scope = called_scope; + } } fcic.object = object ? Z_OBJ_P(object) : NULL; result = zend_call_function(&fci, &fcic); diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index a14f60080b2..52c3b4ce1c9 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -1137,6 +1137,7 @@ ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, zend_st zend_function *fbc = NULL; char *lc_class_name; zend_string *lc_function_name; + zend_object *object; if (EXPECTED(key != NULL)) { lc_function_name = Z_STR_P(key); @@ -1164,12 +1165,12 @@ ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, zend_st zend_string_release(lc_function_name); } if (ce->__call && - Z_OBJ(EG(current_execute_data)->This) && - instanceof_function(Z_OBJCE(EG(current_execute_data)->This), ce)) { + (object = zend_get_this_object(EG(current_execute_data))) != NULL && + instanceof_function(object->ce, ce)) { /* Call the top-level defined __call(). * see: tests/classes/__call_004.phpt */ - zend_class_entry *call_ce = Z_OBJCE(EG(current_execute_data)->This); + zend_class_entry *call_ce = object->ce; while (!call_ce->__call) { call_ce = call_ce->parent; diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 9a50c9b7d53..899b18a89db 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -3391,9 +3391,6 @@ ZEND_VM_HANDLER(129, ZEND_DO_ICALL, ANY, ANY) SAVE_OPLINE(); EX(call) = call->prev_execute_data; - call->called_scope = EX(called_scope); - Z_OBJ(call->This) = Z_OBJ(EX(This)); - call->prev_execute_data = execute_data; EG(current_execute_data) = call; @@ -3505,9 +3502,6 @@ ZEND_VM_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY) } } - call->called_scope = EX(called_scope); - Z_OBJ(call->This) = Z_OBJ(EX(This)); - call->prev_execute_data = execute_data; EG(current_execute_data) = call; @@ -3627,9 +3621,6 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY) if (fbc->common.scope) { should_change_scope = 1; EG(scope) = fbc->common.scope; - } else { - call->called_scope = EX(called_scope); - Z_OBJ(call->This) = Z_OBJ(EX(This)); } call->prev_execute_data = execute_data; diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 9f224ee0ddc..3a2ed291eb9 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -423,7 +423,7 @@ ZEND_API void zend_execute(zend_op_array *op_array, zval *return_value) } execute_data = zend_vm_stack_push_call_frame(ZEND_CALL_TOP_CODE, - (zend_function*)op_array, 0, EG(current_execute_data) ? EG(current_execute_data)->called_scope : NULL, EG(current_execute_data) ? Z_OBJ(EG(current_execute_data)->This) : NULL); + (zend_function*)op_array, 0, zend_get_called_scope(EG(current_execute_data)), zend_get_this_object(EG(current_execute_data))); if (EG(current_execute_data)) { execute_data->symbol_table = zend_rebuild_symbol_table(); } else { @@ -548,9 +548,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_ICALL_SPEC_HANDLER(ZEND_OPC SAVE_OPLINE(); EX(call) = call->prev_execute_data; - call->called_scope = EX(called_scope); - Z_OBJ(call->This) = Z_OBJ(EX(This)); - call->prev_execute_data = execute_data; EG(current_execute_data) = call; @@ -662,9 +659,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER( } } - call->called_scope = EX(called_scope); - Z_OBJ(call->This) = Z_OBJ(EX(This)); - call->prev_execute_data = execute_data; EG(current_execute_data) = call; @@ -784,9 +778,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPC if (fbc->common.scope) { should_change_scope = 1; EG(scope) = fbc->common.scope; - } else { - call->called_scope = EX(called_scope); - Z_OBJ(call->This) = Z_OBJ(EX(This)); } call->prev_execute_data = execute_data; diff --git a/Zend/zend_vm_execute.skl b/Zend/zend_vm_execute.skl index 5bbc390f5b3..02fe6bdc360 100644 --- a/Zend/zend_vm_execute.skl +++ b/Zend/zend_vm_execute.skl @@ -29,7 +29,7 @@ ZEND_API void zend_{%EXECUTOR_NAME%}(zend_op_array *op_array, zval *return_value } execute_data = zend_vm_stack_push_call_frame(ZEND_CALL_TOP_CODE, - (zend_function*)op_array, 0, EG(current_execute_data) ? EG(current_execute_data)->called_scope : NULL, EG(current_execute_data) ? Z_OBJ(EG(current_execute_data)->This) : NULL); + (zend_function*)op_array, 0, zend_get_called_scope(EG(current_execute_data)), zend_get_this_object(EG(current_execute_data))); if (EG(current_execute_data)) { execute_data->symbol_table = zend_rebuild_symbol_table(); } else { diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index ebeca422df3..693ac4c8e39 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -4800,6 +4800,7 @@ PHP_FUNCTION(forward_static_call) zval retval; zend_fcall_info fci; zend_fcall_info_cache fci_cache; + zend_class_entry *called_scope; if (zend_parse_parameters(ZEND_NUM_ARGS(), "f*", &fci, &fci_cache, &fci.params, &fci.param_count) == FAILURE) { return; @@ -4811,9 +4812,10 @@ PHP_FUNCTION(forward_static_call) fci.retval = &retval; - if (EX(called_scope) && - instanceof_function(EX(called_scope), fci_cache.calling_scope)) { - fci_cache.called_scope = EX(called_scope); + called_scope = zend_get_called_scope(execute_data); + if (called_scope && + instanceof_function(called_scope, fci_cache.calling_scope)) { + fci_cache.called_scope = called_scope; } if (zend_call_function(&fci, &fci_cache) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) { @@ -4829,6 +4831,7 @@ PHP_FUNCTION(forward_static_call_array) zval *params, retval; zend_fcall_info fci; zend_fcall_info_cache fci_cache; + zend_class_entry *called_scope; if (zend_parse_parameters(ZEND_NUM_ARGS(), "fa/", &fci, &fci_cache, ¶ms) == FAILURE) { return; @@ -4837,9 +4840,10 @@ PHP_FUNCTION(forward_static_call_array) zend_fcall_info_args(&fci, params); fci.retval = &retval; - if (EX(called_scope) && - instanceof_function(EX(called_scope), fci_cache.calling_scope)) { - fci_cache.called_scope = EX(called_scope); + called_scope = zend_get_called_scope(execute_data); + if (called_scope && + instanceof_function(called_scope, fci_cache.calling_scope)) { + fci_cache.called_scope = called_scope; } if (zend_call_function(&fci, &fci_cache) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {