From ee934f8245b58e1a557ed7b3f303f2d9d7cd23a6 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 3 Nov 2020 14:15:05 +0100 Subject: [PATCH] Fix variance checks on resolved union types This is a bit annoying: When preloading is used, types might be resolved during inheritance checks, so we need to deal with CE types rather than just NAME types everywhere. --- Zend/zend_inheritance.c | 110 +++++++++++++------------ ext/opcache/tests/preload_variance.inc | 2 + 2 files changed, 59 insertions(+), 53 deletions(-) diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index 191126eed7..34489938a9 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -364,11 +364,10 @@ typedef enum { } inheritance_status; static inheritance_status zend_perform_covariant_class_type_check( - zend_class_entry *fe_scope, zend_string *fe_class_name, + zend_class_entry *fe_scope, zend_string *fe_class_name, zend_class_entry *fe_ce, zend_class_entry *proto_scope, zend_type proto_type, zend_bool register_unresolved) { zend_bool have_unresolved = 0; - zend_class_entry *fe_ce = NULL; if (ZEND_TYPE_FULL_MASK(proto_type) & MAY_BE_OBJECT) { /* Currently, any class name would be allowed here. We still perform a class lookup * for forward-compatibility reasons, as we may have named types in the future that @@ -391,6 +390,7 @@ static inheritance_status zend_perform_covariant_class_type_check( zend_type *single_type; ZEND_TYPE_FOREACH(proto_type, single_type) { + zend_class_entry *proto_ce; if (ZEND_TYPE_HAS_NAME(*single_type)) { zend_string *proto_class_name = resolve_class_name(proto_scope, ZEND_TYPE_NAME(*single_type)); @@ -398,16 +398,20 @@ static inheritance_status zend_perform_covariant_class_type_check( return INHERITANCE_SUCCESS; } - /* Make sure to always load both classes, to avoid only registering one of them as - * a delayed autoload. */ if (!fe_ce) fe_ce = lookup_class(fe_scope, fe_class_name, register_unresolved); - zend_class_entry *proto_ce = + proto_ce = lookup_class(proto_scope, proto_class_name, register_unresolved); - if (!fe_ce || !proto_ce) { - have_unresolved = 1; - } else if (unlinked_instanceof(fe_ce, proto_ce)) { - return INHERITANCE_SUCCESS; - } + } else if (ZEND_TYPE_HAS_CE(*single_type)) { + if (!fe_ce) fe_ce = lookup_class(fe_scope, fe_class_name, register_unresolved); + proto_ce = ZEND_TYPE_CE(*single_type); + } else { + continue; + } + + if (!fe_ce || !proto_ce) { + have_unresolved = 1; + } else if (unlinked_instanceof(fe_ce, proto_ce)) { + return INHERITANCE_SUCCESS; } } ZEND_TYPE_FOREACH_END(); @@ -448,56 +452,56 @@ static inheritance_status zend_perform_covariant_type_check( } } - if (ZEND_TYPE_HAS_NAME(fe_type)) { - zend_string *fe_class_name = resolve_class_name(fe_scope, ZEND_TYPE_NAME(fe_type)); - inheritance_status status = zend_perform_covariant_class_type_check( - fe_scope, fe_class_name, proto_scope, proto_type, /* register_unresolved */ 0); - if (status != INHERITANCE_UNRESOLVED) { - return status; - } - - zend_perform_covariant_class_type_check( - fe_scope, fe_class_name, proto_scope, proto_type, /* register_unresolved */ 1); - return INHERITANCE_UNRESOLVED; - } - - if (ZEND_TYPE_HAS_LIST(fe_type)) { - zend_type *list_type; - zend_bool all_success = 1; + zend_type *single_type; + zend_bool all_success = 1; - /* First try to check whether we can succeed without resolving anything */ - ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(fe_type), list_type) { - ZEND_ASSERT(ZEND_TYPE_HAS_NAME(*list_type)); + /* First try to check whether we can succeed without resolving anything */ + ZEND_TYPE_FOREACH(fe_type, single_type) { + inheritance_status status; + if (ZEND_TYPE_HAS_NAME(*single_type)) { zend_string *fe_class_name = - resolve_class_name(fe_scope, ZEND_TYPE_NAME(*list_type)); - inheritance_status status = zend_perform_covariant_class_type_check( - fe_scope, fe_class_name, proto_scope, proto_type, /* register_unresolved */ 0); - if (status == INHERITANCE_ERROR) { - return INHERITANCE_ERROR; - } - - if (status != INHERITANCE_SUCCESS) { - all_success = 0; - } - } ZEND_TYPE_LIST_FOREACH_END(); + resolve_class_name(fe_scope, ZEND_TYPE_NAME(*single_type)); + status = zend_perform_covariant_class_type_check( + fe_scope, fe_class_name, NULL, + proto_scope, proto_type, /* register_unresolved */ 0); + } else if (ZEND_TYPE_HAS_CE(*single_type)) { + zend_class_entry *fe_ce = ZEND_TYPE_CE(*single_type); + status = zend_perform_covariant_class_type_check( + fe_scope, fe_ce->name, fe_ce, + proto_scope, proto_type, /* register_unresolved */ 0); + } else { + continue; + } - /* All individual checks succeeded, overall success */ - if (all_success) { - return INHERITANCE_SUCCESS; + if (status == INHERITANCE_ERROR) { + return INHERITANCE_ERROR; } + if (status != INHERITANCE_SUCCESS) { + all_success = 0; + } + } ZEND_TYPE_FOREACH_END(); - /* Register all classes that may have to be resolved */ - ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(fe_type), list_type) { - ZEND_ASSERT(ZEND_TYPE_HAS_NAME(*list_type)); - zend_string *fe_class_name = - resolve_class_name(fe_scope, ZEND_TYPE_NAME(*list_type)); - zend_perform_covariant_class_type_check( - fe_scope, fe_class_name, proto_scope, proto_type, /* register_unresolved */ 1); - } ZEND_TYPE_LIST_FOREACH_END(); - return INHERITANCE_UNRESOLVED; + /* All individual checks succeeded, overall success */ + if (all_success) { + return INHERITANCE_SUCCESS; } - return INHERITANCE_SUCCESS; + /* Register all classes that may have to be resolved */ + ZEND_TYPE_FOREACH(fe_type, single_type) { + if (ZEND_TYPE_HAS_NAME(*single_type)) { + zend_string *fe_class_name = + resolve_class_name(fe_scope, ZEND_TYPE_NAME(*single_type)); + zend_perform_covariant_class_type_check( + fe_scope, fe_class_name, NULL, + proto_scope, proto_type, /* register_unresolved */ 1); + } else if (ZEND_TYPE_HAS_CE(*single_type)) { + zend_class_entry *fe_ce = ZEND_TYPE_CE(*single_type); + zend_perform_covariant_class_type_check( + fe_scope, fe_ce->name, fe_ce, + proto_scope, proto_type, /* register_unresolved */ 1); + } + } ZEND_TYPE_FOREACH_END(); + return INHERITANCE_UNRESOLVED; } /* }}} */ diff --git a/ext/opcache/tests/preload_variance.inc b/ext/opcache/tests/preload_variance.inc index b1e84b5b5d..eae3cd7152 100644 --- a/ext/opcache/tests/preload_variance.inc +++ b/ext/opcache/tests/preload_variance.inc @@ -25,9 +25,11 @@ class D extends C { interface I {} interface J extends I {} class E { + public I|J $prop; public function method($a): I {} } class F extends E { + public J|I $prop; public function method($a): J {} } -- 2.40.0