GH-19153: Validate #[\Attribute] targets (#19154)

Do not allow #[\Attribute] on traits, interfaces, enums, or abstract classes.
This commit is contained in:
Daniel Scherzer 2025-08-11 09:05:57 -07:00 committed by GitHub
parent 5f8d648af6
commit c416191a00
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 69 additions and 0 deletions

2
NEWS
View file

@ -62,6 +62,8 @@ PHP NEWS
. The socket_set_timeout() alias function has been deprecated. (timwolla) . The socket_set_timeout() alias function has been deprecated. (timwolla)
. Passing null to to readdir(), rewinddir(), and closedir() to use the last . Passing null to to readdir(), rewinddir(), and closedir() to use the last
opened directory has been deprecated. (Girgias) opened directory has been deprecated. (Girgias)
. Fixed bug GH-19153 (#[\Attribute] validation should error on
trait/interface/enum/abstract class). (DanielEScherzer)
31 Jul 2025, PHP 8.5.0alpha4 31 Jul 2025, PHP 8.5.0alpha4

View file

@ -0,0 +1,12 @@
--TEST--
#[Attribute] on an abstract class
--FILE--
<?php
#[Attribute]
abstract class Demo {}
echo "Done\n";
?>
--EXPECTF--
Fatal error: Cannot apply #[\Attribute] to abstract class Demo in %s on line %d

View file

@ -0,0 +1,12 @@
--TEST--
#[Attribute] on an enum
--FILE--
<?php
#[Attribute]
enum Demo {}
echo "Done\n";
?>
--EXPECTF--
Fatal error: Cannot apply #[\Attribute] to enum Demo in %s on line %d

View file

@ -0,0 +1,12 @@
--TEST--
#[Attribute] on an interface
--FILE--
<?php
#[Attribute]
interface Demo {}
echo "Done\n";
?>
--EXPECTF--
Fatal error: Cannot apply #[\Attribute] to interface Demo in %s on line %d

View file

@ -0,0 +1,12 @@
--TEST--
#[Attribute] on a trait
--FILE--
<?php
#[Attribute]
trait Demo {}
echo "Done\n";
?>
--EXPECTF--
Fatal error: Cannot apply #[\Attribute] to trait Demo in %s on line %d

View file

@ -95,6 +95,24 @@ static void validate_allow_dynamic_properties(
scope->ce_flags |= ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES; scope->ce_flags |= ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES;
} }
static void validate_attribute(
zend_attribute *attr, uint32_t target, zend_class_entry *scope)
{
const char *msg = NULL;
if (scope->ce_flags & ZEND_ACC_TRAIT) {
msg = "Cannot apply #[\\Attribute] to trait %s";
} else if (scope->ce_flags & ZEND_ACC_INTERFACE) {
msg = "Cannot apply #[\\Attribute] to interface %s";
} else if (scope->ce_flags & ZEND_ACC_ENUM) {
msg = "Cannot apply #[\\Attribute] to enum %s";
} else if (scope->ce_flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) {
msg = "Cannot apply #[\\Attribute] to abstract class %s";
}
if (msg != NULL) {
zend_error_noreturn(E_ERROR, msg, ZSTR_VAL(scope->name));
}
}
ZEND_METHOD(Attribute, __construct) ZEND_METHOD(Attribute, __construct)
{ {
zend_long flags = ZEND_ATTRIBUTE_TARGET_ALL; zend_long flags = ZEND_ATTRIBUTE_TARGET_ALL;
@ -522,6 +540,7 @@ void zend_register_attribute_ce(void)
zend_ce_attribute = register_class_Attribute(); zend_ce_attribute = register_class_Attribute();
attr = zend_mark_internal_attribute(zend_ce_attribute); attr = zend_mark_internal_attribute(zend_ce_attribute);
attr->validator = validate_attribute;
zend_ce_return_type_will_change_attribute = register_class_ReturnTypeWillChange(); zend_ce_return_type_will_change_attribute = register_class_ReturnTypeWillChange();
zend_mark_internal_attribute(zend_ce_return_type_will_change_attribute); zend_mark_internal_attribute(zend_ce_return_type_will_change_attribute);