mirror of
https://github.com/github/codeql.git
synced 2025-12-20 10:46:30 +01:00
Python: Support overflow positional arguments
Currently ignoring starred arguments
This commit is contained in:
@@ -235,6 +235,61 @@ private Node update(Node node) {
|
||||
// Global flow
|
||||
//--------
|
||||
//
|
||||
/** Computes routing of arguments to parameters */
|
||||
module ArgumentPassing {
|
||||
NameNode getParameter(CallableValue callable, int n) {
|
||||
// positional parameter
|
||||
result = callable.getParameter(n)
|
||||
or
|
||||
// vararg
|
||||
exists(Function f |
|
||||
f = callable.getScope() and
|
||||
n = f.getPositionalParameterCount() and
|
||||
result = f.getVararg().getAFlowNode()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the argument to `call` then is passed to the `n`th parameter of `callable`.
|
||||
*/
|
||||
Node getArg(CallNode call, CallableValue callable, int n) {
|
||||
call = callable.getACall() and
|
||||
(
|
||||
// positional argument
|
||||
result = TCfgNode(call.getArg(n))
|
||||
or
|
||||
// keyword argument
|
||||
exists(Function f, string argName |
|
||||
f = callable.getScope() and
|
||||
f.getArgName(n) = argName and
|
||||
result = TCfgNode(call.getArgByName(argName))
|
||||
)
|
||||
or
|
||||
// vararg
|
||||
exists(Function f |
|
||||
f = callable.getScope() and
|
||||
f.hasVarArg() and
|
||||
n = f.getPositionalParameterCount() and
|
||||
result = TPosOverflowNode(call, callable)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
ControlFlowNode getPositionalOverflowArg(CallNode call, CallableValue callable, int n) {
|
||||
call = callable.getACall() and
|
||||
exists(Function f, int posCount, int argNr |
|
||||
f = callable.getScope() and
|
||||
f.hasVarArg() and
|
||||
posCount = f.getPositionalParameterCount() and
|
||||
result = call.getArg(argNr) and
|
||||
argNr >= posCount and
|
||||
argNr = posCount + n
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import ArgumentPassing
|
||||
|
||||
/**
|
||||
* IPA type for DataFlowCallable.
|
||||
*
|
||||
@@ -278,7 +333,7 @@ class DataFlowCallableValue extends DataFlowCallable, TCallableValue {
|
||||
|
||||
override Scope getScope() { result = callable.getScope() }
|
||||
|
||||
override NameNode getParameter(int n) { result = callable.getParameter(n) }
|
||||
override NameNode getParameter(int n) { result = getParameter(callable, n) }
|
||||
|
||||
override string getName() { result = callable.getName() }
|
||||
|
||||
@@ -345,19 +400,6 @@ abstract class DataFlowCall extends TDataFlowCall {
|
||||
Location getLocation() { result = this.getNode().getLocation() }
|
||||
}
|
||||
|
||||
ControlFlowNode getArg(CallNode call, CallableValue callable, int n) {
|
||||
call = callable.getACall() and
|
||||
(
|
||||
result = call.getArg(n)
|
||||
or
|
||||
exists(Function f, string argName |
|
||||
f = callable.getScope() and
|
||||
f.getArgName(n) = argName and
|
||||
result = call.getArgByName(argName)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/** Represents a call to a callable (currently only callable values). */
|
||||
class CallNodeCall extends DataFlowCall, TCallNode {
|
||||
CallNode call;
|
||||
@@ -370,7 +412,7 @@ class CallNodeCall extends DataFlowCall, TCallNode {
|
||||
|
||||
override string toString() { result = call.toString() }
|
||||
|
||||
override Node getArg(int n) { result = TCfgNode(getArg(call, callable.getCallableValue(), n)) }
|
||||
override Node getArg(int n) { result = getArg(call, callable.getCallableValue(), n) }
|
||||
|
||||
override ControlFlowNode getNode() { result = call }
|
||||
|
||||
@@ -394,7 +436,7 @@ class ClassCall extends DataFlowCall, TClassCall {
|
||||
override string toString() { result = call.toString() }
|
||||
|
||||
override Node getArg(int n) {
|
||||
n > 0 and result = TCfgNode(getArg(call, this.getCallableValue(), n - 1))
|
||||
n > 0 and result = getArg(call, this.getCallableValue(), n - 1)
|
||||
or
|
||||
n = 0 and result = TSyntheticPreUpdateNode(TCfgNode(call))
|
||||
}
|
||||
@@ -550,6 +592,8 @@ predicate storeStep(Node nodeFrom, Content c, Node nodeTo) {
|
||||
comprehensionStoreStep(nodeFrom, c, nodeTo)
|
||||
or
|
||||
attributeStoreStep(nodeFrom, c, nodeTo)
|
||||
or
|
||||
posOverflowStoreStep(nodeFrom, c, nodeTo)
|
||||
}
|
||||
|
||||
/** Data flows from an element of a list to the list. */
|
||||
@@ -645,6 +689,14 @@ predicate attributeStoreStep(CfgNode nodeFrom, AttributeContent c, PostUpdateNod
|
||||
)
|
||||
}
|
||||
|
||||
predicate posOverflowStoreStep(CfgNode nodeFrom, TupleElementContent c, Node nodeTo) {
|
||||
exists(CallNode call, CallableValue callable, int n |
|
||||
nodeFrom.asCfgNode() = getPositionalOverflowArg(call, callable, n) and
|
||||
nodeTo = TPosOverflowNode(call, callable) and
|
||||
c.getIndex() = n
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `nodeFrom` to `nodeTo` via a read of content `c`.
|
||||
*/
|
||||
|
||||
@@ -23,12 +23,16 @@ newtype TNode =
|
||||
TEssaNode(EssaVariable var) or
|
||||
/** A node corresponding to a control flow node. */
|
||||
TCfgNode(DataFlowCfgNode node) or
|
||||
/** A synthetic node representing the value of an object before a state change */
|
||||
/** A synthetic node representing the value of an object before a state change. */
|
||||
TSyntheticPreUpdateNode(NeedsSyntheticPreUpdateNode post) or
|
||||
/** A synthetic node representing the value of an object after a state change */
|
||||
/** A synthetic node representing the value of an object after a state change. */
|
||||
TSyntheticPostUpdateNode(NeedsSyntheticPostUpdateNode pre) or
|
||||
/** A node representing a global (module-level) variable in a specific module */
|
||||
TModuleVariableNode(Module m, GlobalVariable v) { v.getScope() = m and v.escapes() }
|
||||
/** A node representing a global (module-level) variable in a specific module. */
|
||||
TModuleVariableNode(Module m, GlobalVariable v) { v.getScope() = m and v.escapes() } or
|
||||
/** A node representing the overflow positional arguments to a call. */
|
||||
TPosOverflowNode(CallNode call, CallableValue callable) {
|
||||
exists(getPositionalOverflowArg(call, callable, _))
|
||||
}
|
||||
|
||||
/**
|
||||
* An element, viewed as a node in a data flow graph. Either an SSA variable
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
| argumentPassing.py:133:46:133:49 | ControlFlowNode for arg1 | argumentPassing.py:118:11:118:13 | ControlFlowNode for foo |
|
||||
| argumentPassing.py:141:14:141:17 | ControlFlowNode for arg1 | argumentPassing.py:139:15:139:15 | ControlFlowNode for a |
|
||||
| argumentPassing.py:148:19:148:22 | ControlFlowNode for arg1 | argumentPassing.py:146:15:146:15 | ControlFlowNode for a |
|
||||
| argumentPassing.py:156:15:156:18 | ControlFlowNode for arg1 | argumentPassing.py:154:19:154:22 | ControlFlowNode for Subscript |
|
||||
| argumentPassing.py:163:13:163:16 | ControlFlowNode for arg1 | argumentPassing.py:161:15:161:15 | ControlFlowNode for a |
|
||||
| argumentPassing.py:170:16:170:19 | ControlFlowNode for arg1 | argumentPassing.py:168:15:168:15 | ControlFlowNode for a |
|
||||
| argumentPassing.py:177:15:177:18 | ControlFlowNode for arg1 | argumentPassing.py:175:15:175:15 | ControlFlowNode for a |
|
||||
|
||||
@@ -28,6 +28,8 @@ edges
|
||||
| datamodel.py:152:14:152:19 | ControlFlowNode for SOURCE | datamodel.py:152:5:152:8 | [post store] ControlFlowNode for self [Attribute b] |
|
||||
| datamodel.py:155:14:155:25 | ControlFlowNode for Customized() [Attribute b] | datamodel.py:159:6:159:15 | ControlFlowNode for customized [Attribute b] |
|
||||
| datamodel.py:159:6:159:15 | ControlFlowNode for customized [Attribute b] | datamodel.py:159:6:159:17 | ControlFlowNode for Attribute |
|
||||
| file://:0:0:0:0 | Data flow node [Tuple element at index 0] | test.py:389:10:389:39 | ControlFlowNode for f_extra_pos() |
|
||||
| file://:0:0:0:0 | Data flow node [Tuple element at index 0] | test.py:482:10:482:39 | ControlFlowNode for f_extra_pos() |
|
||||
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:42:21:42:26 | ControlFlowNode for SOURCE |
|
||||
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:55:9:55:14 | ControlFlowNode for SOURCE |
|
||||
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:87:9:87:14 | ControlFlowNode for SOURCE |
|
||||
@@ -49,9 +51,11 @@ edges
|
||||
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:344:16:344:21 | ControlFlowNode for SOURCE |
|
||||
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:365:28:365:33 | ControlFlowNode for SOURCE |
|
||||
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:373:30:373:35 | ControlFlowNode for SOURCE |
|
||||
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:389:33:389:38 | ControlFlowNode for SOURCE |
|
||||
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:442:12:442:17 | ControlFlowNode for SOURCE |
|
||||
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:449:28:449:33 | ControlFlowNode for SOURCE |
|
||||
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:463:30:463:35 | ControlFlowNode for SOURCE |
|
||||
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:482:33:482:38 | ControlFlowNode for SOURCE |
|
||||
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:499:9:499:14 | ControlFlowNode for SOURCE |
|
||||
| test.py:20:1:20:6 | GSSA Variable SOURCE | test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test |
|
||||
| test.py:20:10:20:17 | ControlFlowNode for Str | test.py:20:1:20:6 | GSSA Variable SOURCE |
|
||||
@@ -150,9 +154,11 @@ edges
|
||||
| test.py:344:16:344:21 | ControlFlowNode for SOURCE | test.py:344:10:344:22 | ControlFlowNode for Dict [Dictionary element at key s] |
|
||||
| test.py:365:28:365:33 | ControlFlowNode for SOURCE | test.py:365:10:365:34 | ControlFlowNode for second() |
|
||||
| test.py:373:30:373:35 | ControlFlowNode for SOURCE | test.py:373:10:373:36 | ControlFlowNode for second() |
|
||||
| test.py:389:33:389:38 | ControlFlowNode for SOURCE | file://:0:0:0:0 | Data flow node [Tuple element at index 0] |
|
||||
| test.py:442:12:442:17 | ControlFlowNode for SOURCE | test.py:442:10:442:18 | ControlFlowNode for f() |
|
||||
| test.py:449:28:449:33 | ControlFlowNode for SOURCE | test.py:449:10:449:34 | ControlFlowNode for second() |
|
||||
| test.py:463:30:463:35 | ControlFlowNode for SOURCE | test.py:463:10:463:36 | ControlFlowNode for second() |
|
||||
| test.py:482:33:482:38 | ControlFlowNode for SOURCE | file://:0:0:0:0 | Data flow node [Tuple element at index 0] |
|
||||
| test.py:499:9:499:14 | ControlFlowNode for SOURCE | test.py:501:10:501:10 | ControlFlowNode for a |
|
||||
| test.py:499:9:499:14 | ControlFlowNode for SOURCE | test.py:506:10:506:10 | ControlFlowNode for b |
|
||||
nodes
|
||||
@@ -175,6 +181,8 @@ nodes
|
||||
| datamodel.py:155:14:155:25 | ControlFlowNode for Customized() [Attribute b] | semmle.label | ControlFlowNode for Customized() [Attribute b] |
|
||||
| datamodel.py:159:6:159:15 | ControlFlowNode for customized [Attribute b] | semmle.label | ControlFlowNode for customized [Attribute b] |
|
||||
| datamodel.py:159:6:159:17 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| file://:0:0:0:0 | Data flow node [Tuple element at index 0] | semmle.label | Data flow node [Tuple element at index 0] |
|
||||
| file://:0:0:0:0 | Data flow node [Tuple element at index 0] | semmle.label | Data flow node [Tuple element at index 0] |
|
||||
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | semmle.label | ModuleVariableNode for Global Variable SOURCE in Module test |
|
||||
| test.py:20:1:20:6 | GSSA Variable SOURCE | semmle.label | GSSA Variable SOURCE |
|
||||
| test.py:20:10:20:17 | ControlFlowNode for Str | semmle.label | ControlFlowNode for Str |
|
||||
@@ -298,12 +306,16 @@ nodes
|
||||
| test.py:365:28:365:33 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
|
||||
| test.py:373:10:373:36 | ControlFlowNode for second() | semmle.label | ControlFlowNode for second() |
|
||||
| test.py:373:30:373:35 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
|
||||
| test.py:389:10:389:39 | ControlFlowNode for f_extra_pos() | semmle.label | ControlFlowNode for f_extra_pos() |
|
||||
| test.py:389:33:389:38 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
|
||||
| test.py:442:10:442:18 | ControlFlowNode for f() | semmle.label | ControlFlowNode for f() |
|
||||
| test.py:442:12:442:17 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
|
||||
| test.py:449:10:449:34 | ControlFlowNode for second() | semmle.label | ControlFlowNode for second() |
|
||||
| test.py:449:28:449:33 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
|
||||
| test.py:463:10:463:36 | ControlFlowNode for second() | semmle.label | ControlFlowNode for second() |
|
||||
| test.py:463:30:463:35 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
|
||||
| test.py:482:10:482:39 | ControlFlowNode for f_extra_pos() | semmle.label | ControlFlowNode for f_extra_pos() |
|
||||
| test.py:482:33:482:38 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
|
||||
| test.py:499:9:499:14 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
|
||||
| test.py:501:10:501:10 | ControlFlowNode for a | semmle.label | ControlFlowNode for a |
|
||||
| test.py:506:10:506:10 | ControlFlowNode for b | semmle.label | ControlFlowNode for b |
|
||||
@@ -378,12 +390,16 @@ nodes
|
||||
| test.py:365:10:365:34 | ControlFlowNode for second() | test.py:365:28:365:33 | ControlFlowNode for SOURCE | test.py:365:10:365:34 | ControlFlowNode for second() | Flow found |
|
||||
| test.py:373:10:373:36 | ControlFlowNode for second() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:373:10:373:36 | ControlFlowNode for second() | Flow found |
|
||||
| test.py:373:10:373:36 | ControlFlowNode for second() | test.py:373:30:373:35 | ControlFlowNode for SOURCE | test.py:373:10:373:36 | ControlFlowNode for second() | Flow found |
|
||||
| test.py:389:10:389:39 | ControlFlowNode for f_extra_pos() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:389:10:389:39 | ControlFlowNode for f_extra_pos() | Flow found |
|
||||
| test.py:389:10:389:39 | ControlFlowNode for f_extra_pos() | test.py:389:33:389:38 | ControlFlowNode for SOURCE | test.py:389:10:389:39 | ControlFlowNode for f_extra_pos() | Flow found |
|
||||
| test.py:442:10:442:18 | ControlFlowNode for f() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:442:10:442:18 | ControlFlowNode for f() | Flow found |
|
||||
| test.py:442:10:442:18 | ControlFlowNode for f() | test.py:442:12:442:17 | ControlFlowNode for SOURCE | test.py:442:10:442:18 | ControlFlowNode for f() | Flow found |
|
||||
| test.py:449:10:449:34 | ControlFlowNode for second() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:449:10:449:34 | ControlFlowNode for second() | Flow found |
|
||||
| test.py:449:10:449:34 | ControlFlowNode for second() | test.py:449:28:449:33 | ControlFlowNode for SOURCE | test.py:449:10:449:34 | ControlFlowNode for second() | Flow found |
|
||||
| test.py:463:10:463:36 | ControlFlowNode for second() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:463:10:463:36 | ControlFlowNode for second() | Flow found |
|
||||
| test.py:463:10:463:36 | ControlFlowNode for second() | test.py:463:30:463:35 | ControlFlowNode for SOURCE | test.py:463:10:463:36 | ControlFlowNode for second() | Flow found |
|
||||
| test.py:482:10:482:39 | ControlFlowNode for f_extra_pos() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:482:10:482:39 | ControlFlowNode for f_extra_pos() | Flow found |
|
||||
| test.py:482:10:482:39 | ControlFlowNode for f_extra_pos() | test.py:482:33:482:38 | ControlFlowNode for SOURCE | test.py:482:10:482:39 | ControlFlowNode for f_extra_pos() | Flow found |
|
||||
| test.py:501:10:501:10 | ControlFlowNode for a | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:501:10:501:10 | ControlFlowNode for a | Flow found |
|
||||
| test.py:501:10:501:10 | ControlFlowNode for a | test.py:499:9:499:14 | ControlFlowNode for SOURCE | test.py:501:10:501:10 | ControlFlowNode for a | Flow found |
|
||||
| test.py:506:10:506:10 | ControlFlowNode for b | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:506:10:506:10 | ControlFlowNode for b | Flow found |
|
||||
|
||||
@@ -386,7 +386,7 @@ def f_extra_pos(a, *b):
|
||||
|
||||
|
||||
def test_call_extra_pos():
|
||||
SINK(f_extra_pos(NONSOURCE, SOURCE)) # Flow missing
|
||||
SINK(f_extra_pos(NONSOURCE, SOURCE))
|
||||
|
||||
|
||||
def f_extra_keyword(a, **b):
|
||||
@@ -479,7 +479,7 @@ def test_lambda_unpack_mapping():
|
||||
|
||||
def test_lambda_extra_pos():
|
||||
f_extra_pos = lambda a, *b: b[0]
|
||||
SINK(f_extra_pos(NONSOURCE, SOURCE)) # Flow missing
|
||||
SINK(f_extra_pos(NONSOURCE, SOURCE))
|
||||
|
||||
|
||||
def test_lambda_extra_keyword():
|
||||
|
||||
Reference in New Issue
Block a user