Skip to content

Commit cee8ed2

Browse files
committed
Merge branch 'PHP-8.4'
* PHP-8.4: Fix GH-19300: Nested array_multisort invocation with error breaks
2 parents 659f55a + b82c8ba commit cee8ed2

File tree

3 files changed

+88
-4
lines changed

3 files changed

+88
-4
lines changed

ext/standard/array.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6051,7 +6051,7 @@ PHP_FUNCTION(array_multisort)
60516051
for (i = 0; i < MULTISORT_LAST; i++) {
60526052
parse_state[i] = 0;
60536053
}
6054-
func = ARRAYG(multisort_func) = ecalloc(argc, sizeof(bucket_compare_func_t));
6054+
func = ecalloc(argc, sizeof(bucket_compare_func_t));
60556055

60566056
/* Here we go through the input arguments and parse them. Each one can
60576057
* be either an array or a sort flag which follows an array. If not
@@ -6067,7 +6067,7 @@ PHP_FUNCTION(array_multisort)
60676067
/* We see the next array, so we update the sort flags of
60686068
* the previous array and reset the sort flags. */
60696069
if (i > 0) {
6070-
ARRAYG(multisort_func)[num_arrays - 1] = php_get_data_compare_func_unstable(sort_type, sort_order != PHP_SORT_ASC);
6070+
func[num_arrays - 1] = php_get_data_compare_func_unstable(sort_type, sort_order != PHP_SORT_ASC);
60716071
sort_order = PHP_SORT_ASC;
60726072
sort_type = PHP_SORT_REGULAR;
60736073
}
@@ -6119,8 +6119,6 @@ PHP_FUNCTION(array_multisort)
61196119
MULTISORT_ABORT;
61206120
}
61216121
}
6122-
/* Take care of the last array sort flags. */
6123-
ARRAYG(multisort_func)[num_arrays - 1] = php_get_data_compare_func_unstable(sort_type, sort_order != PHP_SORT_ASC);
61246122

61256123
/* Make sure the arrays are of the same size. */
61266124
array_size = zend_hash_num_elements(Z_ARRVAL_P(arrays[0]));
@@ -6138,6 +6136,11 @@ PHP_FUNCTION(array_multisort)
61386136
RETURN_TRUE;
61396137
}
61406138

6139+
/* Take care of the last array sort flags. */
6140+
func[num_arrays - 1] = php_get_data_compare_func_unstable(sort_type, sort_order != PHP_SORT_ASC);
6141+
bucket_compare_func_t *old_multisort_func = ARRAYG(multisort_func);
6142+
ARRAYG(multisort_func) = func;
6143+
61416144
/* Create the indirection array. This array is of size MxN, where
61426145
* M is the number of entries in each input array and N is the number
61436146
* of the input arrays + 1. The last column is UNDEF to indicate the end
@@ -6214,6 +6217,7 @@ PHP_FUNCTION(array_multisort)
62146217
efree(indirect);
62156218
efree(func);
62166219
efree(arrays);
6220+
ARRAYG(multisort_func) = old_multisort_func;
62176221
}
62186222
/* }}} */
62196223

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
--TEST--
2+
GH-19300 (Nested array_multisort invocation with error breaks) - correct invocation variation
3+
--FILE--
4+
<?php
5+
class MyStringable {
6+
public function __construct(private string $data) {}
7+
public function __tostring() {
8+
array_multisort([]); // Trigger update of array sort globals in happy path
9+
return $this->data;
10+
}
11+
}
12+
13+
$inputs = [
14+
new MyStringable('3'),
15+
new MyStringable('1'),
16+
new MyStringable('2'),
17+
];
18+
19+
var_dump(array_multisort($inputs, SORT_STRING));
20+
var_dump($inputs);
21+
?>
22+
--EXPECT--
23+
bool(true)
24+
array(3) {
25+
[0]=>
26+
object(MyStringable)#2 (1) {
27+
["data":"MyStringable":private]=>
28+
string(1) "1"
29+
}
30+
[1]=>
31+
object(MyStringable)#3 (1) {
32+
["data":"MyStringable":private]=>
33+
string(1) "2"
34+
}
35+
[2]=>
36+
object(MyStringable)#1 (1) {
37+
["data":"MyStringable":private]=>
38+
string(1) "3"
39+
}
40+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
--TEST--
2+
GH-19300 (Nested array_multisort invocation with error breaks) - error variation
3+
--FILE--
4+
<?php
5+
6+
function error_handle($level, $message, $file = '', $line = 0){
7+
try {
8+
array_multisort($a, SORT_ASC); // Trigger multisort abort
9+
} catch (TypeError $e) {
10+
echo $e->getMessage(), "\n";
11+
}
12+
}
13+
set_error_handler('error_handle');
14+
15+
$inputs = [
16+
new stdClass,
17+
new stdClass,
18+
new stdClass,
19+
];
20+
21+
var_dump(array_multisort($inputs, SORT_NUMERIC));
22+
var_dump($inputs);
23+
?>
24+
--EXPECT--
25+
array_multisort(): Argument #1 ($array) must be an array or a sort flag
26+
array_multisort(): Argument #1 ($array) must be an array or a sort flag
27+
array_multisort(): Argument #1 ($array) must be an array or a sort flag
28+
array_multisort(): Argument #1 ($array) must be an array or a sort flag
29+
bool(true)
30+
array(3) {
31+
[0]=>
32+
object(stdClass)#1 (0) {
33+
}
34+
[1]=>
35+
object(stdClass)#2 (0) {
36+
}
37+
[2]=>
38+
object(stdClass)#3 (0) {
39+
}
40+
}

0 commit comments

Comments
 (0)