Skip to content

Reflection exception messages truncate on null bytes #22905

Closed

Description

@DanielEScherzer

After #22681 I looked into exception messages:

Reflection*::getAttributes() with ReflectionAttribute::IS_INSTANCEOF
<?php

class Demo {}
$r = new ReflectionClass(Demo::class);
$r->getAttributes("foo\0bar", ReflectionAttribute::IS_INSTANCEOF);
ReflectionFunction::__construct()
<?php

new ReflectionFunction("foo\0bar");
ReflectionParameter::__construct() with string function
<?php

new ReflectionParameter("foo\0bar", 0);
ReflectionParameter::__construct() with array with class name
<?php

new ReflectionParameter(["foo\0bar", ""], 0);
ReflectionParameter::__construct() with array with method name
<?php

class Demo {}
new ReflectionParameter([Demo::class, "foo\0bar"], 0);
ReflectionMethod::__construct() with class name
<?php

new ReflectionMethod("foo\0bar", "");
ReflectionMethod::__construct() with method name
<?php

class Demo {}
new ReflectionMethod(Demo::class, "foo\0bar");

the above should also apply to ReflectionMethod::createFromMethodName() - they share the same lookup code

ReflectionClassConstant::__construct() with class name
<?php

new ReflectionClassConstant("foo\0bar", "");
ReflectionClassConstant::__construct() with constant name
<?php

class Demo {}
new ReflectionClassConstant(Demo::class, "foo\0bar");
ReflectionClass::__construct()
<?php

new ReflectionClass("foo\0bar");
ReflectionClass::getStaticPropertyValue()
<?php

class Demo {}
$r = new ReflectionClass(Demo::class);
$r->getStaticPropertyValue("foo\0bar");
ReflectionClass::setStaticPropertyValue()
<?php

class Demo {}
$r = new ReflectionClass(Demo::class);
$r->setStaticPropertyValue("foo\0bar", 123);
ReflectionClass::getMethod()
<?php

class Demo {}
$r = new ReflectionClass(Demo::class);
$r->getMethod("foo\0bar");
ReflectionClass::getProperty()
<?php

class Demo {}
$r = new ReflectionClass(Demo::class);
$r->getProperty("foo\0bar");
ReflectionClass::getProperty() (fully qualified)
<?php

class Base {}
class Demo {}
$r = new ReflectionClass(Demo::class);
$r->getProperty("Base::foo\0bar");
ReflectionClass::isSubclassOf()
<?php

class Demo {}
$r = new ReflectionClass(Demo::class);
$r->isSubclassOf("foo\0bar");
ReflectionClass::implementsInterface()
<?php

class Demo {}
$r = new ReflectionClass(Demo::class);
$r->implementsInterface("foo\0bar");
ReflectionProperty::__construct() with class name
<?php

new ReflectionProperty("foo\0bar", "");
ReflectionProperty::__construct() with property name
<?php

class Demo {}
new ReflectionProperty(Demo::class, "foo\0bar");
ReflectionProperty::skipLazyInitialization() with property name
<?php

$o = (object)["foo\0bar" => "baz"];
$r = new ReflectionProperty($o, "foo\0bar");
$r->skipLazyInitialization($o);

also affects anything else using reflection_property_check_lazy_compatible()

ReflectionEnum::getCase() with missing case
<?php

enum Demo {}
$r = new ReflectionEnum(Demo::class);
$r->getCase("foo\0bar");
ReflectionConstant::__construct()
<?php

new ReflectionConstant("foo\0bar");

Activity

  1. DanielEScherzer commented on Jul 28, 2026

    @DanielEScherzer
    MemberAuthor

    @Girgias on #22685 on the initial version you wrote

    I think I would prefer just two calls: one for the indent, and one for the doc comment. As this const char* cludge might no longer work if the compiler gets smarter.

    with regards to stuff like

      	// %S is used for zend_string pointers by smart str printing, but normally
      	// is for wide character strings and so compilers complain if this is inline
      	const char *format = "%s%S";
      	smart_str_append_printf(str, format, indent, ce->doc_comment);
    

    unfortunately, there doesn't seem to be an easy way to do something similar for exception message printing, and there isn't an _unchecked variant of zend_throw_exception_ex() or similar. Would you be okay with me using %S here in the exception messages (for 8.4+) and then adding an _unchecked variant of the throwing for master?

  2. Girgias commented on Jul 28, 2026

    @Girgias
    Member

    Yeah, I guess for a bugfix that's fine.

  3. DanielEScherzer commented on Jul 29, 2026

    @DanielEScherzer
    MemberAuthor

    Turns out even using %S doesn't work without some extra fixes

    because

  4. DanielEScherzer commented on Aug 3, 2026

    @DanielEScherzer
    MemberAuthor

    Also

    ReflectionZendExtension::__construct():

    <?php
    
    new ReflectionZendExtension("foo\0bar");

    and ReflectionExtension::__construct():

    <?php
    
    new ReflectionExtension("foo\0bar");
  5. added 2 commits that reference this issue on Aug 3, 2026
  6. added a commit that references this issue on Aug 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions