]> granicus.if.org Git - php/commitdiff
Fixed bug #80596: Fix anonymous class union typehint errors
authorDaniil Gentili <daniil@daniil.it>
Wed, 13 Jan 2021 09:43:54 +0000 (10:43 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Thu, 14 Jan 2021 09:04:27 +0000 (10:04 +0100)
Cut off part after null byte when resolving the class name, to
avoid cutting off a larger part lateron.

Closes GH-6601.

NEWS
Zend/tests/type_declarations/union_types/anonymous_class.phpt [new file with mode: 0644]
Zend/zend_compile.c

diff --git a/NEWS b/NEWS
index 60172e52e292e4a4a0b84b7fe65363978749073c..de07189a17fdc48d67e03f16c626cca5b15e1ab0 100644 (file)
--- 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 (file)
index 0000000..1e009f2
--- /dev/null
@@ -0,0 +1,30 @@
+--TEST--
+Union with anonymous class type
+--FILE--
+<?php
+
+$a = new class {
+    public function testParam(self|string $a)
+    {
+    }
+    public function test(): self|string
+    {
+        return new \stdClass;
+    }
+};
+
+try {
+    $a->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
index 83942be57015c499583c21da11be8446f5711808..e7f2b0b04a01620165270b72a2b8bd2db24974e0 100644 (file)
@@ -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);
        }