1
0
mirror of https://github.com/danog/psalm.git synced 2025-01-21 21:31:13 +01:00

Fix #4910 - don’t allow array_merge to create massive keyed arrays

This commit is contained in:
Matthew Brown 2021-05-13 16:27:05 -04:00
parent 78ed9404cb
commit 2ebf97b4cb
2 changed files with 35 additions and 1 deletions

View File

@ -38,6 +38,8 @@ class ArrayMergeReturnTypeProvider implements \Psalm\Plugin\EventHandler\Functio
$all_nonempty_lists = true;
$any_nonempty = false;
$max_keyed_array_size = 0;
foreach ($call_args as $call_arg) {
if (!($call_arg_type = $statements_source->node_data->getType($call_arg->value))) {
return Type::getArray();
@ -77,6 +79,11 @@ class ArrayMergeReturnTypeProvider implements \Psalm\Plugin\EventHandler\Functio
}
if ($unpacked_type_part instanceof Type\Atomic\TKeyedArray) {
$max_keyed_array_size = \max(
$max_keyed_array_size,
count($unpacked_type_part->properties)
);
foreach ($unpacked_type_part->properties as $key => $type) {
if (!\is_string($key)) {
$generic_properties[] = $type;
@ -185,7 +192,13 @@ class ArrayMergeReturnTypeProvider implements \Psalm\Plugin\EventHandler\Functio
$inner_value_type = TypeCombiner::combine($inner_value_types, $codebase, true);
}
if ($generic_properties) {
$generic_property_count = count($generic_properties);
if ($generic_properties
&& $generic_property_count < 64
&& ($generic_property_count < $max_keyed_array_size * 2
|| $generic_property_count < 16)
) {
$objectlike = new Type\Atomic\TKeyedArray($generic_properties);
if ($all_nonempty_lists || $all_int_offsets) {

View File

@ -134,6 +134,27 @@ class ForTest extends \Psalm\Tests\TestCase
for ($i = 20; $arr[$i] === 5 && $i > 0; $i--) {}
}'
],
'noCrashOnLongThing' => [
'<?php
/**
* @param list<array{a: array{int, int}}> $data
*/
function makeData(array $data) : array {
while (rand(0, 1)) {
while (rand(0, 1)) {
while (rand(0, 1)) {
if (rand(0, 1)) {
continue;
}
$data[0]["a"] = array_merge($data[0]["a"], $data[0]["a"]);
}
}
}
return $data;
}'
],
];
}