diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/Call/ArgumentAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/Call/ArgumentAnalyzer.php index 3f19d42e9..1c19769df 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/Call/ArgumentAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/Call/ArgumentAnalyzer.php @@ -1278,27 +1278,28 @@ class ArgumentAnalyzer : null ); - if ($statements_analyzer->data_flow_graph instanceof TaintFlowGraph && strpos($cased_method_id, '::')) { + if ($statements_analyzer->data_flow_graph instanceof TaintFlowGraph + && strpos($cased_method_id, '::') + && !strpos($cased_method_id, '::__construct') + ) { [$fq_classlike_name, $cased_method_name] = explode('::', $cased_method_id); $method_name = strtolower($cased_method_name); $class_storage = $codebase->classlike_storage_provider->get($fq_classlike_name); - if (!strpos($cased_method_id, '::__construct')) { - foreach ($class_storage->dependent_classlikes as $dependent_classlike_lc => $_) { - $dependent_classlike_storage = $codebase->classlike_storage_provider->get( - $dependent_classlike_lc - ); - $new_sink = DataFlowNode::getForMethodArgument( - $dependent_classlike_lc . '::' . $method_name, - $dependent_classlike_storage->name . '::' . $cased_method_name, - $argument_offset, - $arg_location, - null - ); + foreach ($class_storage->dependent_classlikes as $dependent_classlike_lc => $_) { + $dependent_classlike_storage = $codebase->classlike_storage_provider->get( + $dependent_classlike_lc + ); + $new_sink = DataFlowNode::getForMethodArgument( + $dependent_classlike_lc . '::' . $method_name, + $dependent_classlike_storage->name . '::' . $cased_method_name, + $argument_offset, + $arg_location, + null + ); - $statements_analyzer->data_flow_graph->addNode($new_sink); - $statements_analyzer->data_flow_graph->addPath($method_node, $new_sink, 'arg'); - } + $statements_analyzer->data_flow_graph->addNode($new_sink); + $statements_analyzer->data_flow_graph->addPath($method_node, $new_sink, 'arg'); } if (isset($class_storage->overridden_method_ids[$method_name])) { diff --git a/tests/TaintTest.php b/tests/TaintTest.php index d65ead764..a964428a3 100644 --- a/tests/TaintTest.php +++ b/tests/TaintTest.php @@ -700,7 +700,7 @@ class TaintTest extends TestCase $pdo->exec("delete from users where user_id = " . $userId); } }', - 'error_message' => 'TaintedSql - src' . DIRECTORY_SEPARATOR . 'somefile.php:17:40 - Detected tainted SQL in path: $_GET -> $_GET[\'user_id\'] (src/somefile.php:4:45) -> A::getUserId (src/somefile.php:3:55) -> concat (src/somefile.php:8:36) -> A::getAppendedUserId (src/somefile.php:7:63) -> $userId (src/somefile.php:12:29) -> call to A::deleteUser (src/somefile.php:13:53) -> $userId (src/somefile.php:16:69) -> concat (src/somefile.php:17:40) -> call to PDO::exec (src/somefile.php:17:40) -> PDO::exec#1', + 'error_message' => 'TaintedSql - src' . DIRECTORY_SEPARATOR . 'somefile.php:17:40 - Detected tainted SQL in path: $_GET -> $_GET[\'user_id\'] (src/somefile.php:4:45) -> A::getUserId (src/somefile.php:3:55) -> concat (src/somefile.php:8:36) -> A::getAppendedUserId (src/somefile.php:7:63) -> $userId (src/somefile.php:12:29) -> call to A::deleteUser (src/somefile.php:13:53) -> $userId (src/somefile.php:16:69) -> call to PDO::exec (src/somefile.php:17:40) -> PDO::exec#1', ], 'taintedInputToParam' => [ ' 'TaintedSql - 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) -> $user_id (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) -> $userId2 (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' => 'TaintedSql - 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) -> $user_id (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) -> $userId2 (src/somefile.php:19:85) -> call to PDO::exec (src/somefile.php:23:44) -> PDO::exec#1', ], 'taintedInParentLoader' => [ 'foo((string) $_GET["user_id"]);', - 'error_message' => 'TaintedSql - src' . DIRECTORY_SEPARATOR . 'somefile.php:16:44 - Detected tainted SQL in path: $_GET -> $_GET[\'user_id\'] (src/somefile.php:28:43) -> call to C::foo (src/somefile.php:28:34) -> $user_id (src/somefile.php:23:52) -> call to AGrandChild::loadFull (src/somefile.php:24:51) -> AGrandChild::loadFull#1 (src/somefile.php:5:64) -> A::loadFull#1 (src/somefile.php:24:51) -> $sink (src/somefile.php:5:64) -> call to A::loadPartial (src/somefile.php:6:49) -> A::loadPartial#1 (src/somefile.php:3:76) -> AChild::loadPartial#1 (src/somefile.php:6:49) -> $sink (src/somefile.php:15:67) -> concat (src/somefile.php:16:44) -> call to PDO::exec (src/somefile.php:16:44) -> PDO::exec#1', + 'error_message' => 'TaintedSql - src' . DIRECTORY_SEPARATOR . 'somefile.php:16:44 - Detected tainted SQL in path: $_GET -> $_GET[\'user_id\'] (src/somefile.php:28:43) -> call to C::foo (src/somefile.php:28:34) -> $user_id (src/somefile.php:23:52) -> call to AGrandChild::loadFull (src/somefile.php:24:51) -> AGrandChild::loadFull#1 (src/somefile.php:5:64) -> A::loadFull#1 (src/somefile.php:24:51) -> $sink (src/somefile.php:5:64) -> call to A::loadPartial (src/somefile.php:6:49) -> A::loadPartial#1 (src/somefile.php:3:76) -> AChild::loadPartial#1 (src/somefile.php:6:49) -> $sink (src/somefile.php:15:67) -> call to PDO::exec (src/somefile.php:16:44) -> PDO::exec#1', ], 'taintedInputFromProperty' => [ '