Skip to content

Commit e160c85

Browse files
authored
Merge pull request github#5233 from yoff/python-for-tuple-iteration
Python: `for`-iteration of tuples
2 parents 127e778 + d23a8ad commit e160c85

File tree

4 files changed

+44
-5
lines changed

4 files changed

+44
-5
lines changed

python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1508,6 +1508,8 @@ predicate forReadStep(CfgNode nodeFrom, Content c, Node nodeTo) {
15081508
c instanceof ListElementContent
15091509
or
15101510
c instanceof SetElementContent
1511+
or
1512+
c instanceof TupleElementContent
15111513
)
15121514
}
15131515

python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -574,7 +574,12 @@ newtype TContent =
574574
/** An element of a set. */
575575
TSetElementContent() or
576576
/** An element of a tuple at a specific index. */
577-
TTupleElementContent(int index) { exists(any(TupleNode tn).getElement(index)) } or
577+
TTupleElementContent(int index) {
578+
exists(any(TupleNode tn).getElement(index))
579+
or
580+
// Arguments can overflow and end up in the starred parameter tuple.
581+
exists(any(CallNode cn).getArg(index))
582+
} or
578583
/** An element of a dictionary under a specific key. */
579584
TDictionaryElementContent(string key) {
580585
key = any(KeyValuePair kvp).getKey().(StrConst).getS()

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

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,17 @@ edges
336336
| test.py:673:9:673:14 | ControlFlowNode for Tuple [Tuple element at index 0] | test.py:673:9:673:9 | SSA variable x |
337337
| test.py:673:9:673:14 | IterableSequence [Tuple element at index 0] | test.py:673:9:673:14 | ControlFlowNode for Tuple [Tuple element at index 0] |
338338
| test.py:673:19:673:20 | ControlFlowNode for tl [List element, Tuple element at index 0] | test.py:673:9:673:14 | IterableSequence [Tuple element at index 0] |
339-
| test.py:748:16:748:21 | ControlFlowNode for SOURCE | test.py:751:10:751:36 | ControlFlowNode for return_from_inner_scope() |
339+
| test.py:678:39:678:42 | ControlFlowNode for args [Tuple element at index 0] | test.py:679:14:679:17 | ControlFlowNode for args [Tuple element at index 0] |
340+
| test.py:678:39:678:42 | ControlFlowNode for args [Tuple element at index 1] | test.py:679:14:679:17 | ControlFlowNode for args [Tuple element at index 1] |
341+
| test.py:679:7:679:9 | SSA variable arg | test.py:680:10:680:12 | ControlFlowNode for arg |
342+
| test.py:679:14:679:17 | ControlFlowNode for args [Tuple element at index 0] | test.py:679:7:679:9 | SSA variable arg |
343+
| test.py:679:14:679:17 | ControlFlowNode for args [Tuple element at index 1] | test.py:679:7:679:9 | SSA variable arg |
344+
| test.py:685:7:685:12 | ControlFlowNode for SOURCE | test.py:686:51:686:51 | ControlFlowNode for s |
345+
| test.py:686:3:686:52 | PosOverflowNode for iterate_star_args() [Tuple element at index 0] | test.py:678:39:678:42 | ControlFlowNode for args [Tuple element at index 0] |
346+
| test.py:686:3:686:52 | PosOverflowNode for iterate_star_args() [Tuple element at index 1] | test.py:678:39:678:42 | ControlFlowNode for args [Tuple element at index 1] |
347+
| test.py:686:43:686:48 | ControlFlowNode for SOURCE | test.py:686:3:686:52 | PosOverflowNode for iterate_star_args() [Tuple element at index 0] |
348+
| test.py:686:51:686:51 | ControlFlowNode for s | test.py:686:3:686:52 | PosOverflowNode for iterate_star_args() [Tuple element at index 1] |
349+
| test.py:757:16:757:21 | ControlFlowNode for SOURCE | test.py:760:10:760:36 | ControlFlowNode for return_from_inner_scope() |
340350
nodes
341351
| datamodel.py:38:6:38:17 | ControlFlowNode for f() | semmle.label | ControlFlowNode for f() |
342352
| datamodel.py:38:8:38:13 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
@@ -735,8 +745,19 @@ nodes
735745
| test.py:673:9:673:14 | IterableSequence [Tuple element at index 0] | semmle.label | IterableSequence [Tuple element at index 0] |
736746
| test.py:673:19:673:20 | ControlFlowNode for tl [List element, Tuple element at index 0] | semmle.label | ControlFlowNode for tl [List element, Tuple element at index 0] |
737747
| test.py:674:14:674:14 | ControlFlowNode for x | semmle.label | ControlFlowNode for x |
738-
| test.py:748:16:748:21 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
739-
| test.py:751:10:751:36 | ControlFlowNode for return_from_inner_scope() | semmle.label | ControlFlowNode for return_from_inner_scope() |
748+
| test.py:678:39:678:42 | ControlFlowNode for args [Tuple element at index 0] | semmle.label | ControlFlowNode for args [Tuple element at index 0] |
749+
| test.py:678:39:678:42 | ControlFlowNode for args [Tuple element at index 1] | semmle.label | ControlFlowNode for args [Tuple element at index 1] |
750+
| test.py:679:7:679:9 | SSA variable arg | semmle.label | SSA variable arg |
751+
| test.py:679:14:679:17 | ControlFlowNode for args [Tuple element at index 0] | semmle.label | ControlFlowNode for args [Tuple element at index 0] |
752+
| test.py:679:14:679:17 | ControlFlowNode for args [Tuple element at index 1] | semmle.label | ControlFlowNode for args [Tuple element at index 1] |
753+
| test.py:680:10:680:12 | ControlFlowNode for arg | semmle.label | ControlFlowNode for arg |
754+
| test.py:685:7:685:12 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
755+
| test.py:686:3:686:52 | PosOverflowNode for iterate_star_args() [Tuple element at index 0] | semmle.label | PosOverflowNode for iterate_star_args() [Tuple element at index 0] |
756+
| test.py:686:3:686:52 | PosOverflowNode for iterate_star_args() [Tuple element at index 1] | semmle.label | PosOverflowNode for iterate_star_args() [Tuple element at index 1] |
757+
| test.py:686:43:686:48 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
758+
| test.py:686:51:686:51 | ControlFlowNode for s | semmle.label | ControlFlowNode for s |
759+
| test.py:757:16:757:21 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
760+
| test.py:760:10:760:36 | ControlFlowNode for return_from_inner_scope() | semmle.label | ControlFlowNode for return_from_inner_scope() |
740761
#select
741762
| datamodel.py:38:6:38:17 | ControlFlowNode for f() | datamodel.py:38:8:38:13 | ControlFlowNode for SOURCE | datamodel.py:38:6:38:17 | ControlFlowNode for f() | Flow found |
742763
| datamodel.py:71:6:71:24 | ControlFlowNode for Attribute() | datamodel.py:71:15:71:20 | ControlFlowNode for SOURCE | datamodel.py:71:6:71:24 | ControlFlowNode for Attribute() | Flow found |
@@ -841,4 +862,6 @@ nodes
841862
| test.py:667:16:667:16 | ControlFlowNode for y | test.py:663:33:663:38 | ControlFlowNode for SOURCE | test.py:667:16:667:16 | ControlFlowNode for y | Flow found |
842863
| test.py:674:14:674:14 | ControlFlowNode for x | test.py:672:12:672:17 | ControlFlowNode for SOURCE | test.py:674:14:674:14 | ControlFlowNode for x | Flow found |
843864
| test.py:674:14:674:14 | ControlFlowNode for x | test.py:672:33:672:38 | ControlFlowNode for SOURCE | test.py:674:14:674:14 | ControlFlowNode for x | Flow found |
844-
| test.py:751:10:751:36 | ControlFlowNode for return_from_inner_scope() | test.py:748:16:748:21 | ControlFlowNode for SOURCE | test.py:751:10:751:36 | ControlFlowNode for return_from_inner_scope() | Flow found |
865+
| test.py:680:10:680:12 | ControlFlowNode for arg | test.py:685:7:685:12 | ControlFlowNode for SOURCE | test.py:680:10:680:12 | ControlFlowNode for arg | Flow found |
866+
| test.py:680:10:680:12 | ControlFlowNode for arg | test.py:686:43:686:48 | ControlFlowNode for SOURCE | test.py:680:10:680:12 | ControlFlowNode for arg | Flow found |
867+
| test.py:760:10:760:36 | ControlFlowNode for return_from_inner_scope() | test.py:757:16:757:21 | ControlFlowNode for SOURCE | test.py:760:10:760:36 | ControlFlowNode for return_from_inner_scope() | Flow found |

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,15 @@ def test_iterable_star_unpacking_in_for_2():
675675
SINK_F(y) # The list itself is not tainted (and is here empty)
676676
SINK_F(z)
677677

678+
def iterate_star_args(first, second, *args):
679+
for arg in args:
680+
SINK(arg) #$ flow="SOURCE, l:+5 -> arg" flow="SOURCE, l:+6 -> arg"
681+
682+
# FP reported here: https://github.com/github/codeql-python-team/issues/49
683+
@expects(2)
684+
def test_overflow_iteration():
685+
s = SOURCE
686+
iterate_star_args(NONSOURCE, NONSOURCE, SOURCE, s)
678687

679688
def test_deep_callgraph():
680689
# port of python/ql/test/library-tests/taint/general/deep.py

0 commit comments

Comments
 (0)