mirror of
https://github.com/php/php-src.git
synced 2025-08-15 21:48:51 +02:00
Merge branch 'PHP-8.2' into PHP-8.3
* PHP-8.2: Delay #[Attribute] arg validation until runtime
This commit is contained in:
commit
480d08a70a
10 changed files with 106 additions and 28 deletions
4
NEWS
4
NEWS
|
@ -6,6 +6,10 @@ PHP NEWS
|
||||||
. Fixed buffer limit on Windows, replacing read call usage by _read.
|
. Fixed buffer limit on Windows, replacing read call usage by _read.
|
||||||
(David Carlier)
|
(David Carlier)
|
||||||
|
|
||||||
|
- Core:
|
||||||
|
. Fixed bug GH-13970 (Incorrect validation of #[Attribute] flags type for
|
||||||
|
non-compile-time expressions). (ilutov)
|
||||||
|
|
||||||
- DOM:
|
- DOM:
|
||||||
. Fix crashes when entity declaration is removed while still having entity
|
. Fix crashes when entity declaration is removed while still having entity
|
||||||
references. (nielsdos)
|
references. (nielsdos)
|
||||||
|
|
|
@ -6,6 +6,15 @@ Attribute flags type is validated.
|
||||||
#[Attribute("foo")]
|
#[Attribute("foo")]
|
||||||
class A1 { }
|
class A1 { }
|
||||||
|
|
||||||
|
#[A1]
|
||||||
|
class Foo {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
(new ReflectionClass(Foo::class))->getAttributes()[0]->newInstance();
|
||||||
|
} catch (Error $e) {
|
||||||
|
echo $e->getMessage(), "\n";
|
||||||
|
}
|
||||||
|
|
||||||
?>
|
?>
|
||||||
--EXPECTF--
|
--EXPECT--
|
||||||
Fatal error: Attribute::__construct(): Argument #1 ($flags) must be of type int, string given in %s
|
Attribute::__construct(): Argument #1 ($flags) must be of type int, string given
|
||||||
|
|
|
@ -6,6 +6,15 @@ Attribute flags value is validated.
|
||||||
#[Attribute(-1)]
|
#[Attribute(-1)]
|
||||||
class A1 { }
|
class A1 { }
|
||||||
|
|
||||||
|
#[A1]
|
||||||
|
class Foo { }
|
||||||
|
|
||||||
|
try {
|
||||||
|
var_dump((new ReflectionClass(Foo::class))->getAttributes()[0]->newInstance());
|
||||||
|
} catch (Error $e) {
|
||||||
|
echo $e->getMessage(), "\n";
|
||||||
|
}
|
||||||
|
|
||||||
?>
|
?>
|
||||||
--EXPECTF--
|
--EXPECT--
|
||||||
Fatal error: Invalid attribute flags specified in %s
|
Invalid attribute flags specified
|
||||||
|
|
|
@ -6,6 +6,15 @@ Attribute flags value is validated.
|
||||||
#[Attribute(Foo::BAR)]
|
#[Attribute(Foo::BAR)]
|
||||||
class A1 { }
|
class A1 { }
|
||||||
|
|
||||||
|
#[A1]
|
||||||
|
class Bar { }
|
||||||
|
|
||||||
|
try {
|
||||||
|
var_dump((new ReflectionClass(Bar::class))->getAttributes()[0]->newInstance());
|
||||||
|
} catch (Error $e) {
|
||||||
|
echo $e->getMessage(), "\n";
|
||||||
|
}
|
||||||
|
|
||||||
?>
|
?>
|
||||||
--EXPECTF--
|
--EXPECT--
|
||||||
Fatal error: Class "Foo" not found in %s on line %d
|
Class "Foo" not found
|
||||||
|
|
|
@ -1,9 +1,19 @@
|
||||||
--TEST--
|
--TEST--
|
||||||
Validation for "Attribute" does not use a scope when evaluating constant ASTs
|
Validation for "Attribute" uses the class scope when evaluating constant ASTs
|
||||||
--FILE--
|
--FILE--
|
||||||
<?php
|
<?php
|
||||||
#[Attribute(parent::x)]
|
#[Attribute(parent::x)]
|
||||||
class x extends y {}
|
class x extends y {}
|
||||||
|
|
||||||
|
class y {
|
||||||
|
protected const x = Attribute::TARGET_CLASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[x]
|
||||||
|
class z {}
|
||||||
|
|
||||||
|
var_dump((new ReflectionClass(z::class))->getAttributes()[0]->newInstance());
|
||||||
?>
|
?>
|
||||||
--EXPECTF--
|
--EXPECT--
|
||||||
Fatal error: Cannot access "parent" when no class scope is active in %s on line %d
|
object(x)#1 (0) {
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
--TEST--
|
||||||
|
Attribute flags type is not validated at compile time.
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
#[Attribute("foo")]
|
||||||
|
class A1 { }
|
||||||
|
|
||||||
|
?>
|
||||||
|
===DONE===
|
||||||
|
--EXPECT--
|
||||||
|
===DONE===
|
|
@ -36,31 +36,39 @@ static zend_object_handlers attributes_object_handlers_sensitive_parameter_value
|
||||||
static HashTable internal_attributes;
|
static HashTable internal_attributes;
|
||||||
|
|
||||||
void validate_attribute(zend_attribute *attr, uint32_t target, zend_class_entry *scope)
|
void validate_attribute(zend_attribute *attr, uint32_t target, zend_class_entry *scope)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t zend_attribute_attribute_get_flags(zend_attribute *attr, zend_class_entry *scope)
|
||||||
{
|
{
|
||||||
// TODO: More proper signature validation: Too many args, incorrect arg names.
|
// TODO: More proper signature validation: Too many args, incorrect arg names.
|
||||||
if (attr->argc > 0) {
|
if (attr->argc > 0) {
|
||||||
zval flags;
|
zval flags;
|
||||||
|
|
||||||
/* As this is run in the middle of compilation, fetch the attribute value without
|
if (FAILURE == zend_get_attribute_value(&flags, attr, 0, scope)) {
|
||||||
* specifying a scope. The class is not fully linked yet, and we may seen an
|
ZEND_ASSERT(EG(exception));
|
||||||
* inconsistent state. */
|
return 0;
|
||||||
if (FAILURE == zend_get_attribute_value(&flags, attr, 0, NULL)) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Z_TYPE(flags) != IS_LONG) {
|
if (Z_TYPE(flags) != IS_LONG) {
|
||||||
zend_error_noreturn(E_ERROR,
|
zend_throw_error(NULL,
|
||||||
"Attribute::__construct(): Argument #1 ($flags) must be of type int, %s given",
|
"Attribute::__construct(): Argument #1 ($flags) must be of type int, %s given",
|
||||||
zend_zval_value_name(&flags)
|
zend_zval_value_name(&flags)
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
if (Z_LVAL(flags) & ~ZEND_ATTRIBUTE_FLAGS) {
|
|
||||||
zend_error_noreturn(E_ERROR, "Invalid attribute flags specified");
|
|
||||||
}
|
|
||||||
|
|
||||||
zval_ptr_dtor(&flags);
|
zval_ptr_dtor(&flags);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t flags_l = Z_LVAL(flags);
|
||||||
|
if (flags_l & ~ZEND_ATTRIBUTE_FLAGS) {
|
||||||
|
zend_throw_error(NULL, "Invalid attribute flags specified");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return flags_l;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ZEND_ATTRIBUTE_TARGET_ALL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void validate_allow_dynamic_properties(
|
static void validate_allow_dynamic_properties(
|
||||||
|
|
|
@ -86,6 +86,8 @@ ZEND_API zend_attribute *zend_add_attribute(
|
||||||
HashTable **attributes, zend_string *name, uint32_t argc,
|
HashTable **attributes, zend_string *name, uint32_t argc,
|
||||||
uint32_t flags, uint32_t offset, uint32_t lineno);
|
uint32_t flags, uint32_t offset, uint32_t lineno);
|
||||||
|
|
||||||
|
uint32_t zend_attribute_attribute_get_flags(zend_attribute *attr, zend_class_entry *scope);
|
||||||
|
|
||||||
END_EXTERN_C()
|
END_EXTERN_C()
|
||||||
|
|
||||||
static zend_always_inline zend_attribute *zend_add_class_attribute(zend_class_entry *ce, zend_string *name, uint32_t argc)
|
static zend_always_inline zend_attribute *zend_add_class_attribute(zend_class_entry *ce, zend_string *name, uint32_t argc)
|
||||||
|
|
|
@ -6772,18 +6772,11 @@ ZEND_METHOD(ReflectionAttribute, newInstance)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ce->type == ZEND_USER_CLASS) {
|
if (ce->type == ZEND_USER_CLASS) {
|
||||||
uint32_t flags = ZEND_ATTRIBUTE_TARGET_ALL;
|
uint32_t flags = zend_attribute_attribute_get_flags(marker, ce);
|
||||||
|
if (EG(exception)) {
|
||||||
if (marker->argc > 0) {
|
|
||||||
zval tmp;
|
|
||||||
|
|
||||||
if (FAILURE == zend_get_attribute_value(&tmp, marker, 0, ce)) {
|
|
||||||
RETURN_THROWS();
|
RETURN_THROWS();
|
||||||
}
|
}
|
||||||
|
|
||||||
flags = (uint32_t) Z_LVAL(tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(attr->target & flags)) {
|
if (!(attr->target & flags)) {
|
||||||
zend_string *location = zend_get_attribute_target_names(attr->target);
|
zend_string *location = zend_get_attribute_target_names(attr->target);
|
||||||
zend_string *allowed = zend_get_attribute_target_names(flags);
|
zend_string *allowed = zend_get_attribute_target_names(flags);
|
||||||
|
|
22
ext/zend_test/tests/gh13970.phpt
Normal file
22
ext/zend_test/tests/gh13970.phpt
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
--TEST--
|
||||||
|
GH-13970 (Incorrect validation of #[\Attribute]'s first parameter)
|
||||||
|
--EXTENSIONS--
|
||||||
|
zend_test
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
#[Attribute(\ZendTestUnitEnum::Foo)]
|
||||||
|
class Foo {}
|
||||||
|
|
||||||
|
#[Foo]
|
||||||
|
function test() {}
|
||||||
|
|
||||||
|
$reflection = new ReflectionFunction('test');
|
||||||
|
|
||||||
|
try {
|
||||||
|
var_dump($reflection->getAttributes()[0]->newInstance());
|
||||||
|
} catch (Error $e) {
|
||||||
|
echo $e->getMessage(), "\n";
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
Attribute::__construct(): Argument #1 ($flags) must be of type int, ZendTestUnitEnum given
|
Loading…
Add table
Add a link
Reference in a new issue