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