From c89d4c33a82fcf8e2809514de51c362caa70528e Mon Sep 17 00:00:00 2001 From: Jorg Sowa Date: Thu, 12 Nov 2026 12:34:47 +0100 Subject: [PATCH] Fix var_dump() printing full anonymous class name with NUL byte The %pS migration made var_dump() and debug_zval_dump() print the whole anonymous class name, including the NUL byte and file path, while property labels and print_r() still show class@anonymous. --- NEWS | 4 +++ Zend/tests/anon/012.phpt | 4 +-- Zend/tests/anon/013.phpt | 4 +-- Zend/tests/bug72598.phpt | 4 +-- Zend/tests/bug73816.phpt | 6 ++-- Zend/tests/constexpr/new_anon_class.phpt | 4 +-- .../partial_application/static_pfa_004.phpt | 2 +- .../property_hooks/oss_fuzz_403308724.phpt | 4 +-- .../typed_properties_001.phpt | 2 +- .../typed_properties_033.phpt | 2 +- .../typed_properties_034.phpt | 2 +- .../typed_properties_037.phpt | 2 +- .../typed_properties_038.phpt | 8 +++--- ext/opcache/tests/bug78937_1.phpt | 2 +- ext/opcache/tests/bug78937_2.phpt | 2 +- ext/opcache/tests/preload_008.phpt | 4 +-- .../tests/ReflectionGenerator_basic.phpt | 4 +-- ext/standard/tests/array/compact_this.phpt | 8 +++--- .../get_object_vars_variation_004.phpt | 4 +-- .../debug_zval_dump_gh19801_memory_leak.phpt | 2 +- .../var_dump_anon_class_name.phpt | 28 +++++++++++++++++++ .../var_dump_gh19801_memory_leak.phpt | 2 +- ext/standard/var.c | 6 ++-- 23 files changed, 72 insertions(+), 38 deletions(-) create mode 100644 ext/standard/tests/general_functions/var_dump_anon_class_name.phpt diff --git a/NEWS b/NEWS index 92cf423f60af..c5418523ae08 100644 --- a/NEWS +++ b/NEWS @@ -120,6 +120,10 @@ PHP NEWS . Fix ReflectionProperty::isReadable() not working for indirect slots. (ndossche) +- Standard: + . Fixed var_dump() and debug_zval_dump() printing the full name of anonymous + classes, including the NUL byte. (Jorg Sowa) + - Streams: . Fixed in-place URL decoding of interned strings in the HTTP and FTP wrappers. (Alejandro Pacheco) diff --git a/Zend/tests/anon/012.phpt b/Zend/tests/anon/012.phpt index 74bf25518e4c..d82f237c1c8c 100644 --- a/Zend/tests/anon/012.phpt +++ b/Zend/tests/anon/012.phpt @@ -4,8 +4,8 @@ Ensure correct unmangling of private property names for anonymous class instance ---EXPECTF-- -object(class@anonymous%0%s)#1 (1) { +--EXPECT-- +object(class@anonymous)#1 (1) { ["foo":"class@anonymous":private]=> NULL } diff --git a/Zend/tests/anon/013.phpt b/Zend/tests/anon/013.phpt index 298ae7837428..b66be660d70c 100644 --- a/Zend/tests/anon/013.phpt +++ b/Zend/tests/anon/013.phpt @@ -10,6 +10,6 @@ $foo = function() { $closure = Closure::bind($foo, $class, $class); var_dump($closure()); ?> ---EXPECTF-- -object(class@anonymous%0%s)#1 (0) { +--EXPECT-- +object(class@anonymous)#1 (0) { } diff --git a/Zend/tests/bug72598.phpt b/Zend/tests/bug72598.phpt index d546332c79f4..741abc35e227 100644 --- a/Zend/tests/bug72598.phpt +++ b/Zend/tests/bug72598.phpt @@ -18,9 +18,9 @@ new class { ?> --EXPECTF-- Warning: ref(): Argument #1 ($ref) must be passed by reference, value given in %s on line %d -object(class@anonymous%0%s)#1 (0) { +object(class@anonymous)#1 (0) { } Warning: ref(): Argument #1 ($ref) must be passed by reference, value given in %s on line %d -object(class@anonymous%0%s)#1 (0) { +object(class@anonymous)#1 (0) { } diff --git a/Zend/tests/bug73816.phpt b/Zend/tests/bug73816.phpt index 08f735607880..aea392be5e18 100644 --- a/Zend/tests/bug73816.phpt +++ b/Zend/tests/bug73816.phpt @@ -13,12 +13,12 @@ var_dump(anon()); var_dump(anon()); ?> ---EXPECTF-- -object(class@anonymous%0%s)#1 (1) { +--EXPECT-- +object(class@anonymous)#1 (1) { ["prop1":"class@anonymous":private]=> NULL } -object(class@anonymous%0%s)#1 (1) { +object(class@anonymous)#1 (1) { ["prop2":"class@anonymous":private]=> NULL } diff --git a/Zend/tests/constexpr/new_anon_class.phpt b/Zend/tests/constexpr/new_anon_class.phpt index 197f594f6881..49fc120f6b92 100644 --- a/Zend/tests/constexpr/new_anon_class.phpt +++ b/Zend/tests/constexpr/new_anon_class.phpt @@ -8,6 +8,6 @@ static $x = new class {}; var_dump($x); ?> ---EXPECTF-- -object(class@anonymous%0%s)#1 (0) { +--EXPECT-- +object(class@anonymous)#1 (0) { } diff --git a/Zend/tests/partial_application/static_pfa_004.phpt b/Zend/tests/partial_application/static_pfa_004.phpt index 9a7de941bf43..093430232d43 100644 --- a/Zend/tests/partial_application/static_pfa_004.phpt +++ b/Zend/tests/partial_application/static_pfa_004.phpt @@ -39,6 +39,6 @@ Closure [ function {closure:pfa:%s:13} ] { Error: Using $this when not in object context # Re-bound PFA -object(class@anonymous%0%s)#3 (0) { +object(class@anonymous)#3 (0) { } bool(true) diff --git a/Zend/tests/property_hooks/oss_fuzz_403308724.phpt b/Zend/tests/property_hooks/oss_fuzz_403308724.phpt index 683814387f4d..b27b08dd703b 100644 --- a/Zend/tests/property_hooks/oss_fuzz_403308724.phpt +++ b/Zend/tests/property_hooks/oss_fuzz_403308724.phpt @@ -19,10 +19,10 @@ $y = $test->y; var_dump($y); var_dump($y[0]->inner); ?> ---EXPECTF-- +--EXPECT-- array(2) { [0]=> - object(class@anonymous%0%s)#2 (0) { + object(class@anonymous)#2 (0) { } [1]=> int(1) diff --git a/Zend/tests/type_declarations/typed_properties_001.phpt b/Zend/tests/type_declarations/typed_properties_001.phpt index d6136642b240..ce791cd4b56e 100644 --- a/Zend/tests/type_declarations/typed_properties_001.phpt +++ b/Zend/tests/type_declarations/typed_properties_001.phpt @@ -21,7 +21,7 @@ var_dump(new class(1, 2.2, true, ["four"], new stdClass) { }); ?> --EXPECTF-- -object(class@anonymous%0%s)#%d (6) { +object(class@anonymous)#%d (6) { ["int"]=> int(1) ["float"]=> diff --git a/Zend/tests/type_declarations/typed_properties_033.phpt b/Zend/tests/type_declarations/typed_properties_033.phpt index b48b54370302..59d5943f1fe5 100644 --- a/Zend/tests/type_declarations/typed_properties_033.phpt +++ b/Zend/tests/type_declarations/typed_properties_033.phpt @@ -26,7 +26,7 @@ var_dump($foo); ?> --EXPECTF-- TypeError: Cannot assign float to reference held by property class@anonymous%0%s::$qux of type int -object(class@anonymous%0%s)#1 (4) { +object(class@anonymous)#1 (4) { ["foo"]=> int(2) ["bar"]=> diff --git a/Zend/tests/type_declarations/typed_properties_034.phpt b/Zend/tests/type_declarations/typed_properties_034.phpt index 9c7f10f91705..1ba07f59bb54 100644 --- a/Zend/tests/type_declarations/typed_properties_034.phpt +++ b/Zend/tests/type_declarations/typed_properties_034.phpt @@ -43,7 +43,7 @@ int(1) int(10) int(10) TypeError: Cannot assign null to reference held by property class@anonymous%0%s::$baz of type int -object(class@anonymous%0%s)#1 (2) { +object(class@anonymous)#1 (2) { ["bar"]=> &int(10) ["baz"]=> diff --git a/Zend/tests/type_declarations/typed_properties_037.phpt b/Zend/tests/type_declarations/typed_properties_037.phpt index 54616103600a..87efa3317a0a 100644 --- a/Zend/tests/type_declarations/typed_properties_037.phpt +++ b/Zend/tests/type_declarations/typed_properties_037.phpt @@ -9,7 +9,7 @@ $foo = new class { var_dump($foo); ?> --EXPECTF-- -object(class@anonymous%0%s)#%d (1) { +object(class@anonymous)#%d (1) { ["bar"]=> int(10) ["qux"]=> diff --git a/Zend/tests/type_declarations/typed_properties_038.phpt b/Zend/tests/type_declarations/typed_properties_038.phpt index d62df628ff8e..0f7ac9b239c7 100644 --- a/Zend/tests/type_declarations/typed_properties_038.phpt +++ b/Zend/tests/type_declarations/typed_properties_038.phpt @@ -41,22 +41,22 @@ var_dump($foo); ?> --EXPECTF-- TypeError: Cannot increment property class@anonymous%0%s::$bar of type int past its maximal value -object(class@anonymous%0%s)#1 (1) { +object(class@anonymous)#1 (1) { ["bar"]=> int(%d) } TypeError: Cannot assign float to property class@anonymous%0%s::$bar of type int -object(class@anonymous%0%s)#1 (1) { +object(class@anonymous)#1 (1) { ["bar"]=> int(%d) } TypeError: Cannot increment property class@anonymous%0%s::$bar of type int past its maximal value -object(class@anonymous%0%s)#1 (1) { +object(class@anonymous)#1 (1) { ["bar"]=> int(%d) } TypeError: Cannot assign float to property class@anonymous%0%s::$bar of type int -object(class@anonymous%0%s)#1 (1) { +object(class@anonymous)#1 (1) { ["bar"]=> int(%d) } diff --git a/ext/opcache/tests/bug78937_1.phpt b/ext/opcache/tests/bug78937_1.phpt index 64c3beed8aee..657b306d68d4 100644 --- a/ext/opcache/tests/bug78937_1.phpt +++ b/ext/opcache/tests/bug78937_1.phpt @@ -19,5 +19,5 @@ var_dump(foo()); ?> --EXPECTF-- Warning: Can't preload unlinked class Bar@anonymous: Unknown parent Bar in %spreload_bug78937.inc on line 3 -object(Bar@anonymous%0%s)#%d (0) { +object(Bar@anonymous)#%d (0) { } diff --git a/ext/opcache/tests/bug78937_2.phpt b/ext/opcache/tests/bug78937_2.phpt index 2415582054d1..eb359cee96be 100644 --- a/ext/opcache/tests/bug78937_2.phpt +++ b/ext/opcache/tests/bug78937_2.phpt @@ -20,5 +20,5 @@ var_dump(foo()); ?> --EXPECTF-- Warning: Can't preload unlinked class Bar@anonymous: Unknown parent Bar in %spreload_bug78937.inc on line 3 -object(Bar@anonymous%0%s)#%d (0) { +object(Bar@anonymous)#%d (0) { } diff --git a/ext/opcache/tests/preload_008.phpt b/ext/opcache/tests/preload_008.phpt index 746f83c00436..c6ae2ce1d3b0 100644 --- a/ext/opcache/tests/preload_008.phpt +++ b/ext/opcache/tests/preload_008.phpt @@ -15,6 +15,6 @@ if (PHP_OS_FAMILY == 'Windows') die('skip Preloading is not supported on Windows ---EXPECTF-- -object(class@anonymous%0%s)#1 (0) { +--EXPECT-- +object(class@anonymous)#1 (0) { } diff --git a/ext/reflection/tests/ReflectionGenerator_basic.phpt b/ext/reflection/tests/ReflectionGenerator_basic.phpt index b541c483e99f..f215bf4c0dd1 100644 --- a/ext/reflection/tests/ReflectionGenerator_basic.phpt +++ b/ext/reflection/tests/ReflectionGenerator_basic.phpt @@ -59,7 +59,7 @@ array(2) { ["class"]=> string(%d) "class@anonymous%s" ["object"]=> - object(class@anonymous%0%s)#%d (0) { + object(class@anonymous)#%d (0) { } ["type"]=> string(2) "->" @@ -80,7 +80,7 @@ object(ReflectionMethod)#8 (2) { ["class"]=> string(%d) "class@anonymous%s" } -object(class@anonymous%0%s)#1 (0) { +object(class@anonymous)#1 (0) { } object(Generator)#%d (1) { ["function"]=> diff --git a/ext/standard/tests/array/compact_this.phpt b/ext/standard/tests/array/compact_this.phpt index b7425c0e8153..f3677e03e276 100644 --- a/ext/standard/tests/array/compact_this.phpt +++ b/ext/standard/tests/array/compact_this.phpt @@ -28,19 +28,19 @@ var_dump( ); ?> ---EXPECTF-- +--EXPECT-- array(1) { ["this"]=> - object(class@anonymous%0%s)#1 (0) { + object(class@anonymous)#1 (0) { } } array(1) { ["this"]=> - object(class@anonymous%0%s)#1 (0) { + object(class@anonymous)#1 (0) { } } array(1) { ["this"]=> - object(class@anonymous%0%s)#1 (0) { + object(class@anonymous)#1 (0) { } } diff --git a/ext/standard/tests/class_object/get_object_vars_variation_004.phpt b/ext/standard/tests/class_object/get_object_vars_variation_004.phpt index a7af049ebd56..84827134c1b1 100644 --- a/ext/standard/tests/class_object/get_object_vars_variation_004.phpt +++ b/ext/standard/tests/class_object/get_object_vars_variation_004.phpt @@ -32,7 +32,7 @@ array(4) { [12]=> int(6) ["test"]=> - object(JsonSerializable@anonymous%0%s)#2 (0) { + object(JsonSerializable@anonymous)#2 (0) { } } array(4) { @@ -43,6 +43,6 @@ array(4) { [12]=> int(6) ["test"]=> - object(JsonSerializable@anonymous%0%s)#2 (0) { + object(JsonSerializable@anonymous)#2 (0) { } } diff --git a/ext/standard/tests/general_functions/debug_zval_dump_gh19801_memory_leak.phpt b/ext/standard/tests/general_functions/debug_zval_dump_gh19801_memory_leak.phpt index 012d0991515a..cf2f1d444f1d 100644 --- a/ext/standard/tests/general_functions/debug_zval_dump_gh19801_memory_leak.phpt +++ b/ext/standard/tests/general_functions/debug_zval_dump_gh19801_memory_leak.phpt @@ -25,7 +25,7 @@ object(stdClass)#2 (1) refcount(%d){ reference refcount(%d) { array(1) packed refcount(%d){ [0]=> - object(class@anonymous%0%s)#1 (0) refcount(%d){ + object(class@anonymous)#1 (0) refcount(%d){ } } } diff --git a/ext/standard/tests/general_functions/var_dump_anon_class_name.phpt b/ext/standard/tests/general_functions/var_dump_anon_class_name.phpt new file mode 100644 index 000000000000..555ad6ad34db --- /dev/null +++ b/ext/standard/tests/general_functions/var_dump_anon_class_name.phpt @@ -0,0 +1,28 @@ +--TEST-- +var_dump() and debug_zval_dump() print the short name of anonymous classes +--FILE-- + +--EXPECT-- +object(class@anonymous)#1 (2) { + ["a"]=> + int(1) + ["p":"class@anonymous":private]=> + NULL +} +object(class@anonymous)#1 (2) refcount(2){ + ["a"]=> + int(1) + ["p":"class@anonymous":private]=> + NULL +} +class@anonymous Object +( + [a] => 1 + [p:class@anonymous:private] => +) diff --git a/ext/standard/tests/general_functions/var_dump_gh19801_memory_leak.phpt b/ext/standard/tests/general_functions/var_dump_gh19801_memory_leak.phpt index 68333d3c884a..f0522916de4e 100644 --- a/ext/standard/tests/general_functions/var_dump_gh19801_memory_leak.phpt +++ b/ext/standard/tests/general_functions/var_dump_gh19801_memory_leak.phpt @@ -24,7 +24,7 @@ object(stdClass)#2 (1) { ["a"]=> &array(1) { [0]=> - object(class@anonymous%0%s)#1 (0) { + object(class@anonymous)#1 (0) { } } } diff --git a/ext/standard/var.c b/ext/standard/var.c index c7db83f0062a..384b5f8ade6c 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -196,7 +196,8 @@ PHPAPI void php_var_dump(zval *struc, int level) /* {{{ */ class_name = Z_OBJ_HANDLER_P(struc, get_class_name)(Z_OBJ_P(struc)); const char *prefix = php_var_dump_object_prefix(Z_OBJ_P(struc)); - php_printf("%s%sobject(%pS)#%d (%d) {\n", COMMON, prefix, class_name, Z_OBJ_HANDLE_P(struc), myht ? zend_array_count(myht) : 0); + /* %s keeps anonymous class names short, matching property labels and print_r(). */ + php_printf("%s%sobject(%s)#%d (%d) {\n", COMMON, prefix, ZSTR_VAL(class_name), Z_OBJ_HANDLE_P(struc), myht ? zend_array_count(myht) : 0); zend_string_release_ex(class_name, 0); } @@ -407,7 +408,8 @@ PHPAPI void php_debug_zval_dump(zval *struc, int level) /* {{{ */ class_name = Z_OBJ_HANDLER_P(struc, get_class_name)(Z_OBJ_P(struc)); const char *prefix = php_var_dump_object_prefix(Z_OBJ_P(struc)); - php_printf("%sobject(%pS)#%d (%d) refcount(%u){\n", prefix, class_name, Z_OBJ_HANDLE_P(struc), myht ? zend_array_count(myht) : 0, Z_REFCOUNT_P(struc)); + /* %s keeps anonymous class names short, matching property labels and print_r(). */ + php_printf("%sobject(%s)#%d (%d) refcount(%u){\n", prefix, ZSTR_VAL(class_name), Z_OBJ_HANDLE_P(struc), myht ? zend_array_count(myht) : 0, Z_REFCOUNT_P(struc)); zend_string_release_ex(class_name, 0); if (myht) { ZEND_HASH_FOREACH_KEY_VAL(myht, index, key, val) {