Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5326125

Browse files
committed
Python: Handle positional construtor arguments
1 parent 2187389 commit 5326125

8 files changed

Lines changed: 899 additions & 499 deletions

File tree

python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -279,12 +279,16 @@ module ArgumentPassing {
279279

280280
/**
281281
* Gets the argument to `call` that is passed to the `n`th parameter of `callable`.
282+
* If it is a positional argument, it must appear at position `argNr`.
283+
* `argNr` will differ from `n` for method- or class calls, where the first parameter
284+
* is `self` and the first positional arguemnt is passed to the second positional parameter.
282285
*/
283-
Node getArg(CallNode call, CallableValue callable, int n) {
286+
Node getArg(CallNode call, int argNr, CallableValue callable, int n) {
284287
connects(call, callable) and
288+
n - argNr in [0, 1] and // constrain for now to limit the size of the predicate; we only use it to insert one argument (self).
285289
(
286290
// positional argument
287-
result = TCfgNode(call.getArg(n))
291+
result = TCfgNode(call.getArg(argNr))
288292
or
289293
// keyword argument
290294
exists(Function f, string argName |
@@ -305,7 +309,7 @@ module ArgumentPassing {
305309
or
306310
// argument unpacked from dict
307311
exists(string name |
308-
call_unpacks(call, callable, name, n) and
312+
call_unpacks(call, argNr, callable, name, n) and
309313
result = TKwUnpacked(call, callable, name)
310314
)
311315
)
@@ -339,11 +343,12 @@ module ArgumentPassing {
339343
* Holds if `call` unpacks a dictionary argument in order to pass it via `name`.
340344
* It will then be passed to the `n`th parameter of `callable`.
341345
*/
342-
predicate call_unpacks(CallNode call, CallableValue callable, string name, int n) {
346+
predicate call_unpacks(CallNode call, int argNr, CallableValue callable, string name, int n) {
343347
connects(call, callable) and
348+
n - argNr in [0, 1] and
344349
exists(Function f |
345350
f = callable.getScope() and
346-
not exists(call.getArg(n)) and // no positional arguement available
351+
not exists(call.getArg(argNr)) and // no positional arguement available
347352
name = f.getArgName(n) and
348353
// not exists(call.getArgByName(name)) and // only matches keyword arguments not preceded by **
349354
not call.getNode().getANamedArg().(Keyword).getArg() = name and // no keyword argument available
@@ -478,7 +483,7 @@ class CallNodeCall extends DataFlowCall, TCallNode {
478483

479484
override string toString() { result = call.toString() }
480485

481-
override Node getArg(int n) { result = getArg(call, callable.getCallableValue(), n) }
486+
override Node getArg(int n) { result = getArg(call, n, callable.getCallableValue(), n) }
482487

483488
override ControlFlowNode getNode() { result = call }
484489

@@ -502,7 +507,7 @@ class ClassCall extends DataFlowCall, TClassCall {
502507
override string toString() { result = call.toString() }
503508

504509
override Node getArg(int n) {
505-
n > 0 and result = getArg(call, this.getCallableValue(), n - 1)
510+
n > 0 and result = getArg(call, n - 1, this.getCallableValue(), n)
506511
or
507512
n = 0 and result = TSyntheticPreUpdateNode(TCfgNode(call))
508513
}
@@ -918,7 +923,7 @@ predicate kwUnpackReadStep(CfgNode nodeFrom, DictionaryElementContent c, Node no
918923
cached
919924
predicate clearsContent(Node n, Content c) {
920925
exists(CallNode call, CallableValue callable, string name |
921-
call_unpacks(call, callable, name, _) and
926+
call_unpacks(call, _, callable, name, _) and
922927
n = TKwOverflowNode(call, callable) and
923928
c.(DictionaryElementContent).getKey() = name
924929
)

python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ newtype TNode =
4646
* to parameter `foo` of `callable.
4747
*/
4848
TKwUnpacked(CallNode call, CallableValue callable, string name) {
49-
call_unpacks(call, callable, name, _)
49+
call_unpacks(call, _, callable, name, _)
5050
}
5151

5252
/**

python/ql/test/experimental/dataflow/fieldflow/allLocalFlow.expected

Lines changed: 107 additions & 71 deletions
Large diffs are not rendered by default.

python/ql/test/experimental/dataflow/fieldflow/dataflow.expected

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ edges
2121
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:46:19:46:24 | ControlFlowNode for SOURCE |
2222
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:51:9:51:14 | ControlFlowNode for SOURCE |
2323
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:62:17:62:22 | ControlFlowNode for SOURCE |
24+
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:67:21:67:26 | ControlFlowNode for SOURCE |
2425
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:78:33:78:38 | ControlFlowNode for SOURCE |
2526
| test.py:3:1:3:6 | GSSA Variable SOURCE | test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test |
2627
| test.py:3:10:3:17 | ControlFlowNode for Str | test.py:3:1:3:6 | GSSA Variable SOURCE |
@@ -36,6 +37,9 @@ edges
3637
| test.py:62:11:62:23 | ControlFlowNode for MyObj() [Attribute foo] | test.py:63:10:63:12 | ControlFlowNode for obj [Attribute foo] |
3738
| test.py:62:17:62:22 | ControlFlowNode for SOURCE | test.py:62:11:62:23 | ControlFlowNode for MyObj() [Attribute foo] |
3839
| test.py:63:10:63:12 | ControlFlowNode for obj [Attribute foo] | test.py:63:10:63:16 | ControlFlowNode for Attribute |
40+
| test.py:67:11:67:27 | ControlFlowNode for MyObj() [Attribute foo] | test.py:68:10:68:12 | ControlFlowNode for obj [Attribute foo] |
41+
| test.py:67:21:67:26 | ControlFlowNode for SOURCE | test.py:67:11:67:27 | ControlFlowNode for MyObj() [Attribute foo] |
42+
| test.py:68:10:68:12 | ControlFlowNode for obj [Attribute foo] | test.py:68:10:68:16 | ControlFlowNode for Attribute |
3943
| test.py:78:33:78:38 | ControlFlowNode for SOURCE | test.py:78:10:78:39 | ControlFlowNode for fields_with_local_flow() |
4044
nodes
4145
| examples.py:27:8:27:12 | [post arg] ControlFlowNode for myobj [Attribute foo] | semmle.label | [post arg] ControlFlowNode for myobj [Attribute foo] |
@@ -73,6 +77,10 @@ nodes
7377
| test.py:62:17:62:22 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
7478
| test.py:63:10:63:12 | ControlFlowNode for obj [Attribute foo] | semmle.label | ControlFlowNode for obj [Attribute foo] |
7579
| test.py:63:10:63:16 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
80+
| test.py:67:11:67:27 | ControlFlowNode for MyObj() [Attribute foo] | semmle.label | ControlFlowNode for MyObj() [Attribute foo] |
81+
| test.py:67:21:67:26 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
82+
| test.py:68:10:68:12 | ControlFlowNode for obj [Attribute foo] | semmle.label | ControlFlowNode for obj [Attribute foo] |
83+
| test.py:68:10:68:16 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
7684
| test.py:78:10:78:39 | ControlFlowNode for fields_with_local_flow() | semmle.label | ControlFlowNode for fields_with_local_flow() |
7785
| test.py:78:33:78:38 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
7886
#select
@@ -92,5 +100,7 @@ nodes
92100
| test.py:58:10:58:18 | ControlFlowNode for Attribute | test.py:51:9:51:14 | ControlFlowNode for SOURCE | test.py:58:10:58:18 | ControlFlowNode for Attribute | Flow found |
93101
| test.py:63:10:63:16 | ControlFlowNode for Attribute | test.py:3:10:3:17 | ControlFlowNode for Str | test.py:63:10:63:16 | ControlFlowNode for Attribute | Flow found |
94102
| test.py:63:10:63:16 | ControlFlowNode for Attribute | test.py:62:17:62:22 | ControlFlowNode for SOURCE | test.py:63:10:63:16 | ControlFlowNode for Attribute | Flow found |
103+
| test.py:68:10:68:16 | ControlFlowNode for Attribute | test.py:3:10:3:17 | ControlFlowNode for Str | test.py:68:10:68:16 | ControlFlowNode for Attribute | Flow found |
104+
| test.py:68:10:68:16 | ControlFlowNode for Attribute | test.py:67:21:67:26 | ControlFlowNode for SOURCE | test.py:68:10:68:16 | ControlFlowNode for Attribute | Flow found |
95105
| test.py:78:10:78:39 | ControlFlowNode for fields_with_local_flow() | test.py:3:10:3:17 | ControlFlowNode for Str | test.py:78:10:78:39 | ControlFlowNode for fields_with_local_flow() | Flow found |
96106
| test.py:78:10:78:39 | ControlFlowNode for fields_with_local_flow() | test.py:78:33:78:38 | ControlFlowNode for SOURCE | test.py:78:10:78:39 | ControlFlowNode for fields_with_local_flow() | Flow found |

0 commit comments

Comments
 (0)