1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-26 20:34:47 +01:00

Allow taints to flow where no return type exists

Fixes #3652
This commit is contained in:
Brown 2020-06-23 15:52:19 -04:00
parent f46236ad71
commit 13fc8a75fd
3 changed files with 88 additions and 22 deletions

View File

@ -359,9 +359,7 @@ class FunctionCallAnalyzer extends CallAnalyzer
$context
);
if ($stmt_type) {
$statements_analyzer->node_data->setType($real_stmt, $stmt_type);
}
$statements_analyzer->node_data->setType($real_stmt, $stmt_type);
if ($config->after_every_function_checks) {
foreach ($config->after_every_function_checks as $plugin_fq_class_name) {
@ -897,7 +895,7 @@ class FunctionCallAnalyzer extends CallAnalyzer
?FunctionLikeStorage $function_storage,
TemplateResult $template_result,
Context $context
) : ?Type\Union {
) : Type\Union {
$stmt_type = null;
$config = $codebase->config;
@ -1026,7 +1024,11 @@ class FunctionCallAnalyzer extends CallAnalyzer
}
}
if ($function_storage && $stmt_type) {
if (!$stmt_type) {
$stmt_type = Type::getMixed();
}
if ($function_storage) {
self::taintReturnType($statements_analyzer, $stmt, $function_id, $function_storage, $stmt_type);
}

View File

@ -1239,24 +1239,24 @@ class StaticCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\
}
}
if ($return_type_candidate) {
self::taintReturnType(
$statements_analyzer,
$stmt,
$method_id,
$cased_method_id,
$return_type_candidate,
$method_storage
);
$return_type_candidate = $return_type_candidate ?: Type::getMixed();
if ($stmt_type = $statements_analyzer->node_data->getType($stmt)) {
$statements_analyzer->node_data->setType(
$stmt,
Type::combineUnionTypes($stmt_type, $return_type_candidate)
);
} else {
$statements_analyzer->node_data->setType($stmt, $return_type_candidate);
}
self::taintReturnType(
$statements_analyzer,
$stmt,
$method_id,
$cased_method_id,
$return_type_candidate,
$method_storage
);
if ($stmt_type = $statements_analyzer->node_data->getType($stmt)) {
$statements_analyzer->node_data->setType(
$stmt,
Type::combineUnionTypes($stmt_type, $return_type_candidate)
);
} else {
$statements_analyzer->node_data->setType($stmt, $return_type_candidate);
}
} else {
if ($stmt->name instanceof PhpParser\Node\Expr) {

View File

@ -1775,4 +1775,68 @@ class TaintTest extends TestCase
$this->analyzeFile('somefile.php', new Context());
}
public function testTaintedFunctionWithNoTypes() : void
{
$this->expectException(\Psalm\Exception\CodeException::class);
$this->expectExceptionMessage('TaintedInput');
$this->project_analyzer->trackTaintedInputs();
$this->addFile(
'somefile.php',
'<?php
function rawinput() {
return $_GET[\'rawinput\'];
}
echo rawinput();'
);
$this->analyzeFile('somefile.php', new Context());
}
public function testTaintedStaticCallWithNoTypes() : void
{
$this->expectException(\Psalm\Exception\CodeException::class);
$this->expectExceptionMessage('TaintedInput');
$this->project_analyzer->trackTaintedInputs();
$this->addFile(
'somefile.php',
'<?php
class A {
public static function rawinput() {
return $_GET[\'rawinput\'];
}
}
echo A::rawinput();'
);
$this->analyzeFile('somefile.php', new Context());
}
public function testTaintedInstanceCallWithNoTypes() : void
{
$this->expectException(\Psalm\Exception\CodeException::class);
$this->expectExceptionMessage('TaintedInput');
$this->project_analyzer->trackTaintedInputs();
$this->addFile(
'somefile.php',
'<?php
class A {
public function rawinput() {
return $_GET[\'rawinput\'];
}
}
echo (new A())->rawinput();'
);
$this->analyzeFile('somefile.php', new Context());
}
}