Skip to content

Commit 46faba6

Browse files
committed
Python: Fix for-iteration of tuples
1 parent 0aecf33 commit 46faba6

File tree

4 files changed

+47
-2
lines changed

4 files changed

+47
-2
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
@@ -544,7 +544,12 @@ newtype TContent =
544544
/** An element of a set. */
545545
TSetElementContent() or
546546
/** An element of a tuple at a specific index. */
547-
TTupleElementContent(int index) { exists(any(TupleNode tn).getElement(index)) } or
547+
TTupleElementContent(int index) {
548+
exists(any(TupleNode tn).getElement(index))
549+
or
550+
// Arguments can overflow and end up in the starred parameter tuple.
551+
exists(any(CallNode cn).getArg(index))
552+
} or
548553
/** An element of a dictionary under a specific key. */
549554
TDictionaryElementContent(string key) {
550555
key = any(KeyValuePair kvp).getKey().(StrConst).getS()

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

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,24 @@ 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: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] |
339349
| test.py:757:16:757:21 | ControlFlowNode for SOURCE | test.py:760:10:760:36 | ControlFlowNode for return_from_inner_scope() |
350+
| user_test.py:2:10:2:17 | ControlFlowNode for Str | user_test.py:12:7:12:14 | ControlFlowNode for source() |
351+
| user_test.py:7:23:7:26 | ControlFlowNode for args [Tuple element at index 1] | user_test.py:8:14:8:17 | ControlFlowNode for args [Tuple element at index 1] |
352+
| user_test.py:8:7:8:9 | SSA variable arg | user_test.py:9:10:9:12 | ControlFlowNode for arg |
353+
| user_test.py:8:14:8:17 | ControlFlowNode for args [Tuple element at index 1] | user_test.py:8:7:8:9 | SSA variable arg |
354+
| user_test.py:12:7:12:14 | ControlFlowNode for source() | user_test.py:13:20:13:20 | ControlFlowNode for s |
355+
| user_test.py:13:3:13:21 | PosOverflowNode for f() [Tuple element at index 1] | user_test.py:7:23:7:26 | ControlFlowNode for args [Tuple element at index 1] |
356+
| user_test.py:13:20:13:20 | ControlFlowNode for s | user_test.py:13:3:13:21 | PosOverflowNode for f() [Tuple element at index 1] |
340357
nodes
341358
| datamodel.py:38:6:38:17 | ControlFlowNode for f() | semmle.label | ControlFlowNode for f() |
342359
| datamodel.py:38:8:38:13 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
@@ -735,8 +752,27 @@ nodes
735752
| test.py:673:9:673:14 | IterableSequence [Tuple element at index 0] | semmle.label | IterableSequence [Tuple element at index 0] |
736753
| 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] |
737754
| test.py:674:14:674:14 | ControlFlowNode for x | semmle.label | ControlFlowNode for x |
755+
| test.py:678:39:678:42 | ControlFlowNode for args [Tuple element at index 0] | semmle.label | ControlFlowNode for args [Tuple element at index 0] |
756+
| test.py:678:39:678:42 | ControlFlowNode for args [Tuple element at index 1] | semmle.label | ControlFlowNode for args [Tuple element at index 1] |
757+
| test.py:679:7:679:9 | SSA variable arg | semmle.label | SSA variable arg |
758+
| test.py:679:14:679:17 | ControlFlowNode for args [Tuple element at index 0] | semmle.label | ControlFlowNode for args [Tuple element at index 0] |
759+
| test.py:679:14:679:17 | ControlFlowNode for args [Tuple element at index 1] | semmle.label | ControlFlowNode for args [Tuple element at index 1] |
760+
| test.py:680:10:680:12 | ControlFlowNode for arg | semmle.label | ControlFlowNode for arg |
761+
| test.py:685:7:685:12 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
762+
| 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] |
763+
| 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] |
764+
| test.py:686:43:686:48 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
765+
| test.py:686:51:686:51 | ControlFlowNode for s | semmle.label | ControlFlowNode for s |
738766
| test.py:757:16:757:21 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
739767
| test.py:760:10:760:36 | ControlFlowNode for return_from_inner_scope() | semmle.label | ControlFlowNode for return_from_inner_scope() |
768+
| user_test.py:2:10:2:17 | ControlFlowNode for Str | semmle.label | ControlFlowNode for Str |
769+
| user_test.py:7:23:7:26 | ControlFlowNode for args [Tuple element at index 1] | semmle.label | ControlFlowNode for args [Tuple element at index 1] |
770+
| user_test.py:8:7:8:9 | SSA variable arg | semmle.label | SSA variable arg |
771+
| user_test.py:8:14:8:17 | ControlFlowNode for args [Tuple element at index 1] | semmle.label | ControlFlowNode for args [Tuple element at index 1] |
772+
| user_test.py:9:10:9:12 | ControlFlowNode for arg | semmle.label | ControlFlowNode for arg |
773+
| user_test.py:12:7:12:14 | ControlFlowNode for source() | semmle.label | ControlFlowNode for source() |
774+
| user_test.py:13:3:13:21 | PosOverflowNode for f() [Tuple element at index 1] | semmle.label | PosOverflowNode for f() [Tuple element at index 1] |
775+
| user_test.py:13:20:13:20 | ControlFlowNode for s | semmle.label | ControlFlowNode for s |
740776
#select
741777
| 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 |
742778
| 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 +877,6 @@ nodes
841877
| 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 |
842878
| 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 |
843879
| 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 |
880+
| 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 |
881+
| 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 |
844882
| 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: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -677,7 +677,7 @@ def test_iterable_star_unpacking_in_for_2():
677677

678678
def iterate_star_args(first, second, *args):
679679
for arg in args:
680-
SINK(arg) #$ MISSING: flow="SOURCE, l:+5 -> arg" flow="SOURCE, l:+6 -> arg"
680+
SINK(arg) #$ flow="SOURCE, l:+5 -> arg" flow="SOURCE, l:+6 -> arg"
681681

682682
# FP reported here: https://github.com/github/codeql-python-team/issues/49
683683
@expects(2)

0 commit comments

Comments
 (0)