From f9fbba41b66e0e9ccd40ff064d00cfe987c2c5bb Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Wed, 13 Jan 2021 10:43:54 +0100 Subject: [PATCH] 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. --- NEWS | 2 ++ .../union_types/anonymous_class.phpt | 30 +++++++++++++++++++ Zend/zend_compile.c | 16 ++++++++-- 3 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 Zend/tests/type_declarations/union_types/anonymous_class.phpt diff --git a/NEWS b/NEWS index 60172e52e2..de07189a17 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,8 @@ PHP NEWS . Fixed bug #80523 (bogus parse error on >4GB source code). (Nikita) . Fixed bug #80384 (filter buffers entire read until file closed). (Adam Seitz, cmb) + . Fixed bug #80596 (Invalid union type TypeError in anonymous classes). + (Daniil Gentili) - BCMath: . Fixed bug #80545 (bcadd('a', 'a') doesn't throw an exception). diff --git a/Zend/tests/type_declarations/union_types/anonymous_class.phpt b/Zend/tests/type_declarations/union_types/anonymous_class.phpt new file mode 100644 index 0000000000..1e009f22b0 --- /dev/null +++ b/Zend/tests/type_declarations/union_types/anonymous_class.phpt @@ -0,0 +1,30 @@ +--TEST-- +Union with anonymous class type +--FILE-- +testParam(null); +} catch (\Throwable $e) { + echo $e->getMessage()."\n"; +} + +try { + $a->test(); +} catch (\Throwable $e) { + echo $e->getMessage()."\n"; +} +?> +--EXPECTF-- +class@anonymous(): Argument #1 ($a) must be of type class@anonymous|string, null given, called in %s on line %d +class@anonymous::test(): Return value must be of type class@anonymous|string, stdClass returned diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 83942be570..e7f2b0b04a 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1167,7 +1167,15 @@ static zend_string *resolve_class_name(zend_string *name, zend_class_entry *scop name = scope->parent->name; } } - return name; + + /* The resolved name for anonymous classes contains null bytes. Cut off everything after the + * null byte here, to avoid larger parts of the type being omitted by printing code later. */ + size_t len = strlen(ZSTR_VAL(name)); + if (len != ZSTR_LEN(name)) { + ZEND_ASSERT(scope && "This should only happen with resolved types"); + return zend_string_init(ZSTR_VAL(name), len, 0); + } + return zend_string_copy(name); } 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 if (ZEND_TYPE_HAS_CE(*list_type)) { str = add_type_string(str, ZEND_TYPE_CE(*list_type)->name); } else { - str = add_type_string(str, resolve_class_name(ZEND_TYPE_NAME(*list_type), scope)); + zend_string *resolved = resolve_class_name(ZEND_TYPE_NAME(*list_type), scope); + str = add_type_string(str, resolved); + zend_string_release(resolved); } } ZEND_TYPE_LIST_FOREACH_END(); } else if (ZEND_TYPE_HAS_NAME(type)) { - str = zend_string_copy(resolve_class_name(ZEND_TYPE_NAME(type), scope)); + str = resolve_class_name(ZEND_TYPE_NAME(type), scope); } else if (ZEND_TYPE_HAS_CE(type)) { str = zend_string_copy(ZEND_TYPE_CE(type)->name); } -- 2.50.1