Merge branch 'PHP-8.2'

* PHP-8.2:
  Fix segfault in format_default_value due to unexpected enum/object
This commit is contained in:
Ilija Tovilo 2023-08-17 18:44:37 +02:00
commit 48ede64506
No known key found for this signature in database
GPG key ID: A4F5D403F118200A
7 changed files with 115 additions and 2 deletions

2
NEWS
View file

@ -2,6 +2,8 @@ PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
?? ??? ????, PHP 8.3.0RC1
- Core:
. Fixed bug GH-11937 (Constant ASTs containing objects). (ilutov)
17 Aug 2023, PHP 8.3.0beta3

View file

@ -1553,6 +1553,35 @@ ZEND_API zend_result zend_unmangle_property_name_ex(const zend_string *name, con
}
/* }}} */
static bool array_is_const_ex(zend_array *array, uint32_t *max_checks)
{
if (zend_hash_num_elements(array) > *max_checks) {
return false;
}
*max_checks -= zend_hash_num_elements(array);
zval *element;
ZEND_HASH_FOREACH_VAL(array, element) {
if (Z_TYPE_P(element) < IS_ARRAY) {
continue;
} else if (Z_TYPE_P(element) == IS_ARRAY) {
if (!array_is_const_ex(array, max_checks)) {
return false;
}
} else if (UNEXPECTED(Z_TYPE_P(element) >=IS_OBJECT)) {
return false;
}
} ZEND_HASH_FOREACH_END();
return true;
}
static bool array_is_const(zend_array *array)
{
uint32_t max_checks = 50;
return array_is_const_ex(array, &max_checks);
}
static bool can_ct_eval_const(zend_constant *c) {
if (ZEND_CONSTANT_FLAGS(c) & CONST_DEPRECATED) {
return 0;
@ -1563,9 +1592,13 @@ static bool can_ct_eval_const(zend_constant *c) {
&& (CG(compiler_options) & ZEND_COMPILE_WITH_FILE_CACHE))) {
return 1;
}
if (Z_TYPE(c->value) < IS_OBJECT
if (Z_TYPE(c->value) < IS_ARRAY
&& !(CG(compiler_options) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION)) {
return 1;
} else if (Z_TYPE(c->value) == IS_ARRAY
&& !(CG(compiler_options) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION)
&& array_is_const(Z_ARR(c->value))) {
return 1;
}
return 0;
}
@ -1792,7 +1825,10 @@ static bool zend_try_ct_eval_class_const(zval *zv, zend_string *class_name, zend
c = &cc->value;
/* Substitute case-sensitive (or lowercase) persistent class constants */
if (Z_TYPE_P(c) < IS_OBJECT) {
if (Z_TYPE_P(c) < IS_ARRAY) {
ZVAL_COPY_OR_DUP(zv, c);
return 1;
} else if (Z_TYPE_P(c) == IS_ARRAY && array_is_const(Z_ARR_P(c))) {
ZVAL_COPY_OR_DUP(zv, c);
return 1;
}

View file

@ -643,6 +643,7 @@ static int format_default_value(smart_str *str, zval *value) {
} ZEND_HASH_FOREACH_END();
smart_str_appendc(str, ']');
} else if (Z_TYPE_P(value) == IS_OBJECT) {
/* This branch may only be reached for default properties, which don't support arbitrary objects. */
zend_object *obj = Z_OBJ_P(value);
zend_class_entry *class = obj->ce;
ZEND_ASSERT(class->ce_flags & ZEND_ACC_ENUM);

View file

@ -0,0 +1,13 @@
<?php
#[Attribute]
class Attr {
public function __construct(public $value) {}
}
class Foo {
public function __construct(public $value) {}
}
#[Attr(new Foo(TestEnum::CASES))]
function test() {}

View file

@ -0,0 +1,30 @@
--TEST--
GH-11937: Segfault in format_default_value due to unexpected enum/object
--FILE--
<?php
enum TestEnum {
case One;
case Two;
const CASES = [self::One, self::Two];
}
var_dump(TestEnum::CASES);
require __DIR__ . '/gh11937_1.inc';
echo (new ReflectionFunction('test'))->getAttributes('Attr')[0];
?>
--EXPECT--
array(2) {
[0]=>
enum(TestEnum::One)
[1]=>
enum(TestEnum::Two)
}
Attribute [ Attr ] {
- Arguments [1] {
Argument #0 [ new \Foo(TestEnum::CASES) ]
}
}

View file

@ -0,0 +1,4 @@
<?php
#[Attr(FOOS)]
function test() {}

View file

@ -0,0 +1,27 @@
--TEST--
GH-11937: Segfault in format_default_value due to unexpected enum/object
--FILE--
<?php
class Foo {}
const FOOS = [new Foo()];
var_dump(FOOS);
require __DIR__ . '/gh11937_2.inc';
echo (new ReflectionFunction('test'))->getAttributes('Attr')[0];
?>
--EXPECT--
array(1) {
[0]=>
object(Foo)#1 (0) {
}
}
Attribute [ Attr ] {
- Arguments [1] {
Argument #0 [ FOOS ]
}
}