From ccf2ce7cad3161b4989f80b66a54e4b7278f3417 Mon Sep 17 00:00:00 2001 From: Ilia Alshanetsky Date: Fri, 31 Jul 2026 07:56:20 -0400 Subject: [PATCH] Avoid truncation on null bytes in class and function names Follow-up to GH-22681. _class_string() and _function_string() still formatted the class name and the function name with %s, so Reflection*::__toString() cut them at the first NUL. Anonymous class names embed one, both directly and inside the name of a closure declared in such a class. Closes GH-22971 --- ext/reflection/php_reflection.c | 5 +-- .../tests/gh22681/ReflectionClass_name.phpt | 32 +++++++++++++++++++ .../ReflectionFunctionAbstract_name.phpt | 21 ++++++++++++ 3 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 ext/reflection/tests/gh22681/ReflectionClass_name.phpt create mode 100644 ext/reflection/tests/gh22681/ReflectionFunctionAbstract_name.phpt diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 0945c9574c62..ad5397bcf22c 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -364,7 +364,7 @@ static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, const } smart_str_append_printf(str, "class "); } - smart_str_append_printf(str, "%s", ZSTR_VAL(ce->name)); + smart_str_append(str, ce->name); if (ce->parent) { smart_str_append_printf(str, " extends %s", ZSTR_VAL(ce->parent->name)); } @@ -904,7 +904,8 @@ static void _function_string(smart_str *str, zend_function *fptr, zend_class_ent if (fptr->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { smart_str_appendc(str, '&'); } - smart_str_append_printf(str, "%s ] {\n", ZSTR_VAL(fptr->common.function_name)); + smart_str_append(str, fptr->common.function_name); + smart_str_appends(str, " ] {\n"); /* The information where a function is declared is only available for user classes */ if (fptr->type == ZEND_USER_FUNCTION) { smart_str_append_printf(str, "%s @@ %s %d - %d\n", indent, diff --git a/ext/reflection/tests/gh22681/ReflectionClass_name.phpt b/ext/reflection/tests/gh22681/ReflectionClass_name.phpt new file mode 100644 index 000000000000..c1c24b5c2e5f --- /dev/null +++ b/ext/reflection/tests/gh22681/ReflectionClass_name.phpt @@ -0,0 +1,32 @@ +--TEST-- +GH-22681: null bytes in name truncate ReflectionClass::__toString() +--FILE-- +getName() ); + +?> +--EXPECTF-- +Class [ class class@anonymous%0%s ] { + @@ %s %d-%d + + - Constants [0] { + } + + - Static properties [0] { + } + + - Static methods [0] { + } + + - Properties [0] { + } + + - Methods [0] { + } +} +string(%d) "class@anonymous%0%s" diff --git a/ext/reflection/tests/gh22681/ReflectionFunctionAbstract_name.phpt b/ext/reflection/tests/gh22681/ReflectionFunctionAbstract_name.phpt new file mode 100644 index 000000000000..477af1e38fbc --- /dev/null +++ b/ext/reflection/tests/gh22681/ReflectionFunctionAbstract_name.phpt @@ -0,0 +1,21 @@ +--TEST-- +GH-22681: null bytes in name truncate ReflectionFunction::__toString() +--FILE-- +make()); +echo $r; +var_dump( $r->getName() ); + +?> +--EXPECTF-- +Closure [ public method {closure:class@anonymous%0%s::make():%d} ] { + @@ %s %d - %d +} +string(%d) "{closure:class@anonymous%0%s::make():%d}"