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

Skip to content

Commit b0ed7af

Browse files
committed
Python: Approximate **arg -> **param
1 parent 4ae422c commit b0ed7af

6 files changed

Lines changed: 26 additions & 15 deletions

File tree

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

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -279,15 +279,15 @@ module ArgumentPassing {
279279
result = TCfgNode(call.getArgByName(argName))
280280
)
281281
or
282-
// argument -1 is a synthezised argument passed to the starred parameter
282+
// a synthezised argument passed to the starred parameter (at position -1)
283283
exists(Function f |
284284
f = callable.getScope() and
285285
f.hasVarArg() and
286286
n = -1 and
287287
result = TPosOverflowNode(call, callable)
288288
)
289289
or
290-
// argument -2 is a synthezised argument passed to the doubly starred parameter
290+
// a synthezised argument passed to the doubly starred parameter (at position -2)
291291
exists(Function f |
292292
f = callable.getScope() and
293293
f.hasKwArg() and
@@ -300,6 +300,11 @@ module ArgumentPassing {
300300
call_unpacks(call, callable, name, n) and
301301
result = TKwUnpacked(call, callable, name)
302302
)
303+
or
304+
// Dict argument is passed to the doubly starred parameter (at position -2).
305+
// This is an overaaproximation, not removing unpacked arguments.
306+
n = -2 and
307+
result = TCfgNode(call.getNode().getKwargs().getAFlowNode())
303308
)
304309
}
305310

@@ -332,6 +337,7 @@ module ArgumentPassing {
332337
* It will then be passed to the `n`th parameter of `callable`.
333338
*/
334339
predicate call_unpacks(CallNode call, CallableValue callable, string name, int n) {
340+
call = callable.getACall() and
335341
exists(Function f |
336342
f = callable.getScope() and
337343
not exists(call.getArg(n)) and // no positional arguement available
@@ -893,8 +899,7 @@ predicate attributeReadStep(CfgNode nodeFrom, AttributeContent c, CfgNode nodeTo
893899
* synthezised unpacked argument with the name indicated by `c`.
894900
*/
895901
predicate kwUnpackReadStep(CfgNode nodeFrom, DictionaryElementContent c, Node nodeTo) {
896-
exists(CallNode call, CallableValue callable, string name, int n |
897-
call_unpacks(call, callable, name, n) and
902+
exists(CallNode call, CallableValue callable, string name |
898903
nodeFrom.asCfgNode() = call.getNode().getKwargs().getAFlowNode() and
899904
nodeTo = TKwUnpacked(call, callable, name) and
900905
name = c.getKey()

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,11 @@ newtype TNode =
3737
TKwOverflowNode(CallNode call, CallableValue callable) {
3838
exists(getKeywordOverflowArg(call, callable, _))
3939
} or
40-
/** A node representing an unpacked element of a dictionary argument. */
40+
/**
41+
* A node representing an unpacked element of a dictionary argument.
42+
* That is, `call` contains argument `**{"foo": bar}` which is passed
43+
* to parameter `foo` of `callable.
44+
*/
4145
TKwUnpacked(CallNode call, CallableValue callable, string name) {
4246
call_unpacks(call, callable, name, _)
4347
}

python/ql/test/experimental/dataflow/coverage/argumentPassing.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ def grab_foo_bar_baz(foo, **kwargs):
122122
def grab_bar_baz(bar, **kwargs):
123123
SINK2(bar)
124124
try:
125-
SINK2(kwargs["bar"])
125+
SINK2(kwargs["bar"]) # FP
126126
except:
127127
print("OK")
128128
grab_baz(**kwargs)

python/ql/test/experimental/dataflow/coverage/argumentRouting1.expected

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@
66
| argumentPassing.py:98:27:98:30 | ControlFlowNode for arg1 | argumentPassing.py:90:11:90:11 | ControlFlowNode for a |
77
| argumentPassing.py:99:27:99:30 | ControlFlowNode for arg1 | argumentPassing.py:90:11:90:11 | ControlFlowNode for a |
88
| argumentPassing.py:111:28:111:31 | ControlFlowNode for arg1 | argumentPassing.py:103:11:103:11 | ControlFlowNode for a |
9-
| argumentPassing.py:133:46:133:49 | ControlFlowNode for arg1 | argumentPassing.py:118:11:118:13 | ControlFlowNode for foo |
10-
| argumentPassing.py:141:14:141:17 | ControlFlowNode for arg1 | argumentPassing.py:139:15:139:15 | ControlFlowNode for a |
11-
| argumentPassing.py:148:19:148:22 | ControlFlowNode for arg1 | argumentPassing.py:146:15:146:15 | ControlFlowNode for a |
12-
| argumentPassing.py:156:15:156:18 | ControlFlowNode for arg1 | argumentPassing.py:154:19:154:22 | ControlFlowNode for Subscript |
13-
| argumentPassing.py:163:13:163:16 | ControlFlowNode for arg1 | argumentPassing.py:161:15:161:15 | ControlFlowNode for a |
14-
| argumentPassing.py:170:16:170:19 | ControlFlowNode for arg1 | argumentPassing.py:168:15:168:15 | ControlFlowNode for a |
15-
| argumentPassing.py:177:15:177:18 | ControlFlowNode for arg1 | argumentPassing.py:175:15:175:15 | ControlFlowNode for a |
16-
| argumentPassing.py:184:23:184:26 | ControlFlowNode for arg1 | argumentPassing.py:182:15:182:20 | ControlFlowNode for Subscript |
9+
| argumentPassing.py:137:46:137:49 | ControlFlowNode for arg1 | argumentPassing.py:118:11:118:13 | ControlFlowNode for foo |
10+
| argumentPassing.py:145:14:145:17 | ControlFlowNode for arg1 | argumentPassing.py:143:15:143:15 | ControlFlowNode for a |
11+
| argumentPassing.py:152:19:152:22 | ControlFlowNode for arg1 | argumentPassing.py:150:15:150:15 | ControlFlowNode for a |
12+
| argumentPassing.py:160:15:160:18 | ControlFlowNode for arg1 | argumentPassing.py:158:19:158:22 | ControlFlowNode for Subscript |
13+
| argumentPassing.py:167:13:167:16 | ControlFlowNode for arg1 | argumentPassing.py:165:15:165:15 | ControlFlowNode for a |
14+
| argumentPassing.py:174:16:174:19 | ControlFlowNode for arg1 | argumentPassing.py:172:15:172:15 | ControlFlowNode for a |
15+
| argumentPassing.py:181:15:181:18 | ControlFlowNode for arg1 | argumentPassing.py:179:15:179:15 | ControlFlowNode for a |
16+
| argumentPassing.py:188:23:188:26 | ControlFlowNode for arg1 | argumentPassing.py:186:15:186:20 | ControlFlowNode for Subscript |
1717
| classes.py:563:5:563:16 | SSA variable with_getitem | classes.py:557:15:557:18 | ControlFlowNode for self |
1818
| classes.py:578:5:578:16 | SSA variable with_setitem | classes.py:573:15:573:18 | ControlFlowNode for self |
1919
| classes.py:593:5:593:16 | SSA variable with_delitem | classes.py:588:15:588:18 | ControlFlowNode for self |

python/ql/test/experimental/dataflow/coverage/argumentRouting2.expected

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
| argumentPassing.py:85:27:85:30 | ControlFlowNode for arg2 | argumentPassing.py:79:11:79:11 | ControlFlowNode for b |
33
| argumentPassing.py:97:29:97:32 | ControlFlowNode for arg2 | argumentPassing.py:91:11:91:11 | ControlFlowNode for b |
44
| argumentPassing.py:112:30:112:33 | ControlFlowNode for arg2 | argumentPassing.py:104:11:104:11 | ControlFlowNode for b |
5-
| argumentPassing.py:133:36:133:39 | ControlFlowNode for arg2 | argumentPassing.py:123:11:123:13 | ControlFlowNode for bar |
5+
| argumentPassing.py:137:36:137:39 | ControlFlowNode for arg2 | argumentPassing.py:123:11:123:13 | ControlFlowNode for bar |
6+
| argumentPassing.py:137:36:137:39 | ControlFlowNode for arg2 | argumentPassing.py:125:15:125:27 | ControlFlowNode for Subscript |
67
| classes.py:565:18:565:21 | ControlFlowNode for arg2 | classes.py:556:15:556:17 | ControlFlowNode for key |
78
| classes.py:581:18:581:21 | ControlFlowNode for arg2 | classes.py:572:15:572:17 | ControlFlowNode for key |
89
| classes.py:595:22:595:25 | ControlFlowNode for arg2 | classes.py:587:15:587:17 | ControlFlowNode for key |

python/ql/test/experimental/dataflow/coverage/argumentRouting3.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@
22
| argumentPassing.py:98:43:98:46 | ControlFlowNode for arg3 | argumentPassing.py:92:11:92:11 | ControlFlowNode for c |
33
| argumentPassing.py:99:41:99:44 | ControlFlowNode for arg3 | argumentPassing.py:92:11:92:11 | ControlFlowNode for c |
44
| argumentPassing.py:113:36:113:39 | ControlFlowNode for arg3 | argumentPassing.py:105:11:105:11 | ControlFlowNode for c |
5+
| argumentPassing.py:137:26:137:29 | ControlFlowNode for arg3 | argumentPassing.py:132:11:132:13 | ControlFlowNode for baz |
56
| classes.py:581:26:581:29 | ControlFlowNode for arg3 | classes.py:571:15:571:19 | ControlFlowNode for value |

0 commit comments

Comments
 (0)