Add reproducer for possible issue with object return type inheritance (#6961)

Fix early inheritance

Co-authored-by: Joe Watkins <krakjoe@php.net>
This commit is contained in:
Máté Kocsis 2021-05-10 12:52:59 +02:00 committed by GitHub
parent f71bfe4544
commit fcd18757b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 88 additions and 23 deletions

View File

@ -0,0 +1,16 @@
--TEST--
Internal class variance
--EXTENSIONS--
zend_test
--FILE--
<?php
$test = new _ZendTestChildClass;
try {
$test->returnsThrowable();
} catch (\Error) {
echo "OK";
}
?>
--EXPECT--
OK

View File

@ -200,22 +200,45 @@ static bool class_visible(zend_class_entry *ce) {
}
}
static zend_always_inline void register_unresolved_class(zend_string *name) {
/* We'll autoload this class and process delayed variance obligations later. */
if (!CG(delayed_autoloads)) {
ALLOC_HASHTABLE(CG(delayed_autoloads));
zend_hash_init(CG(delayed_autoloads), 0, NULL, NULL, 0);
}
zend_hash_add_empty_element(CG(delayed_autoloads), name);
}
static zend_class_entry *lookup_class(
zend_class_entry *scope, zend_string *name, bool register_unresolved) {
uint32_t flags = ZEND_FETCH_CLASS_ALLOW_UNLINKED | ZEND_FETCH_CLASS_NO_AUTOLOAD;
zend_class_entry *ce = zend_lookup_class_ex(name, NULL, flags);
zend_class_entry *ce;
if (UNEXPECTED(!EG(active))) {
zend_string *lc_name = zend_string_tolower(name);
ce = zend_hash_find_ptr(CG(class_table), lc_name);
zend_string_release(lc_name);
if (register_unresolved && !ce) {
zend_error_noreturn(
E_COMPILE_ERROR, "%s must be registered before %s",
ZSTR_VAL(name), ZSTR_VAL(scope->name));
}
return ce;
}
ce = zend_lookup_class_ex(
name, NULL, ZEND_FETCH_CLASS_ALLOW_UNLINKED | ZEND_FETCH_CLASS_NO_AUTOLOAD);
if (!CG(in_compilation)) {
if (ce) {
return ce;
}
if (register_unresolved) {
/* We'll autoload this class and process delayed variance obligations later. */
if (!CG(delayed_autoloads)) {
ALLOC_HASHTABLE(CG(delayed_autoloads));
zend_hash_init(CG(delayed_autoloads), 0, NULL, NULL, 0);
}
zend_hash_add_empty_element(CG(delayed_autoloads), name);
register_unresolved_class(name);
}
} else {
if (ce && class_visible(ce)) {

View File

@ -257,22 +257,25 @@ static zend_object *zend_test_class_new(zend_class_entry *class_type) /* {{{ */
/* }}} */
static zend_function *zend_test_class_method_get(zend_object **object, zend_string *name, const zval *key) /* {{{ */ {
zend_internal_function *fptr;
if (zend_string_equals_literal_ci(name, "test")) {
zend_internal_function *fptr;
if (EXPECTED(EG(trampoline).common.function_name == NULL)) {
fptr = (zend_internal_function *) &EG(trampoline);
} else {
fptr = emalloc(sizeof(zend_internal_function));
}
memset(fptr, 0, sizeof(zend_internal_function));
fptr->type = ZEND_INTERNAL_FUNCTION;
fptr->num_args = 1;
fptr->scope = (*object)->ce;
fptr->fn_flags = ZEND_ACC_CALL_VIA_HANDLER;
fptr->function_name = zend_string_copy(name);
fptr->handler = ZEND_FN(zend_test_func);
if (EXPECTED(EG(trampoline).common.function_name == NULL)) {
fptr = (zend_internal_function *) &EG(trampoline);
} else {
fptr = emalloc(sizeof(zend_internal_function));
}
memset(fptr, 0, sizeof(zend_internal_function));
fptr->type = ZEND_INTERNAL_FUNCTION;
fptr->num_args = 1;
fptr->scope = (*object)->ce;
fptr->fn_flags = ZEND_ACC_CALL_VIA_HANDLER;
fptr->function_name = zend_string_copy(name);
fptr->handler = ZEND_FN(zend_test_func);
return (zend_function*)fptr;
return (zend_function*)fptr;
}
return zend_std_get_method(object, name, key);
}
/* }}} */
@ -322,6 +325,16 @@ static ZEND_METHOD(_ZendTestClass, returnsStatic) {
object_init_ex(return_value, zend_get_called_scope(execute_data));
}
static ZEND_METHOD(_ZendTestClass, returnsThrowable) {
ZEND_PARSE_PARAMETERS_NONE();
zend_throw_error(NULL, "Dummy");
}
static ZEND_METHOD(_ZendTestChildClass, returnsThrowable) {
ZEND_PARSE_PARAMETERS_NONE();
zend_throw_error(NULL, "Dummy");
}
static ZEND_METHOD(_ZendTestTrait, testMethod) {
ZEND_PARSE_PARAMETERS_NONE();
RETURN_TRUE;

View File

@ -24,10 +24,13 @@ class _ZendTestClass implements _ZendTestInterface {
public function __toString(): string {}
public function returnsStatic(): static {}
public function returnsThrowable(): Throwable {}
}
class _ZendTestChildClass extends _ZendTestClass
{
public function returnsThrowable(): Exception {}
}
trait _ZendTestTrait {

View File

@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: cf8958513064fb7257203b3304c8dc67c8e008b9 */
* Stub hash: 70374ed7b55604eb98e85148d7ff19e79258ce92 */
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_array_return, 0, 0, IS_ARRAY, 0)
ZEND_END_ARG_INFO()
@ -63,6 +63,12 @@ ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class__ZendTestClass_returnsStatic, 0, 0, IS_STATIC, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class__ZendTestClass_returnsThrowable, 0, 0, Throwable, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class__ZendTestChildClass_returnsThrowable, 0, 0, Exception, 0)
ZEND_END_ARG_INFO()
#define arginfo_class__ZendTestTrait_testMethod arginfo_ZendTestNS2_ZendSubNS_namespaced_func
#define arginfo_class_ZendTestNS_Foo_method arginfo_zend_test_void_return
@ -89,6 +95,8 @@ static ZEND_FUNCTION(namespaced_func);
static ZEND_METHOD(_ZendTestClass, is_object);
static ZEND_METHOD(_ZendTestClass, __toString);
static ZEND_METHOD(_ZendTestClass, returnsStatic);
static ZEND_METHOD(_ZendTestClass, returnsThrowable);
static ZEND_METHOD(_ZendTestChildClass, returnsThrowable);
static ZEND_METHOD(_ZendTestTrait, testMethod);
static ZEND_METHOD(ZendTestNS_Foo, method);
static ZEND_METHOD(ZendTestNS2_Foo, method);
@ -123,11 +131,13 @@ static const zend_function_entry class__ZendTestClass_methods[] = {
ZEND_ME(_ZendTestClass, is_object, arginfo_class__ZendTestClass_is_object, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
ZEND_ME(_ZendTestClass, __toString, arginfo_class__ZendTestClass___toString, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED)
ZEND_ME(_ZendTestClass, returnsStatic, arginfo_class__ZendTestClass_returnsStatic, ZEND_ACC_PUBLIC)
ZEND_ME(_ZendTestClass, returnsThrowable, arginfo_class__ZendTestClass_returnsThrowable, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
static const zend_function_entry class__ZendTestChildClass_methods[] = {
ZEND_ME(_ZendTestChildClass, returnsThrowable, arginfo_class__ZendTestChildClass_returnsThrowable, ZEND_ACC_PUBLIC)
ZEND_FE_END
};