[php-src] master: Merge branch 'PHP-8.5'

Ilia Alshanetsky <[email protected]>
Newsgroups gmane.comp.php.cvs.general
Message-ID <[email protected]>
Author: Ilia Alshanetsky (iliaal)
Date: 2026-06-26T14:40:58-04:00

Commit: https://github.com/php/php-src/commit/565da77f1274ccbe38a215bebee6e687e163c9ec
Raw diff: https://github.com/php/php-src/commit/565da77f1274ccbe38a215bebee6e687e163c9ec.diff

Merge branch 'PHP-8.5'

* PHP-8.5:
  Fix use-after-free in Collator::sort() with a mutating comparator

Changed paths:
  A  ext/intl/tests/collator_sort_modify_during_compare.phpt
  M  ext/intl/collator/collator_sort.cpp


Diff:

diff --git a/ext/intl/collator/collator_sort.cpp b/ext/intl/collator/collator_sort.cpp
index 2b1122cb747a..b7c2b8736596 100644
--- a/ext/intl/collator/collator_sort.cpp
+++ b/ext/intl/collator/collator_sort.cpp
@@ -262,12 +262,13 @@ static void collator_sort_internal( int renumber, INTERNAL_FUNCTION_PARAMETERS )
 	UCollator*     saved_collator;
 	zval*          array            = nullptr;
 	HashTable*     hash             = nullptr;
+	zend_array*    sorted           = nullptr;
 	zend_long           sort_flags       = COLLATOR_SORT_REGULAR;
 
 	COLLATOR_METHOD_INIT_VARS
 
 	/* Parse parameters. */
-	if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "Oa/|l",
+	if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "Oa|l",
 		&object, Collator_ce_ptr, &array, &sort_flags ) == FAILURE )
 	{
 		RETURN_THROWS();
@@ -286,8 +287,14 @@ static void collator_sort_internal( int renumber, INTERNAL_FUNCTION_PARAMETERS )
 
 	hash = Z_ARRVAL_P( array );
 
+	/* Copy array, so the in-place modifications will not be visible to the callback function */
+	sorted = zend_array_dup( hash );
+
 	/* Convert strings in the specified array from UTF-8 to UTF-16. */
-	collator_convert_hash_from_utf8_to_utf16( hash, COLLATOR_ERROR_CODE_P( co ) );
+	collator_convert_hash_from_utf8_to_utf16( sorted, COLLATOR_ERROR_CODE_P( co ) );
+	if( U_FAILURE( COLLATOR_ERROR_CODE( co ) ) ) {
+		zend_array_destroy( sorted );
+	}
 	COLLATOR_CHECK_STATUS( co, "Error converting hash from UTF-8 to UTF-16" );
 
 	/* Save specified collator in the request-global (?) variable. */
@@ -295,15 +302,23 @@ static void collator_sort_internal( int renumber, INTERNAL_FUNCTION_PARAMETERS )
 	INTL_G( current_collator ) = co->ucoll;
 
 	/* Sort specified array. */
-	zend_hash_sort(hash, collator_compare_func, renumber);
+	zend_hash_sort( sorted, collator_compare_func, renumber );
 
 	/* Restore saved collator. */
 	INTL_G( current_collator ) = saved_collator;
 
 	/* Convert strings in the specified array back to UTF-8. */
-	collator_convert_hash_from_utf16_to_utf8( hash, COLLATOR_ERROR_CODE_P( co ) );
+	collator_convert_hash_from_utf16_to_utf8( sorted, COLLATOR_ERROR_CODE_P( co ) );
+	if( U_FAILURE( COLLATOR_ERROR_CODE( co ) ) ) {
+		zend_array_destroy( sorted );
+	}
 	COLLATOR_CHECK_STATUS( co, "Error converting hash from UTF-16 to UTF-8" );
 
+	zval garbage;
+	ZVAL_COPY_VALUE( &garbage, array );
+	ZVAL_ARR( array, sorted );
+	zval_ptr_dtor( &garbage );
+
 	RETURN_TRUE;
 }
 /* }}} */
diff --git a/ext/intl/tests/collator_sort_modify_during_compare.phpt b/ext/intl/tests/collator_sort_modify_during_compare.phpt
new file mode 100644
index 000000000000..427f5833f1fc
--- /dev/null
+++ b/ext/intl/tests/collator_sort_modify_during_compare.phpt
@@ -0,0 +1,36 @@
+--TEST--
+Collator::sort(): mutating the array from __toString() during comparison must not corrupt the sort
+--EXTENSIONS--
+intl
+--FILE--
+<?php
+$c = new Collator('en_US');
+
+class Grow {
+    public static array $ref;
+    public function __toString(): string {
+        for ($i = 0; $i < 2000; $i++) {
+            self::$ref[] = "x$i";
+        }
+        return "m";
+    }
+}
+
+$arr = ["z", new Grow(), "a", "b"];
+Grow::$ref = &$arr;
+var_dump($c->sort($arr));
+var_dump($arr);
+?>
+--EXPECT--
+bool(true)
+array(4) {
+  [0]=>
+  string(1) "a"
+  [1]=>
+  string(1) "b"
+  [2]=>
+  object(Grow)#2 (0) {
+  }
+  [3]=>
+  string(1) "z"
+}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.