mirror of
https://github.com/php/php-src.git
synced 2025-08-15 21:48:51 +02:00
Merge branch 'PHP-8.2'
* PHP-8.2: Fix segfault in format_default_value due to unexpected enum/object
This commit is contained in:
commit
48ede64506
7 changed files with 115 additions and 2 deletions
2
NEWS
2
NEWS
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
13
ext/reflection/tests/gh11937_1.inc
Normal file
13
ext/reflection/tests/gh11937_1.inc
Normal 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() {}
|
30
ext/reflection/tests/gh11937_1.phpt
Normal file
30
ext/reflection/tests/gh11937_1.phpt
Normal 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) ]
|
||||
}
|
||||
}
|
4
ext/reflection/tests/gh11937_2.inc
Normal file
4
ext/reflection/tests/gh11937_2.inc
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?php
|
||||
|
||||
#[Attr(FOOS)]
|
||||
function test() {}
|
27
ext/reflection/tests/gh11937_2.phpt
Normal file
27
ext/reflection/tests/gh11937_2.phpt
Normal 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 ]
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue