Python: Add basic flow for class attributes

This commit is contained in:
Rasmus Wriedt Larsen
2023-11-07 11:21:01 +01:00
parent 6c50c2bfe6
commit 6568332e3d
2 changed files with 34 additions and 8 deletions

View File

@@ -846,10 +846,27 @@ predicate comprehensionStoreStep(CfgNode nodeFrom, Content c, CfgNode nodeTo) {
* ```
* data flows from `x` to the attribute `foo` of (the post-update node for) `obj`.
*/
predicate attributeStoreStep(Node nodeFrom, AttributeContent c, PostUpdateNode nodeTo) {
exists(AttrWrite write |
write.accesses(nodeTo.getPreUpdateNode(), c.getAttribute()) and
nodeFrom = write.getValue()
predicate attributeStoreStep(Node nodeFrom, AttributeContent c, Node nodeTo) {
exists(Node object |
// normally we target any PostUpdateNode. However, for class definitions the class
// is only constructed after evaluating its' entire scope, so in terms of python
// evaluations there is no post or pre update nodes, just one node for the class
// expression. Therefore we target the class expression directly.
//
// Note: Due to the way we handle decorators, using a class decorator will result in
// there being a post-update node for the class (argument to the decorator). We do
// not want to differentiate between these two cases, so still target the class
// expression directly.
object = nodeTo.(PostUpdateNode).getPreUpdateNode() and
not object.asExpr() instanceof ClassExpr
or
object = nodeTo and
object.asExpr() instanceof ClassExpr
|
exists(AttrWrite write |
write.accesses(object, c.getAttribute()) and
nodeFrom = write.getValue()
)
)
}

View File

@@ -248,15 +248,24 @@ class WithTuple:
SINK(self.my_tuple[0]) # $ MISSING: flow
SINK_F(self.my_tuple[1])
def test_inst_no_call(self):
SINK(self.my_tuple[0]) # $ MISSING: flow
SINK_F(self.my_tuple[1])
@classmethod
def test_cm(cls):
SINK(cls.my_tuple[0]) # $ MISSING: flow
SINK(cls.my_tuple[0]) # $ flow="SOURCE, l:-12 -> cls.my_tuple[0]"
SINK_F(cls.my_tuple[1])
@classmethod
def test_cm_no_call(cls):
SINK(cls.my_tuple[0]) # $ MISSING: flow="SOURCE, l:-8 -> cls.my_tuple[0]"
SINK_F(cls.my_tuple[1])
@expects(2*4) # $ unresolved_call=expects(..) unresolved_call=expects(..)(..)
def test_WithTuple():
SINK(WithTuple.my_tuple[0]) # $ MISSING: flow="SOURCE, l:-7 -> WithTuple.my_tuple[0]"
SINK(WithTuple.my_tuple[0]) # $ flow="SOURCE, l:-23 -> WithTuple.my_tuple[0]"
SINK_F(WithTuple.my_tuple[1])
WithTuple.test_cm()
@@ -264,7 +273,7 @@ def test_WithTuple():
inst = WithTuple()
inst.test_inst()
SINK(inst.my_tuple[0]) # $ MISSING: flow="SOURCE, l:-18 -> inst.my_tuple[0]"
SINK(inst.my_tuple[0]) # $ MISSING: flow
SINK_F(inst.my_tuple[1])
@@ -279,7 +288,7 @@ def test_inst_override():
SINK_F(inst.my_tuple[0])
SINK(inst.my_tuple[1]) # $ flow="SOURCE, l:-3 -> inst.my_tuple[1]"
SINK(WithTuple.my_tuple[0]) # $ MISSING: flow="SOURCE, l:-27 -> WithTuple.my_tuple[0]"
SINK(WithTuple.my_tuple[0]) # $ flow="SOURCE, l:-46 -> WithTuple.my_tuple[0]"
SINK_F(WithTuple.my_tuple[1])