Skip to content

Commit 3a918d6

Browse files
committed
Fix segfault in format_default_value due to unexpected enum/object
Evaluating constants at comptime can result in arrays that contain objects. This is problematic for printing the default value of constant ASTs containing objects, because we don't actually know what the constructor arguments were. Avoid this by not propagating array constants. Fixes GH-11937
1 parent 0d922aa commit 3a918d6

File tree

6 files changed

+77
-2
lines changed

6 files changed

+77
-2
lines changed

Zend/zend_compile.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1468,7 +1468,7 @@ static bool can_ct_eval_const(zend_constant *c) {
14681468
&& (CG(compiler_options) & ZEND_COMPILE_WITH_FILE_CACHE))) {
14691469
return 1;
14701470
}
1471-
if (Z_TYPE(c->value) < IS_OBJECT
1471+
if (Z_TYPE(c->value) < IS_ARRAY
14721472
&& !(CG(compiler_options) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION)) {
14731473
return 1;
14741474
}
@@ -1690,7 +1690,7 @@ static bool zend_try_ct_eval_class_const(zval *zv, zend_string *class_name, zend
16901690
c = &cc->value;
16911691

16921692
/* Substitute case-sensitive (or lowercase) persistent class constants */
1693-
if (Z_TYPE_P(c) < IS_OBJECT) {
1693+
if (Z_TYPE_P(c) < IS_ARRAY) {
16941694
ZVAL_COPY_OR_DUP(zv, c);
16951695
return 1;
16961696
}

ext/reflection/php_reflection.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,7 @@ static int format_default_value(smart_str *str, zval *value) {
639639
} ZEND_HASH_FOREACH_END();
640640
smart_str_appendc(str, ']');
641641
} else if (Z_TYPE_P(value) == IS_OBJECT) {
642+
/* This branch may only be reached for default properties, which don't support arbitrary objects. */
642643
zend_object *obj = Z_OBJ_P(value);
643644
zend_class_entry *class = obj->ce;
644645
ZEND_ASSERT(class->ce_flags & ZEND_ACC_ENUM);

ext/reflection/tests/gh11937_1.inc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
#[Attribute]
4+
class Attr {
5+
public function __construct(public $value) {}
6+
}
7+
8+
class Foo {
9+
public function __construct(public $value) {}
10+
}
11+
12+
#[Attr(new Foo(TestEnum::CASES))]
13+
function test() {}

ext/reflection/tests/gh11937_1.phpt

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
--TEST--
2+
GH-11937: Segfault in format_default_value due to unexpected enum/object
3+
--FILE--
4+
<?php
5+
6+
enum TestEnum {
7+
case One;
8+
case Two;
9+
const CASES = [self::One, self::Two];
10+
}
11+
12+
var_dump(TestEnum::CASES);
13+
14+
require __DIR__ . '/gh11937_1.inc';
15+
16+
echo (new ReflectionFunction('test'))->getAttributes('Attr')[0];
17+
18+
?>
19+
--EXPECT--
20+
array(2) {
21+
[0]=>
22+
enum(TestEnum::One)
23+
[1]=>
24+
enum(TestEnum::Two)
25+
}
26+
Attribute [ Attr ] {
27+
- Arguments [1] {
28+
Argument #0 [ new \Foo(TestEnum::CASES) ]
29+
}
30+
}

ext/reflection/tests/gh11937_2.inc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?php
2+
3+
#[Attr(FOOS)]
4+
function test() {}

ext/reflection/tests/gh11937_2.phpt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
--TEST--
2+
GH-11937: Segfault in format_default_value due to unexpected enum/object
3+
--FILE--
4+
<?php
5+
6+
class Foo {}
7+
8+
const FOOS = [new Foo()];
9+
10+
var_dump(FOOS);
11+
12+
require __DIR__ . '/gh11937_2.inc';
13+
14+
echo (new ReflectionFunction('test'))->getAttributes('Attr')[0];
15+
16+
?>
17+
--EXPECT--
18+
array(1) {
19+
[0]=>
20+
object(Foo)#1 (0) {
21+
}
22+
}
23+
Attribute [ Attr ] {
24+
- Arguments [1] {
25+
Argument #0 [ FOOS ]
26+
}
27+
}

0 commit comments

Comments
 (0)