Commit e44db0cdfd0 for php.net

commit e44db0cdfd0bb3595dd7e95b48dd5ebf5a25eddd
Author: Xuyang Zhang <119476662+kn1g78@users.noreply.github.com>
Date:   Mon Jun 29 22:12:46 2026 +0800

    ext/intl: Reset IntlChar error state on method entry (#22500)

    IntlChar methods could leave stale global intl error state after a later successful call.

    Reset the intl error state when entering each IntlChar method so successful calls report U_ZERO_ERROR.

    Closes #22500

diff --git a/NEWS b/NEWS
index 86ef47098f7..57d91e34545 100644
--- a/NEWS
+++ b/NEWS
@@ -11,6 +11,8 @@ PHP                                                                        NEWS
     fallback locale when a language tag cannot be canonicalized. (Weilin Du)
   . Fixed memory leaks when calling Collator::__construct() or
     Spoofchecker::__construct() twice. (Weilin Du)
+  . Fixed IntlChar methods leaving stale global error state after successful
+    calls. (Xuyang Zhang)

 - Phar:
   . Fixed inconsistent handling of the magic ".phar" directory. Paths such as
diff --git a/ext/intl/tests/intlchar_reset_error.phpt b/ext/intl/tests/intlchar_reset_error.phpt
new file mode 100644
index 00000000000..45f6d1df296
--- /dev/null
+++ b/ext/intl/tests/intlchar_reset_error.phpt
@@ -0,0 +1,19 @@
+--TEST--
+IntlChar methods reset intl error on success
+--EXTENSIONS--
+intl
+--FILE--
+<?php
+var_dump(IntlChar::digit('a', 1));
+var_dump(intl_get_error_code() !== U_ZERO_ERROR);
+
+var_dump(IntlChar::forDigit(1) === ord('1'));
+var_dump(intl_get_error_code() === U_ZERO_ERROR);
+var_dump(intl_get_error_message() === 'U_ZERO_ERROR');
+?>
+--EXPECT--
+bool(false)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
diff --git a/ext/intl/uchar/uchar.c b/ext/intl/uchar/uchar.c
index f194e0e0b93..32bb83a09a4 100644
--- a/ext/intl/uchar/uchar.c
+++ b/ext/intl/uchar/uchar.c
@@ -54,6 +54,8 @@ IC_METHOD(chr) {
 	char buffer[5];
 	int buffer_len = 0;

+	intl_error_reset(NULL);
+
 	if (parse_code_point_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, &cp) == FAILURE) {
 		RETURN_NULL();
 	}
@@ -73,6 +75,8 @@ IC_METHOD(chr) {
 IC_METHOD(ord) {
 	UChar32 cp;

+	intl_error_reset(NULL);
+
 	if (parse_code_point_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, &cp) == FAILURE) {
 		RETURN_NULL();
 	}
@@ -88,6 +92,8 @@ IC_METHOD(hasBinaryProperty) {
 	zend_string *string_codepoint;
 	zend_long int_codepoint = 0;

+	intl_error_reset(NULL);
+
 	ZEND_PARSE_PARAMETERS_START(2, 2)
 		Z_PARAM_STR_OR_LONG(string_codepoint, int_codepoint)
 		Z_PARAM_LONG(prop)
@@ -108,6 +114,8 @@ IC_METHOD(getIntPropertyValue) {
 	zend_string *string_codepoint;
 	zend_long int_codepoint = 0;

+	intl_error_reset(NULL);
+
 	ZEND_PARSE_PARAMETERS_START(2, 2)
 		Z_PARAM_STR_OR_LONG(string_codepoint, int_codepoint)
 		Z_PARAM_LONG(prop)
@@ -125,6 +133,8 @@ IC_METHOD(getIntPropertyValue) {
 IC_METHOD(getIntPropertyMinValue) {
 	zend_long prop;

+	intl_error_reset(NULL);
+
 	ZEND_PARSE_PARAMETERS_START(1, 1)
 		Z_PARAM_LONG(prop)
 	ZEND_PARSE_PARAMETERS_END();
@@ -137,6 +147,8 @@ IC_METHOD(getIntPropertyMinValue) {
 IC_METHOD(getIntPropertyMaxValue) {
 	zend_long prop;

+	intl_error_reset(NULL);
+
 	ZEND_PARSE_PARAMETERS_START(1, 1)
 		Z_PARAM_LONG(prop)
 	ZEND_PARSE_PARAMETERS_END();
@@ -149,6 +161,8 @@ IC_METHOD(getIntPropertyMaxValue) {
 IC_METHOD(getNumericValue) {
 	UChar32 cp;

+	intl_error_reset(NULL);
+
 	if (parse_code_point_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, &cp) == FAILURE) {
 		RETURN_NULL();
 	}
@@ -191,6 +205,8 @@ static UBool enumCharType_callback(enumCharType_data *context,
 IC_METHOD(enumCharTypes) {
 	enumCharType_data context;

+	intl_error_reset(NULL);
+
 	ZEND_PARSE_PARAMETERS_START(1, 1)
 		Z_PARAM_FUNC(context.fci, context.fci_cache)
 	ZEND_PARSE_PARAMETERS_END();
@@ -202,6 +218,8 @@ IC_METHOD(enumCharTypes) {
 IC_METHOD(getBlockCode) {
 	UChar32 cp;

+	intl_error_reset(NULL);
+
 	if (parse_code_point_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, &cp) == FAILURE) {
 		RETURN_NULL();
 	}
@@ -220,6 +238,8 @@ IC_METHOD(charName) {
 	zend_string *buffer = NULL;
 	int32_t buffer_len;

+	intl_error_reset(NULL);
+
 	ZEND_PARSE_PARAMETERS_START(1, 2)
 		Z_PARAM_STR_OR_LONG(string_codepoint, int_codepoint)
 		Z_PARAM_OPTIONAL
@@ -250,6 +270,8 @@ IC_METHOD(charFromName) {
 	UChar32 ret;
 	UErrorCode error = U_ZERO_ERROR;

+	intl_error_reset(NULL);
+
 	ZEND_PARSE_PARAMETERS_START(1, 2)
 		Z_PARAM_STRING(name, name_len)
 		Z_PARAM_OPTIONAL
@@ -301,6 +323,7 @@ IC_METHOD(enumCharNames) {
 	zend_long nameChoice = U_UNICODE_CHAR_NAME;
 	UErrorCode error = U_ZERO_ERROR;

+	intl_error_reset(NULL);

 	ZEND_PARSE_PARAMETERS_START(3, 4)
 		Z_PARAM_STR_OR_LONG(string_start, int_start)
@@ -326,6 +349,8 @@ IC_METHOD(getPropertyName) {
 	zend_long nameChoice = U_LONG_PROPERTY_NAME;
 	const char *ret;

+	intl_error_reset(NULL);
+
 	ZEND_PARSE_PARAMETERS_START(1, 2)
 		Z_PARAM_LONG(property)
 		Z_PARAM_OPTIONAL
@@ -348,6 +373,8 @@ IC_METHOD(getPropertyEnum) {
 	char *alias;
 	size_t alias_len;

+	intl_error_reset(NULL);
+
 	ZEND_PARSE_PARAMETERS_START(1, 1)
 		Z_PARAM_STRING(alias, alias_len)
 	ZEND_PARSE_PARAMETERS_END();
@@ -361,6 +388,8 @@ IC_METHOD(getPropertyValueName) {
 	zend_long property, value, nameChoice = U_LONG_PROPERTY_NAME;
 	const char *ret;

+	intl_error_reset(NULL);
+
 	ZEND_PARSE_PARAMETERS_START(2, 3)
 		Z_PARAM_LONG(property)
 		Z_PARAM_LONG(value)
@@ -385,6 +414,8 @@ IC_METHOD(getPropertyValueEnum) {
 	char *name;
 	size_t name_len;

+	intl_error_reset(NULL);
+
 	ZEND_PARSE_PARAMETERS_START(2, 2)
 		Z_PARAM_LONG(property)
 		Z_PARAM_STRING(name, name_len)
@@ -401,6 +432,8 @@ IC_METHOD(foldCase) {
 	zend_string *string_codepoint;
 	zend_long int_codepoint = 0;

+	intl_error_reset(NULL);
+
 	ZEND_PARSE_PARAMETERS_START(1, 2)
 		Z_PARAM_STR_OR_LONG(string_codepoint, int_codepoint)
 		Z_PARAM_OPTIONAL
@@ -432,6 +465,8 @@ IC_METHOD(digit) {
 	zend_string *string_codepoint;
 	zend_long int_codepoint = 0;

+	intl_error_reset(NULL);
+
 	ZEND_PARSE_PARAMETERS_START(1, 2)
 		Z_PARAM_STR_OR_LONG(string_codepoint, int_codepoint)
 		Z_PARAM_OPTIONAL
@@ -456,6 +491,8 @@ IC_METHOD(digit) {
 IC_METHOD(forDigit) {
 	zend_long digit, radix = 10;

+	intl_error_reset(NULL);
+
 	ZEND_PARSE_PARAMETERS_START(1, 2)
 		Z_PARAM_LONG(digit)
 		Z_PARAM_OPTIONAL
@@ -472,6 +509,8 @@ IC_METHOD(charAge) {
 	UVersionInfo version;
 	int i;

+	intl_error_reset(NULL);
+
 	if (parse_code_point_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, &cp) == FAILURE) {
 		RETURN_NULL();
 	}
@@ -489,6 +528,8 @@ IC_METHOD(getUnicodeVersion) {
 	UVersionInfo version;
 	int i;

+	intl_error_reset(NULL);
+
 	ZEND_PARSE_PARAMETERS_NONE();

 	u_getUnicodeVersion(version);
@@ -507,6 +548,8 @@ IC_METHOD(getFC_NFKC_Closure) {
 	int32_t closure_len;
 	UErrorCode error = U_ZERO_ERROR;

+	intl_error_reset(NULL);
+
 	if (parse_code_point_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, &cp) == FAILURE) {
 		RETURN_NULL();
 	}
@@ -535,6 +578,7 @@ IC_METHOD(getFC_NFKC_Closure) {
 #define IC_BOOL_METHOD_CHAR(name) \
 IC_METHOD(name) { \
 	UChar32 cp; \
+	intl_error_reset(NULL); \
 	if (parse_code_point_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, &cp) == FAILURE) { \
 		RETURN_NULL(); \
 	} \
@@ -575,6 +619,7 @@ IC_BOOL_METHOD_CHAR(isJavaIDPart)
 #define IC_INT_METHOD_CHAR(name) \
 IC_METHOD(name) { \
 	UChar32 cp; \
+	intl_error_reset(NULL); \
 	if (parse_code_point_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, &cp) == FAILURE) { \
 		RETURN_NULL(); \
 	} \
@@ -595,6 +640,7 @@ IC_METHOD(name) { \
 	UChar32 cp, ret; \
 	zend_string *string_codepoint; \
 		zend_long int_codepoint = -1; \
+		intl_error_reset(NULL); \
 		ZEND_PARSE_PARAMETERS_START(1, 1) \
 			Z_PARAM_STR_OR_LONG(string_codepoint, int_codepoint) \
 		ZEND_PARSE_PARAMETERS_END(); \