[php-src] PHP-8.4: Add regression tests for `Reflection*::__toString()` with null bytes

Daniel Scherzer <[email protected]>
Newsgroups gmane.comp.php.cvs.general
Message-ID <[email protected]>
Author: Daniel Scherzer (DanielEScherzer)
Date: 2026-07-13T14:08:57-07:00

Commit: https://github.com/php/php-src/commit/1db6c840500192ecd26979a199068a23610cbc93
Raw diff: https://github.com/php/php-src/commit/1db6c840500192ecd26979a199068a23610cbc93.diff

Add regression tests for `Reflection*::__toString()` with null bytes

So that when the outputs are fixed the changes can be confirmed in tests

Changed paths:
  A  ext/reflection/tests/gh22681/ReflectionClassConstant_doc_comment.phpt
  A  ext/reflection/tests/gh22681/ReflectionClass_doc_comment.phpt
  A  ext/reflection/tests/gh22681/ReflectionConstant_name.phpt
  A  ext/reflection/tests/gh22681/ReflectionEnum_case_doc_comment.phpt
  A  ext/reflection/tests/gh22681/ReflectionExtension_ini_value.phpt
  A  ext/reflection/tests/gh22681/ReflectionFunctionAbstract_doc_comment.phpt
  A  ext/reflection/tests/gh22681/ReflectionProperty_doc_comment.phpt
  A  ext/reflection/tests/gh22681/ReflectionProperty_dynamic_name.phpt


Diff:

diff --git a/ext/reflection/tests/gh22681/ReflectionClassConstant_doc_comment.phpt b/ext/reflection/tests/gh22681/ReflectionClassConstant_doc_comment.phpt
new file mode 100644
index 000000000000..49d646a4a191
--- /dev/null
+++ b/ext/reflection/tests/gh22681/ReflectionClassConstant_doc_comment.phpt
@@ -0,0 +1,44 @@
+--TEST--
+GH-22681: null bytes in doc comment truncate ReflectionClassConstant::__toString()
+--FILE--
+<?php
+
+eval(<<<END
+class Demo {
+    /** F\0oo */
+    public const DEMO = true;
+}
+END
+);
+
+$r = new ReflectionClassConstant(Demo::class, 'DEMO');
+echo $r;
+var_dump( $r->getDocComment() );
+
+echo new ReflectionClass(Demo::class);
+
+?>
+--EXPECTF--
+/** F
+Constant [ public bool DEMO ] { 1 }
+string(11) "/** F%0oo */"
+Class [ <user> class Demo ] {
+  @@ %s(%d) : eval()'d code %d-%d
+
+  - Constants [1] {
+    /** F
+    Constant [ public bool DEMO ] { 1 }
+  }
+
+  - Static properties [0] {
+  }
+
+  - Static methods [0] {
+  }
+
+  - Properties [0] {
+  }
+
+  - Methods [0] {
+  }
+}
diff --git a/ext/reflection/tests/gh22681/ReflectionClass_doc_comment.phpt b/ext/reflection/tests/gh22681/ReflectionClass_doc_comment.phpt
new file mode 100644
index 000000000000..c2da0400dcbd
--- /dev/null
+++ b/ext/reflection/tests/gh22681/ReflectionClass_doc_comment.phpt
@@ -0,0 +1,37 @@
+--TEST--
+GH-22681: null bytes in doc comment truncate ReflectionClass::__toString()
+--FILE--
+<?php
+
+eval(<<<END
+/** F\0oo */
+class Demo {}
+END
+);
+
+$r = new ReflectionClass(Demo::class);
+echo $r;
+var_dump( $r->getDocComment() );
+
+?>
+--EXPECTF--
+/** F
+Class [ <user> class Demo ] {
+  @@ %s(%d) : eval()'d code %d-%d
+
+  - Constants [0] {
+  }
+
+  - Static properties [0] {
+  }
+
+  - Static methods [0] {
+  }
+
+  - Properties [0] {
+  }
+
+  - Methods [0] {
+  }
+}
+string(11) "/** F%0oo */"
diff --git a/ext/reflection/tests/gh22681/ReflectionConstant_name.phpt b/ext/reflection/tests/gh22681/ReflectionConstant_name.phpt
new file mode 100644
index 000000000000..a322596fa042
--- /dev/null
+++ b/ext/reflection/tests/gh22681/ReflectionConstant_name.phpt
@@ -0,0 +1,15 @@
+--TEST--
+GH-22681: null bytes in name truncate ReflectionConstant::__toString()
+--FILE--
+<?php
+
+define("F\0oo", true);
+
+$r = new ReflectionConstant("F\0oo");
+echo $r;
+var_dump( $r->getName() );
+
+?>
+--EXPECTF--
+Constant [ bool F ] { 1 }
+string(4) "F%0oo"
diff --git a/ext/reflection/tests/gh22681/ReflectionEnum_case_doc_comment.phpt b/ext/reflection/tests/gh22681/ReflectionEnum_case_doc_comment.phpt
new file mode 100644
index 000000000000..e76c0007c51c
--- /dev/null
+++ b/ext/reflection/tests/gh22681/ReflectionEnum_case_doc_comment.phpt
@@ -0,0 +1,46 @@
+--TEST--
+GH-22681: null bytes in doc comment truncate ReflectionEnum::__toString()
+--FILE--
+<?php
+
+eval(<<<END
+enum Demo {
+    /** F\0oo */
+    case C;
+}
+END
+);
+
+$r = new ReflectionEnum(Demo::class);
+echo $r;
+var_dump( new ReflectionEnumUnitCase(Demo::class, 'C')->getDocComment() );
+?>
+--EXPECTF--
+Class [ <user> final class Demo implements UnitEnum ] {
+  @@ %s(%d) : eval()'d code %d-%d
+
+  - Constants [1] {
+    /** F
+    Constant [ public Demo C ] { Object }
+  }
+
+  - Static properties [0] {
+  }
+
+  - Static methods [1] {
+    Method [ <internal, prototype UnitEnum> static public method cases ] {
+
+      - Parameters [0] {
+      }
+      - Return [ array ]
+    }
+  }
+
+  - Properties [1] {
+    Property [ public protected(set) readonly string $name ]
+  }
+
+  - Methods [0] {
+  }
+}
+string(11) "/** F%0oo */"
diff --git a/ext/reflection/tests/gh22681/ReflectionExtension_ini_value.phpt b/ext/reflection/tests/gh22681/ReflectionExtension_ini_value.phpt
new file mode 100644
index 000000000000..42777ffd2fd2
--- /dev/null
+++ b/ext/reflection/tests/gh22681/ReflectionExtension_ini_value.phpt
@@ -0,0 +1,23 @@
+--TEST--
+GH-22681: null bytes in INI values truncate ReflectionExtension::__toString()
+--FILE--
+<?php
+
+ini_set('arg_separator.output', "f\0oo");
+$r = new ReflectionExtension('core');
+$str = (string)$r;
+$index = strpos($str, 'Entry [ arg_separator.output');
+$str = substr($str, $index);
+$index = strpos($str, 'Entry', 1);
+$str = substr($str, 0, $index);
+echo $str . "\n";
+var_dump( $r->getINIEntries()['arg_separator.output'] );
+
+?>
+--EXPECTF--
+Entry [ arg_separator.output <ALL> ]
+      Current = 'f'
+      Default = '&'
+    }
+    
+string(4) "f%0oo"
diff --git a/ext/reflection/tests/gh22681/ReflectionFunctionAbstract_doc_comment.phpt b/ext/reflection/tests/gh22681/ReflectionFunctionAbstract_doc_comment.phpt
new file mode 100644
index 000000000000..b7673de6c567
--- /dev/null
+++ b/ext/reflection/tests/gh22681/ReflectionFunctionAbstract_doc_comment.phpt
@@ -0,0 +1,36 @@
+--TEST--
+GH-22681: null bytes in doc comment truncate ReflectionFunctionAbstract::__toString()
+--FILE--
+<?php
+
+eval(<<<END
+/** F\0oo */
+function demo() {}
+
+class Demo {
+    /** B\0ar */
+    public function demo() {}
+}
+END
+);
+
+$r = new ReflectionFunction('demo');
+echo $r;
+var_dump( $r->getDocComment() );
+
+$r = new ReflectionMethod(Demo::class, 'demo');
+echo $r;
+var_dump( $r->getDocComment() );
+
+?>
+--EXPECTF--
+/** F
+Function [ <user> function demo ] {
+  @@ %s(%d) : eval()'d code %d - %d
+}
+string(11) "/** F%0oo */"
+/** B
+Method [ <user> public method demo ] {
+  @@ %s(%d) : eval()'d code %d - %d
+}
+string(11) "/** B%0ar */"
diff --git a/ext/reflection/tests/gh22681/ReflectionProperty_doc_comment.phpt b/ext/reflection/tests/gh22681/ReflectionProperty_doc_comment.phpt
new file mode 100644
index 000000000000..4f6f7c875e17
--- /dev/null
+++ b/ext/reflection/tests/gh22681/ReflectionProperty_doc_comment.phpt
@@ -0,0 +1,44 @@
+--TEST--
+GH-22681: null bytes in doc comment truncate ReflectionProperty::__toString()
+--FILE--
+<?php
+
+eval(<<<END
+class Demo {
+    /** F\0oo */
+    public \$prop;
+}
+END
+);
+
+$r = new ReflectionProperty(Demo::class, 'prop');
+echo $r;
+var_dump( $r->getDocComment() );
+
+echo new ReflectionClass(Demo::class);
+
+?>
+--EXPECTF--
+/** F
+Property [ public $prop = NULL ]
+string(11) "/** F%0oo */"
+Class [ <user> class Demo ] {
+  @@ %s(%d) : eval()'d code %d-%d
+
+  - Constants [0] {
+  }
+
+  - Static properties [0] {
+  }
+
+  - Static methods [0] {
+  }
+
+  - Properties [1] {
+    /** F
+    Property [ public $prop = NULL ]
+  }
+
+  - Methods [0] {
+  }
+}
diff --git a/ext/reflection/tests/gh22681/ReflectionProperty_dynamic_name.phpt b/ext/reflection/tests/gh22681/ReflectionProperty_dynamic_name.phpt
new file mode 100644
index 000000000000..921a738ea117
--- /dev/null
+++ b/ext/reflection/tests/gh22681/ReflectionProperty_dynamic_name.phpt
@@ -0,0 +1,37 @@
+--TEST--
+GH-22681: null bytes in name truncate ReflectionProperty::__toString()
+--FILE--
+<?php
+
+$obj = (object)["F\0oo" => true];
+$r = new ReflectionProperty($obj, "F\0oo");
+echo $r;
+var_dump( $r->getDocComment() );
+
+echo new ReflectionObject($obj);
+
+?>
+--EXPECT--
+Property [ <dynamic> public $F ]
+bool(false)
+Object of class [ <internal:Core> class stdClass ] {
+
+  - Constants [0] {
+  }
+
+  - Static properties [0] {
+  }
+
+  - Static methods [0] {
+  }
+
+  - Properties [0] {
+  }
+
+  - Dynamic properties [1] {
+    Property [ <dynamic> public $F ]
+  }
+
+  - Methods [0] {
+  }
+}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.