Commit f4397bd1a8b for php.net
commit f4397bd1a8b5df835526b4bd81d3aaa85fd0ee2e
Merge: 84f789e6a50 97e0b1c7853
Author: Daniel Scherzer <daniel.e.scherzer@gmail.com>
Date: Mon Aug 3 10:46:00 2026 -0700
Merge branch 'PHP-8.5'
* PHP-8.5:
NEWS for PHP 8.5
NEWS for PHP 8.4
GH-22905: avoid truncation on null bytes in reflection exceptions
Reflection: Add regression tests for error messages with null bytes
diff --cc ext/reflection/php_reflection.c
index c2dbbb38897,9aa6a908627..8fa8593387d
--- a/ext/reflection/php_reflection.c
+++ b/ext/reflection/php_reflection.c
@@@ -1697,11 -1791,25 +1700,14 @@@ ZEND_METHOD(ReflectionFunction, __const
if (closure_obj) {
fptr = (zend_function*)zend_get_closure_method_def(closure_obj);
} else {
- if (UNEXPECTED(ZSTR_VAL(fname)[0] == '\\')) {
- /* Ignore leading "\" */
- ALLOCA_FLAG(use_heap)
- ZSTR_ALLOCA_ALLOC(lcname, ZSTR_LEN(fname) - 1, use_heap);
- zend_str_tolower_copy(ZSTR_VAL(lcname), ZSTR_VAL(fname) + 1, ZSTR_LEN(fname) - 1);
- fptr = zend_fetch_function(lcname);
- ZSTR_ALLOCA_FREE(lcname, use_heap);
- } else {
- lcname = zend_string_tolower(fname);
- fptr = zend_fetch_function(lcname);
- zend_string_release(lcname);
- }
+ fptr = zend_fetch_function(fname);
if (fptr == NULL) {
+ // %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 = "Function %S() does not exist";
zend_throw_exception_ex(reflection_exception_ptr, 0,
- "Function %s() does not exist", ZSTR_VAL(fname));
+ format, fname);
RETURN_THROWS();
}
}
@@@ -2417,84 -2555,105 +2423,93 @@@ ZEND_METHOD(ReflectionParameter, __cons
/* First, find the function */
switch (Z_TYPE_P(reference)) {
- case IS_STRING:
- {
- zend_string *fname = Z_STR_P(reference);
- zend_string *lcname;
- if (UNEXPECTED(ZSTR_VAL(fname)[0] == '\\')) {
- /* Ignore leading "\" */
- ALLOCA_FLAG(use_heap)
- ZSTR_ALLOCA_ALLOC(lcname, ZSTR_LEN(fname) - 1, use_heap);
- zend_str_tolower_copy(ZSTR_VAL(lcname), ZSTR_VAL(fname) + 1, ZSTR_LEN(fname) - 1);
- fptr = zend_fetch_function(lcname);
- ZSTR_ALLOCA_FREE(lcname, use_heap);
- } else {
- lcname = zend_string_tolower(fname);
- fptr = zend_fetch_function(lcname);
- zend_string_release(lcname);
- }
- if (!fptr) {
- // %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 = "Function %S() does not exist";
- zend_throw_exception_ex(reflection_exception_ptr, 0,
- format, Z_STR_P(reference));
- RETURN_THROWS();
- }
- ce = fptr->common.scope;
+ case IS_STRING: {
+ zend_string *fname = Z_STR_P(reference);
+ fptr = zend_fetch_function(fname);
+ if (!fptr) {
++ // %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 = "Function %S() does not exist";
+ zend_throw_exception_ex(reflection_exception_ptr, 0,
- "Function %s() does not exist", Z_STRVAL_P(reference));
++ format, Z_STR_P(reference));
+ RETURN_THROWS();
}
+ ce = fptr->common.scope;
break;
+ }
case IS_ARRAY: {
- zval *classref;
- zval *method;
- zend_string *name, *lcname;
-
- if (((classref = zend_hash_index_find(Z_ARRVAL_P(reference), 0)) == NULL)
- || ((method = zend_hash_index_find(Z_ARRVAL_P(reference), 1)) == NULL))
- {
- _DO_THROW("Expected array($object, $method) or array($classname, $method)");
- RETURN_THROWS();
- }
-
- if (Z_TYPE_P(classref) == IS_OBJECT) {
- ce = Z_OBJCE_P(classref);
- } else {
- name = zval_try_get_string(classref);
- if (UNEXPECTED(!name)) {
- return;
- }
- if ((ce = zend_lookup_class(name)) == NULL) {
- // %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 = "Class \"%S\" does not exist";
- zend_throw_exception_ex(reflection_exception_ptr, 0,
- format, name);
- zend_string_release(name);
- RETURN_THROWS();
- }
- zend_string_release(name);
- }
+ zval *classref;
+ zval *method;
+ zend_string *name;
+
+ if (((classref = zend_hash_index_find(Z_ARRVAL_P(reference), 0)) == NULL)
+ || ((method = zend_hash_index_find(Z_ARRVAL_P(reference), 1)) == NULL)
+ ) {
+ zend_throw_exception(reflection_exception_ptr, "Expected array($object, $method) or array($classname, $method)", 0);
+ RETURN_THROWS();
+ }
- name = zval_try_get_string(method);
+ if (Z_TYPE_P(classref) == IS_OBJECT) {
+ ce = Z_OBJCE_P(classref);
+ } else {
+ name = zval_try_get_string(classref);
if (UNEXPECTED(!name)) {
return;
}
-
- lcname = zend_string_tolower(name);
- if (Z_TYPE_P(classref) == IS_OBJECT && is_closure_invoke(ce, lcname)
- && (fptr = zend_get_closure_invoke_method(Z_OBJ_P(classref))) != NULL)
- {
- /* nothing to do. don't set is_closure since is the invoke handler,
- not the closure itself */
- } else if ((fptr = zend_hash_find_ptr(&ce->function_table, lcname)) == NULL) {
+ if ((ce = zend_lookup_class(name)) == NULL) {
+ // %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 = "Method %S::%S() does not exist";
++ const char *format = "Class \"%S\" does not exist";
zend_throw_exception_ex(reflection_exception_ptr, 0,
- "Class \"%s\" does not exist", ZSTR_VAL(name));
- format, ce->name, name);
++ format, name);
zend_string_release(name);
- zend_string_release(lcname);
RETURN_THROWS();
}
zend_string_release(name);
+ }
+
+ name = zval_try_get_string(method);
+ if (UNEXPECTED(!name)) {
+ return;
+ }
+
+ zend_string *lcname = zend_string_tolower(name);
+ if (Z_TYPE_P(classref) == IS_OBJECT && is_closure_invoke(ce, lcname)
+ && (fptr = zend_get_closure_invoke_method(Z_OBJ_P(classref))) != NULL)
+ {
+ /* nothing to do. don't set is_closure since is the invoke handler,
+ not the closure itself */
+ } else if ((fptr = zend_hash_find_ptr(&ce->function_table, lcname)) == NULL) {
++ // %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 = "Method %S::%S() does not exist";
+ zend_throw_exception_ex(reflection_exception_ptr, 0,
- "Method %s::%s() does not exist", ZSTR_VAL(ce->name), ZSTR_VAL(name));
++ format, ce->name, name);
+ zend_string_release(name);
zend_string_release(lcname);
+ RETURN_THROWS();
}
+ zend_string_release(name);
+ zend_string_release(lcname);
break;
+ }
case IS_OBJECT: {
- ce = Z_OBJCE_P(reference);
-
- if (instanceof_function(ce, zend_ce_closure)) {
- fptr = (zend_function *)zend_get_closure_method_def(Z_OBJ_P(reference));
- Z_ADDREF_P(reference);
- is_closure = 1;
- } else if ((fptr = zend_hash_find_ptr(&ce->function_table, ZSTR_KNOWN(ZEND_STR_MAGIC_INVOKE))) == NULL) {
- zend_throw_exception_ex(reflection_exception_ptr, 0,
- "Method %s::%s() does not exist", ZSTR_VAL(ce->name), ZEND_INVOKE_FUNC_NAME);
- RETURN_THROWS();
- }
+ ce = Z_OBJCE_P(reference);
+
+ // No need for instanceof_function, the Closure class is final
+ if (ce == zend_ce_closure) {
+ fptr = (zend_function *)zend_get_closure_method_def(Z_OBJ_P(reference));
+ Z_ADDREF_P(reference);
+ is_closure = true;
+ } else if ((fptr = zend_hash_find_ptr(&ce->function_table, ZSTR_KNOWN(ZEND_STR_MAGIC_INVOKE))) == NULL) {
+ zend_throw_exception_ex(reflection_exception_ptr, 0,
+ "Method %s::%s() does not exist", ZSTR_VAL(ce->name), ZEND_INVOKE_FUNC_NAME);
+ RETURN_THROWS();
}
break;
+ }
default:
zend_argument_error(reflection_exception_ptr, 1, "must be a string, an array(class, method), or a callable object, %s given", zend_zval_value_name(reference));
@@@ -3243,18 -3424,20 +3261,26 @@@ static void instantiate_reflection_meth
&& memcmp(lcname, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0
&& (mptr = zend_get_closure_invoke_method(orig_obj)) != NULL)
{
- /* do nothing, mptr already set */
+ /* Store the original closure object so we can validate it in invoke/invokeArgs.
+ * Each closure has a unique __invoke signature, so we must reject different closures. */
+ zval_ptr_dtor(&intern->obj);
+ ZVAL_OBJ_COPY(&intern->obj, orig_obj);
} else if ((mptr = zend_hash_str_find_ptr(&ce->function_table, lcname, method_name_len)) == NULL) {
efree(lcname);
+ // %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 = "Method %S::%S() does not exist";
+ ALLOCA_FLAG(use_heap);
+ zend_string *method_name_zstr;
+ ZSTR_ALLOCA_INIT(method_name_zstr, method_name, method_name_len, use_heap);
zend_throw_exception_ex(reflection_exception_ptr, 0,
- "Method %s::%s() does not exist", ZSTR_VAL(ce->name), method_name);
+ format, ce->name, method_name_zstr);
+ ZSTR_ALLOCA_FREE(method_name_zstr, use_heap);
+
RETURN_THROWS();
+ } else {
+ zval_ptr_dtor(&intern->obj);
+ ZVAL_UNDEF(&intern->obj);
}
efree(lcname);
@@@ -3752,19 -3915,26 +3778,25 @@@ ZEND_METHOD(ReflectionClassConstant, __
Z_PARAM_STR(constname)
ZEND_PARSE_PARAMETERS_END();
+ zend_class_entry *ce;
if (classname_obj) {
ce = classname_obj->ce;
- } else {
- if ((ce = zend_lookup_class(classname_str)) == NULL) {
- // %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 = "Class \"%S\" does not exist";
- zend_throw_exception_ex(reflection_exception_ptr, 0, format, classname_str);
- RETURN_THROWS();
- }
+ } else if ((ce = zend_lookup_class(classname_str)) == NULL) {
- zend_throw_exception_ex(reflection_exception_ptr, 0, "Class \"%s\" does not exist", ZSTR_VAL(classname_str));
++ // %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 = "Class \"%S\" does not exist";
++ zend_throw_exception_ex(reflection_exception_ptr, 0, format, classname_str);
+ RETURN_THROWS();
}
- object = ZEND_THIS;
- intern = Z_REFLECTION_P(object);
+ zval *object = ZEND_THIS;
+ reflection_object *intern = Z_REFLECTION_P(object);
if ((constant = zend_hash_find_ptr(CE_CONSTANTS_TABLE(ce), constname)) == NULL) {
- zend_throw_exception_ex(reflection_exception_ptr, 0, "Constant %s::%s does not exist", ZSTR_VAL(ce->name), ZSTR_VAL(constname));
+ // %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 = "Constant %S::%S does not exist";
+ zend_throw_exception_ex(reflection_exception_ptr, 0, format, ce->name, constname);
RETURN_THROWS();
}
@@@ -4013,10 -4198,12 +4045,13 @@@ static void reflection_class_object_cto
ZVAL_OBJ_COPY(&intern->obj, arg_obj);
}
} else {
+ zend_class_entry *ce;
if ((ce = zend_lookup_class(arg_class)) == NULL) {
if (!EG(exception)) {
- zend_throw_exception_ex(reflection_exception_ptr, -1, "Class \"%s\" does not exist", ZSTR_VAL(arg_class));
+ // %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 = "Class \"%S\" does not exist";
+ zend_throw_exception_ex(reflection_exception_ptr, -1, format, arg_class);
}
RETURN_THROWS();
}
@@@ -4191,8 -4378,11 +4229,11 @@@ ZEND_METHOD(ReflectionClass, setStaticP
EG(fake_scope) = old_scope;
if (!variable_ptr) {
zend_clear_exception();
+ // %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 = "Class %S does not have a property named %S";
++ const char *format = "Property %S::$%S does not exist";
zend_throw_exception_ex(reflection_exception_ptr, 0,
- "Property %s::$%s does not exist", ZSTR_VAL(ce->name), ZSTR_VAL(name));
+ format, ce->name, name);
RETURN_THROWS();
}
@@@ -4437,12 -4621,16 +4478,15 @@@ ZEND_METHOD(ReflectionClass, getMethod
method and not the closure definition itself */
reflection_method_factory(ce, mptr, NULL, return_value);
zval_ptr_dtor(&obj_tmp);
- } else if ((mptr = zend_hash_find_ptr(&ce->function_table, lc_name)) != NULL) {
+ } else if ((mptr = zend_hash_find_ptr_lc(&ce->function_table, name)) != NULL) {
reflection_method_factory(ce, mptr, NULL, return_value);
} else {
+ // %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 = "Method %S::%S() does not exist";
zend_throw_exception_ex(reflection_exception_ptr, 0,
- "Method %s::%s() does not exist", ZSTR_VAL(ce->name), ZSTR_VAL(name));
+ format, ce->name, name);
}
- zend_string_release(lc_name);
}
/* }}} */
@@@ -4566,26 -4753,35 +4610,37 @@@ ZEND_METHOD(ReflectionClass, getPropert
return;
}
}
- str_name = ZSTR_VAL(name);
+ const char *str_name = ZSTR_VAL(name);
+ const char *tmp;
++ size_t str_name_len;
+ bool fully_qualified = false;
if ((tmp = zend_memnstr(ZSTR_VAL(name), "::", 2, ZSTR_VAL(name) + ZSTR_LEN(name))) != NULL) {
+ fully_qualified = true;
- classname_len = tmp - ZSTR_VAL(name);
- classname = zend_string_init(ZSTR_VAL(name), classname_len, 0);
+ size_t classname_len = tmp - ZSTR_VAL(name);
+ zend_string *classname = zend_string_init(ZSTR_VAL(name), classname_len, false);
- size_t str_name_len = ZSTR_LEN(name) - (classname_len + 2);
+ str_name_len = ZSTR_LEN(name) - (classname_len + 2);
str_name = tmp + 2;
- ce2 = zend_lookup_class(classname);
+ zend_class_entry *ce2 = zend_lookup_class(classname);
if (!ce2) {
if (!EG(exception)) {
zend_throw_exception_ex(reflection_exception_ptr, -1, "Class \"%s\" does not exist", ZSTR_VAL(classname));
}
- zend_string_release_ex(classname, 0);
+ zend_string_release_ex(classname, false);
RETURN_THROWS();
}
- zend_string_release_ex(classname, 0);
+ zend_string_release_ex(classname, false);
if (!instanceof_function(ce, ce2)) {
- zend_throw_exception_ex(reflection_exception_ptr, -1, "Fully qualified property name %s::$%s does not specify a base class of %s", ZSTR_VAL(ce2->name), str_name, ZSTR_VAL(ce->name));
+ // %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 = "Fully qualified property name %S::$%S does not specify a base class of %S";
+ ALLOCA_FLAG(use_heap);
+ zend_string *prop_name_zstr;
+ ZSTR_ALLOCA_INIT(prop_name_zstr, str_name, str_name_len, use_heap);
+ zend_throw_exception_ex(reflection_exception_ptr, -1, format, ce2->name, prop_name_zstr, ce->name);
+ ZSTR_ALLOCA_FREE(prop_name_zstr, use_heap);
+
RETURN_THROWS();
}
ce = ce2;
@@@ -5447,9 -5684,14 +5517,12 @@@ ZEND_METHOD(ReflectionClass, implements
}
interface_ce = argument->ptr;
- } else {
- if ((interface_ce = zend_lookup_class(interface_str)) == NULL) {
- // %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 = "Interface \"%S\" does not exist";
- zend_throw_exception_ex(reflection_exception_ptr, 0, format, interface_str);
- RETURN_THROWS();
- }
+ } else if ((interface_ce = zend_lookup_class(interface_str)) == NULL) {
- zend_throw_exception_ex(reflection_exception_ptr, 0, "Interface \"%s\" does not exist", ZSTR_VAL(interface_str));
++ // %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 = "Interface \"%S\" does not exist";
++ zend_throw_exception_ex(reflection_exception_ptr, 0, format, interface_str);
+ RETURN_THROWS();
}
if (!(interface_ce->ce_flags & ZEND_ACC_INTERFACE)) {
@@@ -5596,25 -5843,31 +5669,31 @@@ ZEND_METHOD(ReflectionProperty, __const
if (classname_obj) {
ce = classname_obj->ce;
- } else {
- if ((ce = zend_lookup_class(classname_str)) == NULL) {
- // %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 = "Class \"%S\" does not exist";
- zend_throw_exception_ex(reflection_exception_ptr, 0, format, classname_str);
- RETURN_THROWS();
- }
+ } else if ((ce = zend_lookup_class(classname_str)) == NULL) {
- zend_throw_exception_ex(reflection_exception_ptr, 0, "Class \"%s\" does not exist", ZSTR_VAL(classname_str));
++ // %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 = "Class \"%S\" does not exist";
++ zend_throw_exception_ex(reflection_exception_ptr, 0, format, classname_str);
+ RETURN_THROWS();
}
- property_info = zend_hash_find_ptr(&ce->properties_info, name);
+ zend_property_info *property_info = zend_hash_find_ptr(&ce->properties_info, name);
+ bool dynam_prop = false;
if (property_info == NULL
- || ((property_info->flags & ZEND_ACC_PRIVATE)
- && property_info->ce != ce)) {
+ || ((property_info->flags & ZEND_ACC_PRIVATE)
+ && property_info->ce != ce)
+ ) {
/* Check for dynamic properties */
- if (property_info == NULL && classname_obj) {
- if (zend_hash_exists(classname_obj->handlers->get_properties(classname_obj), name)) {
- dynam_prop = 1;
- }
+ if (property_info == NULL && classname_obj
+ && zend_hash_exists(classname_obj->handlers->get_properties(classname_obj), name)
+ ) {
+ dynam_prop = true;
}
- if (dynam_prop == 0) {
+ if (!dynam_prop) {
- zend_throw_exception_ex(reflection_exception_ptr, 0, "Property %s::$%s does not exist", ZSTR_VAL(ce->name), ZSTR_VAL(name));
+ // %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 = "Property %S::$%S does not exist";
+ zend_throw_exception_ex(reflection_exception_ptr, 0, format, ce->name, name);
RETURN_THROWS();
}
}
@@@ -6029,16 -6274,20 +6108,20 @@@ ZEND_METHOD(ReflectionProperty, setRawV
}
static zend_result reflection_property_check_lazy_compatible(
- zend_property_info *prop, zend_string *unmangled_name,
- reflection_object *intern, zend_object *object, const char *method)
+ const zend_property_info *prop, zend_string *unmangled_name,
+ const zend_class_entry *scope, const zend_object *object, const char *method)
{
- if (!prop) {
+ if (!prop) {
+ // %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 = "Can not use %s on dynamic property %S::$%S";
++ const char *format = "Cannot use %s() on dynamic property %S::$%S";
zend_throw_exception_ex(reflection_exception_ptr, 0,
- "Cannot use %s() on dynamic property %s::$%s",
- method, ZSTR_VAL(scope->name),
- ZSTR_VAL(unmangled_name));
+ format,
- method, intern->ce->name,
++ method, scope->name,
+ unmangled_name);
return FAILURE;
}
+ // Non-dynamic properties cannot have null bytes so %s is fine
if (prop->flags & ZEND_ACC_STATIC) {
zend_throw_exception_ex(reflection_exception_ptr, 0,
@@@ -6809,14 -6818,20 +6892,17 @@@ ZEND_METHOD(ReflectionExtension, __cons
RETURN_THROWS();
}
- object = ZEND_THIS;
- intern = Z_REFLECTION_P(object);
- lcname = do_alloca(ZSTR_LEN(name_zstr) + 1, use_heap);
- zend_str_tolower_copy(lcname, ZSTR_VAL(name_zstr), ZSTR_LEN(name_zstr));
- if ((module = zend_hash_str_find_ptr(&module_registry, lcname, ZSTR_LEN(name_zstr))) == NULL) {
- free_alloca(lcname, use_heap);
+ zval *object = ZEND_THIS;
+ reflection_object *intern = Z_REFLECTION_P(object);
+ zend_module_entry *module;
+ if ((module = zend_hash_find_ptr_lc(&module_registry, name_str)) == NULL) {
+ // %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 = "Extension \"%S\" does not exist";
zend_throw_exception_ex(reflection_exception_ptr, 0,
- "Extension \"%s\" does not exist", ZSTR_VAL(name_str));
- format, name_zstr);
++ format, name_str);
RETURN_THROWS();
}
- free_alloca(lcname, use_heap);
zval *prop_name = reflection_prop_name(object);
zval_ptr_dtor(prop_name);
ZVAL_STRING(prop_name, module->name);
@@@ -7102,20 -7126,25 +7188,22 @@@ ZEND_METHOD(ReflectionExtension, isTemp
/* {{{ Constructor. Throws an Exception in case the given Zend extension does not exist */
ZEND_METHOD(ReflectionZendExtension, __construct)
{
- const char *name_str;
- size_t name_len;
- zval *object;
- reflection_object *intern;
- zend_extension *extension;
+ zend_string *name_zstr;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name_str, &name_len) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name_zstr) == FAILURE) {
RETURN_THROWS();
}
- object = ZEND_THIS;
- intern = Z_REFLECTION_P(object);
+ zval *object = ZEND_THIS;
+ reflection_object *intern = Z_REFLECTION_P(object);
- zend_extension *extension = zend_get_extension(name_str);
- extension = zend_get_extension(ZSTR_VAL(name_zstr));
++ zend_extension *extension = zend_get_extension(ZSTR_VAL(name_zstr));
if (!extension) {
+ // %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 = "Zend Extension \"%S\" does not exist";
zend_throw_exception_ex(reflection_exception_ptr, 0,
- "Zend Extension \"%s\" does not exist", name_str);
+ format, name_zstr);
RETURN_THROWS();
}
ZVAL_STRING(reflection_prop_name(object), extension->name);
diff --cc ext/reflection/tests/gh22905/ReflectionClass_setStaticPropertyValue.phpt
index 00000000000,c450f41cb6e..e94defd0fdf
mode 000000,100644..100644
--- a/ext/reflection/tests/gh22905/ReflectionClass_setStaticPropertyValue.phpt
+++ b/ext/reflection/tests/gh22905/ReflectionClass_setStaticPropertyValue.phpt
@@@ -1,0 -1,16 +1,16 @@@
+ --TEST--
+ GH-22905: null bytes in ReflectionClass::setStaticPropertyValue() error messages
+ --FILE--
+ <?php
+
+ class Demo {}
+ $r = new ReflectionClass(Demo::class);
+ $r->setStaticPropertyValue("foo\0bar", 123);
+
+ ?>
+ --EXPECTF--
-Fatal error: Uncaught ReflectionException: Class Demo does not have a property named foo%0bar in %s:%d
++Fatal error: Uncaught ReflectionException: Property Demo::$foo%0bar does not exist in %s:%d
+ Stack trace:
+ #0 %s(%d): ReflectionClass->setStaticPropertyValue('foo\x00bar', 123)
+ #1 {main}
+ thrown in %s on line %d
diff --cc ext/reflection/tests/gh22905/ReflectionProperty_setRawValueWithoutLazyInitialization.phpt
index 00000000000,d2d609bcf28..36643187c0b
mode 000000,100644..100644
--- a/ext/reflection/tests/gh22905/ReflectionProperty_setRawValueWithoutLazyInitialization.phpt
+++ b/ext/reflection/tests/gh22905/ReflectionProperty_setRawValueWithoutLazyInitialization.phpt
@@@ -1,0 -1,16 +1,16 @@@
+ --TEST--
+ GH-22905: null bytes in ReflectionProperty::setRawValueWithoutLazyInitialization() error messages
+ --FILE--
+ <?php
+
+ $o = (object)["foo\0bar" => "baz"];
+ $r = new ReflectionProperty($o, "foo\0bar");
+ $r->setRawValueWithoutLazyInitialization($o, 123);
+
+ ?>
+ --EXPECTF--
-Fatal error: Uncaught ReflectionException: Can not use setRawValueWithoutLazyInitialization on dynamic property stdClass::$foo%0bar in %s:%d
++Fatal error: Uncaught ReflectionException: Cannot use setRawValueWithoutLazyInitialization() on dynamic property stdClass::$foo%0bar in %s:%d
+ Stack trace:
+ #0 %s(%d): ReflectionProperty->setRawValueWithoutLazyInitialization(Object(stdClass), 123)
+ #1 {main}
+ thrown in %s on line %d
diff --cc ext/reflection/tests/gh22905/ReflectionProperty_skipLazyInitialization.phpt
index 00000000000,49bad02ab4d..9db8de311ab
mode 000000,100644..100644
--- a/ext/reflection/tests/gh22905/ReflectionProperty_skipLazyInitialization.phpt
+++ b/ext/reflection/tests/gh22905/ReflectionProperty_skipLazyInitialization.phpt
@@@ -1,0 -1,16 +1,16 @@@
+ --TEST--
+ GH-22905: null bytes in ReflectionProperty::skipLazyInitialization() error messages
+ --FILE--
+ <?php
+
+ $o = (object)["foo\0bar" => "baz"];
+ $r = new ReflectionProperty($o, "foo\0bar");
+ $r->skipLazyInitialization($o);
+
+ ?>
+ --EXPECTF--
-Fatal error: Uncaught ReflectionException: Can not use skipLazyInitialization on dynamic property stdClass::$foo%0bar in %s:%d
++Fatal error: Uncaught ReflectionException: Cannot use skipLazyInitialization() on dynamic property stdClass::$foo%0bar in %s:%d
+ Stack trace:
+ #0 %s(%d): ReflectionProperty->skipLazyInitialization(Object(stdClass))
+ #1 {main}
+ thrown in %s on line %d