Skip to content

Commit 82972f4

Browse files
committed
Merge branch 'PHP-8.2'
* PHP-8.2: Fix various bugs related to DNF types
2 parents 63a7f22 + 02a80c5 commit 82972f4

File tree

7 files changed

+112
-34
lines changed

7 files changed

+112
-34
lines changed

NEWS

+8
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@ PHP NEWS
66
. Fixed strerror_r detection at configuration time. (Kévin Dunglas)
77
. Fixed segfault during freeing of some incompletely initialized objects due
88
to OOM error (PDO, SPL, XSL). (ilutov)
9+
. Fixed trait typed properties using a DNF type not being correctly bound.
10+
(Girgias)
11+
. Fixed trait property types not being arena allocated if copied from
12+
an internal trait. (Girgias)
13+
. Fixed deep copy of property DNF type during lazy class load.
14+
(Girgias, ilutov)
15+
. Fixed memory freeing of DNF types for non arena allocated types.
16+
(Girgias, ju1ius)
917

1018
- DOM:
1119
. adoptNode now respects the strict error checking property. (nielsdos)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
Property types must be invariant
3+
--FILE--
4+
<?php
5+
6+
interface X {}
7+
interface Y {}
8+
9+
class A {
10+
public (X&Y&Z)|L $prop;
11+
}
12+
class B extends A {
13+
public (X&Y)|L $prop;
14+
}
15+
16+
?>
17+
--EXPECTF--
18+
Fatal error: Type of B::$prop must be (X&Y&Z)|L (as in class A) in %s on line %d
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
--TEST--
2+
Internal trait used typed property (union type)
3+
--EXTENSIONS--
4+
zend_test
5+
--FILE--
6+
<?php
7+
8+
class C {
9+
use _ZendTestTrait;
10+
}
11+
12+
$o = new C();
13+
var_dump($o);
14+
15+
$prop = new \ReflectionProperty(C::class, 'classUnionProp');
16+
$union = $prop->getType();
17+
$types = $union->getTypes();
18+
var_dump($types, (string)$types[0], (string)$types[1]);
19+
20+
?>
21+
===DONE===
22+
--EXPECT--
23+
object(C)#1 (1) {
24+
["testProp"]=>
25+
NULL
26+
["classUnionProp"]=>
27+
uninitialized(Traversable|Countable)
28+
}
29+
array(2) {
30+
[0]=>
31+
object(ReflectionNamedType)#4 (0) {
32+
}
33+
[1]=>
34+
object(ReflectionNamedType)#5 (0) {
35+
}
36+
}
37+
string(11) "Traversable"
38+
string(9) "Countable"
39+
===DONE===

Zend/zend_inheritance.c

+30-23
Original file line numberDiff line numberDiff line change
@@ -60,20 +60,33 @@ static void ZEND_COLD emit_incompatible_method_error(
6060
const zend_function *parent, zend_class_entry *parent_scope,
6161
inheritance_status status);
6262

63-
static void zend_type_copy_ctor(zend_type *type, bool persistent) {
63+
static void zend_type_copy_ctor(zend_type *const type, bool use_arena, bool persistent);
64+
65+
static void zend_type_list_copy_ctor(
66+
zend_type *const parent_type,
67+
bool use_arena,
68+
bool persistent
69+
) {
70+
const zend_type_list *const old_list = ZEND_TYPE_LIST(*parent_type);
71+
size_t size = ZEND_TYPE_LIST_SIZE(old_list->num_types);
72+
zend_type_list *new_list = use_arena
73+
? zend_arena_alloc(&CG(arena), size) : pemalloc(size, persistent);
74+
75+
memcpy(new_list, old_list, size);
76+
ZEND_TYPE_SET_LIST(*parent_type, new_list);
77+
if (use_arena) {
78+
ZEND_TYPE_FULL_MASK(*parent_type) |= _ZEND_TYPE_ARENA_BIT;
79+
}
80+
81+
zend_type *list_type;
82+
ZEND_TYPE_LIST_FOREACH(new_list, list_type) {
83+
zend_type_copy_ctor(list_type, use_arena, persistent);
84+
} ZEND_TYPE_LIST_FOREACH_END();
85+
}
86+
87+
static void zend_type_copy_ctor(zend_type *const type, bool use_arena, bool persistent) {
6488
if (ZEND_TYPE_HAS_LIST(*type)) {
65-
zend_type_list *old_list = ZEND_TYPE_LIST(*type);
66-
size_t size = ZEND_TYPE_LIST_SIZE(old_list->num_types);
67-
zend_type_list *new_list = ZEND_TYPE_USES_ARENA(*type)
68-
? zend_arena_alloc(&CG(arena), size) : pemalloc(size, persistent);
69-
memcpy(new_list, old_list, ZEND_TYPE_LIST_SIZE(old_list->num_types));
70-
ZEND_TYPE_SET_PTR(*type, new_list);
71-
72-
zend_type *list_type;
73-
ZEND_TYPE_LIST_FOREACH(new_list, list_type) {
74-
ZEND_ASSERT(ZEND_TYPE_HAS_NAME(*list_type));
75-
zend_string_addref(ZEND_TYPE_NAME(*list_type));
76-
} ZEND_TYPE_LIST_FOREACH_END();
89+
zend_type_list_copy_ctor(type, use_arena, persistent);
7790
} else if (ZEND_TYPE_HAS_NAME(*type)) {
7891
zend_string_addref(ZEND_TYPE_NAME(*type));
7992
}
@@ -2506,7 +2519,8 @@ static void zend_do_traits_property_binding(zend_class_entry *ce, zend_class_ent
25062519
doc_comment = property_info->doc_comment ? zend_string_copy(property_info->doc_comment) : NULL;
25072520

25082521
zend_type type = property_info->type;
2509-
zend_type_copy_ctor(&type, /* persistent */ 0);
2522+
/* Assumption: only userland classes can use traits, as such the type must be arena allocated */
2523+
zend_type_copy_ctor(&type, /* use arena */ true, /* persistent */ false);
25102524
new_prop = zend_declare_typed_property(ce, prop_name, prop_value, flags, doc_comment, type);
25112525

25122526
if (property_info->attributes) {
@@ -2920,15 +2934,8 @@ static zend_class_entry *zend_lazy_class_load(zend_class_entry *pce)
29202934
Z_PTR(p->val) = new_prop_info;
29212935
memcpy(new_prop_info, prop_info, sizeof(zend_property_info));
29222936
new_prop_info->ce = ce;
2923-
if (ZEND_TYPE_HAS_LIST(new_prop_info->type)) {
2924-
zend_type_list *new_list;
2925-
zend_type_list *list = ZEND_TYPE_LIST(new_prop_info->type);
2926-
2927-
new_list = zend_arena_alloc(&CG(arena), ZEND_TYPE_LIST_SIZE(list->num_types));
2928-
memcpy(new_list, list, ZEND_TYPE_LIST_SIZE(list->num_types));
2929-
ZEND_TYPE_SET_PTR(new_prop_info->type, list);
2930-
ZEND_TYPE_FULL_MASK(new_prop_info->type) |= _ZEND_TYPE_ARENA_BIT;
2931-
}
2937+
/* Deep copy the type information */
2938+
zend_type_copy_ctor(&new_prop_info->type, /* use_arena */ true, /* persistent */ false);
29322939
}
29332940
}
29342941

Zend/zend_opcode.c

+2-10
Original file line numberDiff line numberDiff line change
@@ -110,17 +110,9 @@ ZEND_API void destroy_zend_function(zend_function *function)
110110

111111
ZEND_API void zend_type_release(zend_type type, bool persistent) {
112112
if (ZEND_TYPE_HAS_LIST(type)) {
113-
zend_type *list_type, *sublist_type;
113+
zend_type *list_type;
114114
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(type), list_type) {
115-
if (ZEND_TYPE_HAS_LIST(*list_type)) {
116-
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(*list_type), sublist_type) {
117-
if (ZEND_TYPE_HAS_NAME(*sublist_type)) {
118-
zend_string_release(ZEND_TYPE_NAME(*sublist_type));
119-
}
120-
} ZEND_TYPE_LIST_FOREACH_END();
121-
} else if (ZEND_TYPE_HAS_NAME(*list_type)) {
122-
zend_string_release(ZEND_TYPE_NAME(*list_type));
123-
}
115+
zend_type_release(*list_type, persistent);
124116
} ZEND_TYPE_LIST_FOREACH_END();
125117
if (!ZEND_TYPE_USES_ARENA(type)) {
126118
pefree(ZEND_TYPE_LIST(type), persistent);

ext/zend_test/test.stub.php

+1
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ public function returnsThrowable(): Exception {}
6363
trait _ZendTestTrait {
6464
/** @var mixed */
6565
public $testProp;
66+
public Traversable|Countable $classUnionProp;
6667

6768
public function testMethod(): bool {}
6869
}

ext/zend_test/test_arginfo.h

+14-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)