diff --git a/src/Psalm/Internal/Analyzer/NamespaceAnalyzer.php b/src/Psalm/Internal/Analyzer/NamespaceAnalyzer.php index 934704522..c6d06ce08 100644 --- a/src/Psalm/Internal/Analyzer/NamespaceAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/NamespaceAnalyzer.php @@ -82,7 +82,7 @@ class NamespaceAnalyzer extends SourceAnalyzer implements StatementsSource $context->is_global = true; $context->defineGlobals(); $context->collect_exceptions = $codebase->config->check_for_throws_in_global_scope; - $statements_analyzer->analyze($leftover_stmts, $context); + $statements_analyzer->analyze($leftover_stmts, $context, null, true); $file_context = $this->source->context; if ($file_context) { diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallAnalyzer.php index ab2b2a5f9..3bbc1b2e4 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallAnalyzer.php @@ -1068,18 +1068,18 @@ class FunctionCallAnalyzer extends CallAnalyzer return; } - $return_location = new CodeLocation($statements_analyzer->getSource(), $stmt); + $node_location = new CodeLocation($statements_analyzer->getSource(), $stmt); - $function_return_sink = TaintNode::getForMethodReturn( + $function_call_node = TaintNode::getForMethodReturn( $function_id, $function_id, - $return_location, - $function_storage->specialize_call ? $return_location : null + $function_storage->signature_return_type_location ?: $function_storage->location, + $function_storage->specialize_call ? $node_location : null ); - $statements_analyzer->taint_graph->addTaintNode($function_return_sink); + $statements_analyzer->taint_graph->addTaintNode($function_call_node); - $stmt_type->parent_nodes[] = $function_return_sink; + $stmt_type->parent_nodes[] = $function_call_node; if ($function_storage->return_source_params) { $removed_taints = $function_storage->removed_taints; @@ -1126,14 +1126,14 @@ class FunctionCallAnalyzer extends CallAnalyzer $function_id, $i, $arg_location, - $function_storage->specialize_call ? $return_location : null + $function_storage->specialize_call ? $node_location : null ); $statements_analyzer->taint_graph->addTaintNode($function_param_sink); $statements_analyzer->taint_graph->addPath( $function_param_sink, - $function_return_sink, + $function_call_node, $path_type, $function_storage->added_taints, $removed_taints @@ -1145,7 +1145,7 @@ class FunctionCallAnalyzer extends CallAnalyzer $method_node = Source::getForMethodReturn( $function_id, $function_id, - $return_location + $node_location ); $method_node->taints = $function_storage->taint_source_types; diff --git a/src/Psalm/Internal/Analyzer/Statements/ReturnAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/ReturnAnalyzer.php index 0fa44da0a..1aee9b4f0 100644 --- a/src/Psalm/Internal/Analyzer/Statements/ReturnAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/ReturnAnalyzer.php @@ -505,7 +505,7 @@ class ReturnAnalyzer $method_node = TaintNode::getForMethodReturn( strtolower($cased_method_id), $cased_method_id, - $storage->location + $storage->signature_return_type_location ?: $storage->location, ); $statements_analyzer->taint_graph->addTaintNode($method_node); diff --git a/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php b/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php index 9aea676d2..f6c9e7ae1 100644 --- a/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php @@ -135,7 +135,7 @@ class StatementsAnalyzer extends SourceAnalyzer implements StatementsSource $this->file_analyzer = $source->getFileAnalyzer(); $this->codebase = $source->getCodebase(); $this->node_data = $node_data; - $this->taint_graph = $this->codebase->taint_graph; + $this->taint_graph = $this->codebase->taint_graph ? new TaintGraph() : null; } /** @@ -191,6 +191,10 @@ class StatementsAnalyzer extends SourceAnalyzer implements StatementsSource } } + if ($root_scope && $this->taint_graph && $this->codebase->taint_graph) { + $this->codebase->taint_graph->addGraph($this->taint_graph); + } + return null; } diff --git a/src/Psalm/Internal/Codebase/Analyzer.php b/src/Psalm/Internal/Codebase/Analyzer.php index 335e66081..fdd1d0e9d 100644 --- a/src/Psalm/Internal/Codebase/Analyzer.php +++ b/src/Psalm/Internal/Codebase/Analyzer.php @@ -483,7 +483,7 @@ class Analyzer } if ($codebase->taint_graph && $pool_data['taint_data']) { - $codebase->taint_graph->addData($pool_data['taint_data']); + $codebase->taint_graph->addGraph($pool_data['taint_data']); } $codebase->file_reference_provider->addNonMethodReferencesToClasses( diff --git a/src/Psalm/Internal/Codebase/Scanner.php b/src/Psalm/Internal/Codebase/Scanner.php index d55cba68b..ac0dd98eb 100644 --- a/src/Psalm/Internal/Codebase/Scanner.php +++ b/src/Psalm/Internal/Codebase/Scanner.php @@ -413,7 +413,7 @@ class Scanner $pool_data['diff_map'] ); if ($this->codebase->taint_graph && $pool_data['taint_data']) { - $this->codebase->taint_graph->addData($pool_data['taint_data']); + $this->codebase->taint_graph->addGraph($pool_data['taint_data']); } $this->codebase->file_storage_provider->addMore($pool_data['file_storage']); diff --git a/src/Psalm/Internal/Codebase/TaintGraph.php b/src/Psalm/Internal/Codebase/TaintGraph.php index 0a659fa4c..21513b5ed 100644 --- a/src/Psalm/Internal/Codebase/TaintGraph.php +++ b/src/Psalm/Internal/Codebase/TaintGraph.php @@ -151,7 +151,7 @@ class TaintGraph return [$node]; } - public function addData(self $taint) : void + public function addGraph(self $taint) : void { $this->sources += $taint->sources; $this->sinks += $taint->sinks; diff --git a/tests/TaintTest.php b/tests/TaintTest.php index 7d02043cc..d9ba6d743 100644 --- a/tests/TaintTest.php +++ b/tests/TaintTest.php @@ -516,7 +516,7 @@ class TaintTest extends TestCase } echo getName();', - 'error_message' => 'TaintedInput - src' . DIRECTORY_SEPARATOR . 'somefile.php:6:26 - Detected tainted html in path: $_GET -> $_GET[\'name\'] (src/somefile.php:3:32) -> getname (src/somefile.php:6:26) -> call to echo (src/somefile.php:6:26) -> echo#1', + 'error_message' => 'TaintedInput - src' . DIRECTORY_SEPARATOR . 'somefile.php:6:26 - Detected tainted html in path: $_GET -> $_GET[\'name\'] (src/somefile.php:3:32) -> getName (src/somefile.php:2:42) -> call to echo (src/somefile.php:6:26) -> echo#1', ], 'taintedInputFromExplicitTaintSource' => [ ' 'TaintedInput - src' . DIRECTORY_SEPARATOR . 'somefile.php:23:44 - Detected tainted sql in path: $_GET -> $_GET[\'user_id\'] (src/somefile.php:7:67) -> call to A::getAppendedUserId (src/somefile.php:7:58) -> A::getAppendedUserId#1 (src/somefile.php:11:66) -> concat (src/somefile.php:12:36) -> A::getAppendedUserId (src/somefile.php:11:41) -> call to A::deleteUser (src/somefile.php:7:33) -> A::deleteUser#3 (src/somefile.php:19:85) -> concat (src/somefile.php:23:44) -> call to PDO::exec (src/somefile.php:23:44) -> PDO::exec#1', + 'error_message' => 'TaintedInput - src' . DIRECTORY_SEPARATOR . 'somefile.php:23:44 - Detected tainted sql in path: $_GET -> $_GET[\'user_id\'] (src/somefile.php:7:67) -> call to A::getAppendedUserId (src/somefile.php:7:58) -> A::getAppendedUserId#1 (src/somefile.php:11:66) -> concat (src/somefile.php:12:36) -> A::getAppendedUserId (src/somefile.php:11:78) -> call to A::deleteUser (src/somefile.php:7:33) -> A::deleteUser#3 (src/somefile.php:19:85) -> concat (src/somefile.php:23:44) -> call to PDO::exec (src/somefile.php:23:44) -> PDO::exec#1', ], 'taintedInParentLoader' => [ '