Skip to content

Commit f9fbba4

Browse files
danognikic
authored andcommitted
Fixed bug #80596: Fix anonymous class union typehint errors
Cut off part after null byte when resolving the class name, to avoid cutting off a larger part lateron. Closes GH-6601.
1 parent 3edf5c9 commit f9fbba4

File tree

3 files changed

+45
-3
lines changed

3 files changed

+45
-3
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ PHP NEWS
66
. Fixed bug #80523 (bogus parse error on >4GB source code). (Nikita)
77
. Fixed bug #80384 (filter buffers entire read until file closed). (Adam
88
Seitz, cmb)
9+
. Fixed bug #80596 (Invalid union type TypeError in anonymous classes).
10+
(Daniil Gentili)
911

1012
- BCMath:
1113
. Fixed bug #80545 (bcadd('a', 'a') doesn't throw an exception).
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
--TEST--
2+
Union with anonymous class type
3+
--FILE--
4+
<?php
5+
6+
$a = new class {
7+
public function testParam(self|string $a)
8+
{
9+
}
10+
public function test(): self|string
11+
{
12+
return new \stdClass;
13+
}
14+
};
15+
16+
try {
17+
$a->testParam(null);
18+
} catch (\Throwable $e) {
19+
echo $e->getMessage()."\n";
20+
}
21+
22+
try {
23+
$a->test();
24+
} catch (\Throwable $e) {
25+
echo $e->getMessage()."\n";
26+
}
27+
?>
28+
--EXPECTF--
29+
class@anonymous(): Argument #1 ($a) must be of type class@anonymous|string, null given, called in %s on line %d
30+
class@anonymous::test(): Return value must be of type class@anonymous|string, stdClass returned

Zend/zend_compile.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1167,7 +1167,15 @@ static zend_string *resolve_class_name(zend_string *name, zend_class_entry *scop
11671167
name = scope->parent->name;
11681168
}
11691169
}
1170-
return name;
1170+
1171+
/* The resolved name for anonymous classes contains null bytes. Cut off everything after the
1172+
* null byte here, to avoid larger parts of the type being omitted by printing code later. */
1173+
size_t len = strlen(ZSTR_VAL(name));
1174+
if (len != ZSTR_LEN(name)) {
1175+
ZEND_ASSERT(scope && "This should only happen with resolved types");
1176+
return zend_string_init(ZSTR_VAL(name), len, 0);
1177+
}
1178+
return zend_string_copy(name);
11711179
}
11721180

11731181
zend_string *zend_type_to_string_resolved(zend_type type, zend_class_entry *scope) {
@@ -1179,11 +1187,13 @@ zend_string *zend_type_to_string_resolved(zend_type type, zend_class_entry *scop
11791187
if (ZEND_TYPE_HAS_CE(*list_type)) {
11801188
str = add_type_string(str, ZEND_TYPE_CE(*list_type)->name);
11811189
} else {
1182-
str = add_type_string(str, resolve_class_name(ZEND_TYPE_NAME(*list_type), scope));
1190+
zend_string *resolved = resolve_class_name(ZEND_TYPE_NAME(*list_type), scope);
1191+
str = add_type_string(str, resolved);
1192+
zend_string_release(resolved);
11831193
}
11841194
} ZEND_TYPE_LIST_FOREACH_END();
11851195
} else if (ZEND_TYPE_HAS_NAME(type)) {
1186-
str = zend_string_copy(resolve_class_name(ZEND_TYPE_NAME(type), scope));
1196+
str = resolve_class_name(ZEND_TYPE_NAME(type), scope);
11871197
} else if (ZEND_TYPE_HAS_CE(type)) {
11881198
str = zend_string_copy(ZEND_TYPE_CE(type)->name);
11891199
}

0 commit comments

Comments
 (0)