mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
Python: Track dictionary keys
Also, less hacky comprehension, but I think we still want to fix the extractor
This commit is contained in:
@@ -230,6 +230,7 @@ predicate storeStep(Node nodeFrom, Content c, Node nodeTo) {
|
||||
// `[..., 42, ...]`
|
||||
// nodeFrom is `42`, cfg node
|
||||
// nodeTo is the sequence, say `[..., 42, ...]`, cfg node
|
||||
// c denotes list or c denotes tuple and index of 42
|
||||
//
|
||||
// List
|
||||
nodeTo.(CfgNode).getNode().(ListNode).getAnElement() = nodeFrom.(CfgNode).getNode() and
|
||||
@@ -237,9 +238,15 @@ predicate storeStep(Node nodeFrom, Content c, Node nodeTo) {
|
||||
or
|
||||
// Tuple
|
||||
exists(int n |
|
||||
nodeTo.(CfgNode).getNode().(TupleNode).getNode().(Tuple).getElt(n) = nodeFrom.(CfgNode).getNode().getNode() and
|
||||
c.(TupleElementContent).getIndex() = n and
|
||||
nodeFrom.(CfgNode).getNode().(NameNode).getId() = "SOURCE"
|
||||
nodeTo.(CfgNode).getNode().(TupleNode).getElement(n) = nodeFrom.(CfgNode).getNode() and
|
||||
c.(TupleElementContent).getIndex() = n
|
||||
)
|
||||
or
|
||||
// Dict
|
||||
exists(KeyValuePair item |
|
||||
item = nodeTo.(CfgNode).getNode().(DictNode).getNode().(Dict).getAnItem() and
|
||||
nodeFrom.(CfgNode).getNode().getNode() = item.getValue() and
|
||||
c.(DictionaryElementContent).getKey() = item.getKey().(StrConst).getS()
|
||||
)
|
||||
or
|
||||
//
|
||||
@@ -247,6 +254,7 @@ predicate storeStep(Node nodeFrom, Content c, Node nodeTo) {
|
||||
// `[x+1 for x in l]`
|
||||
// nodeFrom is `x+1`, cfg node
|
||||
// nodeTo is `[x+1 for x in l]`, cfg node
|
||||
// c denotes list or set or dictionary without index
|
||||
//
|
||||
// List
|
||||
nodeTo.(CfgNode).getNode().getNode().(ListComp).getElt() = nodeFrom.(CfgNode).getNode().getNode() and
|
||||
@@ -269,6 +277,7 @@ predicate readStep(Node nodeFrom, Content c, Node nodeTo) {
|
||||
// `l[3]`
|
||||
// nodeFrom is `l`, cfg node
|
||||
// nodeTo is `l[3]`, cfg node
|
||||
// c is compatible with 3
|
||||
nodeFrom.(CfgNode).getNode() = nodeTo.(CfgNode).getNode().(SubscriptNode).getObject() and
|
||||
(
|
||||
c instanceof ListElementContent
|
||||
@@ -277,18 +286,22 @@ predicate readStep(Node nodeFrom, Content c, Node nodeTo) {
|
||||
or
|
||||
c instanceof DictionaryElementAnyContent
|
||||
or
|
||||
c.(TupleElementContent).getIndex() = nodeTo.(CfgNode).getNode().(SubscriptNode).getIndex().getNode().(IntegerLiteral).getValue()
|
||||
c.(TupleElementContent).getIndex() =
|
||||
nodeTo.(CfgNode).getNode().(SubscriptNode).getIndex().getNode().(IntegerLiteral).getValue()
|
||||
or
|
||||
c.(DictionaryElementContent).getKey() = nodeTo.(CfgNode).getNode().(SubscriptNode).getIndex().getNode().(StrConst).getS()
|
||||
c.(DictionaryElementContent).getKey() =
|
||||
nodeTo.(CfgNode).getNode().(SubscriptNode).getIndex().getNode().(StrConst).getS()
|
||||
)
|
||||
or
|
||||
// set.pop
|
||||
// set.pop or list.pop
|
||||
// `s.pop()`
|
||||
// nodeFrom is `s`, cfg node
|
||||
// nodeTo is `s.pop()`, cfg node
|
||||
// c denotes list or set
|
||||
exists(CallNode call, AttrNode a |
|
||||
call.getFunction() = a and
|
||||
a.getName() = "pop" and // TODO: Should be made more robust, like Value::named("set.pop").getACall()
|
||||
not exists(call.getAnArg()) and
|
||||
nodeFrom.(CfgNode).getNode() = a.getObject() and
|
||||
nodeTo.(CfgNode).getNode() = call and
|
||||
(
|
||||
@@ -298,16 +311,51 @@ predicate readStep(Node nodeFrom, Content c, Node nodeTo) {
|
||||
)
|
||||
)
|
||||
or
|
||||
// dict.pop
|
||||
// `d.pop(key)`
|
||||
// nodeFrom is `d`, cfg node
|
||||
// nodeTo is `d.pop(key)`, cfg node
|
||||
// c denotes key
|
||||
exists(CallNode call, AttrNode a |
|
||||
call.getFunction() = a and
|
||||
a.getName() = "pop" and // TODO: Should be made more robust, like Value::named("set.pop").getACall()
|
||||
nodeFrom.(CfgNode).getNode() = a.getObject() and
|
||||
nodeTo.(CfgNode).getNode() = call and
|
||||
c.(DictionaryElementContent).getKey() = call.getArg(0).getNode().(StrConst).getS()
|
||||
)
|
||||
or
|
||||
// Comprehension
|
||||
// `[x+1 for x in l]`
|
||||
// nodeFrom is `l`, cfg node
|
||||
// nodeTo is `x`, essa var
|
||||
// c denotes list or set
|
||||
exists(For f, Comp comp |
|
||||
// Seems to need extractor changes to write this part properly
|
||||
nodeFrom.(CfgNode).getNode().(SequenceNode).getNode().getParentNode() = comp and
|
||||
colocated(f.getIter(), comp) and
|
||||
f = getCompFor(comp) and
|
||||
nodeFrom.(CfgNode).getNode().(SequenceNode).getNode() = getCompIter(comp) and
|
||||
nodeTo.(EssaNode).getVar().getDefinition().(AssignmentDefinition).getDefiningNode().getNode() =
|
||||
f.getTarget()
|
||||
f.getTarget() and
|
||||
(
|
||||
c instanceof ListElementContent
|
||||
or
|
||||
c instanceof SetElementContent
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/** This seems to compensate for extractor shortcomings */
|
||||
For getCompFor(Comp c) {
|
||||
c.contains(result) and
|
||||
c.getFunction() = result.getScope()
|
||||
}
|
||||
|
||||
/** This seems to compensate for extractor shortcomings */
|
||||
AstNode getCompIter(Comp c) {
|
||||
c.contains(result) and
|
||||
c.getScope() = result.getScope() and
|
||||
not result = c.getFunction() and
|
||||
not exists(AstNode between |
|
||||
c.contains(between) and
|
||||
between.contains(result)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -30,13 +30,21 @@ edges
|
||||
| test.py:95:21:95:28 | ControlFlowNode for List [List element] | test.py:95:16:95:16 | SSA variable y |
|
||||
| test.py:95:22:95:27 | ControlFlowNode for SOURCE | test.py:95:21:95:28 | ControlFlowNode for List [List element] |
|
||||
| test.py:96:10:96:10 | ControlFlowNode for x [Set element] | test.py:96:10:96:16 | ControlFlowNode for Attribute() |
|
||||
| test.py:222:11:222:16 | ControlFlowNode for SOURCE | test.py:222:11:222:17 | ControlFlowNode for Tuple [Tuple element at 0] |
|
||||
| test.py:222:11:222:17 | ControlFlowNode for Tuple [Tuple element at 0] | test.py:222:10:222:21 | ControlFlowNode for Subscript |
|
||||
| test.py:225:10:225:17 | ControlFlowNode for List [List element] | test.py:225:10:225:20 | ControlFlowNode for Subscript |
|
||||
| test.py:225:11:225:16 | ControlFlowNode for SOURCE | test.py:225:10:225:17 | ControlFlowNode for List [List element] |
|
||||
| test.py:246:28:246:33 | ControlFlowNode for SOURCE | test.py:246:10:246:34 | ControlFlowNode for second() |
|
||||
| test.py:305:12:305:17 | ControlFlowNode for SOURCE | test.py:305:10:305:18 | ControlFlowNode for f() |
|
||||
| test.py:309:28:309:33 | ControlFlowNode for SOURCE | test.py:309:10:309:34 | ControlFlowNode for second() |
|
||||
| test.py:104:9:104:21 | ControlFlowNode for Dict [Dictionary element at s] | test.py:105:10:105:10 | ControlFlowNode for x [Dictionary element at s] |
|
||||
| test.py:104:15:104:20 | ControlFlowNode for SOURCE | test.py:104:9:104:21 | ControlFlowNode for Dict [Dictionary element at s] |
|
||||
| test.py:105:10:105:10 | ControlFlowNode for x [Dictionary element at s] | test.py:105:10:105:15 | ControlFlowNode for Subscript |
|
||||
| test.py:108:9:108:21 | ControlFlowNode for Dict [Dictionary element at s] | test.py:109:10:109:10 | ControlFlowNode for x [Dictionary element at s] |
|
||||
| test.py:108:15:108:20 | ControlFlowNode for SOURCE | test.py:108:9:108:21 | ControlFlowNode for Dict [Dictionary element at s] |
|
||||
| test.py:109:10:109:10 | ControlFlowNode for x [Dictionary element at s] | test.py:109:10:109:19 | ControlFlowNode for Attribute() |
|
||||
| test.py:234:11:234:16 | ControlFlowNode for SOURCE | test.py:234:11:234:17 | ControlFlowNode for Tuple [Tuple element at 0] |
|
||||
| test.py:234:11:234:17 | ControlFlowNode for Tuple [Tuple element at 0] | test.py:234:10:234:21 | ControlFlowNode for Subscript |
|
||||
| test.py:237:10:237:17 | ControlFlowNode for List [List element] | test.py:237:10:237:20 | ControlFlowNode for Subscript |
|
||||
| test.py:237:11:237:16 | ControlFlowNode for SOURCE | test.py:237:10:237:17 | ControlFlowNode for List [List element] |
|
||||
| test.py:240:10:240:21 | ControlFlowNode for Dict [Dictionary element at s] | test.py:240:10:240:26 | ControlFlowNode for Subscript |
|
||||
| test.py:240:15:240:20 | ControlFlowNode for SOURCE | test.py:240:10:240:21 | ControlFlowNode for Dict [Dictionary element at s] |
|
||||
| test.py:258:28:258:33 | ControlFlowNode for SOURCE | test.py:258:10:258:34 | ControlFlowNode for second() |
|
||||
| test.py:317:12:317:17 | ControlFlowNode for SOURCE | test.py:317:10:317:18 | ControlFlowNode for f() |
|
||||
| test.py:321:28:321:33 | ControlFlowNode for SOURCE | test.py:321:10:321:34 | ControlFlowNode for second() |
|
||||
nodes
|
||||
| test.py:24:10:24:26 | ControlFlowNode for Tuple [Tuple element at 1] | semmle.label | ControlFlowNode for Tuple [Tuple element at 1] |
|
||||
| test.py:24:21:24:26 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
|
||||
@@ -81,18 +89,29 @@ nodes
|
||||
| test.py:95:22:95:27 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
|
||||
| test.py:96:10:96:10 | ControlFlowNode for x [Set element] | semmle.label | ControlFlowNode for x [Set element] |
|
||||
| test.py:96:10:96:16 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| test.py:222:10:222:21 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| test.py:222:11:222:16 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
|
||||
| test.py:222:11:222:17 | ControlFlowNode for Tuple [Tuple element at 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at 0] |
|
||||
| test.py:225:10:225:17 | ControlFlowNode for List [List element] | semmle.label | ControlFlowNode for List [List element] |
|
||||
| test.py:225:10:225:20 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| test.py:225:11:225:16 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
|
||||
| test.py:246:10:246:34 | ControlFlowNode for second() | semmle.label | ControlFlowNode for second() |
|
||||
| test.py:246:28:246:33 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
|
||||
| test.py:305:10:305:18 | ControlFlowNode for f() | semmle.label | ControlFlowNode for f() |
|
||||
| test.py:305:12:305:17 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
|
||||
| test.py:309:10:309:34 | ControlFlowNode for second() | semmle.label | ControlFlowNode for second() |
|
||||
| test.py:309:28:309:33 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
|
||||
| test.py:104:9:104:21 | ControlFlowNode for Dict [Dictionary element at s] | semmle.label | ControlFlowNode for Dict [Dictionary element at s] |
|
||||
| test.py:104:15:104:20 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
|
||||
| test.py:105:10:105:10 | ControlFlowNode for x [Dictionary element at s] | semmle.label | ControlFlowNode for x [Dictionary element at s] |
|
||||
| test.py:105:10:105:15 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| test.py:108:9:108:21 | ControlFlowNode for Dict [Dictionary element at s] | semmle.label | ControlFlowNode for Dict [Dictionary element at s] |
|
||||
| test.py:108:15:108:20 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
|
||||
| test.py:109:10:109:10 | ControlFlowNode for x [Dictionary element at s] | semmle.label | ControlFlowNode for x [Dictionary element at s] |
|
||||
| test.py:109:10:109:19 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| test.py:234:10:234:21 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| test.py:234:11:234:16 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
|
||||
| test.py:234:11:234:17 | ControlFlowNode for Tuple [Tuple element at 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at 0] |
|
||||
| test.py:237:10:237:17 | ControlFlowNode for List [List element] | semmle.label | ControlFlowNode for List [List element] |
|
||||
| test.py:237:10:237:20 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| test.py:237:11:237:16 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
|
||||
| test.py:240:10:240:21 | ControlFlowNode for Dict [Dictionary element at s] | semmle.label | ControlFlowNode for Dict [Dictionary element at s] |
|
||||
| test.py:240:10:240:26 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| test.py:240:15:240:20 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
|
||||
| test.py:258:10:258:34 | ControlFlowNode for second() | semmle.label | ControlFlowNode for second() |
|
||||
| test.py:258:28:258:33 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
|
||||
| test.py:317:10:317:18 | ControlFlowNode for f() | semmle.label | ControlFlowNode for f() |
|
||||
| test.py:317:12:317:17 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
|
||||
| test.py:321:10:321:34 | ControlFlowNode for second() | semmle.label | ControlFlowNode for second() |
|
||||
| test.py:321:28:321:33 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
|
||||
#select
|
||||
| test.py:26:10:26:10 | ControlFlowNode for y | test.py:24:21:24:26 | ControlFlowNode for SOURCE | test.py:26:10:26:10 | ControlFlowNode for y | <message> |
|
||||
| test.py:36:10:36:10 | ControlFlowNode for x | test.py:35:9:35:14 | ControlFlowNode for SOURCE | test.py:36:10:36:10 | ControlFlowNode for x | <message> |
|
||||
@@ -106,8 +125,11 @@ nodes
|
||||
| test.py:79:10:79:13 | ControlFlowNode for Subscript | test.py:78:22:78:27 | ControlFlowNode for SOURCE | test.py:79:10:79:13 | ControlFlowNode for Subscript | <message> |
|
||||
| test.py:92:10:92:16 | ControlFlowNode for Attribute() | test.py:91:10:91:15 | ControlFlowNode for SOURCE | test.py:92:10:92:16 | ControlFlowNode for Attribute() | <message> |
|
||||
| test.py:96:10:96:16 | ControlFlowNode for Attribute() | test.py:95:22:95:27 | ControlFlowNode for SOURCE | test.py:96:10:96:16 | ControlFlowNode for Attribute() | <message> |
|
||||
| test.py:222:10:222:21 | ControlFlowNode for Subscript | test.py:222:11:222:16 | ControlFlowNode for SOURCE | test.py:222:10:222:21 | ControlFlowNode for Subscript | <message> |
|
||||
| test.py:225:10:225:20 | ControlFlowNode for Subscript | test.py:225:11:225:16 | ControlFlowNode for SOURCE | test.py:225:10:225:20 | ControlFlowNode for Subscript | <message> |
|
||||
| test.py:246:10:246:34 | ControlFlowNode for second() | test.py:246:28:246:33 | ControlFlowNode for SOURCE | test.py:246:10:246:34 | ControlFlowNode for second() | <message> |
|
||||
| test.py:305:10:305:18 | ControlFlowNode for f() | test.py:305:12:305:17 | ControlFlowNode for SOURCE | test.py:305:10:305:18 | ControlFlowNode for f() | <message> |
|
||||
| test.py:309:10:309:34 | ControlFlowNode for second() | test.py:309:28:309:33 | ControlFlowNode for SOURCE | test.py:309:10:309:34 | ControlFlowNode for second() | <message> |
|
||||
| test.py:105:10:105:15 | ControlFlowNode for Subscript | test.py:104:15:104:20 | ControlFlowNode for SOURCE | test.py:105:10:105:15 | ControlFlowNode for Subscript | <message> |
|
||||
| test.py:109:10:109:19 | ControlFlowNode for Attribute() | test.py:108:15:108:20 | ControlFlowNode for SOURCE | test.py:109:10:109:19 | ControlFlowNode for Attribute() | <message> |
|
||||
| test.py:234:10:234:21 | ControlFlowNode for Subscript | test.py:234:11:234:16 | ControlFlowNode for SOURCE | test.py:234:10:234:21 | ControlFlowNode for Subscript | <message> |
|
||||
| test.py:237:10:237:20 | ControlFlowNode for Subscript | test.py:237:11:237:16 | ControlFlowNode for SOURCE | test.py:237:10:237:20 | ControlFlowNode for Subscript | <message> |
|
||||
| test.py:240:10:240:26 | ControlFlowNode for Subscript | test.py:240:15:240:20 | ControlFlowNode for SOURCE | test.py:240:10:240:26 | ControlFlowNode for Subscript | <message> |
|
||||
| test.py:258:10:258:34 | ControlFlowNode for second() | test.py:258:28:258:33 | ControlFlowNode for SOURCE | test.py:258:10:258:34 | ControlFlowNode for second() | <message> |
|
||||
| test.py:317:10:317:18 | ControlFlowNode for f() | test.py:317:12:317:17 | ControlFlowNode for SOURCE | test.py:317:10:317:18 | ControlFlowNode for f() | <message> |
|
||||
| test.py:321:10:321:34 | ControlFlowNode for second() | test.py:321:28:321:33 | ControlFlowNode for SOURCE | test.py:321:10:321:34 | ControlFlowNode for second() | <message> |
|
||||
|
||||
@@ -102,16 +102,28 @@ def test_nested_set_display():
|
||||
# 6.2.7. Dictionary displays
|
||||
def test_dict_display():
|
||||
x = {"s": SOURCE}
|
||||
SINK(x["s"]) # Flow missing
|
||||
SINK(x["s"])
|
||||
|
||||
def test_dict_display_pop():
|
||||
x = {"s": SOURCE}
|
||||
SINK(x.pop("s"))
|
||||
|
||||
def test_dict_comprehension():
|
||||
x = {y: SOURCE for y in ["s"]}
|
||||
SINK(x["s"]) # Flow missing
|
||||
|
||||
def test_dict_comprehension_pop():
|
||||
x = {y: SOURCE for y in ["s"]}
|
||||
SINK(x.pop("s")) # Flow missing
|
||||
|
||||
def test_nested_dict_display():
|
||||
x = {** {"s": SOURCE}}
|
||||
SINK(x["s"]) # Flow missing
|
||||
|
||||
def test_nested_dict_display_pop():
|
||||
x = {** {"s": SOURCE}}
|
||||
SINK(x.pop("s")) # Flow missing
|
||||
|
||||
# 6.2.8. Generator expressions
|
||||
def test_generator():
|
||||
x = (SOURCE for y in [NONSOURCE])
|
||||
@@ -225,7 +237,7 @@ def test_subscription_list():
|
||||
SINK([SOURCE][0])
|
||||
|
||||
def test_subscription_mapping():
|
||||
SINK({"s":SOURCE}["s"]) # Flow missing
|
||||
SINK({"s":SOURCE}["s"])
|
||||
|
||||
# overriding __getitem__ should be tested by the class coverage tests
|
||||
|
||||
|
||||
Reference in New Issue
Block a user