Commit 630128392b3 for php.net
commit 630128392b3f936551139eb8b457d8694c7116df
Author: Ilia Alshanetsky <ilia@ilia.ws>
Date: Mon Aug 24 10:51:55 2026 -0400
ext/intl: Reject unconstructed Collator in attribute and strength methods
Collator::getAttribute(), setAttribute(), getStrength() and setStrength()
dereferenced a NULL ICU collator when called on an object whose constructor
skipped parent::__construct(), returning bogus values instead of failing,
while compare(), getLocale(), sort() and getSortKey() already throw
"Object not initialized". Apply the same guard to the four remaining
methods through a collator_check_initialized() helper, which also replaces
four existing copies.
Closes GH-23797
diff --git a/NEWS b/NEWS
index a37bfa30e4b..e7f45c810b2 100644
--- a/NEWS
+++ b/NEWS
@@ -32,6 +32,8 @@ PHP NEWS
. Fixed cloning IntlDateFormatter and MessageFormatter losing PHP-side state
such as dateType, timeType, calendar and the message pattern.
(Ilia Alshanetsky)
+ . Fixed Collator attribute and strength methods not rejecting an
+ unconstructed Collator. (Ilia Alshanetsky)
- Lexbor:
. Merge patches lexbor/lexbor@8a14bc0 and lexbor/lexbor@f67ce4b, fixing a
diff --git a/ext/intl/collator/collator_attr.c b/ext/intl/collator/collator_attr.c
index f16ae0cc528..0bc68026092 100644
--- a/ext/intl/collator/collator_attr.c
+++ b/ext/intl/collator/collator_attr.c
@@ -40,6 +40,10 @@ PHP_FUNCTION( collator_get_attribute )
/* Fetch the object. */
COLLATOR_METHOD_FETCH_OBJECT;
+ if (collator_check_initialized(co) == FAILURE) {
+ RETURN_THROWS();
+ }
+
value = ucol_getAttribute( co->ucoll, attribute, COLLATOR_ERROR_CODE_P( co ) );
COLLATOR_CHECK_STATUS( co, "Error getting attribute value" );
@@ -64,6 +68,10 @@ PHP_FUNCTION( collator_set_attribute )
/* Fetch the object. */
COLLATOR_METHOD_FETCH_OBJECT;
+ if (collator_check_initialized(co) == FAILURE) {
+ RETURN_THROWS();
+ }
+
/* Set new value for the given attribute. */
ucol_setAttribute( co->ucoll, attribute, value, COLLATOR_ERROR_CODE_P( co ) );
COLLATOR_CHECK_STATUS( co, "Error setting attribute value" );
@@ -87,6 +95,10 @@ PHP_FUNCTION( collator_get_strength )
/* Fetch the object. */
COLLATOR_METHOD_FETCH_OBJECT;
+ if (collator_check_initialized(co) == FAILURE) {
+ RETURN_THROWS();
+ }
+
/* Get current strength and return it. */
RETURN_LONG( ucol_getStrength( co->ucoll ) );
}
@@ -109,6 +121,10 @@ PHP_FUNCTION( collator_set_strength )
/* Fetch the object. */
COLLATOR_METHOD_FETCH_OBJECT;
+ if (collator_check_initialized(co) == FAILURE) {
+ RETURN_THROWS();
+ }
+
/* Set given strength. */
ucol_setStrength( co->ucoll, strength );
diff --git a/ext/intl/collator/collator_class.h b/ext/intl/collator/collator_class.h
index 5c69c2e5aff..9fdfbb0d01b 100644
--- a/ext/intl/collator/collator_class.h
+++ b/ext/intl/collator/collator_class.h
@@ -46,6 +46,22 @@ static inline Collator_object *php_intl_collator_fetch_object(zend_object *obj)
}
#define Z_INTL_COLLATOR_P(zv) php_intl_collator_fetch_object(Z_OBJ_P(zv))
+static zend_always_inline zend_result collator_check_initialized(Collator_object *co)
+{
+ ZEND_ASSERT(co != NULL);
+
+ if (UNEXPECTED(co->ucoll == NULL)) {
+ intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) );
+ intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ),
+ "Object not initialized", 0 );
+ zend_throw_error(NULL, "Object not initialized");
+
+ return FAILURE;
+ }
+
+ return SUCCESS;
+}
+
void collator_register_Collator_symbols(int module_number);
void collator_object_init( Collator_object* co );
void collator_object_destroy( Collator_object* co );
diff --git a/ext/intl/collator/collator_compare.c b/ext/intl/collator/collator_compare.c
index f71d57f74f8..26d05601f94 100644
--- a/ext/intl/collator/collator_compare.c
+++ b/ext/intl/collator/collator_compare.c
@@ -48,12 +48,7 @@ PHP_FUNCTION( collator_compare )
/* Fetch the object. */
COLLATOR_METHOD_FETCH_OBJECT;
- if (!co || !co->ucoll) {
- intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) );
- intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ),
- "Object not initialized", 0 );
- zend_throw_error(NULL, "Object not initialized");
-
+ if (collator_check_initialized(co) == FAILURE) {
RETURN_THROWS();
}
diff --git a/ext/intl/collator/collator_locale.c b/ext/intl/collator/collator_locale.c
index e1cdcdf2a60..22c6e672a5a 100644
--- a/ext/intl/collator/collator_locale.c
+++ b/ext/intl/collator/collator_locale.c
@@ -41,12 +41,7 @@ PHP_FUNCTION( collator_get_locale )
/* Fetch the object. */
COLLATOR_METHOD_FETCH_OBJECT;
- if (!co || !co->ucoll) {
- intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) );
- intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ),
- "Object not initialized", 0 );
- zend_throw_error(NULL, "Object not initialized");
-
+ if (collator_check_initialized(co) == FAILURE) {
RETURN_THROWS();
}
diff --git a/ext/intl/collator/collator_sort.c b/ext/intl/collator/collator_sort.c
index 9d4cb422020..6b8feaaa03f 100644
--- a/ext/intl/collator/collator_sort.c
+++ b/ext/intl/collator/collator_sort.c
@@ -376,12 +376,7 @@ PHP_FUNCTION( collator_sort_with_sort_keys )
/* Fetch the object. */
COLLATOR_METHOD_FETCH_OBJECT;
- if (!co || !co->ucoll) {
- intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) );
- intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ),
- "Object not initialized", 0 );
- zend_throw_error(NULL, "Object not initialized");
-
+ if (collator_check_initialized(co) == FAILURE) {
RETURN_THROWS();
}
@@ -532,12 +527,7 @@ PHP_FUNCTION( collator_get_sort_key )
/* Fetch the object. */
COLLATOR_METHOD_FETCH_OBJECT;
- if (!co || !co->ucoll) {
- intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) );
- intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ),
- "Object not initialized", 0 );
- zend_throw_error(NULL, "Object not initialized");
-
+ if (collator_check_initialized(co) == FAILURE) {
RETURN_THROWS();
}
diff --git a/ext/intl/tests/collator_attribute_unconstructed.phpt b/ext/intl/tests/collator_attribute_unconstructed.phpt
new file mode 100644
index 00000000000..f8eb5afa01d
--- /dev/null
+++ b/ext/intl/tests/collator_attribute_unconstructed.phpt
@@ -0,0 +1,55 @@
+--TEST--
+Collator attribute and strength methods on unconstructed object
+--EXTENSIONS--
+intl
+--FILE--
+<?php
+
+class Collator2 extends Collator {
+ public function __construct() {
+ // omitting parent::__construct($someLocale);
+ }
+}
+
+$c = new Collator2();
+
+$methods = [
+ 'getAttribute' => fn() => $c->getAttribute(Collator::NUMERIC_COLLATION),
+ 'setAttribute' => fn() => $c->setAttribute(Collator::NUMERIC_COLLATION, Collator::ON),
+ 'getStrength' => fn() => $c->getStrength(),
+ 'setStrength' => fn() => $c->setStrength(Collator::SECONDARY),
+];
+
+foreach ($methods as $method => $call) {
+ try {
+ $call();
+ } catch (Error $e) {
+ echo $method, ': ', $e::class, ': ', $e->getMessage(), PHP_EOL;
+ }
+}
+
+$functions = [
+ 'collator_get_attribute' => fn() => collator_get_attribute($c, Collator::NUMERIC_COLLATION),
+ 'collator_set_attribute' => fn() => collator_set_attribute($c, Collator::NUMERIC_COLLATION, Collator::ON),
+ 'collator_get_strength' => fn() => collator_get_strength($c),
+ 'collator_set_strength' => fn() => collator_set_strength($c, Collator::SECONDARY),
+];
+
+foreach ($functions as $function => $call) {
+ try {
+ $call();
+ } catch (Error $e) {
+ echo $function, ': ', $e::class, ': ', $e->getMessage(), PHP_EOL;
+ }
+}
+
+?>
+--EXPECT--
+getAttribute: Error: Object not initialized
+setAttribute: Error: Object not initialized
+getStrength: Error: Object not initialized
+setStrength: Error: Object not initialized
+collator_get_attribute: Error: Object not initialized
+collator_set_attribute: Error: Object not initialized
+collator_get_strength: Error: Object not initialized
+collator_set_strength: Error: Object not initialized