diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallAnalyzer.php index 233907ed7..f62a93e89 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallAnalyzer.php @@ -1426,28 +1426,40 @@ class FunctionCallAnalyzer extends CallAnalyzer continue; } - $arg_location = new CodeLocation( - $statements_analyzer->getSource(), - $stmt->args[$i]->value - ); + $current_arg_is_variadic = $function_storage->params[$i]->is_variadic; + $taintableArgIndex = [$i]; - $function_param_sink = DataFlowNode::getForMethodArgument( - $function_id, - $function_id, - $i, - $arg_location, - $function_storage->specialize_call ? $node_location : null - ); + if ($current_arg_is_variadic) { + $max_params = count($stmt->args) - 1; + for ($arg_index = $i + 1; $arg_index <= $max_params; $arg_index++) { + $taintableArgIndex[] = $arg_index; + } + } - $statements_analyzer->data_flow_graph->addNode($function_param_sink); + foreach ($taintableArgIndex as $argIndex) { + $arg_location = new CodeLocation( + $statements_analyzer->getSource(), + $stmt->args[$argIndex]->value + ); - $statements_analyzer->data_flow_graph->addPath( - $function_param_sink, - $function_call_node, - $path_type, - $function_storage->added_taints, - $removed_taints - ); + $function_param_sink = DataFlowNode::getForMethodArgument( + $function_id, + $function_id, + $argIndex, + $arg_location, + $function_storage->specialize_call ? $node_location : null + ); + + $statements_analyzer->data_flow_graph->addNode($function_param_sink); + + $statements_analyzer->data_flow_graph->addPath( + $function_param_sink, + $function_call_node, + $path_type, + $function_storage->added_taints, + $removed_taints + ); + } } } diff --git a/tests/TaintTest.php b/tests/TaintTest.php index a512dc755..3024e43fa 100644 --- a/tests/TaintTest.php +++ b/tests/TaintTest.php @@ -1826,6 +1826,22 @@ class TaintTest extends TestCase setcookie($_GET[\'taint\'], \'value\');', 'error_message' => 'TaintedCookie', ], + 'variadicTaintPropagation' => [ + ' return + */ + function variadic_test(string $format, ...$args) : string { + } + + echo variadic_test(\'\', \'\', $_GET[\'taint\'], \'\');', + 'error_message' => 'TaintedHtml' + ], 'potentialTaintThroughChildClassSettingProperty' => [ '