diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index e6038dd5399..63f6d33698f 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -1973,6 +1973,18 @@ predicate clearsContent(Node n, Content c) { kwOverflowClearStep(n, c) or matchClearStep(n, c) + or + attributeClearStep(n, c) +} + +/** + * Holds if values stored inside attribute `c` are cleared at node `n`. + * + * In `obj.foo = x` the any old value stored in `foo` is cleared at the pre-update node + * associated with `obj` + */ +predicate attributeClearStep(Node n, AttributeContent c) { + exists(PostUpdateNode post | post.getPreUpdateNode() = n | attributeStoreStep(_, c, post)) } //-------- diff --git a/python/ql/test/experimental/dataflow/fieldflow/test.py b/python/ql/test/experimental/dataflow/fieldflow/test.py index bc3c06e1325..4b7ac3ff5b3 100644 --- a/python/ql/test/experimental/dataflow/fieldflow/test.py +++ b/python/ql/test/experimental/dataflow/fieldflow/test.py @@ -67,7 +67,7 @@ def test_direct_assign_overwrite(): myobj = MyObj(NONSOURCE) myobj.foo = SOURCE myobj.foo = NONSOURCE - SINK_F(myobj.foo) # $ SPURIOUS: flow="SOURCE, l:-2 -> myobj.foo" + SINK_F(myobj.foo) def test_direct_if_assign(cond = False): @@ -75,7 +75,7 @@ def test_direct_if_assign(cond = False): myobj.foo = SOURCE if cond: myobj.foo = NONSOURCE - SINK_F(myobj.foo) # $ SPURIOUS: flow="SOURCE, l:-3 -> myobj.foo" + SINK_F(myobj.foo) SINK(myobj.foo) # $ flow="SOURCE, l:-4 -> myobj.foo" @@ -85,11 +85,11 @@ def test_direct_if_always_assign(cond = True): myobj.foo = SOURCE if cond: myobj.foo = NONSOURCE - SINK_F(myobj.foo) # $ SPURIOUS: flow="SOURCE, l:-3 -> myobj.foo" + SINK_F(myobj.foo) else: myobj.foo = NONSOURCE - SINK_F(myobj.foo) # $ SPURIOUS: flow="SOURCE, l:-6 -> myobj.foo" - SINK_F(myobj.foo) # $ SPURIOUS: flow="SOURCE, l:-7 -> myobj.foo" + SINK_F(myobj.foo) + SINK_F(myobj.foo) def test_getattr():