Commit 7a3dd1b952e for php.net
commit 7a3dd1b952e38450420369bf43c796f1b6768e6e
Merge: 9820f01cd16 4efca409534
Author: Weilin Du <weilindu@php.net>
Date: Sat Jun 20 13:08:51 2026 +0800
Merge branch 'PHP-8.4' into PHP-8.5
* PHP-8.4:
ext/intl: Fix Locale::lookup() fallback on invalid language tags (#22306)
diff --cc NEWS
index a1a2776e037,df93cb5b77b..7319f666bbb
--- a/NEWS
+++ b/NEWS
@@@ -41,13 -46,22 +41,15 @@@ PH
(Weilin Du)
. Fixed IntlTimeZone::getDisplayName() to synchronize object error state
for invalid display types. (Weilin Du)
- . Fixed Spoofchecker restriction-level APIs to only be exposed with ICU 53
- and later. (Graham Campbell)
+ . Fixed Locale::lookup() and locale_lookup() to return NULL instead of the
+ fallback locale when a language tag cannot be canonicalized. (Weilin Du)
-- mysqli:
- . Fix stmt->query leak in mysqli_execute_query() validation errors.
- (David Carlier)
-
- Opcache:
+ . Fixed bug GH-22265 (Another tailcall vm_interrupt bug). (Levi Morrison)
. Fixed bug GH-20469 (Unsafe inheritance cache replay with reentrant
autoloading). (Levi Morrison)
-
-- OpenSSL:
- . Fixed bug GH-22187 (Memory corruption (zend_mm_heap corrupted) in
- openssl_encrypt with AES-WRAP-PAD). (David Carlier)
+ . Fixed bug GH-21972 (Corrupted variable type when a typed by-value return
+ contains a reference wrapper). (Weilin Du)
- Phar:
. Fixed a bypass of the magic ".phar" directory protection in
diff --cc ext/intl/locale/locale_methods.cpp
index 57c3fd396f2,b5d48257338..f98ea55a185
--- a/ext/intl/locale/locale_methods.cpp
+++ b/ext/intl/locale/locale_methods.cpp
@@@ -1431,18 -1435,15 +1431,19 @@@ static zend_string* lookup_loc_range(co
zend_argument_type_error(2, "must only contain string values");
LOOKUP_CLEAN_RETURN(NULL);
}
+ if (zend_str_has_nul_byte(Z_STR_P(ele_value))) {
+ zend_argument_value_error(2, "must not contain any null bytes");
+ LOOKUP_CLEAN_RETURN(NULL);
+ }
- cur_arr[cur_arr_len*2] = estrndup(Z_STRVAL_P(ele_value), Z_STRLEN_P(ele_value));
- result = strToMatch(Z_STRVAL_P(ele_value), cur_arr[cur_arr_len*2]);
+ i = cur_arr_len*2;
+ cur_arr[i] = estrndup(Z_STRVAL_P(ele_value), Z_STRLEN_P(ele_value));
+ cur_arr_len++;
+ result = strToMatch(Z_STRVAL_P(ele_value), cur_arr[i]);
if(result == 0) {
- intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "lookup_loc_range: unable to canonicalize lang_tag", 0);
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "unable to canonicalize lang_tag");
LOOKUP_CLEAN_RETURN(NULL);
}
- cur_arr[cur_arr_len*2+1] = Z_STRVAL_P(ele_value);
- cur_arr_len++ ;
+ cur_arr[i+1] = Z_STRVAL_P(ele_value);
} ZEND_HASH_FOREACH_END(); /* end of for */
/* Canonicalize array elements */
diff --cc ext/intl/tests/locale_lookup_invalid_language_tag.phpt
index 00000000000,6f7c7517f95..ea4e3ec1cd0
mode 000000,100644..100644
--- a/ext/intl/tests/locale_lookup_invalid_language_tag.phpt
+++ b/ext/intl/tests/locale_lookup_invalid_language_tag.phpt
@@@ -1,0 -1,35 +1,35 @@@
+ --TEST--
+ Locale::lookup() returns null for invalid language tags
+ --EXTENSIONS--
+ intl
+ --FILE--
+ <?php
+
+ var_dump(Locale::lookup([''], 'de-DE', false, 'en-US'));
+ var_dump(intl_get_error_message());
+
+ var_dump(locale_lookup([''], 'de-DE', false, 'en-US'));
+ var_dump(intl_get_error_message());
+
+ ini_set('intl.use_exceptions', '1');
+
+ try {
+ Locale::lookup([''], 'de-DE', false, 'en-US');
+ } catch (IntlException $e) {
+ echo $e->getMessage(), PHP_EOL;
+ }
+
+ try {
+ locale_lookup([''], 'de-DE', false, 'en-US');
+ } catch (IntlException $e) {
+ echo $e->getMessage(), PHP_EOL;
+ }
+
+ ?>
+ --EXPECT--
+ NULL
-string(75) "lookup_loc_range: unable to canonicalize lang_tag: U_ILLEGAL_ARGUMENT_ERROR"
++string(57) "unable to canonicalize lang_tag: U_ILLEGAL_ARGUMENT_ERROR"
+ NULL
-string(75) "lookup_loc_range: unable to canonicalize lang_tag: U_ILLEGAL_ARGUMENT_ERROR"
-lookup_loc_range: unable to canonicalize lang_tag
-lookup_loc_range: unable to canonicalize lang_tag
++string(57) "unable to canonicalize lang_tag: U_ILLEGAL_ARGUMENT_ERROR"
++unable to canonicalize lang_tag
++unable to canonicalize lang_tag