Skip to content

Commit 8b64f74

Browse files
committed
proper fix for bug #50006
add modify protection to all user array sorts
1 parent 937358e commit 8b64f74

File tree

3 files changed

+80
-3
lines changed

3 files changed

+80
-3
lines changed

ext/standard/array.c

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -768,6 +768,7 @@ static int php_array_user_key_compare(const void *a, const void *b TSRMLS_DC) /*
768768
PHP_FUNCTION(uksort)
769769
{
770770
zval *array;
771+
int refcount;
771772
PHP_ARRAY_CMP_FUNC_VARS;
772773

773774
PHP_ARRAY_CMP_FUNC_BACKUP();
@@ -777,13 +778,31 @@ PHP_FUNCTION(uksort)
777778
return;
778779
}
779780

781+
/* Clear the is_ref flag, so the attemts to modify the array in user
782+
* comaprison function will create a copy of array and won't affect the
783+
* original array. The fact of modification is detected using refcount
784+
* comparison. The result of sorting in such case is undefined and the
785+
* function returns FALSE.
786+
*/
787+
Z_UNSET_ISREF_P(array);
788+
refcount = Z_REFCOUNT_P(array);
789+
780790
if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_user_key_compare, 0 TSRMLS_CC) == FAILURE) {
781-
PHP_ARRAY_CMP_FUNC_RESTORE();
782-
RETURN_FALSE;
791+
RETVAL_FALSE;
792+
} else {
793+
if (refcount > Z_REFCOUNT_P(array)) {
794+
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Array was modified by the user comparison function");
795+
RETVAL_FALSE;
796+
} else {
797+
RETVAL_TRUE;
798+
}
799+
}
800+
801+
if (Z_REFCOUNT_P(array) > 1) {
802+
Z_SET_ISREF_P(array);
783803
}
784804

785805
PHP_ARRAY_CMP_FUNC_RESTORE();
786-
RETURN_TRUE;
787806
}
788807
/* }}} */
789808

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
--TEST--
2+
Bug #50006 (Segfault caused by uksort()) - usort variant
3+
--FILE--
4+
<?php
5+
6+
$data = array(
7+
'bar-bazbazbaz.',
8+
'bar-bazbazbaz-',
9+
'foo'
10+
);
11+
usort($data, 'magic_sort_cmp');
12+
print_r($data);
13+
14+
function magic_sort_cmp($a, $b) {
15+
$a = substr($a, 1);
16+
$b = substr($b, 1);
17+
if (!$a) return $b ? -1 : 0;
18+
if (!$b) return 1;
19+
return magic_sort_cmp($a, $b);
20+
}
21+
22+
?>
23+
--EXPECTF--
24+
Array
25+
(
26+
[0] => foo
27+
[1] => bar-bazbazbaz-
28+
[2] => bar-bazbazbaz.
29+
)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
--TEST--
2+
Bug #50006 (Segfault caused by uksort()) - uasort variant
3+
--FILE--
4+
<?php
5+
6+
$data = array(
7+
'bar-bazbazbaz.',
8+
'bar-bazbazbaz-',
9+
'foo'
10+
);
11+
uasort($data, 'magic_sort_cmp');
12+
print_r($data);
13+
14+
function magic_sort_cmp($a, $b) {
15+
$a = substr($a, 1);
16+
$b = substr($b, 1);
17+
if (!$a) return $b ? -1 : 0;
18+
if (!$b) return 1;
19+
return magic_sort_cmp($a, $b);
20+
}
21+
22+
?>
23+
--EXPECTF--
24+
Array
25+
(
26+
[2] => foo
27+
[1] => bar-bazbazbaz-
28+
[0] => bar-bazbazbaz.
29+
)

0 commit comments

Comments
 (0)