Merge branch 'PHP-7.4'

This commit is contained in:
Nikita Popov 2019-05-23 10:41:27 +02:00
commit c3ee12e786
7 changed files with 36 additions and 7 deletions

View file

@ -10,4 +10,4 @@ var_dump($a instanceOf A);
echo "ok\n"; echo "ok\n";
?> ?>
--EXPECTF-- --EXPECTF--
Fatal error: Interface RecurisiveFooFar cannot implement itself in %sbug30922.php on line %d Fatal error: Interface 'RecurisiveFooFar' not found in %sbug30922.php on line %d

View file

@ -0,0 +1,20 @@
--TEST--
Classes can only be used once they are fully linked
--FILE--
<?php
spl_autoload_register(function($class) {
echo new ReflectionClass(A::class), "\n";
});
class A implements I {
}
?>
--EXPECTF--
Fatal error: During class fetch: Uncaught ReflectionException: Class A does not exist in %s:%d
Stack trace:
#0 %s(%d): ReflectionClass->__construct('A')
#1 [internal function]: {closure}('I')
#2 %s(%d): spl_autoload_call('I')
#3 {main} in %s on line %d

View file

@ -269,6 +269,9 @@ typedef struct _zend_oparray_context {
/* Children must reuse parent get_iterator() | | | */ /* Children must reuse parent get_iterator() | | | */
#define ZEND_ACC_REUSE_GET_ITERATOR (1 << 18) /* X | | | */ #define ZEND_ACC_REUSE_GET_ITERATOR (1 << 18) /* X | | | */
/* | | | */ /* | | | */
/* Class is being linked. Don't free strings. | | | */
#define ZEND_ACC_LINKING_IN_PROGRESS (1 << 19) /* X | | | */
/* | | | */
/* Function Flags (unused: 28...30) | | | */ /* Function Flags (unused: 28...30) | | | */
/* ============== | | | */ /* ============== | | | */
/* | | | */ /* | | | */

View file

@ -861,7 +861,11 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string *
if (!key) { if (!key) {
zend_string_release_ex(lc_name, 0); zend_string_release_ex(lc_name, 0);
} }
return (zend_class_entry*)Z_PTR_P(zv); ce = (zend_class_entry*)Z_PTR_P(zv);
if (UNEXPECTED(!(ce->ce_flags & ZEND_ACC_LINKED))) {
return NULL;
}
return ce;
} }
/* The compiler is not-reentrant. Make sure we __autoload() only during run-time /* The compiler is not-reentrant. Make sure we __autoload() only during run-time

View file

@ -1961,7 +1961,7 @@ void zend_verify_abstract_class(zend_class_entry *ce) /* {{{ */
ZEND_API void zend_do_link_class(zend_class_entry *ce, zend_class_entry *parent) /* {{{ */ ZEND_API void zend_do_link_class(zend_class_entry *ce, zend_class_entry *parent) /* {{{ */
{ {
ce->ce_flags |= ZEND_ACC_LINKED; ce->ce_flags |= ZEND_ACC_LINKING_IN_PROGRESS;
if (parent) { if (parent) {
zend_do_inheritance(ce, parent); zend_do_inheritance(ce, parent);
} }
@ -1976,5 +1976,7 @@ ZEND_API void zend_do_link_class(zend_class_entry *ce, zend_class_entry *parent)
} }
zend_build_properties_info_table(ce); zend_build_properties_info_table(ce);
ce->ce_flags &= ~ZEND_ACC_LINKING_IN_PROGRESS;
ce->ce_flags |= ZEND_ACC_LINKED;
} }
/* }}} */ /* }}} */

View file

@ -291,7 +291,7 @@ static int zend_implement_traversable(zend_class_entry *interface, zend_class_en
return SUCCESS; return SUCCESS;
} }
if (class_type->num_interfaces) { if (class_type->num_interfaces) {
ZEND_ASSERT(class_type->ce_flags & ZEND_ACC_LINKED); ZEND_ASSERT(class_type->ce_flags & (ZEND_ACC_LINKED|ZEND_ACC_LINKING_IN_PROGRESS));
for (i = 0; i < class_type->num_interfaces; i++) { for (i = 0; i < class_type->num_interfaces; i++) {
if (class_type->interfaces[i] == zend_ce_aggregate || class_type->interfaces[i] == zend_ce_iterator) { if (class_type->interfaces[i] == zend_ce_aggregate || class_type->interfaces[i] == zend_ce_iterator) {
return SUCCESS; return SUCCESS;
@ -321,7 +321,7 @@ static int zend_implement_aggregate(zend_class_entry *interface, zend_class_entr
} else if (class_type->get_iterator != zend_user_it_get_new_iterator) { } else if (class_type->get_iterator != zend_user_it_get_new_iterator) {
/* c-level get_iterator cannot be changed (exception being only Traversable is implemented) */ /* c-level get_iterator cannot be changed (exception being only Traversable is implemented) */
if (class_type->num_interfaces) { if (class_type->num_interfaces) {
ZEND_ASSERT(class_type->ce_flags & ZEND_ACC_LINKED); ZEND_ASSERT(class_type->ce_flags & (ZEND_ACC_LINKED|ZEND_ACC_LINKING_IN_PROGRESS));
for (i = 0; i < class_type->num_interfaces; i++) { for (i = 0; i < class_type->num_interfaces; i++) {
if (class_type->interfaces[i] == zend_ce_iterator) { if (class_type->interfaces[i] == zend_ce_iterator) {
zend_error_noreturn(E_ERROR, "Class %s cannot implement both %s and %s at the same time", zend_error_noreturn(E_ERROR, "Class %s cannot implement both %s and %s at the same time",

View file

@ -238,7 +238,7 @@ ZEND_API void destroy_zend_class(zval *zv)
} }
switch (ce->type) { switch (ce->type) {
case ZEND_USER_CLASS: case ZEND_USER_CLASS:
if (ce->parent_name && !(ce->ce_flags & ZEND_ACC_LINKED)) { if (ce->parent_name && !(ce->ce_flags & (ZEND_ACC_LINKED|ZEND_ACC_LINKING_IN_PROGRESS))) {
zend_string_release_ex(ce->parent_name, 0); zend_string_release_ex(ce->parent_name, 0);
} }
if (ce->default_properties_table) { if (ce->default_properties_table) {
@ -298,7 +298,7 @@ ZEND_API void destroy_zend_class(zval *zv)
} }
zend_hash_destroy(&ce->constants_table); zend_hash_destroy(&ce->constants_table);
if (ce->num_interfaces > 0) { if (ce->num_interfaces > 0) {
if (!(ce->ce_flags & ZEND_ACC_LINKED)) { if (!(ce->ce_flags & (ZEND_ACC_LINKED|ZEND_ACC_LINKING_IN_PROGRESS))) {
uint32_t i; uint32_t i;
for (i = 0; i < ce->num_interfaces; i++) { for (i = 0; i < ce->num_interfaces; i++) {