Commit 9cce500a504 for php.net
commit 9cce500a5043f2e9827a704a66682089e351a90b
Author: Ilia Alshanetsky <ilia@ilia.ws>
Date: Tue Sep 1 08:33:05 2026 -0400
[intl] Record the ICU error code on Spoofchecker failures (#23520)
Spoofchecker::isSuspicious(), ::areConfusable(), ::areBidiConfusable(),
::setChecks(), ::setAllowedLocales() and ::setAllowedChars() warn on
U_FAILURE but never record the code, so intl_get_error_code() still reads
U_ZERO_ERROR after a failed call. They now record it, which is what
SPOOFCHECKER_CHECK_STATUS in spoofchecker_class.h already prescribes for
this class.
Closes GH-23520
diff --git a/NEWS b/NEWS
index f3a3914a263..c2735429778 100644
--- a/NEWS
+++ b/NEWS
@@ -24,6 +24,8 @@ PHP NEWS
read. (iliaal)
. Fixed a use-after-free when IntlRuleBasedBreakIterator is constructed
from compiled rules. (iliaal)
+ . Fixed Spoofchecker methods not recording the ICU error code when an ICU
+ call fails. (Ilia Alshanetsky)
- PDO_PGSQL:
. Added Pdo\Pgsql::ATTR_CHUNK_SIZE to fetch a result set in chunks of the
diff --git a/ext/intl/spoofchecker/spoofchecker_main.cpp b/ext/intl/spoofchecker/spoofchecker_main.cpp
index d7e1b4e0553..7a3ffd9b809 100644
--- a/ext/intl/spoofchecker/spoofchecker_main.cpp
+++ b/ext/intl/spoofchecker/spoofchecker_main.cpp
@@ -46,6 +46,7 @@ U_CFUNC PHP_METHOD(Spoofchecker, isSuspicious)
ret = intl_icu_compat_uspoof_check_utf8(co->uspoof, ZSTR_VAL(text), ZSTR_LEN(text), co->uspoofres, SPOOFCHECKER_ERROR_CODE_P(co));
if (U_FAILURE(SPOOFCHECKER_ERROR_CODE(co))) {
+ intl_error_set_code(NULL, SPOOFCHECKER_ERROR_CODE(co));
php_error_docref(NULL, E_WARNING, "(%d) %s", SPOOFCHECKER_ERROR_CODE(co), u_errorName(SPOOFCHECKER_ERROR_CODE(co)));
if (intl_icu_compat_uspoof_check_result_mismatch(co->uspoofres, ret, &errmask, SPOOFCHECKER_ERROR_CODE_P(co))) {
@@ -83,6 +84,7 @@ U_CFUNC PHP_METHOD(Spoofchecker, areConfusable)
ret = uspoof_areConfusableUTF8(co->uspoof, ZSTR_VAL(s1), (int32_t)ZSTR_LEN(s1), ZSTR_VAL(s2), (int32_t)ZSTR_LEN(s2), SPOOFCHECKER_ERROR_CODE_P(co));
}
if (U_FAILURE(SPOOFCHECKER_ERROR_CODE(co))) {
+ intl_error_set_code(NULL, SPOOFCHECKER_ERROR_CODE(co));
php_error_docref(NULL, E_WARNING, "(%d) %s", SPOOFCHECKER_ERROR_CODE(co), u_errorName(SPOOFCHECKER_ERROR_CODE(co)));
RETURN_TRUE;
}
@@ -109,6 +111,7 @@ U_CFUNC PHP_METHOD(Spoofchecker, setAllowedLocales)
uspoof_setAllowedLocales(co->uspoof, ZSTR_VAL(locales), SPOOFCHECKER_ERROR_CODE_P(co));
if (U_FAILURE(SPOOFCHECKER_ERROR_CODE(co))) {
+ intl_error_set_code(NULL, SPOOFCHECKER_ERROR_CODE(co));
php_error_docref(NULL, E_WARNING, "(%d) %s", SPOOFCHECKER_ERROR_CODE(co), u_errorName(SPOOFCHECKER_ERROR_CODE(co)));
return;
}
@@ -130,6 +133,7 @@ U_CFUNC PHP_METHOD(Spoofchecker, setChecks)
uspoof_setChecks(co->uspoof, checks, SPOOFCHECKER_ERROR_CODE_P(co));
if (U_FAILURE(SPOOFCHECKER_ERROR_CODE(co))) {
+ intl_error_set_code(NULL, SPOOFCHECKER_ERROR_CODE(co));
php_error_docref(NULL, E_WARNING, "(%d) %s", SPOOFCHECKER_ERROR_CODE(co), u_errorName(SPOOFCHECKER_ERROR_CODE(co)));
}
}
@@ -220,6 +224,7 @@ U_CFUNC PHP_METHOD(Spoofchecker, setAllowedChars)
efree(upattern);
if (U_FAILURE(SPOOFCHECKER_ERROR_CODE(co))) {
+ intl_error_set_code(NULL, SPOOFCHECKER_ERROR_CODE(co));
php_error_docref(NULL, E_WARNING, "(%d) %s", SPOOFCHECKER_ERROR_CODE(co), u_errorName(SPOOFCHECKER_ERROR_CODE(co)));
}
}
@@ -355,6 +360,7 @@ U_CFUNC PHP_METHOD(Spoofchecker, areBidiConfusable)
ret = uspoof_areBidiConfusableUTF8(co->uspoof, (UBiDiDirection)direction, ZSTR_VAL(s1), (int32_t)ZSTR_LEN(s1), ZSTR_VAL(s2), (int32_t)ZSTR_LEN(s2), SPOOFCHECKER_ERROR_CODE_P(co));
}
if (U_FAILURE(SPOOFCHECKER_ERROR_CODE(co))) {
+ intl_error_set_code(NULL, SPOOFCHECKER_ERROR_CODE(co));
php_error_docref(NULL, E_WARNING, "(%d) %s", SPOOFCHECKER_ERROR_CODE(co), u_errorName(SPOOFCHECKER_ERROR_CODE(co)));
RETURN_TRUE;
}
diff --git a/ext/intl/tests/spoofchecker_setchecks_error_code.phpt b/ext/intl/tests/spoofchecker_setchecks_error_code.phpt
new file mode 100644
index 00000000000..a9c1eaeab45
--- /dev/null
+++ b/ext/intl/tests/spoofchecker_setchecks_error_code.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Spoofchecker::setChecks() records the ICU error code
+--EXTENSIONS--
+intl
+--SKIPIF--
+<?php if (!class_exists("Spoofchecker")) print 'skip'; ?>
+--FILE--
+<?php
+
+$s = new Spoofchecker();
+$s->setChecks(1 << 20);
+var_dump(intl_get_error_code(), intl_get_error_message());
+
+?>
+--EXPECTF--
+Warning: Spoofchecker::setChecks(): (1) U_ILLEGAL_ARGUMENT_ERROR in %s on line %d
+int(1)
+string(24) "U_ILLEGAL_ARGUMENT_ERROR"