Skip to content

Commit 6f8d0ba

Browse files
committed
Fix bug #79868
This simply restores the code from PHP 7.4 which I incorrectly "simplified" in master.
1 parent 7fd4212 commit 6f8d0ba

File tree

3 files changed

+71
-8
lines changed

3 files changed

+71
-8
lines changed

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ PHP NEWS
1616
. Fixed bug #79867 (Promoted untyped properties should get null default
1717
value). (Nikita)
1818

19+
- Standard:
20+
. Fixed bug #79868 (Sorting with array_unique gives unwanted result). (Nikita)
21+
1922
09 Jul 2020, PHP 8.0.0alpha2
2023

2124
- FFI:

ext/standard/array.c

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4462,13 +4462,30 @@ PHP_FUNCTION(array_change_key_case)
44624462
}
44634463
/* }}} */
44644464

4465+
struct bucketindex {
4466+
Bucket b;
4467+
unsigned int i;
4468+
};
4469+
4470+
static void array_bucketindex_swap(void *p, void *q)
4471+
{
4472+
struct bucketindex *f = (struct bucketindex *)p;
4473+
struct bucketindex *g = (struct bucketindex *)q;
4474+
struct bucketindex t;
4475+
t = *f;
4476+
*f = *g;
4477+
*g = t;
4478+
}
4479+
44654480
/* {{{ Removes duplicate values from array */
44664481
PHP_FUNCTION(array_unique)
44674482
{
44684483
zval *array;
4469-
Bucket *p, *lastkept = NULL;
4484+
Bucket *p;
44704485
zend_long sort_type = PHP_SORT_STRING;
44714486
bucket_compare_func_t cmp;
4487+
struct bucketindex *arTmp, *cmpdata, *lastkept;
4488+
uint32_t i, idx;
44724489

44734490
ZEND_PARSE_PARAMETERS_START(1, 2)
44744491
Z_PARAM_ARRAY(array)
@@ -4520,19 +4537,47 @@ PHP_FUNCTION(array_unique)
45204537
return;
45214538
}
45224539

4523-
cmp = php_get_data_compare_func(sort_type, 0);
4540+
cmp = php_get_data_compare_func_unstable(sort_type, 0);
45244541

45254542
RETVAL_ARR(zend_array_dup(Z_ARRVAL_P(array)));
4526-
zend_hash_sort(Z_ARRVAL_P(return_value), cmp, /* reindex */ 0);
45274543

4544+
/* create and sort array with pointers to the target_hash buckets */
4545+
arTmp = pemalloc((Z_ARRVAL_P(array)->nNumOfElements + 1) * sizeof(struct bucketindex), GC_FLAGS(Z_ARRVAL_P(array)) & IS_ARRAY_PERSISTENT);
4546+
for (i = 0, idx = 0; idx < Z_ARRVAL_P(array)->nNumUsed; idx++) {
4547+
p = Z_ARRVAL_P(array)->arData + idx;
4548+
if (Z_TYPE(p->val) == IS_UNDEF) continue;
4549+
if (Z_TYPE(p->val) == IS_INDIRECT && Z_TYPE_P(Z_INDIRECT(p->val)) == IS_UNDEF) continue;
4550+
arTmp[i].b = *p;
4551+
arTmp[i].i = i;
4552+
i++;
4553+
}
4554+
ZVAL_UNDEF(&arTmp[i].b.val);
4555+
zend_sort((void *) arTmp, i, sizeof(struct bucketindex),
4556+
(compare_func_t) cmp, (swap_func_t) array_bucketindex_swap);
45284557
/* go through the sorted array and delete duplicates from the copy */
4529-
ZEND_HASH_FOREACH_BUCKET(Z_ARRVAL_P(return_value), p) {
4530-
if (!lastkept || cmp(lastkept, p)) {
4531-
lastkept = p;
4558+
lastkept = arTmp;
4559+
for (cmpdata = arTmp + 1; Z_TYPE(cmpdata->b.val) != IS_UNDEF; cmpdata++) {
4560+
if (cmp(&lastkept->b, &cmpdata->b)) {
4561+
lastkept = cmpdata;
45324562
} else {
4533-
zend_hash_del_bucket(Z_ARRVAL_P(return_value), p);
4563+
if (lastkept->i > cmpdata->i) {
4564+
p = &lastkept->b;
4565+
lastkept = cmpdata;
4566+
} else {
4567+
p = &cmpdata->b;
4568+
}
4569+
if (p->key == NULL) {
4570+
zend_hash_index_del(Z_ARRVAL_P(return_value), p->h);
4571+
} else {
4572+
if (Z_ARRVAL_P(return_value) == &EG(symbol_table)) {
4573+
zend_delete_global_variable(p->key);
4574+
} else {
4575+
zend_hash_del(Z_ARRVAL_P(return_value), p->key);
4576+
}
4577+
}
45344578
}
4535-
} ZEND_HASH_FOREACH_END();
4579+
}
4580+
pefree(arTmp, GC_FLAGS(Z_ARRVAL_P(array)) & IS_ARRAY_PERSISTENT);
45364581
}
45374582
/* }}} */
45384583

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
--TEST--
2+
Bug #79868: Sorting with array_unique gives unwanted result
3+
--FILE--
4+
<?php
5+
6+
var_dump(array_unique(['b', 'a', 'b'], SORT_REGULAR));
7+
8+
?>
9+
--EXPECT--
10+
array(2) {
11+
[0]=>
12+
string(1) "b"
13+
[1]=>
14+
string(1) "a"
15+
}

0 commit comments

Comments
 (0)