Python: More precise dataflow for tuples

(and dictionaries, but that is not fleshed out)
This commit is contained in:
Rasmus Lerchedahl Petersen
2020-08-05 19:22:54 +02:00
parent 2639e68a0d
commit 7c235597de
4 changed files with 139 additions and 59 deletions

View File

@@ -230,13 +230,35 @@ predicate storeStep(Node nodeFrom, Content c, Node nodeTo) {
// `[..., 42, ...]`
// nodeFrom is `42`, cfg node
// nodeTo is the sequence, say `[..., 42, ...]`, cfg node
nodeTo.(CfgNode).getNode().(SequenceNode).getAnElement() = nodeFrom.(CfgNode).getNode()
//
// List
nodeTo.(CfgNode).getNode().(ListNode).getAnElement() = nodeFrom.(CfgNode).getNode() and
c instanceof ListElementContent
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"
)
or
//
// Comprehension
// `[x+1 for x in l]`
// nodeFrom is `x+1`, cfg node
// nodeTo is `[x+1 for x in l]`, cfg node
nodeTo.(CfgNode).getNode().getNode().(Comp).getElt() = nodeFrom.(CfgNode).getNode().getNode()
//
// List
nodeTo.(CfgNode).getNode().getNode().(ListComp).getElt() = nodeFrom.(CfgNode).getNode().getNode() and
c instanceof ListElementContent
or
// Set
nodeTo.(CfgNode).getNode().getNode().(SetComp).getElt() = nodeFrom.(CfgNode).getNode().getNode() and
c instanceof SetElementContent
or
// Dictionary
nodeTo.(CfgNode).getNode().getNode().(DictComp).getElt() = nodeFrom.(CfgNode).getNode().getNode() and
c instanceof DictionaryElementAnyContent
}
/**
@@ -247,7 +269,18 @@ predicate readStep(Node nodeFrom, Content c, Node nodeTo) {
// `l[3]`
// nodeFrom is `l`, cfg node
// nodeTo is `l[3]`, cfg node
nodeFrom.(CfgNode).getNode() = nodeTo.(CfgNode).getNode().(SubscriptNode).getObject()
nodeFrom.(CfgNode).getNode() = nodeTo.(CfgNode).getNode().(SubscriptNode).getObject() and
(
c instanceof ListElementContent
or
c instanceof SetElementContent
or
c instanceof DictionaryElementAnyContent
or
c.(TupleElementContent).getIndex() = nodeTo.(CfgNode).getNode().(SubscriptNode).getIndex().getNode().(IntegerLiteral).getValue()
or
c.(DictionaryElementContent).getKey() = nodeTo.(CfgNode).getNode().(SubscriptNode).getIndex().getNode().(StrConst).getS()
)
or
// set.pop
// `s.pop()`
@@ -257,7 +290,12 @@ predicate readStep(Node nodeFrom, Content c, Node nodeTo) {
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
nodeTo.(CfgNode).getNode() = call and
(
c instanceof ListElementContent
or
c instanceof SetElementContent
)
)
or
// Comprehension

View File

@@ -145,6 +145,58 @@ class BarrierGuard extends Expr {
/**
* A reference contained in an object. This is either a field or a property.
*/
class Content extends string {
Content() { this = "Content" }
newtype TContent =
/** An element of a list. */
TListElementContent() or
/** An element of a set. */
TSetElementContent() or
/** An element of a tuple at a specifik index. */
TTupleElementContent(int index) { exists(IntegerLiteral lit | lit.getValue() = index) } or
/** An element of a dictionary under a specific key. */
TDictionaryElementContent(string key) { exists(StrConst s | s.getS() = key ) } or
/** An element of a dictionary at any key. */
TDictionaryElementAnyContent()
class Content extends TContent {
/** Gets a textual representation of this element. */
string toString() { result = "Content" }
}
class ListElementContent extends TListElementContent, Content {
/** Gets a textual representation of this element. */
override string toString() { result = "List element" }
}
class SetElementContent extends TSetElementContent, Content {
/** Gets a textual representation of this element. */
override string toString() { result = "Set element" }
}
class TupleElementContent extends TTupleElementContent, Content {
int index;
TupleElementContent() { this = TTupleElementContent(index) }
/** Gets the index for this tuple element */
int getIndex() { result = index }
/** Gets a textual representation of this element. */
override string toString() { result = "Tuple element at " + index.toString() }
}
class DictionaryElementContent extends TDictionaryElementContent, Content {
string key;
DictionaryElementContent() { this = TDictionaryElementContent(key) }
/** Gets the index for this tuple element */
string getKey() { result = key }
/** Gets a textual representation of this element. */
override string toString() { result = "Dictionary element at " + key }
}
class DictionaryElementAnyContent extends TDictionaryElementAnyContent, Content {
/** Gets a textual representation of this element. */
override string toString() { result = "Any dictionary element" }
}