Python: Implement field-stores, -reads, and -content

This commit is contained in:
Rasmus Lerchedahl Petersen
2020-09-16 13:00:09 +02:00
parent a2d006fe47
commit 27b25565ca
11 changed files with 427 additions and 9 deletions

View File

@@ -361,7 +361,7 @@ class DataFlowType extends TDataFlowType {
}
/** A node that performs a type cast. */
class CastNode extends Node {
class CastNode extends CfgNode {
CastNode() { none() }
}
@@ -423,6 +423,8 @@ predicate storeStep(Node nodeFrom, Content c, Node nodeTo) {
dictStoreStep(nodeFrom, c, nodeTo)
or
comprehensionStoreStep(nodeFrom, c, nodeTo)
or
attributeStoreStep(nodeFrom, c, nodeTo)
}
/** Data flows from an element of a list to the list. */
@@ -497,6 +499,30 @@ predicate comprehensionStoreStep(CfgNode nodeFrom, Content c, CfgNode nodeTo) {
c instanceof ListElementContent
}
/**
* In
* ```python
* obj.foo = x
* ```
* data flows from `x` to (the post-update node for) `obj` via assignment to `foo`.
*/
predicate attributeStoreStep(CfgNode nodeFrom, Content c, PostUpdateNode nodeTo) {
exists(AssignStmt a, Attribute attr |
a.getValue().getAFlowNode() = nodeFrom.getNode() and
a.getATarget().(Attribute) = attr and
attr.getName() = c.(AttributeContent).getAttribute() and
attr.getObject().getAFlowNode() = nodeTo.getPreUpdateNode().(CfgNode).getNode() and
attr.getCtx() instanceof Store
)
or
exists(AssignExpr ae |
ae.getValue().getAFlowNode() = nodeFrom.getNode() and
ae.getTarget().(Attribute).getName() = c.(AttributeContent).getAttribute() and
ae.getTarget().(Attribute).getObject().getAFlowNode() =
nodeTo.getPreUpdateNode().(CfgNode).getNode()
)
}
/**
* Holds if data can flow from `nodeFrom` to `nodeTo` via a read of content `c`.
*/
@@ -506,6 +532,8 @@ predicate readStep(Node nodeFrom, Content c, Node nodeTo) {
popReadStep(nodeFrom, c, nodeTo)
or
comprehensionReadStep(nodeFrom, c, nodeTo)
or
attributeReadStep(nodeFrom, c, nodeTo)
}
/** Data flows from a sequence to a subscript of the sequence. */
@@ -592,6 +620,22 @@ predicate comprehensionReadStep(CfgNode nodeFrom, Content c, EssaNode nodeTo) {
)
}
/**
* In
* ```python
* obj.foo
* ```
* data flows from `obj` to `obj.foo` via a read from `foo`.
*/
predicate attributeReadStep(CfgNode nodeFrom, Content c, CfgNode nodeTo) {
exists(Attribute attr |
nodeTo.asCfgNode().(AttrNode).getNode() = attr and
nodeFrom.asCfgNode() = attr.getObject().getAFlowNode() and
attr.getName() = c.(AttributeContent).getAttribute() and
attr.getCtx() instanceof Load
)
}
/**
* Holds if values stored inside content `c` are cleared at node `n`. For example,
* any value stored inside `f` is cleared at the pre-update node associated with `x`

View File

@@ -202,7 +202,9 @@ newtype TContent =
key = any(Keyword kw).getArg()
} or
/** An element of a dictionary at any key. */
TDictionaryElementAnyContent()
TDictionaryElementAnyContent() or
/** An object attribute. */
TAttributeContent(string attr) { attr = any(Attribute a).getName() }
class Content extends TContent {
/** Gets a textual representation of this element. */
@@ -210,12 +212,10 @@ class Content extends TContent {
}
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" }
}
@@ -224,10 +224,9 @@ class TupleElementContent extends TTupleElementContent, Content {
TupleElementContent() { this = TTupleElementContent(index) }
/** Gets the index for this tuple element */
/** 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 " + index.toString() }
}
@@ -236,14 +235,23 @@ class DictionaryElementContent extends TDictionaryElementContent, Content {
DictionaryElementContent() { this = TDictionaryElementContent(key) }
/** Gets the index for this tuple element */
/** Gets the key for this dictionary element. */
string getKey() { result = key }
/** Gets a textual representation of this element. */
override string toString() { result = "Dictionary element at key " + key }
}
class DictionaryElementAnyContent extends TDictionaryElementAnyContent, Content {
/** Gets a textual representation of this element. */
override string toString() { result = "Any dictionary element" }
}
class AttributeContent extends TAttributeContent, Content {
private string attr;
AttributeContent() { this = TAttributeContent(attr) }
/** Gets the name of the attribute under which this content is stored. */
string getAttribute() { result = attr }
override string toString() { result = "Attribute " + attr }
}