diff --git a/ext/intl/collator/collator_sort.c b/ext/intl/collator/collator_sort.c index 47e48624e6b7..9d4cb4220203 100644 --- a/ext/intl/collator/collator_sort.c +++ b/ext/intl/collator/collator_sort.c @@ -259,12 +259,13 @@ static void collator_sort_internal( int renumber, INTERNAL_FUNCTION_PARAMETERS ) UCollator* saved_collator; zval* array = NULL; HashTable* hash = NULL; + zend_array* sorted = NULL; 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(); @@ -283,8 +284,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. */ @@ -292,15 +299,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-- +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" +}