mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
Merge branch 'PHP-8.3' into PHP-8.4
* PHP-8.3: Fix array going away during sorting
This commit is contained in:
1
NEWS
1
NEWS
@@ -9,6 +9,7 @@ PHP NEWS
|
||||
(nielsdos)
|
||||
. Fixed bug GH-16615 (Assertion failure in zend_std_read_property). (Arnaud)
|
||||
. Fixed bug GH-16342 (Added ReflectionProperty::isLazy()). (Arnaud)
|
||||
. Fixed bug GH-16648 (Use-after-free during array sorting). (ilutov)
|
||||
|
||||
- Date:
|
||||
. Fixed bug GH-14732 (date_sun_info() fails for non-finite values). (cmb)
|
||||
|
||||
49
Zend/tests/gh16648.phpt
Normal file
49
Zend/tests/gh16648.phpt
Normal file
@@ -0,0 +1,49 @@
|
||||
--TEST--
|
||||
GH-16648: Use-after-free during array sorting
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function resize_arr() {
|
||||
global $arr;
|
||||
for ($i = 0; $i < 10; $i++) {
|
||||
$arr[$i] = $i;
|
||||
}
|
||||
}
|
||||
|
||||
class C {
|
||||
function __toString() {
|
||||
resize_arr();
|
||||
return '3';
|
||||
}
|
||||
}
|
||||
|
||||
$arr = ['a' => '1', '3' => new C, '2' => '2'];
|
||||
asort($arr);
|
||||
var_dump($arr);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
array(11) {
|
||||
["a"]=>
|
||||
string(1) "1"
|
||||
[3]=>
|
||||
int(3)
|
||||
[2]=>
|
||||
int(2)
|
||||
[0]=>
|
||||
int(0)
|
||||
[1]=>
|
||||
int(1)
|
||||
[4]=>
|
||||
int(4)
|
||||
[5]=>
|
||||
int(5)
|
||||
[6]=>
|
||||
int(6)
|
||||
[7]=>
|
||||
int(7)
|
||||
[8]=>
|
||||
int(8)
|
||||
[9]=>
|
||||
int(9)
|
||||
}
|
||||
@@ -2973,13 +2973,12 @@ ZEND_API void zend_hash_bucket_packed_swap(Bucket *p, Bucket *q)
|
||||
q->h = h;
|
||||
}
|
||||
|
||||
ZEND_API void ZEND_FASTCALL zend_hash_sort_ex(HashTable *ht, sort_func_t sort, bucket_compare_func_t compar, bool renumber)
|
||||
static void zend_hash_sort_internal(HashTable *ht, sort_func_t sort, bucket_compare_func_t compar, bool renumber)
|
||||
{
|
||||
Bucket *p;
|
||||
uint32_t i, j;
|
||||
|
||||
IS_CONSISTENT(ht);
|
||||
HT_ASSERT_RC1(ht);
|
||||
|
||||
if (!(ht->nNumOfElements>1) && !(renumber && ht->nNumOfElements>0)) {
|
||||
/* Doesn't require sorting */
|
||||
@@ -3066,6 +3065,33 @@ ZEND_API void ZEND_FASTCALL zend_hash_sort_ex(HashTable *ht, sort_func_t sort, b
|
||||
}
|
||||
}
|
||||
|
||||
ZEND_API void ZEND_FASTCALL zend_hash_sort_ex(HashTable *ht, sort_func_t sort, bucket_compare_func_t compar, bool renumber)
|
||||
{
|
||||
HT_ASSERT_RC1(ht);
|
||||
zend_hash_sort_internal(ht, sort, compar, renumber);
|
||||
}
|
||||
|
||||
void ZEND_FASTCALL zend_array_sort_ex(HashTable *ht, sort_func_t sort, bucket_compare_func_t compar, bool renumber)
|
||||
{
|
||||
HT_ASSERT_RC1(ht);
|
||||
|
||||
/* Unpack the array early to avoid RCn assertion failures. */
|
||||
if (HT_IS_PACKED(ht)) {
|
||||
zend_hash_packed_to_hash(ht);
|
||||
}
|
||||
|
||||
/* Adding a refcount prevents the array from going away. */
|
||||
GC_ADDREF(ht);
|
||||
|
||||
zend_hash_sort_internal(ht, sort, compar, renumber);
|
||||
|
||||
if (UNEXPECTED(GC_DELREF(ht) == 0)) {
|
||||
zend_array_destroy(ht);
|
||||
} else {
|
||||
gc_check_possible_root((zend_refcounted *)ht);
|
||||
}
|
||||
}
|
||||
|
||||
static zend_always_inline int zend_hash_compare_impl(HashTable *ht1, HashTable *ht2, compare_func_t compar, bool ordered) {
|
||||
uint32_t idx1, idx2;
|
||||
zend_string *key1, *key2;
|
||||
|
||||
@@ -299,12 +299,20 @@ ZEND_API void zend_hash_bucket_packed_swap(Bucket *p, Bucket *q);
|
||||
typedef int (*bucket_compare_func_t)(Bucket *a, Bucket *b);
|
||||
ZEND_API int zend_hash_compare(HashTable *ht1, HashTable *ht2, compare_func_t compar, bool ordered);
|
||||
ZEND_API void ZEND_FASTCALL zend_hash_sort_ex(HashTable *ht, sort_func_t sort_func, bucket_compare_func_t compare_func, bool renumber);
|
||||
void ZEND_FASTCALL zend_array_sort_ex(HashTable *ht, sort_func_t sort_func, bucket_compare_func_t compare_func, bool renumber);
|
||||
ZEND_API zval* ZEND_FASTCALL zend_hash_minmax(const HashTable *ht, compare_func_t compar, uint32_t flag);
|
||||
|
||||
static zend_always_inline void ZEND_FASTCALL zend_hash_sort(HashTable *ht, bucket_compare_func_t compare_func, bool renumber) {
|
||||
zend_hash_sort_ex(ht, zend_sort, compare_func, renumber);
|
||||
}
|
||||
|
||||
/* Use this variant over zend_hash_sort() when sorting user arrays that may
|
||||
* trigger user code. It will ensure the user code cannot free the array during
|
||||
* sorting. */
|
||||
static zend_always_inline void zend_array_sort(HashTable *ht, bucket_compare_func_t compare_func, zend_bool renumber) {
|
||||
zend_array_sort_ex(ht, zend_sort, compare_func, renumber);
|
||||
}
|
||||
|
||||
static zend_always_inline uint32_t zend_hash_num_elements(const HashTable *ht) {
|
||||
return ht->nNumOfElements;
|
||||
}
|
||||
|
||||
@@ -292,7 +292,7 @@ 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_array_sort(hash, collator_compare_func, renumber);
|
||||
|
||||
/* Restore saved collator. */
|
||||
INTL_G( current_collator ) = saved_collator;
|
||||
|
||||
@@ -700,9 +700,9 @@ static void php_natsort(INTERNAL_FUNCTION_PARAMETERS, int fold_case) /* {{{ */
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
|
||||
if (fold_case) {
|
||||
zend_hash_sort(Z_ARRVAL_P(array), php_array_natural_case_compare, 0);
|
||||
zend_array_sort(Z_ARRVAL_P(array), php_array_natural_case_compare, 0);
|
||||
} else {
|
||||
zend_hash_sort(Z_ARRVAL_P(array), php_array_natural_compare, 0);
|
||||
zend_array_sort(Z_ARRVAL_P(array), php_array_natural_compare, 0);
|
||||
}
|
||||
|
||||
RETURN_TRUE;
|
||||
@@ -738,7 +738,7 @@ PHP_FUNCTION(asort)
|
||||
|
||||
cmp = php_get_data_compare_func(sort_type, 0);
|
||||
|
||||
zend_hash_sort(Z_ARRVAL_P(array), cmp, 0);
|
||||
zend_array_sort(Z_ARRVAL_P(array), cmp, 0);
|
||||
|
||||
RETURN_TRUE;
|
||||
}
|
||||
@@ -759,7 +759,7 @@ PHP_FUNCTION(arsort)
|
||||
|
||||
cmp = php_get_data_compare_func(sort_type, 1);
|
||||
|
||||
zend_hash_sort(Z_ARRVAL_P(array), cmp, 0);
|
||||
zend_array_sort(Z_ARRVAL_P(array), cmp, 0);
|
||||
|
||||
RETURN_TRUE;
|
||||
}
|
||||
@@ -780,7 +780,7 @@ PHP_FUNCTION(sort)
|
||||
|
||||
cmp = php_get_data_compare_func(sort_type, 0);
|
||||
|
||||
zend_hash_sort(Z_ARRVAL_P(array), cmp, 1);
|
||||
zend_array_sort(Z_ARRVAL_P(array), cmp, 1);
|
||||
|
||||
RETURN_TRUE;
|
||||
}
|
||||
@@ -801,7 +801,7 @@ PHP_FUNCTION(rsort)
|
||||
|
||||
cmp = php_get_data_compare_func(sort_type, 1);
|
||||
|
||||
zend_hash_sort(Z_ARRVAL_P(array), cmp, 1);
|
||||
zend_array_sort(Z_ARRVAL_P(array), cmp, 1);
|
||||
|
||||
RETURN_TRUE;
|
||||
}
|
||||
@@ -899,7 +899,7 @@ static void php_usort(INTERNAL_FUNCTION_PARAMETERS, bucket_compare_func_t compar
|
||||
/* Copy array, so the in-place modifications will not be visible to the callback function */
|
||||
arr = zend_array_dup(arr);
|
||||
|
||||
zend_hash_sort(arr, compare_func, renumber);
|
||||
zend_array_sort(arr, compare_func, renumber);
|
||||
|
||||
zval garbage;
|
||||
ZVAL_COPY_VALUE(&garbage, array);
|
||||
|
||||
Reference in New Issue
Block a user