mirror of
https://github.com/danog/psalm.git
synced 2024-11-26 20:34:47 +01:00
Support taint flows in more functions
This commit is contained in:
parent
7f05b3c530
commit
e8be2c500e
@ -468,8 +468,9 @@ class CommentAnalyzer
|
||||
}
|
||||
|
||||
if (isset($parsed_docblock->tags['psalm-flow'])) {
|
||||
$flow = trim(reset($parsed_docblock->tags['psalm-flow']));
|
||||
$info->flow = $flow;
|
||||
foreach ($parsed_docblock->tags['psalm-flow'] as $param) {
|
||||
$info->flows[] = trim($param);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($parsed_docblock->tags['psalm-taint-sink'])) {
|
||||
|
@ -1092,7 +1092,7 @@ class FunctionCallAnalyzer extends CallAnalyzer
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($function_storage->return_source_params as $i) {
|
||||
foreach ($function_storage->return_source_params as $i => $path_type) {
|
||||
if (!isset($stmt->args[$i])) {
|
||||
continue;
|
||||
}
|
||||
@ -1115,7 +1115,7 @@ class FunctionCallAnalyzer extends CallAnalyzer
|
||||
$codebase->taint->addPath(
|
||||
$function_param_sink,
|
||||
$function_return_sink,
|
||||
'arg',
|
||||
$path_type,
|
||||
$function_storage->added_taints,
|
||||
$removed_taints
|
||||
);
|
||||
|
@ -2515,21 +2515,35 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
|
||||
$storage->added_taints = $docblock_info->added_taints;
|
||||
$storage->removed_taints = $docblock_info->removed_taints;
|
||||
|
||||
if ($docblock_info->flow) {
|
||||
$flow_parts = explode('->', $docblock_info->flow);
|
||||
if ($docblock_info->flows) {
|
||||
foreach ($docblock_info->flows as $flow) {
|
||||
$path_type = 'arg';
|
||||
|
||||
if (isset($flow_parts[1]) && trim($flow_parts[1]) === 'return') {
|
||||
$source_param_string = trim($flow_parts[0]);
|
||||
$fancy_path_regex = '/-\(([a-z\-]+)\)->/';
|
||||
|
||||
if ($source_param_string[0] === '(' && substr($source_param_string, -1) === ')') {
|
||||
$source_params = preg_split('/, ?/', substr($source_param_string, 1, -1));
|
||||
if (preg_match($fancy_path_regex, $flow, $matches)) {
|
||||
if (isset($matches[1])) {
|
||||
$path_type = $matches[1];
|
||||
}
|
||||
|
||||
foreach ($source_params as $source_param) {
|
||||
$source_param = substr($source_param, 1);
|
||||
$flow = preg_replace($fancy_path_regex, '->', $flow);
|
||||
}
|
||||
|
||||
foreach ($storage->params as $i => $param_storage) {
|
||||
if ($param_storage->name === $source_param) {
|
||||
$storage->return_source_params[] = $i;
|
||||
$flow_parts = explode('->', $flow);
|
||||
|
||||
if (isset($flow_parts[1]) && trim($flow_parts[1]) === 'return') {
|
||||
$source_param_string = trim($flow_parts[0]);
|
||||
|
||||
if ($source_param_string[0] === '(' && substr($source_param_string, -1) === ')') {
|
||||
$source_params = preg_split('/, ?/', substr($source_param_string, 1, -1));
|
||||
|
||||
foreach ($source_params as $source_param) {
|
||||
$source_param = substr($source_param, 1);
|
||||
|
||||
foreach ($storage->params as $i => $param_storage) {
|
||||
if ($param_storage->name === $source_param) {
|
||||
$storage->return_source_params[$i] = $path_type;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -91,9 +91,9 @@ class FunctionDocblockComment
|
||||
/**
|
||||
* Represents the flow from function params to return type
|
||||
*
|
||||
* @var ?string
|
||||
* @var array<string>
|
||||
*/
|
||||
public $flow;
|
||||
public $flows = [];
|
||||
|
||||
/**
|
||||
* @var array<string>
|
||||
|
@ -480,6 +480,27 @@ function strtolower(string $str) : string {}
|
||||
*/
|
||||
function strtoupper(string $str) : string {}
|
||||
|
||||
/**
|
||||
* @psalm-pure
|
||||
*
|
||||
* @psalm-flow ($str) -> return
|
||||
*/
|
||||
function trim(string $str, string $character_mask = " \t\n\r\0\x0B") : string {}
|
||||
|
||||
/**
|
||||
* @psalm-pure
|
||||
*
|
||||
* @psalm-flow ($str) -> return
|
||||
*/
|
||||
function ltrim(string $str, string $character_mask = " \t\n\r\0\x0B") : string {}
|
||||
|
||||
/**
|
||||
* @psalm-pure
|
||||
*
|
||||
* @psalm-flow ($str) -> return
|
||||
*/
|
||||
function rtrim(string $str, string $character_mask = " \t\n\r\0\x0B") : string {}
|
||||
|
||||
/**
|
||||
* @psalm-pure
|
||||
*
|
||||
@ -493,10 +514,18 @@ function strtoupper(string $str) : string {}
|
||||
* : string
|
||||
* )
|
||||
*
|
||||
* @psalm-flow ($glue, $pieces) -> return
|
||||
* @psalm-flow ($glue) -> return
|
||||
* @psalm-flow ($pieces) -(array-fetch)-> return
|
||||
*/
|
||||
function implode($glue, array $pieces = []) : string {}
|
||||
|
||||
/**
|
||||
* @psalm-pure
|
||||
*
|
||||
* @psalm-flow ($string) -(array-assignment)-> return
|
||||
*/
|
||||
function explode(string $delimiter, string $string, int $limit = -1) : array {}
|
||||
|
||||
/**
|
||||
* @param array $input
|
||||
*
|
||||
@ -514,7 +543,7 @@ function array_sum(array $input) {}
|
||||
/**
|
||||
* @psalm-pure
|
||||
*
|
||||
* @psalm-taint-remove html
|
||||
* @psalm-taint-escape html
|
||||
* @psalm-flow ($str) -> return
|
||||
*/
|
||||
function strip_tags(string $str, ?string $allowable_tags = null) : string {}
|
||||
@ -522,7 +551,7 @@ function strip_tags(string $str, ?string $allowable_tags = null) : string {}
|
||||
/**
|
||||
* @psalm-pure
|
||||
*
|
||||
* @psalm-taint-remove html
|
||||
* @psalm-taint-escape html
|
||||
*
|
||||
* @psalm-flow ($string) -> return
|
||||
*/
|
||||
|
@ -205,7 +205,7 @@ abstract class FunctionLikeStorage
|
||||
public $removed_taints = [];
|
||||
|
||||
/**
|
||||
* @var list<int>
|
||||
* @var array<int, string>
|
||||
*/
|
||||
public $return_source_params = [];
|
||||
|
||||
|
@ -1698,4 +1698,23 @@ class TaintTest extends TestCase
|
||||
|
||||
$this->analyzeFile('somefile.php', new Context());
|
||||
}
|
||||
|
||||
public function testImplodeExplode() : void
|
||||
{
|
||||
$this->expectException(\Psalm\Exception\CodeException::class);
|
||||
$this->expectExceptionMessage('TaintedInput');
|
||||
|
||||
$this->project_analyzer->trackTaintedInputs();
|
||||
|
||||
$this->addFile(
|
||||
'somefile.php',
|
||||
'<?php
|
||||
$a = $_GET["name"];
|
||||
$b = explode(" ", $a);
|
||||
$c = implode(" ", $b);
|
||||
echo $c;'
|
||||
);
|
||||
|
||||
$this->analyzeFile('somefile.php', new Context());
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user