From 823ed447df465beee6ca6d7fb5d6f410d2708c35 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Thu, 12 Nov 2020 21:57:29 +0100 Subject: [PATCH 01/16] Python: Add new-style tests should perhaps move `LocalFlowStepTest` and `MaximalFlowStep` into where they are referenced (they did not seem too reusable after all). Should also add argument tests in the same way. --- .../dataflow/FlowTestUtil/FlowTest.qll | 31 ++++ .../FlowTestUtil/LocalFlowStepTest.qll | 13 ++ .../dataflow/FlowTestUtil/MaximalFlowTest.qll | 34 +++++ .../dataflow/basic/localFlowStepTest.expected | 0 .../dataflow/basic/localFlowStepTest.ql | 1 + .../dataflow/basic/maximalFlowTest.expected | 0 .../dataflow/basic/maximalFlowTest.ql | 1 + .../test/experimental/dataflow/basic/test.py | 12 +- .../dataflow/coverage/dataflowTest.expected | 0 .../dataflow/coverage/dataflowTest.ql | 13 ++ .../dataflow/coverage/datamodel.py | 12 +- .../coverage/maximalFlowTest.expected | 0 .../dataflow/coverage/maximalFlowTest.ql | 1 + .../experimental/dataflow/coverage/test.py | 140 +++++++++--------- 14 files changed, 176 insertions(+), 82 deletions(-) create mode 100644 python/ql/test/experimental/dataflow/FlowTestUtil/FlowTest.qll create mode 100644 python/ql/test/experimental/dataflow/FlowTestUtil/LocalFlowStepTest.qll create mode 100644 python/ql/test/experimental/dataflow/FlowTestUtil/MaximalFlowTest.qll create mode 100644 python/ql/test/experimental/dataflow/basic/localFlowStepTest.expected create mode 100644 python/ql/test/experimental/dataflow/basic/localFlowStepTest.ql create mode 100644 python/ql/test/experimental/dataflow/basic/maximalFlowTest.expected create mode 100644 python/ql/test/experimental/dataflow/basic/maximalFlowTest.ql create mode 100644 python/ql/test/experimental/dataflow/coverage/dataflowTest.expected create mode 100644 python/ql/test/experimental/dataflow/coverage/dataflowTest.ql create mode 100644 python/ql/test/experimental/dataflow/coverage/maximalFlowTest.expected create mode 100644 python/ql/test/experimental/dataflow/coverage/maximalFlowTest.ql diff --git a/python/ql/test/experimental/dataflow/FlowTestUtil/FlowTest.qll b/python/ql/test/experimental/dataflow/FlowTestUtil/FlowTest.qll new file mode 100644 index 000000000000..9f0762f64881 --- /dev/null +++ b/python/ql/test/experimental/dataflow/FlowTestUtil/FlowTest.qll @@ -0,0 +1,31 @@ +import python +import semmle.python.dataflow.new.DataFlow +import TestUtilities.InlineExpectationsTest + +abstract class FlowTest extends InlineExpectationsTest { + bindingset[this] + FlowTest() { any() } + + abstract string flowTag(); + + abstract predicate relevantFlow(DataFlow::Node fromNode, DataFlow::Node toNode); + + override string getARelevantTag() { result = this.flowTag() } + + override predicate hasActualResult(Location location, string element, string tag, string value) { + exists(DataFlow::Node fromNode, DataFlow::Node toNode | this.relevantFlow(fromNode, toNode) | + location = toNode.getLocation() and + tag = this.flowTag() and + value = + "\"" + fromNode.toString() + lineStr(fromNode, toNode) + " -> " + toNode.toString() + "\"" and + element = toNode.toString() + ) + } + + pragma[inline] + private string lineStr(DataFlow::Node fromNode, DataFlow::Node toNode) { + if fromNode.getLocation().getStartLine() = toNode.getLocation().getStartLine() + then result = "" + else result = ", l:" + fromNode.getLocation().getStartLine() + } +} diff --git a/python/ql/test/experimental/dataflow/FlowTestUtil/LocalFlowStepTest.qll b/python/ql/test/experimental/dataflow/FlowTestUtil/LocalFlowStepTest.qll new file mode 100644 index 000000000000..c2c180627ece --- /dev/null +++ b/python/ql/test/experimental/dataflow/FlowTestUtil/LocalFlowStepTest.qll @@ -0,0 +1,13 @@ +import python +import semmle.python.dataflow.new.DataFlow +import FlowTest + +class LocalFlowStepTest extends FlowTest { + LocalFlowStepTest() { this = "LocalFlowStepTest" } + + override string flowTag() { result = "step" } + + override predicate relevantFlow(DataFlow::Node fromNode, DataFlow::Node toNode) { + DataFlow::localFlowStep(fromNode, toNode) + } +} diff --git a/python/ql/test/experimental/dataflow/FlowTestUtil/MaximalFlowTest.qll b/python/ql/test/experimental/dataflow/FlowTestUtil/MaximalFlowTest.qll new file mode 100644 index 000000000000..792aa2b848d4 --- /dev/null +++ b/python/ql/test/experimental/dataflow/FlowTestUtil/MaximalFlowTest.qll @@ -0,0 +1,34 @@ +import python +import semmle.python.dataflow.new.DataFlow +import FlowTest + +class MaximalFlowTest extends FlowTest { + MaximalFlowTest() { this = "MaximalFlowTest" } + + override string flowTag() { result = "flow" } + + override predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) { + source != sink and + exists(MaximalFlowsConfig cfg | cfg.hasFlow(source, sink)) + } +} + +/** + * A configuration to find all "maximal" flows. + * To be used on small programs. + */ +class MaximalFlowsConfig extends DataFlow::Configuration { + MaximalFlowsConfig() { this = "MaximalFlowsConfig" } + + override predicate isSource(DataFlow::Node node) { + not node.asCfgNode() instanceof CallNode and + not node.asCfgNode().getNode() instanceof Return and + not node instanceof DataFlow::ParameterNode and + not exists(DataFlow::Node pred | DataFlow::localFlowStep(pred, node)) + } + + override predicate isSink(DataFlow::Node node) { + not any(CallNode c).getArg(_) = node.asCfgNode() and + not exists(DataFlow::Node succ | DataFlow::localFlowStep(node, succ)) + } +} diff --git a/python/ql/test/experimental/dataflow/basic/localFlowStepTest.expected b/python/ql/test/experimental/dataflow/basic/localFlowStepTest.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/ql/test/experimental/dataflow/basic/localFlowStepTest.ql b/python/ql/test/experimental/dataflow/basic/localFlowStepTest.ql new file mode 100644 index 000000000000..6e57f26cd0f1 --- /dev/null +++ b/python/ql/test/experimental/dataflow/basic/localFlowStepTest.ql @@ -0,0 +1 @@ +import experimental.dataflow.FlowTestUtil.LocalFlowStepTest diff --git a/python/ql/test/experimental/dataflow/basic/maximalFlowTest.expected b/python/ql/test/experimental/dataflow/basic/maximalFlowTest.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/ql/test/experimental/dataflow/basic/maximalFlowTest.ql b/python/ql/test/experimental/dataflow/basic/maximalFlowTest.ql new file mode 100644 index 000000000000..ec171dcd9fd9 --- /dev/null +++ b/python/ql/test/experimental/dataflow/basic/maximalFlowTest.ql @@ -0,0 +1 @@ +import experimental.dataflow.FlowTestUtil.MaximalFlowTest diff --git a/python/ql/test/experimental/dataflow/basic/test.py b/python/ql/test/experimental/dataflow/basic/test.py index 416467d9dc9d..e97068a041c5 100644 --- a/python/ql/test/experimental/dataflow/basic/test.py +++ b/python/ql/test/experimental/dataflow/basic/test.py @@ -1,7 +1,7 @@ -def obfuscated_id(x): - y = x - z = y - return z +def obfuscated_id(x): #$ step="ControlFlowNode for FunctionExpr -> GSSA Variable obfuscated_id" + y = x #$ step="ControlFlowNode for x -> SSA variable y" step="SSA variable x, l:1 -> ControlFlowNode for x" + z = y #$ step="ControlFlowNode for y -> SSA variable z" step="SSA variable y, l:2 -> ControlFlowNode for y" + return z #$ flow="ControlFlowNode for IntegerLiteral, l:6 -> ControlFlowNode for z" step="SSA variable z, l:3 -> ControlFlowNode for z" -a = 42 -b = obfuscated_id(a) +a = 42 #$ step="ControlFlowNode for IntegerLiteral -> GSSA Variable a" +b = obfuscated_id(a) #$ flow="ControlFlowNode for IntegerLiteral, l:6 -> GSSA Variable b" flow="ControlFlowNode for FunctionExpr, l:1 -> ControlFlowNode for obfuscated_id" step="ControlFlowNode for obfuscated_id() -> GSSA Variable b" step="GSSA Variable obfuscated_id, l:1 -> ControlFlowNode for obfuscated_id" step="GSSA Variable a, l:6 -> ControlFlowNode for a" diff --git a/python/ql/test/experimental/dataflow/coverage/dataflowTest.expected b/python/ql/test/experimental/dataflow/coverage/dataflowTest.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/ql/test/experimental/dataflow/coverage/dataflowTest.ql b/python/ql/test/experimental/dataflow/coverage/dataflowTest.ql new file mode 100644 index 000000000000..c7b2b5bfe15a --- /dev/null +++ b/python/ql/test/experimental/dataflow/coverage/dataflowTest.ql @@ -0,0 +1,13 @@ +import python +import experimental.dataflow.FlowTestUtil.FlowTest +import experimental.dataflow.testConfig + +class DataFlowTest extends FlowTest { + DataFlowTest() { this = "DataFlowTest" } + + override string flowTag() { result = "flow" } + + override predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) { + exists(TestConfiguration cfg | cfg.hasFlow(source, sink)) + } +} diff --git a/python/ql/test/experimental/dataflow/coverage/datamodel.py b/python/ql/test/experimental/dataflow/coverage/datamodel.py index f5f3680dd55c..d6ab9bd3dcbc 100644 --- a/python/ql/test/experimental/dataflow/coverage/datamodel.py +++ b/python/ql/test/experimental/dataflow/coverage/datamodel.py @@ -35,7 +35,7 @@ def SINK_F(x): def f(a, b): return a -SINK(f(SOURCE, 3)) +SINK(f(SOURCE, 3)) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for f()" flow="ControlFlowNode for Str, l:13 -> ControlFlowNode for f()" # Instance methods # An instance method object combines a class, a class instance and any callable object (normally a user-defined function). @@ -68,8 +68,8 @@ async def coro(self, x): func_obj = c.method.__func__ # When an instance method object is called, the underlying function (__func__) is called, inserting the class instance (__self__) in front of the argument list. For instance, when C is a class which contains a definition for a function f(), and x is an instance of C, calling x.f(1) is equivalent to calling C.f(x, 1). -SINK(c.method(SOURCE, C)) -SINK(C.method(c, SOURCE, C)) +SINK(c.method(SOURCE, C)) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for Attribute()" flow="ControlFlowNode for SOURCE, l:38 -> ControlFlowNode for Attribute()" flow="ControlFlowNode for Str, l:13 -> ControlFlowNode for Attribute()" +SINK(C.method(c, SOURCE, C)) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for Attribute()" flow="ControlFlowNode for SOURCE, l:38 -> ControlFlowNode for Attribute()" flow="ControlFlowNode for SOURCE, l:71 -> ControlFlowNode for Attribute()" flow="ControlFlowNode for Str, l:13 -> ControlFlowNode for Attribute()" SINK(func_obj(c, SOURCE, C)) @@ -77,8 +77,8 @@ async def coro(self, x): c_func_obj = C.classmethod.__func__ # When an instance method object is derived from a class method object, the “class instance” stored in __self__ will actually be the class itself, so that calling either x.f(1) or C.f(1) is equivalent to calling f(C,1) where f is the underlying function. -SINK(c.classmethod(SOURCE)) -SINK(C.classmethod(SOURCE)) +SINK(c.classmethod(SOURCE)) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for Attribute()" flow="ControlFlowNode for SOURCE, l:38 -> ControlFlowNode for Attribute()" flow="ControlFlowNode for SOURCE, l:71 -> ControlFlowNode for Attribute()" flow="ControlFlowNode for SOURCE, l:72 -> ControlFlowNode for Attribute()" flow="ControlFlowNode for SOURCE, l:73 -> ControlFlowNode for Attribute()" flow="ControlFlowNode for Str, l:13 -> ControlFlowNode for Attribute()" +SINK(C.classmethod(SOURCE)) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for Attribute()" flow="ControlFlowNode for SOURCE, l:38 -> ControlFlowNode for Attribute()" flow="ControlFlowNode for SOURCE, l:71 -> ControlFlowNode for Attribute()" flow="ControlFlowNode for SOURCE, l:72 -> ControlFlowNode for Attribute()" flow="ControlFlowNode for SOURCE, l:73 -> ControlFlowNode for Attribute()" flow="ControlFlowNode for SOURCE, l:80 -> ControlFlowNode for Attribute()" flow="ControlFlowNode for Str, l:13 -> ControlFlowNode for Attribute()" SINK(c_func_obj(C, SOURCE)) # Generator functions @@ -156,4 +156,4 @@ def __init__(self): SINK(Customized.a) SINK_F(Customized.b) SINK(customized.a) -SINK(customized.b) # Flow found +SINK(customized.b) #$ flow="ControlFlowNode for SOURCE, l:152 -> ControlFlowNode for Attribute" flow="ControlFlowNode for Str, l:13 -> ControlFlowNode for Attribute" diff --git a/python/ql/test/experimental/dataflow/coverage/maximalFlowTest.expected b/python/ql/test/experimental/dataflow/coverage/maximalFlowTest.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/ql/test/experimental/dataflow/coverage/maximalFlowTest.ql b/python/ql/test/experimental/dataflow/coverage/maximalFlowTest.ql new file mode 100644 index 000000000000..ec171dcd9fd9 --- /dev/null +++ b/python/ql/test/experimental/dataflow/coverage/maximalFlowTest.ql @@ -0,0 +1 @@ +import experimental.dataflow.FlowTestUtil.MaximalFlowTest diff --git a/python/ql/test/experimental/dataflow/coverage/test.py b/python/ql/test/experimental/dataflow/coverage/test.py index cddb88f5ccbf..ab7b9f024050 100644 --- a/python/ql/test/experimental/dataflow/coverage/test.py +++ b/python/ql/test/experimental/dataflow/coverage/test.py @@ -41,7 +41,7 @@ def SINK_F(x): def test_tuple_with_local_flow(): x = (NONSOURCE, SOURCE) y = x[1] - SINK(y) + SINK(y) #$ flow="ControlFlowNode for SOURCE, l:42 -> ControlFlowNode for y" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for y" def test_tuple_negative(): @@ -53,45 +53,45 @@ def test_tuple_negative(): # 6.2.1. Identifiers (Names) def test_names(): x = SOURCE - SINK(x) + SINK(x) #$ flow="ControlFlowNode for SOURCE, l:55 -> ControlFlowNode for x" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for x" # 6.2.2. Literals def test_string_literal(): x = "source" - SINK(x) + SINK(x) #$ flow="ControlFlowNode for Str, l:61 -> ControlFlowNode for x" def test_bytes_literal(): x = b"source" - SINK(x) + SINK(x) #$ flow="ControlFlowNode for Str, l:66 -> ControlFlowNode for x" def test_integer_literal(): x = 42 - SINK(x) + SINK(x) #$ flow="ControlFlowNode for IntegerLiteral, l:71 -> ControlFlowNode for x" def test_floatnumber_literal(): x = 42.0 - SINK(x) + SINK(x) #$ flow="ControlFlowNode for FloatLiteral, l:76 -> ControlFlowNode for x" def test_imagnumber_literal(): x = 42j - SINK(x) # Flow missing + SINK(x) #$ MISSING:flow="ControlFlowNode for FloatLiteral, l:81 -> ControlFlowNode for x" # 6.2.3. Parenthesized forms def test_parenthesized_form(): x = (SOURCE) - SINK(x) + SINK(x) #$ flow="ControlFlowNode for SOURCE, l:87 -> ControlFlowNode for x" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for x" # 6.2.5. List displays def test_list_display(): x = [SOURCE] - SINK(x[0]) + SINK(x[0]) #$ flow="ControlFlowNode for SOURCE, l:93 -> ControlFlowNode for Subscript" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" def test_list_display_negative(): @@ -101,109 +101,109 @@ def test_list_display_negative(): def test_list_comprehension(): x = [SOURCE for y in [NONSOURCE]] - SINK(x[0]) + SINK(x[0]) #$ flow="ControlFlowNode for SOURCE, l:103 -> ControlFlowNode for Subscript" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" def test_list_comprehension_flow(): x = [y for y in [SOURCE]] - SINK(x[0]) + SINK(x[0]) #$ flow="ControlFlowNode for SOURCE, l:108 -> ControlFlowNode for Subscript" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" def test_list_comprehension_inflow(): l = [SOURCE] x = [y for y in l] - SINK(x[0]) + SINK(x[0]) #$ flow="ControlFlowNode for SOURCE, l:113 -> ControlFlowNode for Subscript" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" def test_nested_list_display(): x = [*[SOURCE]] - SINK(x[0]) # Flow missing + SINK(x[0]) #$ MISSING:flow="ControlFlowNode for SOURCE, l:119 -> ControlFlowNode for Subscript" MISSING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" # 6.2.6. Set displays def test_set_display(): x = {SOURCE} - SINK(x.pop()) + SINK(x.pop()) #$ flow="ControlFlowNode for SOURCE, l:125 -> ControlFlowNode for Attribute()" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Attribute()" def test_set_comprehension(): x = {SOURCE for y in [NONSOURCE]} - SINK(x.pop()) + SINK(x.pop()) #$ flow="ControlFlowNode for SOURCE, l:130 -> ControlFlowNode for Attribute()" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Attribute()" def test_set_comprehension_flow(): x = {y for y in [SOURCE]} - SINK(x.pop()) + SINK(x.pop()) #$ flow="ControlFlowNode for SOURCE, l:135 -> ControlFlowNode for Attribute()" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Attribute()" def test_set_comprehension_inflow(): l = {SOURCE} x = {y for y in l} - SINK(x.pop()) + SINK(x.pop()) #$ flow="ControlFlowNode for SOURCE, l:140 -> ControlFlowNode for Attribute()" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Attribute()" def test_nested_set_display(): x = {*{SOURCE}} - SINK(x.pop()) # Flow missing + SINK(x.pop()) #$ MISSING:flow="ControlFlowNode for SOURCE, l:146 -> ControlFlowNode for Attribute()" MISSING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Attribute()" # 6.2.7. Dictionary displays def test_dict_display(): x = {"s": SOURCE} - SINK(x["s"]) + SINK(x["s"]) #$ flow="ControlFlowNode for SOURCE, l:152 -> ControlFlowNode for Subscript" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" def test_dict_display_pop(): x = {"s": SOURCE} - SINK(x.pop("s")) + SINK(x.pop("s")) #$ flow="ControlFlowNode for SOURCE, l:157 -> ControlFlowNode for Attribute()" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Attribute()" def test_dict_comprehension(): x = {y: SOURCE for y in ["s"]} - SINK(x["s"]) # Flow missing + SINK(x["s"]) #$ MISSING:flow="ControlFlowNode for SOURCE, l:152 -> ControlFlowNode for Subscript" MISING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" def test_dict_comprehension_pop(): x = {y: SOURCE for y in ["s"]} - SINK(x.pop("s")) # Flow missing + SINK(x.pop("s")) #$ MISSING:flow="ControlFlowNode for SOURCE, l:167 -> ControlFlowNode for Attribute()" MISSING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Attribute()" def test_nested_dict_display(): x = {**{"s": SOURCE}} - SINK(x["s"]) # Flow missing + SINK(x["s"]) #$ MISSING:flow="ControlFlowNode for SOURCE, l:172 -> ControlFlowNode for Subscript" MISING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" def test_nested_dict_display_pop(): x = {**{"s": SOURCE}} - SINK(x.pop("s")) # Flow missing + SINK(x.pop("s")) #$ MISSING:flow="ControlFlowNode for SOURCE, l:177 -> ControlFlowNode for Attribute()" MISSING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Attribute()" # Nested comprehensions def test_nested_comprehension(): x = [y for z in [[SOURCE]] for y in z] - SINK(x[0]) + SINK(x[0]) #$ flow="ControlFlowNode for SOURCE, l:183 -> ControlFlowNode for Subscript" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" def test_nested_comprehension_deep_with_local_flow(): x = [y for v in [[[[SOURCE]]]] for u in v for z in u for y in z] - SINK(x[0]) + SINK(x[0]) #$ flow="ControlFlowNode for SOURCE, l:188 -> ControlFlowNode for Subscript" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" def test_nested_comprehension_dict(): d = {"s": [SOURCE]} x = [y for k, v in d.items() for y in v] - SINK(x[0]) # Flow missing + SINK(x[0]) #$ MISSING:flow="ControlFlowNode for SOURCE, l:193 -> ControlFlowNode for Subscript" MISING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" def test_nested_comprehension_paren(): x = [y for y in (z for z in [SOURCE])] - SINK(x[0]) + SINK(x[0]) #$ flow="ControlFlowNode for SOURCE, l:199 -> ControlFlowNode for Subscript" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" # 6.2.8. Generator expressions def test_generator(): x = (SOURCE for y in [NONSOURCE]) - SINK([*x][0]) # Flow missing + SINK([*x][0]) #$ MISSING:flow="ControlFlowNode for SOURCE, l:205 -> ControlFlowNode for Subscript" MISING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" # 6.2.9. Yield expressions @@ -213,7 +213,7 @@ def gen(x): def test_yield(): g = gen(SOURCE) - SINK(next(g)) # Flow missing + SINK(next(g)) #$ MISSING:flow="ControlFlowNode for SOURCE, l:215 -> ControlFlowNode for next()" MISING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for next()" def gen_from(x): @@ -222,19 +222,19 @@ def gen_from(x): def test_yield_from(): g = gen_from(SOURCE) - SINK(next(g)) # Flow missing + SINK(next(g)) #$ MISSING:flow="ControlFlowNode for SOURCE, l:224 -> ControlFlowNode for next()" MISING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for next()" # a statement rather than an expression, but related to generators def test_for(): for x in gen(SOURCE): - SINK(x) # Flow missing + SINK(x) #$ MISSING:flow="ControlFlowNode for SOURCE, l:230 -> ControlFlowNode for x" MISING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for x" # 6.2.9.1. Generator-iterator methods def test___next__(): g = gen(SOURCE) - SINK(g.__next__()) # Flow missing + SINK(g.__next__()) #$ MISSING:flow="ControlFlowNode for SOURCE, l:236 -> ControlFlowNode for Attribute()" MISSING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Attribute()" def gen2(x): @@ -246,7 +246,7 @@ def gen2(x): def test_send(): g = gen2(NONSOURCE) n = next(g) - SINK(g.send(SOURCE)) # Flow missing + SINK(g.send(SOURCE)) #$ MISSING:flow="ControlFlowNode for SOURCE -> ControlFlowNode for Attribute()" MISSING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Attribute()" def gen_ex(x): @@ -259,7 +259,7 @@ def gen_ex(x): def test_throw(): g = gen_ex(SOURCE) n = next(g) - SINK(g.throw(TypeError)) # Flow missing + SINK(g.throw(TypeError)) #$ MISSING:flow="ControlFlowNode for SOURCE, l:260 -> ControlFlowNode for Attribute()" MISSING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Attribute()" # no `test_close` as `close` involves no data flow @@ -280,7 +280,7 @@ def runa(a): async def atest___anext__(): g = agen(SOURCE) - SINK(await g.__anext__()) # Flow missing + SINK(await g.__anext__()) #$ MISSING:flow="ControlFlowNode for SOURCE, l:282 -> ControlFlowNode for Attribute()" MISSING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Attribute()" def test___anext__(): @@ -296,7 +296,7 @@ async def agen2(x): async def atest_asend(): g = agen2(NONSOURCE) n = await g.__anext__() - SINK(await g.asend(SOURCE)) # Flow missing + SINK(await g.asend(SOURCE)) #$ MISSING:flow="ControlFlowNode for SOURCE -> ControlFlowNode for Attribute()" MISSING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Attribute()" def test_asend(): @@ -313,7 +313,7 @@ async def agen_ex(x): async def atest_athrow(): g = agen_ex(SOURCE) n = await g.__anext__() - SINK(await g.athrow(TypeError)) # Flow missing + SINK(await g.athrow(TypeError)) #$ MISSING:flow="ControlFlowNode for SOURCE, l:314 -> ControlFlowNode for Attribute()" MISSING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Attribute()" def test_athrow(): @@ -326,22 +326,22 @@ class C: def test_attribute_reference(): - SINK(C.a) # Flow missing + SINK(C.a) #$ MISSING:flow="ControlFlowNode for SOURCE, l:325 -> ControlFlowNode for Attribute" MISSING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Attribute" # overriding __getattr__ should be tested by the class coverage tests # 6.3.2. Subscriptions def test_subscription_tuple(): - SINK((SOURCE,)[0]) + SINK((SOURCE,)[0]) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for Subscript" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" def test_subscription_list(): - SINK([SOURCE][0]) + SINK([SOURCE][0]) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for Subscript" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" def test_subscription_mapping(): - SINK({"s": SOURCE}["s"]) + SINK({"s": SOURCE}["s"]) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for Subscript" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" # overriding __getitem__ should be tested by the class coverage tests @@ -353,7 +353,7 @@ def test_subscription_mapping(): def test_slicing(): s = l[0:1:1] - SINK(s[0]) # Flow missing + SINK(s[0]) #$ MISSING:flow="ControlFlowNode for SOURCE -> ControlFlowNode for Subscript" MISSING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" # The grammar seems to allow `l[0:1:1, 0:1]`, but the interpreter does not like it @@ -364,7 +364,7 @@ def second(a, b): def test_call_positional(): - SINK(second(NONSOURCE, SOURCE)) + SINK(second(NONSOURCE, SOURCE)) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for second()" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for second()" def test_call_positional_negative(): @@ -372,15 +372,15 @@ def test_call_positional_negative(): def test_call_keyword(): - SINK(second(NONSOURCE, b=SOURCE)) + SINK(second(NONSOURCE, b=SOURCE)) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for second()" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for second()" def test_call_unpack_iterable(): - SINK(second(NONSOURCE, *[SOURCE])) # Flow missing + SINK(second(NONSOURCE, *[SOURCE])) #$ MISSING:flow="ControlFlowNode for SOURCE -> ControlFlowNode for second()" MISING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for second()" def test_call_unpack_mapping(): - SINK(second(NONSOURCE, **{"b": SOURCE})) + SINK(second(NONSOURCE, **{"b": SOURCE})) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for second()" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for second()" def f_extra_pos(a, *b): @@ -388,7 +388,7 @@ def f_extra_pos(a, *b): def test_call_extra_pos(): - SINK(f_extra_pos(NONSOURCE, SOURCE)) + SINK(f_extra_pos(NONSOURCE, SOURCE)) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for f_extra_pos()" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for f_extra_pos()" def f_extra_keyword(a, **b): @@ -396,7 +396,7 @@ def f_extra_keyword(a, **b): def test_call_extra_keyword(): - SINK(f_extra_keyword(NONSOURCE, b=SOURCE)) + SINK(f_extra_keyword(NONSOURCE, b=SOURCE)) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for f_extra_keyword()" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for f_extra_keyword()" # return the name of the first extra keyword argument @@ -406,18 +406,18 @@ def f_extra_keyword_flow(**a): # call the function with our source as the name of the keyword arguemnt def test_call_extra_keyword_flow(): - SINK(f_extra_keyword_flow(**{SOURCE: None})) # Flow missing + SINK(f_extra_keyword_flow(**{SOURCE: None})) #$ MISSING:flow="ControlFlowNode for SOURCE -> ControlFlowNode for f_extra_keyword()" MISSING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for f_extra_keyword()" # 6.12. Assignment expressions def test_assignment_expression(): x = NONSOURCE - SINK(x := SOURCE) # Flow missing + SINK(x := SOURCE) #$ MISSING:flow="ControlFlowNode for SOURCE -> ControlFlowNode for x" MISSING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for x" # 6.13. Conditional expressions def test_conditional_true(): - SINK(SOURCE if True else NONSOURCE) + SINK(SOURCE if True else NONSOURCE) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for IfExp" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for IfExp" def test_conditional_true_guards(): @@ -425,7 +425,7 @@ def test_conditional_true_guards(): def test_conditional_false(): - SINK(NONSOURCE if False else SOURCE) + SINK(NONSOURCE if False else SOURCE) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for IfExp" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for IfExp" def test_conditional_false_guards(): @@ -435,13 +435,13 @@ def test_conditional_false_guards(): # Condition is evaluated first, so x is SOURCE once chosen def test_conditional_evaluation_true(): x = NONSOURCE - SINK(x if (SOURCE == (x := SOURCE)) else NONSOURCE) # Flow missing + SINK(x if (SOURCE == (x := SOURCE)) else NONSOURCE) #$ MISSING:flow="ControlFlowNode for SOURCE -> ControlFlowNode for IfExp" MISSING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for IfExp" # Condition is evaluated first, so x is SOURCE once chosen def test_conditional_evaluation_false(): x = NONSOURCE - SINK(NONSOURCE if (NONSOURCE == (x := SOURCE)) else x) # Flow missing + SINK(NONSOURCE if (NONSOURCE == (x := SOURCE)) else x) #$ MISSING:flow="ControlFlowNode for SOURCE -> ControlFlowNode for IfExp" MISSING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for IfExp" # 6.14. Lambdas @@ -449,14 +449,14 @@ def test_lambda(): def f(x): return x - SINK(f(SOURCE)) + SINK(f(SOURCE)) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for f()" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for f()" def test_lambda_positional(): def second(a, b): return b - SINK(second(NONSOURCE, SOURCE)) + SINK(second(NONSOURCE, SOURCE)) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for second()" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for second()" def test_lambda_positional_negative(): @@ -470,50 +470,50 @@ def test_lambda_keyword(): def second(a, b): return b - SINK(second(NONSOURCE, b=SOURCE)) + SINK(second(NONSOURCE, b=SOURCE)) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for second()" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for second()" def test_lambda_unpack_iterable(): def second(a, b): return b - SINK(second(NONSOURCE, *[SOURCE])) # Flow missing + SINK(second(NONSOURCE, *[SOURCE])) #$ MISSING:flow="ControlFlowNode for SOURCE -> ControlFlowNode for second()" MISSING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for second()" # Flow missing def test_lambda_unpack_mapping(): def second(a, b): return b - SINK(second(NONSOURCE, **{"b": SOURCE})) + SINK(second(NONSOURCE, **{"b": SOURCE})) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for second()" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for second()" def test_lambda_extra_pos(): f_extra_pos = lambda a, *b: b[0] - SINK(f_extra_pos(NONSOURCE, SOURCE)) + SINK(f_extra_pos(NONSOURCE, SOURCE)) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for f_extra_pos()" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for f_extra_pos()" def test_lambda_extra_keyword(): f_extra_keyword = lambda a, **b: b["b"] - SINK(f_extra_keyword(NONSOURCE, b=SOURCE)) + SINK(f_extra_keyword(NONSOURCE, b=SOURCE)) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for f_extra_keyword()" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for f_extra_keyword()" # call the function with our source as the name of the keyword argument def test_lambda_extra_keyword_flow(): # return the name of the first extra keyword argument f_extra_keyword_flow = lambda **a: [*a][0] - SINK(f_extra_keyword_flow(**{SOURCE: None})) # Flow missing + SINK(f_extra_keyword_flow(**{SOURCE: None})) #$ MISSING:flow="ControlFlowNode for SOURCE -> ControlFlowNode for f_extra_keyword()" MISSING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for f_extra_keyword()" @expects(4) def test_swap(): a = SOURCE b = NONSOURCE - SINK(a) + SINK(a) #$ flow="ControlFlowNode for SOURCE, l:509 -> ControlFlowNode for a" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for a" SINK_F(b) a, b = b, a SINK_F(a) - SINK(b) + SINK(b) #$ flow="ControlFlowNode for SOURCE, l:509 -> ControlFlowNode for b" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for b" def test_deep_callgraph(): @@ -538,7 +538,7 @@ def f6(arg): return f5(arg) x = f6(SOURCE) - SINK(x) # Flow missing + SINK(x) #$ MISSING:flow="ControlFlowNode for SOURCE, l:540 -> ControlFlowNode for x" MISING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for x" @expects(2) @@ -547,7 +547,7 @@ def test_dynamic_tuple_creation_1(): tup += (SOURCE,) tup += (NONSOURCE,) - SINK(tup[0]) # Flow missing + SINK(tup[0]) #$ MISSING:flow="ControlFlowNode for SOURCE, l:547 -> ControlFlowNode for Subscript" MISING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" SINK_F(tup[1]) @@ -557,7 +557,7 @@ def test_dynamic_tuple_creation_2(): tup += (SOURCE,) tup += (NONSOURCE,) - SINK(tup[0]) # Flow missing + SINK(tup[0]) #$ MISSING:flow="ControlFlowNode for SOURCE, l:557 -> ControlFlowNode for Subscript" MISING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" SINK_F(tup[1]) @@ -567,7 +567,7 @@ def test_dynamic_tuple_creation_3(): tup2 = (NONSOURCE,) tup = tup1 + tup2 - SINK(tup[0]) # Flow missing + SINK(tup[0]) #$ MISSING:flow="ControlFlowNode for SOURCE, l:566 -> ControlFlowNode for Subscript" MISING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" SINK_F(tup[1]) @@ -578,5 +578,5 @@ def test_dynamic_tuple_creation_4(): for item in [SOURCE, NONSOURCE]: tup += (item,) - SINK(tup[0]) # Flow missing + SINK(tup[0]) #$ MISSING:flow="ControlFlowNode for SOURCE, l:578 -> ControlFlowNode for Subscript" MISING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" SINK_F(tup[1]) From 4fe2576b9ab6d6ca6daec333ba7a10f9a3d6806e Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Thu, 12 Nov 2020 22:43:34 +0100 Subject: [PATCH 02/16] Python: start modernizing routing tests --- .../dataflow/coverage/argumentPassing.py | 34 ++++---- .../coverage/argumentRoutingTest.expected | 32 +++++++ .../dataflow/coverage/argumentRoutingTest.ql | 83 +++++++++++++++++++ 3 files changed, 132 insertions(+), 17 deletions(-) create mode 100644 python/ql/test/experimental/dataflow/coverage/argumentRoutingTest.expected create mode 100644 python/ql/test/experimental/dataflow/coverage/argumentRoutingTest.ql diff --git a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py index c1efdd1d28f7..38f3123fab51 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py +++ b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py @@ -72,8 +72,8 @@ def argument_passing( f, **g, ): - SINK1(a) - SINK2(b) + SINK1(a) #$ arg1="ControlFlowNode for arg1, l:89 -> ControlFlowNode for a" arg1="ControlFlowNode for arg1, l:94 -> ControlFlowNode for a" + SINK2(b) #$ arg2="ControlFlowNode for arg2, l:94 -> ControlFlowNode for b" MISSING:arg2="ControlFlowNode for arg2, l:89 -> ControlFlowNode for b" SINK3(c) SINK4(d) SINK5(e) @@ -95,8 +95,8 @@ def test_argument_passing2(): def with_pos_only(a, /, b): - SINK1(a) - SINK2(b) + SINK1(a) #$ arg1="ControlFlowNode for arg1, l:104 -> ControlFlowNode for a" arg1="ControlFlowNode for arg1, l:105 -> ControlFlowNode for a" arg1="ControlFlowNode for arg1, l:106 -> ControlFlowNode for a" + SINK2(b) #$ arg2="ControlFlowNode for arg2, l:104 -> ControlFlowNode for b" arg2="ControlFlowNode for arg2, l:105 -> ControlFlowNode for b" MISSING: arg2="ControlFlowNode for arg2, l:106 -> ControlFlowNode for b" @expects(6) @@ -107,8 +107,8 @@ def test_pos_only(): def with_multiple_kw_args(a, b, c): - SINK1(a) - SINK2(b) + SINK1(a) #$ arg1="ControlFlowNode for arg1, l:117 -> ControlFlowNode for a" arg1="ControlFlowNode for arg1, l:118 -> ControlFlowNode for a" arg1="ControlFlowNode for arg1, l:119 -> ControlFlowNode for a" arg1="ControlFlowNode for arg1, l:120 -> ControlFlowNode for a" + SINK2(b) #$ arg2="ControlFlowNode for arg2, l:117 -> ControlFlowNode for b" arg2="ControlFlowNode for arg2, l:120 -> ControlFlowNode for b" MISSING: arg2="ControlFlowNode for arg2, l:118 -> ControlFlowNode for b" arg2="ControlFlowNode for arg2, l:119 -> ControlFlowNode for b" SINK3(c) @@ -121,8 +121,8 @@ def test_multiple_kw_args(): def with_default_arguments(a=arg1, b=arg2, c=arg3): - SINK1(a) - SINK2(b) + SINK1(a) #$ arg1="ControlFlowNode for arg1, l:132 -> ControlFlowNode for a" MISSING:arg1="ControlFlowNode for arg1, l:123 -> ControlFlowNode for a" + SINK2(b) #$ arg2="ControlFlowNode for arg2, l:133 -> ControlFlowNode for b" MISSING: arg2="ControlFlowNode for arg2, l:123 -> ControlFlowNode for b" SINK3(c) @@ -136,14 +136,14 @@ def test_default_arguments(): # Nested constructor pattern def grab_foo_bar_baz(foo, **kwargs): - SINK1(foo) + SINK1(foo) #$ arg1="ControlFlowNode for arg1, l:160 -> ControlFlowNode for foo" grab_bar_baz(**kwargs) # It is not possible to pass `bar` into `kwargs`, # since `bar` is a valid keyword argument. def grab_bar_baz(bar, **kwargs): - SINK2(bar) + SINK2(bar) #$ arg2="ControlFlowNode for arg2, l:160 -> ControlFlowNode for bar" try: SINK2_F(kwargs["bar"]) except: @@ -163,14 +163,14 @@ def test_grab(): # All combinations def test_pos_pos(): def with_pos(a): - SINK1(a) + SINK1(a) #$ arg1="ControlFlowNode for arg1, l:168 -> ControlFlowNode for a" with_pos(arg1) def test_pos_pos_only(): def with_pos_only(a, /): - SINK1(a) + SINK1(a) #$ arg1="ControlFlowNode for arg1, l:175 -> ControlFlowNode for a" with_pos_only(arg1) @@ -178,34 +178,34 @@ def with_pos_only(a, /): def test_pos_star(): def with_star(*a): if len(a) > 0: - SINK1(a[0]) + SINK1(a[0]) #$ arg1="ControlFlowNode for arg1, l:183 -> ControlFlowNode for Subscript" with_star(arg1) def test_pos_kw(): def with_kw(a=""): - SINK1(a) + SINK1(a) #$ arg1="ControlFlowNode for arg1, l:190 -> ControlFlowNode for a" with_kw(arg1) def test_kw_pos(): def with_pos(a): - SINK1(a) + SINK1(a) #$ arg1="ControlFlowNode for arg1, l:197 -> ControlFlowNode for a" with_pos(a=arg1) def test_kw_kw(): def with_kw(a=""): - SINK1(a) + SINK1(a) #$ arg1="ControlFlowNode for arg1, l:204 -> ControlFlowNode for a" with_kw(a=arg1) def test_kw_doublestar(): def with_doublestar(**a): - SINK1(a["a"]) + SINK1(a["a"]) #$ arg1="ControlFlowNode for arg1, l:211 -> ControlFlowNode for Subscript" with_doublestar(a=arg1) diff --git a/python/ql/test/experimental/dataflow/coverage/argumentRoutingTest.expected b/python/ql/test/experimental/dataflow/coverage/argumentRoutingTest.expected new file mode 100644 index 000000000000..5dfe09633875 --- /dev/null +++ b/python/ql/test/experimental/dataflow/coverage/argumentRoutingTest.expected @@ -0,0 +1,32 @@ +| classes.py:556:15:556:17 | ControlFlowNode for key | Unexpected result: arg2="ControlFlowNode for arg2, l:565 -> ControlFlowNode for key" | +| classes.py:557:15:557:18 | ControlFlowNode for self | Unexpected result: arg1="SSA variable with_getitem, l:563 -> ControlFlowNode for self" | +| classes.py:572:15:572:17 | ControlFlowNode for key | Unexpected result: arg2="ControlFlowNode for arg2, l:581 -> ControlFlowNode for key" | +| classes.py:573:15:573:18 | ControlFlowNode for self | Unexpected result: arg1="SSA variable with_setitem, l:578 -> ControlFlowNode for self" | +| classes.py:587:15:587:17 | ControlFlowNode for key | Unexpected result: arg2="ControlFlowNode for arg2, l:595 -> ControlFlowNode for key" | +| classes.py:588:15:588:18 | ControlFlowNode for self | Unexpected result: arg1="SSA variable with_delitem, l:593 -> ControlFlowNode for self" | +| classes.py:658:15:658:19 | ControlFlowNode for other | Unexpected result: arg2="ControlFlowNode for arg2, l:667 -> ControlFlowNode for other" | +| classes.py:659:15:659:18 | ControlFlowNode for self | Unexpected result: arg1="SSA variable with_add, l:665 -> ControlFlowNode for self" | +| classes.py:673:15:673:19 | ControlFlowNode for other | Unexpected result: arg2="ControlFlowNode for arg2, l:682 -> ControlFlowNode for other" | +| classes.py:674:15:674:18 | ControlFlowNode for self | Unexpected result: arg1="SSA variable with_sub, l:680 -> ControlFlowNode for self" | +| classes.py:688:15:688:19 | ControlFlowNode for other | Unexpected result: arg2="ControlFlowNode for arg2, l:697 -> ControlFlowNode for other" | +| classes.py:689:15:689:18 | ControlFlowNode for self | Unexpected result: arg1="SSA variable with_mul, l:695 -> ControlFlowNode for self" | +| classes.py:703:15:703:19 | ControlFlowNode for other | Unexpected result: arg2="ControlFlowNode for arg2, l:712 -> ControlFlowNode for other" | +| classes.py:704:15:704:18 | ControlFlowNode for self | Unexpected result: arg1="SSA variable with_matmul, l:710 -> ControlFlowNode for self" | +| classes.py:718:15:718:19 | ControlFlowNode for other | Unexpected result: arg2="ControlFlowNode for arg2, l:727 -> ControlFlowNode for other" | +| classes.py:719:15:719:18 | ControlFlowNode for self | Unexpected result: arg1="SSA variable with_truediv, l:725 -> ControlFlowNode for self" | +| classes.py:733:15:733:19 | ControlFlowNode for other | Unexpected result: arg2="ControlFlowNode for arg2, l:742 -> ControlFlowNode for other" | +| classes.py:734:15:734:18 | ControlFlowNode for self | Unexpected result: arg1="SSA variable with_floordiv, l:740 -> ControlFlowNode for self" | +| classes.py:748:15:748:19 | ControlFlowNode for other | Unexpected result: arg2="ControlFlowNode for arg2, l:757 -> ControlFlowNode for other" | +| classes.py:749:15:749:18 | ControlFlowNode for self | Unexpected result: arg1="SSA variable with_mod, l:755 -> ControlFlowNode for self" | +| classes.py:778:15:778:19 | ControlFlowNode for other | Unexpected result: arg2="ControlFlowNode for arg2, l:793 -> ControlFlowNode for other" | +| classes.py:779:15:779:18 | ControlFlowNode for self | Unexpected result: arg1="SSA variable with_pow, l:791 -> ControlFlowNode for self" | +| classes.py:799:15:799:19 | ControlFlowNode for other | Unexpected result: arg2="ControlFlowNode for arg2, l:808 -> ControlFlowNode for other" | +| classes.py:800:15:800:18 | ControlFlowNode for self | Unexpected result: arg1="SSA variable with_lshift, l:806 -> ControlFlowNode for self" | +| classes.py:814:15:814:19 | ControlFlowNode for other | Unexpected result: arg2="ControlFlowNode for arg2, l:823 -> ControlFlowNode for other" | +| classes.py:815:15:815:18 | ControlFlowNode for self | Unexpected result: arg1="SSA variable with_rshift, l:821 -> ControlFlowNode for self" | +| classes.py:829:15:829:19 | ControlFlowNode for other | Unexpected result: arg2="ControlFlowNode for arg2, l:838 -> ControlFlowNode for other" | +| classes.py:830:15:830:18 | ControlFlowNode for self | Unexpected result: arg1="SSA variable with_and, l:836 -> ControlFlowNode for self" | +| classes.py:844:15:844:19 | ControlFlowNode for other | Unexpected result: arg2="ControlFlowNode for arg2, l:853 -> ControlFlowNode for other" | +| classes.py:845:15:845:18 | ControlFlowNode for self | Unexpected result: arg1="SSA variable with_xor, l:851 -> ControlFlowNode for self" | +| classes.py:859:15:859:19 | ControlFlowNode for other | Unexpected result: arg2="ControlFlowNode for arg2, l:868 -> ControlFlowNode for other" | +| classes.py:860:15:860:18 | ControlFlowNode for self | Unexpected result: arg1="SSA variable with_or, l:866 -> ControlFlowNode for self" | diff --git a/python/ql/test/experimental/dataflow/coverage/argumentRoutingTest.ql b/python/ql/test/experimental/dataflow/coverage/argumentRoutingTest.ql new file mode 100644 index 000000000000..5b8e80cad2a5 --- /dev/null +++ b/python/ql/test/experimental/dataflow/coverage/argumentRoutingTest.ql @@ -0,0 +1,83 @@ +import python +import semmle.python.dataflow.new.DataFlow +private import semmle.python.dataflow.new.internal.DataFlowPrivate as DataFlowPrivate +import experimental.dataflow.FlowTestUtil.FlowTest + +class Argument1RoutingTest extends FlowTest { + Argument1RoutingTest() { this = "Argument1RoutingTest" } + + override string flowTag() { result = "arg1" } + + override predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) { + exists(Argument1RoutingConfig cfg | cfg.hasFlow(source, sink)) + } +} + +/** + * A configuration to check routing of arguments through magic methods. + */ +class Argument1RoutingConfig extends DataFlow::Configuration { + Argument1RoutingConfig() { this = "Argument1RoutingConfig" } + + override predicate isSource(DataFlow::Node node) { + node.(DataFlow::CfgNode).getNode().(NameNode).getId() = "arg1" + or + exists(AssignmentDefinition def, DataFlowPrivate::DataFlowCall call | + def.getVariable() = node.(DataFlow::EssaNode).getVar() and + def.getValue() = call.getNode() and + call.getNode().(CallNode).getFunction().(NameNode).getId().matches("With\\_%") + ) and + node.(DataFlow::EssaNode).getVar().getName().matches("with\\_%") + } + + override predicate isSink(DataFlow::Node node) { + exists(CallNode call | + call.getFunction().(NameNode).getId() = "SINK1" and + node.(DataFlow::CfgNode).getNode() = call.getAnArg() + ) + } + + /** + * We want to be able to use `arg` in a sequence of calls such as `func(kw=arg); ... ; func(arg)`. + * Use-use flow lets the argument to the first call reach the sink inside the second call, + * making it seem like we handle all cases even if we only handle the last one. + * We make the test honest by preventing flow into source nodes. + */ + override predicate isBarrierIn(DataFlow::Node node) { isSource(node) } +} + +class Argument2RoutingTest extends FlowTest { + Argument2RoutingTest() { this = "Argument2RoutingTest" } + + override string flowTag() { result = "arg2" } + + override predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) { + exists(Argument2RoutingConfig cfg | cfg.hasFlow(source, sink)) + } +} + +/** + * A configuration to check routing of arguments through magic methods. + */ +class Argument2RoutingConfig extends DataFlow::Configuration { + Argument2RoutingConfig() { this = "Argument2RoutingConfig" } + + override predicate isSource(DataFlow::Node node) { + node.(DataFlow::CfgNode).getNode().(NameNode).getId() = "arg2" + } + + override predicate isSink(DataFlow::Node node) { + exists(CallNode call | + call.getFunction().(NameNode).getId() = "SINK2" and + node.(DataFlow::CfgNode).getNode() = call.getAnArg() + ) + } + + /** + * We want to be able to use `arg` in a sequence of calls such as `func(kw=arg); ... ; func(arg)`. + * Use-use flow lets the argument to the first call reach the sink inside the second call, + * making it seem like we handle all cases even if we only handle the last one. + * We make the test honest by preventing flow into source nodes. + */ + override predicate isBarrierIn(DataFlow::Node node) { isSource(node) } +} From e468d49b1905470a8e03a01a21ce0b838db546cf Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Thu, 12 Nov 2020 23:07:01 +0100 Subject: [PATCH 03/16] Python: routing tests 3-7 and some annotations --- .../dataflow/coverage/argumentPassing.py | 16 +- .../coverage/argumentRoutingTest.expected | 1 + .../dataflow/coverage/argumentRoutingTest.ql | 180 ++++++++++++++++++ 3 files changed, 189 insertions(+), 8 deletions(-) diff --git a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py index 38f3123fab51..7f1a832bf613 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py +++ b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py @@ -74,12 +74,12 @@ def argument_passing( ): SINK1(a) #$ arg1="ControlFlowNode for arg1, l:89 -> ControlFlowNode for a" arg1="ControlFlowNode for arg1, l:94 -> ControlFlowNode for a" SINK2(b) #$ arg2="ControlFlowNode for arg2, l:94 -> ControlFlowNode for b" MISSING:arg2="ControlFlowNode for arg2, l:89 -> ControlFlowNode for b" - SINK3(c) - SINK4(d) - SINK5(e) - SINK6(f) + SINK3(c) #$ arg3="ControlFlowNode for arg3, l:94 -> ControlFlowNode for c" MISSING: arg3="ControlFlowNode for arg3, l:89 -> ControlFlowNode for c" + SINK4(d) #$ MISSING: arg4="ControlFlowNode for arg4, l:89 -> ControlFlowNode for d" + SINK5(e) #$ MISSING: arg5="ControlFlowNode for arg5, l:89 -> ControlFlowNode for e" + SINK6(f) #$ MISSING: arg6="ControlFlowNode for arg6, l:89 -> ControlFlowNode for f" try: - SINK7(g["g"]) + SINK7(g["g"]) #$ arg7="ControlFlowNode for arg7, l:89 -> ControlFlowNode for Subscript" except: print("OK") @@ -109,7 +109,7 @@ def test_pos_only(): def with_multiple_kw_args(a, b, c): SINK1(a) #$ arg1="ControlFlowNode for arg1, l:117 -> ControlFlowNode for a" arg1="ControlFlowNode for arg1, l:118 -> ControlFlowNode for a" arg1="ControlFlowNode for arg1, l:119 -> ControlFlowNode for a" arg1="ControlFlowNode for arg1, l:120 -> ControlFlowNode for a" SINK2(b) #$ arg2="ControlFlowNode for arg2, l:117 -> ControlFlowNode for b" arg2="ControlFlowNode for arg2, l:120 -> ControlFlowNode for b" MISSING: arg2="ControlFlowNode for arg2, l:118 -> ControlFlowNode for b" arg2="ControlFlowNode for arg2, l:119 -> ControlFlowNode for b" - SINK3(c) + SINK3(c) #$ arg3="ControlFlowNode for arg3, l:117 -> ControlFlowNode for c" arg3="ControlFlowNode for arg3, l:119 -> ControlFlowNode for c" arg3="ControlFlowNode for arg3, l:120 -> ControlFlowNode for c" MISSING: arg3="ControlFlowNode for arg3, l:118 -> ControlFlowNode for c" @expects(9) @@ -123,7 +123,7 @@ def test_multiple_kw_args(): def with_default_arguments(a=arg1, b=arg2, c=arg3): SINK1(a) #$ arg1="ControlFlowNode for arg1, l:132 -> ControlFlowNode for a" MISSING:arg1="ControlFlowNode for arg1, l:123 -> ControlFlowNode for a" SINK2(b) #$ arg2="ControlFlowNode for arg2, l:133 -> ControlFlowNode for b" MISSING: arg2="ControlFlowNode for arg2, l:123 -> ControlFlowNode for b" - SINK3(c) + SINK3(c) #$ arg3="ControlFlowNode for arg3, l:134 -> ControlFlowNode for c" MISSING: arg3="ControlFlowNode for arg3, l:123 -> ControlFlowNode for c" @expects(12) @@ -152,7 +152,7 @@ def grab_bar_baz(bar, **kwargs): def grab_baz(baz): - SINK3(baz) + SINK3(baz) #$ arg3="ControlFlowNode for arg3, l:160 -> ControlFlowNode for baz" @expects(4) diff --git a/python/ql/test/experimental/dataflow/coverage/argumentRoutingTest.expected b/python/ql/test/experimental/dataflow/coverage/argumentRoutingTest.expected index 5dfe09633875..5624d283462b 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentRoutingTest.expected +++ b/python/ql/test/experimental/dataflow/coverage/argumentRoutingTest.expected @@ -1,5 +1,6 @@ | classes.py:556:15:556:17 | ControlFlowNode for key | Unexpected result: arg2="ControlFlowNode for arg2, l:565 -> ControlFlowNode for key" | | classes.py:557:15:557:18 | ControlFlowNode for self | Unexpected result: arg1="SSA variable with_getitem, l:563 -> ControlFlowNode for self" | +| classes.py:571:15:571:19 | ControlFlowNode for value | Unexpected result: arg3="ControlFlowNode for arg3, l:581 -> ControlFlowNode for value" | | classes.py:572:15:572:17 | ControlFlowNode for key | Unexpected result: arg2="ControlFlowNode for arg2, l:581 -> ControlFlowNode for key" | | classes.py:573:15:573:18 | ControlFlowNode for self | Unexpected result: arg1="SSA variable with_setitem, l:578 -> ControlFlowNode for self" | | classes.py:587:15:587:17 | ControlFlowNode for key | Unexpected result: arg2="ControlFlowNode for arg2, l:595 -> ControlFlowNode for key" | diff --git a/python/ql/test/experimental/dataflow/coverage/argumentRoutingTest.ql b/python/ql/test/experimental/dataflow/coverage/argumentRoutingTest.ql index 5b8e80cad2a5..00cc3a49656a 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentRoutingTest.ql +++ b/python/ql/test/experimental/dataflow/coverage/argumentRoutingTest.ql @@ -81,3 +81,183 @@ class Argument2RoutingConfig extends DataFlow::Configuration { */ override predicate isBarrierIn(DataFlow::Node node) { isSource(node) } } + +class Argument3RoutingTest extends FlowTest { + Argument3RoutingTest() { this = "Argument3RoutingTest" } + + override string flowTag() { result = "arg3" } + + override predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) { + exists(Argument3RoutingConfig cfg | cfg.hasFlow(source, sink)) + } +} + +/** + * A configuration to check routing of arguments through magic methods. + */ +class Argument3RoutingConfig extends DataFlow::Configuration { + Argument3RoutingConfig() { this = "Argument3RoutingConfig" } + + override predicate isSource(DataFlow::Node node) { + node.(DataFlow::CfgNode).getNode().(NameNode).getId() = "arg3" + } + + override predicate isSink(DataFlow::Node node) { + exists(CallNode call | + call.getFunction().(NameNode).getId() = "SINK3" and + node.(DataFlow::CfgNode).getNode() = call.getAnArg() + ) + } + + /** + * We want to be able to use `arg` in a sequence of calls such as `func(kw=arg); ... ; func(arg)`. + * Use-use flow lets the argument to the first call reach the sink inside the second call, + * making it seem like we handle all cases even if we only handle the last one. + * We make the test honest by preventing flow into source nodes. + */ + override predicate isBarrierIn(DataFlow::Node node) { isSource(node) } +} + +class Argument4RoutingTest extends FlowTest { + Argument4RoutingTest() { this = "Argument4RoutingTest" } + + override string flowTag() { result = "arg4" } + + override predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) { + exists(Argument4RoutingConfig cfg | cfg.hasFlow(source, sink)) + } +} + +/** + * A configuration to check routing of arguments through magic methods. + */ +class Argument4RoutingConfig extends DataFlow::Configuration { + Argument4RoutingConfig() { this = "Argument4RoutingConfig" } + + override predicate isSource(DataFlow::Node node) { + node.(DataFlow::CfgNode).getNode().(NameNode).getId() = "arg4" + } + + override predicate isSink(DataFlow::Node node) { + exists(CallNode call | + call.getFunction().(NameNode).getId() = "SINK4" and + node.(DataFlow::CfgNode).getNode() = call.getAnArg() + ) + } + + /** + * We want to be able to use `arg` in a sequence of calls such as `func(kw=arg); ... ; func(arg)`. + * Use-use flow lets the argument to the first call reach the sink inside the second call, + * making it seem like we handle all cases even if we only handle the last one. + * We make the test honest by preventing flow into source nodes. + */ + override predicate isBarrierIn(DataFlow::Node node) { isSource(node) } +} + +class Argument5RoutingTest extends FlowTest { + Argument5RoutingTest() { this = "Argument5RoutingTest" } + + override string flowTag() { result = "arg5" } + + override predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) { + exists(Argument5RoutingConfig cfg | cfg.hasFlow(source, sink)) + } +} + +/** + * A configuration to check routing of arguments through magic methods. + */ +class Argument5RoutingConfig extends DataFlow::Configuration { + Argument5RoutingConfig() { this = "Argument5RoutingConfig" } + + override predicate isSource(DataFlow::Node node) { + node.(DataFlow::CfgNode).getNode().(NameNode).getId() = "arg5" + } + + override predicate isSink(DataFlow::Node node) { + exists(CallNode call | + call.getFunction().(NameNode).getId() = "SINK5" and + node.(DataFlow::CfgNode).getNode() = call.getAnArg() + ) + } + + /** + * We want to be able to use `arg` in a sequence of calls such as `func(kw=arg); ... ; func(arg)`. + * Use-use flow lets the argument to the first call reach the sink inside the second call, + * making it seem like we handle all cases even if we only handle the last one. + * We make the test honest by preventing flow into source nodes. + */ + override predicate isBarrierIn(DataFlow::Node node) { isSource(node) } +} + +class Argument6RoutingTest extends FlowTest { + Argument6RoutingTest() { this = "Argument6RoutingTest" } + + override string flowTag() { result = "arg6" } + + override predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) { + exists(Argument6RoutingConfig cfg | cfg.hasFlow(source, sink)) + } +} + +/** + * A configuration to check routing of arguments through magic methods. + */ +class Argument6RoutingConfig extends DataFlow::Configuration { + Argument6RoutingConfig() { this = "Argument6RoutingConfig" } + + override predicate isSource(DataFlow::Node node) { + node.(DataFlow::CfgNode).getNode().(NameNode).getId() = "arg6" + } + + override predicate isSink(DataFlow::Node node) { + exists(CallNode call | + call.getFunction().(NameNode).getId() = "SINK6" and + node.(DataFlow::CfgNode).getNode() = call.getAnArg() + ) + } + + /** + * We want to be able to use `arg` in a sequence of calls such as `func(kw=arg); ... ; func(arg)`. + * Use-use flow lets the argument to the first call reach the sink inside the second call, + * making it seem like we handle all cases even if we only handle the last one. + * We make the test honest by preventing flow into source nodes. + */ + override predicate isBarrierIn(DataFlow::Node node) { isSource(node) } +} + +class Argument7RoutingTest extends FlowTest { + Argument7RoutingTest() { this = "Argument7RoutingTest" } + + override string flowTag() { result = "arg7" } + + override predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) { + exists(Argument7RoutingConfig cfg | cfg.hasFlow(source, sink)) + } +} + +/** + * A configuration to check routing of arguments through magic methods. + */ +class Argument7RoutingConfig extends DataFlow::Configuration { + Argument7RoutingConfig() { this = "Argument7RoutingConfig" } + + override predicate isSource(DataFlow::Node node) { + node.(DataFlow::CfgNode).getNode().(NameNode).getId() = "arg7" + } + + override predicate isSink(DataFlow::Node node) { + exists(CallNode call | + call.getFunction().(NameNode).getId() = "SINK7" and + node.(DataFlow::CfgNode).getNode() = call.getAnArg() + ) + } + + /** + * We want to be able to use `arg` in a sequence of calls such as `func(kw=arg); ... ; func(arg)`. + * Use-use flow lets the argument to the first call reach the sink inside the second call, + * making it seem like we handle all cases even if we only handle the last one. + * We make the test honest by preventing flow into source nodes. + */ + override predicate isBarrierIn(DataFlow::Node node) { isSource(node) } +} From dc91406ff0c6073c9b153ac2ff901c0c5a8cf0fe Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Fri, 13 Nov 2020 09:22:57 +0100 Subject: [PATCH 04/16] Python: make `.expected` empty still need to annotate missing results --- .../coverage/argumentRoutingTest.expected | 33 ---------- .../experimental/dataflow/coverage/classes.py | 66 +++++++++---------- 2 files changed, 33 insertions(+), 66 deletions(-) diff --git a/python/ql/test/experimental/dataflow/coverage/argumentRoutingTest.expected b/python/ql/test/experimental/dataflow/coverage/argumentRoutingTest.expected index 5624d283462b..e69de29bb2d1 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentRoutingTest.expected +++ b/python/ql/test/experimental/dataflow/coverage/argumentRoutingTest.expected @@ -1,33 +0,0 @@ -| classes.py:556:15:556:17 | ControlFlowNode for key | Unexpected result: arg2="ControlFlowNode for arg2, l:565 -> ControlFlowNode for key" | -| classes.py:557:15:557:18 | ControlFlowNode for self | Unexpected result: arg1="SSA variable with_getitem, l:563 -> ControlFlowNode for self" | -| classes.py:571:15:571:19 | ControlFlowNode for value | Unexpected result: arg3="ControlFlowNode for arg3, l:581 -> ControlFlowNode for value" | -| classes.py:572:15:572:17 | ControlFlowNode for key | Unexpected result: arg2="ControlFlowNode for arg2, l:581 -> ControlFlowNode for key" | -| classes.py:573:15:573:18 | ControlFlowNode for self | Unexpected result: arg1="SSA variable with_setitem, l:578 -> ControlFlowNode for self" | -| classes.py:587:15:587:17 | ControlFlowNode for key | Unexpected result: arg2="ControlFlowNode for arg2, l:595 -> ControlFlowNode for key" | -| classes.py:588:15:588:18 | ControlFlowNode for self | Unexpected result: arg1="SSA variable with_delitem, l:593 -> ControlFlowNode for self" | -| classes.py:658:15:658:19 | ControlFlowNode for other | Unexpected result: arg2="ControlFlowNode for arg2, l:667 -> ControlFlowNode for other" | -| classes.py:659:15:659:18 | ControlFlowNode for self | Unexpected result: arg1="SSA variable with_add, l:665 -> ControlFlowNode for self" | -| classes.py:673:15:673:19 | ControlFlowNode for other | Unexpected result: arg2="ControlFlowNode for arg2, l:682 -> ControlFlowNode for other" | -| classes.py:674:15:674:18 | ControlFlowNode for self | Unexpected result: arg1="SSA variable with_sub, l:680 -> ControlFlowNode for self" | -| classes.py:688:15:688:19 | ControlFlowNode for other | Unexpected result: arg2="ControlFlowNode for arg2, l:697 -> ControlFlowNode for other" | -| classes.py:689:15:689:18 | ControlFlowNode for self | Unexpected result: arg1="SSA variable with_mul, l:695 -> ControlFlowNode for self" | -| classes.py:703:15:703:19 | ControlFlowNode for other | Unexpected result: arg2="ControlFlowNode for arg2, l:712 -> ControlFlowNode for other" | -| classes.py:704:15:704:18 | ControlFlowNode for self | Unexpected result: arg1="SSA variable with_matmul, l:710 -> ControlFlowNode for self" | -| classes.py:718:15:718:19 | ControlFlowNode for other | Unexpected result: arg2="ControlFlowNode for arg2, l:727 -> ControlFlowNode for other" | -| classes.py:719:15:719:18 | ControlFlowNode for self | Unexpected result: arg1="SSA variable with_truediv, l:725 -> ControlFlowNode for self" | -| classes.py:733:15:733:19 | ControlFlowNode for other | Unexpected result: arg2="ControlFlowNode for arg2, l:742 -> ControlFlowNode for other" | -| classes.py:734:15:734:18 | ControlFlowNode for self | Unexpected result: arg1="SSA variable with_floordiv, l:740 -> ControlFlowNode for self" | -| classes.py:748:15:748:19 | ControlFlowNode for other | Unexpected result: arg2="ControlFlowNode for arg2, l:757 -> ControlFlowNode for other" | -| classes.py:749:15:749:18 | ControlFlowNode for self | Unexpected result: arg1="SSA variable with_mod, l:755 -> ControlFlowNode for self" | -| classes.py:778:15:778:19 | ControlFlowNode for other | Unexpected result: arg2="ControlFlowNode for arg2, l:793 -> ControlFlowNode for other" | -| classes.py:779:15:779:18 | ControlFlowNode for self | Unexpected result: arg1="SSA variable with_pow, l:791 -> ControlFlowNode for self" | -| classes.py:799:15:799:19 | ControlFlowNode for other | Unexpected result: arg2="ControlFlowNode for arg2, l:808 -> ControlFlowNode for other" | -| classes.py:800:15:800:18 | ControlFlowNode for self | Unexpected result: arg1="SSA variable with_lshift, l:806 -> ControlFlowNode for self" | -| classes.py:814:15:814:19 | ControlFlowNode for other | Unexpected result: arg2="ControlFlowNode for arg2, l:823 -> ControlFlowNode for other" | -| classes.py:815:15:815:18 | ControlFlowNode for self | Unexpected result: arg1="SSA variable with_rshift, l:821 -> ControlFlowNode for self" | -| classes.py:829:15:829:19 | ControlFlowNode for other | Unexpected result: arg2="ControlFlowNode for arg2, l:838 -> ControlFlowNode for other" | -| classes.py:830:15:830:18 | ControlFlowNode for self | Unexpected result: arg1="SSA variable with_and, l:836 -> ControlFlowNode for self" | -| classes.py:844:15:844:19 | ControlFlowNode for other | Unexpected result: arg2="ControlFlowNode for arg2, l:853 -> ControlFlowNode for other" | -| classes.py:845:15:845:18 | ControlFlowNode for self | Unexpected result: arg1="SSA variable with_xor, l:851 -> ControlFlowNode for self" | -| classes.py:859:15:859:19 | ControlFlowNode for other | Unexpected result: arg2="ControlFlowNode for arg2, l:868 -> ControlFlowNode for other" | -| classes.py:860:15:860:18 | ControlFlowNode for self | Unexpected result: arg1="SSA variable with_or, l:866 -> ControlFlowNode for self" | diff --git a/python/ql/test/experimental/dataflow/coverage/classes.py b/python/ql/test/experimental/dataflow/coverage/classes.py index 1977998ab643..613019ce4b8e 100644 --- a/python/ql/test/experimental/dataflow/coverage/classes.py +++ b/python/ql/test/experimental/dataflow/coverage/classes.py @@ -553,8 +553,8 @@ def test_length_hint(): # object.__getitem__(self, key) class With_getitem: def __getitem__(self, key): - SINK2(key) - SINK1(self) + SINK2(key) #$ arg2="ControlFlowNode for arg2, l:565 -> ControlFlowNode for key" + SINK1(self) #$ arg1="SSA variable with_getitem, l:563 -> ControlFlowNode for self" OK() return "" @@ -568,9 +568,9 @@ def test_getitem(): # object.__setitem__(self, key, value) class With_setitem: def __setitem__(self, key, value): - SINK3(value) - SINK2(key) - SINK1(self) + SINK3(value) #$ arg3="ControlFlowNode for arg3, l:581 -> ControlFlowNode for value" + SINK2(key) #$ arg2="ControlFlowNode for arg2, l:581 -> ControlFlowNode for key" + SINK1(self) #$ arg1="SSA variable with_setitem, l:578 -> ControlFlowNode for self" OK() @@ -584,8 +584,8 @@ def test_setitem(): # object.__delitem__(self, key) class With_delitem: def __delitem__(self, key): - SINK2(key) - SINK1(self) + SINK2(key) #$ arg2="ControlFlowNode for arg2, l:595 -> ControlFlowNode for key" + SINK1(self) #$ arg1="SSA variable with_delitem, l:593 -> ControlFlowNode for self" OK() @@ -655,8 +655,8 @@ def test_contains(): # object.__add__(self, other) class With_add: def __add__(self, other): - SINK2(other) - SINK1(self) + SINK2(other) #$ arg2="ControlFlowNode for arg2, l:667 -> ControlFlowNode for other" + SINK1(self) #$ arg1="SSA variable with_add, l:665 -> ControlFlowNode for self" OK() return self @@ -670,8 +670,8 @@ def test_add(): # object.__sub__(self, other) class With_sub: def __sub__(self, other): - SINK2(other) - SINK1(self) + SINK2(other) #$ arg2="ControlFlowNode for arg2, l:682 -> ControlFlowNode for other" + SINK1(self) #$ arg1="SSA variable with_sub, l:680 -> ControlFlowNode for self" OK() return self @@ -685,8 +685,8 @@ def test_sub(): # object.__mul__(self, other) class With_mul: def __mul__(self, other): - SINK2(other) - SINK1(self) + SINK2(other) #$ arg2="ControlFlowNode for arg2, l:697 -> ControlFlowNode for other" + SINK1(self) #$ arg1="SSA variable with_mul, l:695 -> ControlFlowNode for self" OK() return self @@ -700,8 +700,8 @@ def test_mul(): # object.__matmul__(self, other) class With_matmul: def __matmul__(self, other): - SINK2(other) - SINK1(self) + SINK2(other) #$ arg2="ControlFlowNode for arg2, l:712 -> ControlFlowNode for other" + SINK1(self) #$ arg1="SSA variable with_matmul, l:710 -> ControlFlowNode for self" OK() return self @@ -715,8 +715,8 @@ def test_matmul(): # object.__truediv__(self, other) class With_truediv: def __truediv__(self, other): - SINK2(other) - SINK1(self) + SINK2(other) #$ arg2="ControlFlowNode for arg2, l:727 -> ControlFlowNode for other" + SINK1(self) #$ arg1="SSA variable with_truediv, l:725 -> ControlFlowNode for self" OK() return self @@ -730,8 +730,8 @@ def test_truediv(): # object.__floordiv__(self, other) class With_floordiv: def __floordiv__(self, other): - SINK2(other) - SINK1(self) + SINK2(other) #$ arg2="ControlFlowNode for arg2, l:742 -> ControlFlowNode for other" + SINK1(self) #$ arg1="SSA variable with_floordiv, l:740 -> ControlFlowNode for self" OK() return self @@ -745,8 +745,8 @@ def test_floordiv(): # object.__mod__(self, other) class With_mod: def __mod__(self, other): - SINK2(other) - SINK1(self) + SINK2(other) #$ arg2="ControlFlowNode for arg2, l:757 -> ControlFlowNode for other" + SINK1(self) #$ arg1="SSA variable with_mod, l:755 -> ControlFlowNode for self" OK() return self @@ -775,8 +775,8 @@ def test_divmod(): # object.__pow__(self, other[, modulo]) class With_pow: def __pow__(self, other): - SINK2(other) - SINK1(self) + SINK2(other) #$ arg2="ControlFlowNode for arg2, l:793 -> ControlFlowNode for other" + SINK1(self) #$ arg1="SSA variable with_pow, l:791 -> ControlFlowNode for self" OK() return self @@ -796,8 +796,8 @@ def test_pow_op(): # object.__lshift__(self, other) class With_lshift: def __lshift__(self, other): - SINK2(other) - SINK1(self) + SINK2(other) #$ arg2="ControlFlowNode for arg2, l:808 -> ControlFlowNode for other" + SINK1(self) #$ arg1="SSA variable with_lshift, l:806 -> ControlFlowNode for self" OK() return self @@ -811,8 +811,8 @@ def test_lshift(): # object.__rshift__(self, other) class With_rshift: def __rshift__(self, other): - SINK2(other) - SINK1(self) + SINK2(other) #$ arg2="ControlFlowNode for arg2, l:823 -> ControlFlowNode for other" + SINK1(self) #$ arg1="SSA variable with_rshift, l:821 -> ControlFlowNode for self" OK() return self @@ -826,8 +826,8 @@ def test_rshift(): # object.__and__(self, other) class With_and: def __and__(self, other): - SINK2(other) - SINK1(self) + SINK2(other) #$ arg2="ControlFlowNode for arg2, l:838 -> ControlFlowNode for other" + SINK1(self) #$ arg1="SSA variable with_and, l:836 -> ControlFlowNode for self" OK() return self @@ -841,8 +841,8 @@ def test_and(): # object.__xor__(self, other) class With_xor: def __xor__(self, other): - SINK2(other) - SINK1(self) + SINK2(other) #$ arg2="ControlFlowNode for arg2, l:853 -> ControlFlowNode for other" + SINK1(self) #$ arg1="SSA variable with_xor, l:851 -> ControlFlowNode for self" OK() return self @@ -856,8 +856,8 @@ def test_xor(): # object.__or__(self, other) class With_or: def __or__(self, other): - SINK2(other) - SINK1(self) + SINK2(other) #$ arg2="ControlFlowNode for arg2, l:868 -> ControlFlowNode for other" + SINK1(self) #$ arg1="SSA variable with_or, l:866 -> ControlFlowNode for self" OK() return self From a19304a4a068ac9ac5b6bcea16295ff3df34e61c Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 24 Nov 2020 02:17:38 +0100 Subject: [PATCH 05/16] Python: Factor out prettyPrinter and update tests --- .../{FlowTestUtil => TestUtil}/FlowTest.qll | 4 +- .../LocalFlowStepTest.qll | 0 .../MaximalFlowTest.qll | 8 + .../dataflow/TestUtil/PrintNode.qll | 31 ++++ .../dataflow/basic/localFlowStepTest.ql | 2 +- .../dataflow/basic/maximalFlowTest.ql | 2 +- .../test/experimental/dataflow/basic/test.py | 12 +- .../dataflow/coverage/argumentPassing.py | 50 +++---- .../dataflow/coverage/argumentRoutingTest.ql | 2 +- .../experimental/dataflow/coverage/classes.py | 66 ++++----- .../dataflow/coverage/dataflowTest.ql | 2 +- .../dataflow/coverage/datamodel.py | 16 +- .../coverage/maximalFlowTest.expected | 0 .../dataflow/coverage/maximalFlowTest.ql | 1 - .../experimental/dataflow/coverage/test.py | 140 +++++++++--------- .../dataflow/tainttracking/TestTaintLib.qll | 28 +--- 16 files changed, 190 insertions(+), 174 deletions(-) rename python/ql/test/experimental/dataflow/{FlowTestUtil => TestUtil}/FlowTest.qll (82%) rename python/ql/test/experimental/dataflow/{FlowTestUtil => TestUtil}/LocalFlowStepTest.qll (100%) rename python/ql/test/experimental/dataflow/{FlowTestUtil => TestUtil}/MaximalFlowTest.qll (70%) create mode 100644 python/ql/test/experimental/dataflow/TestUtil/PrintNode.qll delete mode 100644 python/ql/test/experimental/dataflow/coverage/maximalFlowTest.expected delete mode 100644 python/ql/test/experimental/dataflow/coverage/maximalFlowTest.ql diff --git a/python/ql/test/experimental/dataflow/FlowTestUtil/FlowTest.qll b/python/ql/test/experimental/dataflow/TestUtil/FlowTest.qll similarity index 82% rename from python/ql/test/experimental/dataflow/FlowTestUtil/FlowTest.qll rename to python/ql/test/experimental/dataflow/TestUtil/FlowTest.qll index 9f0762f64881..edb24373386c 100644 --- a/python/ql/test/experimental/dataflow/FlowTestUtil/FlowTest.qll +++ b/python/ql/test/experimental/dataflow/TestUtil/FlowTest.qll @@ -1,6 +1,7 @@ import python import semmle.python.dataflow.new.DataFlow import TestUtilities.InlineExpectationsTest +import experimental.dataflow.TestUtil.PrintNode abstract class FlowTest extends InlineExpectationsTest { bindingset[this] @@ -17,7 +18,8 @@ abstract class FlowTest extends InlineExpectationsTest { location = toNode.getLocation() and tag = this.flowTag() and value = - "\"" + fromNode.toString() + lineStr(fromNode, toNode) + " -> " + toNode.toString() + "\"" and + "\"" + prettyNode(fromNode).replaceAll("\"", "'") + lineStr(fromNode, toNode) + " -> " + + prettyNode(toNode).replaceAll("\"", "'") + "\"" and element = toNode.toString() ) } diff --git a/python/ql/test/experimental/dataflow/FlowTestUtil/LocalFlowStepTest.qll b/python/ql/test/experimental/dataflow/TestUtil/LocalFlowStepTest.qll similarity index 100% rename from python/ql/test/experimental/dataflow/FlowTestUtil/LocalFlowStepTest.qll rename to python/ql/test/experimental/dataflow/TestUtil/LocalFlowStepTest.qll diff --git a/python/ql/test/experimental/dataflow/FlowTestUtil/MaximalFlowTest.qll b/python/ql/test/experimental/dataflow/TestUtil/MaximalFlowTest.qll similarity index 70% rename from python/ql/test/experimental/dataflow/FlowTestUtil/MaximalFlowTest.qll rename to python/ql/test/experimental/dataflow/TestUtil/MaximalFlowTest.qll index 792aa2b848d4..eb84d197c69a 100644 --- a/python/ql/test/experimental/dataflow/FlowTestUtil/MaximalFlowTest.qll +++ b/python/ql/test/experimental/dataflow/TestUtil/MaximalFlowTest.qll @@ -1,5 +1,6 @@ import python import semmle.python.dataflow.new.DataFlow +private import semmle.python.dataflow.new.internal.DataFlowPrivate import FlowTest class MaximalFlowTest extends FlowTest { @@ -21,14 +22,21 @@ class MaximalFlowsConfig extends DataFlow::Configuration { MaximalFlowsConfig() { this = "MaximalFlowsConfig" } override predicate isSource(DataFlow::Node node) { + exists(node.getLocation().getFile().getRelativePath()) and not node.asCfgNode() instanceof CallNode and not node.asCfgNode().getNode() instanceof Return and not node instanceof DataFlow::ParameterNode and + not node instanceof DataFlow::PostUpdateNode and + // not node.asExpr() instanceof FunctionExpr and + // not node.asExpr() instanceof ClassExpr and not exists(DataFlow::Node pred | DataFlow::localFlowStep(pred, node)) } override predicate isSink(DataFlow::Node node) { + exists(node.getLocation().getFile().getRelativePath()) and not any(CallNode c).getArg(_) = node.asCfgNode() and + not node instanceof ArgumentNode and + not node.asCfgNode().(NameNode).getId().matches("SINK%") and not exists(DataFlow::Node succ | DataFlow::localFlowStep(node, succ)) } } diff --git a/python/ql/test/experimental/dataflow/TestUtil/PrintNode.qll b/python/ql/test/experimental/dataflow/TestUtil/PrintNode.qll new file mode 100644 index 000000000000..84f97d3f6ff6 --- /dev/null +++ b/python/ql/test/experimental/dataflow/TestUtil/PrintNode.qll @@ -0,0 +1,31 @@ +import python +import semmle.python.dataflow.new.DataFlow + +string prettyExp(Expr e) { + not e instanceof Num and + not e instanceof StrConst and + not e instanceof Subscript and + not e instanceof Call and + not e instanceof Attribute and + result = e.toString() + or + result = e.(Num).getN() + or + result = + e.(StrConst).getPrefix() + e.(StrConst).getText() + + e.(StrConst).getPrefix().regexpReplaceAll("[a-zA-Z]+", "") + or + result = prettyExp(e.(Subscript).getObject()) + "[" + prettyExp(e.(Subscript).getIndex()) + "]" + or + ( + if exists(e.(Call).getAnArg()) or exists(e.(Call).getANamedArg()) + then result = prettyExp(e.(Call).getFunc()) + "(..)" + else result = prettyExp(e.(Call).getFunc()) + "()" + ) + or + result = prettyExp(e.(Attribute).getObject()) + "." + e.(Attribute).getName() +} + +string prettyNode(DataFlow::Node node) { + if exists(node.asExpr()) then result = prettyExp(node.asExpr()) else result = node.toString() +} diff --git a/python/ql/test/experimental/dataflow/basic/localFlowStepTest.ql b/python/ql/test/experimental/dataflow/basic/localFlowStepTest.ql index 6e57f26cd0f1..6dca01901569 100644 --- a/python/ql/test/experimental/dataflow/basic/localFlowStepTest.ql +++ b/python/ql/test/experimental/dataflow/basic/localFlowStepTest.ql @@ -1 +1 @@ -import experimental.dataflow.FlowTestUtil.LocalFlowStepTest +import experimental.dataflow.TestUtil.LocalFlowStepTest diff --git a/python/ql/test/experimental/dataflow/basic/maximalFlowTest.ql b/python/ql/test/experimental/dataflow/basic/maximalFlowTest.ql index ec171dcd9fd9..618dae382f1b 100644 --- a/python/ql/test/experimental/dataflow/basic/maximalFlowTest.ql +++ b/python/ql/test/experimental/dataflow/basic/maximalFlowTest.ql @@ -1 +1 @@ -import experimental.dataflow.FlowTestUtil.MaximalFlowTest +import experimental.dataflow.TestUtil.MaximalFlowTest diff --git a/python/ql/test/experimental/dataflow/basic/test.py b/python/ql/test/experimental/dataflow/basic/test.py index e97068a041c5..d0a54a570eb5 100644 --- a/python/ql/test/experimental/dataflow/basic/test.py +++ b/python/ql/test/experimental/dataflow/basic/test.py @@ -1,7 +1,7 @@ -def obfuscated_id(x): #$ step="ControlFlowNode for FunctionExpr -> GSSA Variable obfuscated_id" - y = x #$ step="ControlFlowNode for x -> SSA variable y" step="SSA variable x, l:1 -> ControlFlowNode for x" - z = y #$ step="ControlFlowNode for y -> SSA variable z" step="SSA variable y, l:2 -> ControlFlowNode for y" - return z #$ flow="ControlFlowNode for IntegerLiteral, l:6 -> ControlFlowNode for z" step="SSA variable z, l:3 -> ControlFlowNode for z" +def obfuscated_id(x): #$ step="FunctionExpr -> GSSA Variable obfuscated_id" + y = x #$ step="x -> SSA variable y" step="SSA variable x, l:1 -> x" + z = y #$ step="y -> SSA variable z" step="SSA variable y, l:2 -> y" + return z #$ flow="42, l:6 -> z" step="SSA variable z, l:3 -> z" -a = 42 #$ step="ControlFlowNode for IntegerLiteral -> GSSA Variable a" -b = obfuscated_id(a) #$ flow="ControlFlowNode for IntegerLiteral, l:6 -> GSSA Variable b" flow="ControlFlowNode for FunctionExpr, l:1 -> ControlFlowNode for obfuscated_id" step="ControlFlowNode for obfuscated_id() -> GSSA Variable b" step="GSSA Variable obfuscated_id, l:1 -> ControlFlowNode for obfuscated_id" step="GSSA Variable a, l:6 -> ControlFlowNode for a" +a = 42 #$ step="42 -> GSSA Variable a" +b = obfuscated_id(a) #$ flow="42, l:6 -> GSSA Variable b" flow="FunctionExpr, l:1 -> obfuscated_id" step="obfuscated_id(..) -> GSSA Variable b" step="GSSA Variable obfuscated_id, l:1 -> obfuscated_id" step="GSSA Variable a, l:6 -> a" diff --git a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py index 7f1a832bf613..6de4d56ad137 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py +++ b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py @@ -72,14 +72,14 @@ def argument_passing( f, **g, ): - SINK1(a) #$ arg1="ControlFlowNode for arg1, l:89 -> ControlFlowNode for a" arg1="ControlFlowNode for arg1, l:94 -> ControlFlowNode for a" - SINK2(b) #$ arg2="ControlFlowNode for arg2, l:94 -> ControlFlowNode for b" MISSING:arg2="ControlFlowNode for arg2, l:89 -> ControlFlowNode for b" - SINK3(c) #$ arg3="ControlFlowNode for arg3, l:94 -> ControlFlowNode for c" MISSING: arg3="ControlFlowNode for arg3, l:89 -> ControlFlowNode for c" - SINK4(d) #$ MISSING: arg4="ControlFlowNode for arg4, l:89 -> ControlFlowNode for d" - SINK5(e) #$ MISSING: arg5="ControlFlowNode for arg5, l:89 -> ControlFlowNode for e" - SINK6(f) #$ MISSING: arg6="ControlFlowNode for arg6, l:89 -> ControlFlowNode for f" + SINK1(a) #$ arg1="arg1, l:89 -> a" arg1="arg1, l:94 -> a" + SINK2(b) #$ arg2="arg2, l:94 -> b" MISSING:arg2="arg2, l:89 -> b" + SINK3(c) #$ arg3="arg3, l:94 -> c" MISSING: arg3="arg3, l:89 -> c" + SINK4(d) #$ MISSING: arg4="arg4, l:89 -> d" + SINK5(e) #$ MISSING: arg5="arg5, l:89 -> e" + SINK6(f) #$ MISSING: arg6="arg6, l:89 -> f" try: - SINK7(g["g"]) #$ arg7="ControlFlowNode for arg7, l:89 -> ControlFlowNode for Subscript" + SINK7(g["g"]) #$ arg7="arg7, l:89 -> g['g']" except: print("OK") @@ -95,8 +95,8 @@ def test_argument_passing2(): def with_pos_only(a, /, b): - SINK1(a) #$ arg1="ControlFlowNode for arg1, l:104 -> ControlFlowNode for a" arg1="ControlFlowNode for arg1, l:105 -> ControlFlowNode for a" arg1="ControlFlowNode for arg1, l:106 -> ControlFlowNode for a" - SINK2(b) #$ arg2="ControlFlowNode for arg2, l:104 -> ControlFlowNode for b" arg2="ControlFlowNode for arg2, l:105 -> ControlFlowNode for b" MISSING: arg2="ControlFlowNode for arg2, l:106 -> ControlFlowNode for b" + SINK1(a) #$ arg1="arg1, l:104 -> a" arg1="arg1, l:105 -> a" arg1="arg1, l:106 -> a" + SINK2(b) #$ arg2="arg2, l:104 -> b" arg2="arg2, l:105 -> b" MISSING: arg2="arg2, l:106 -> b" @expects(6) @@ -107,9 +107,9 @@ def test_pos_only(): def with_multiple_kw_args(a, b, c): - SINK1(a) #$ arg1="ControlFlowNode for arg1, l:117 -> ControlFlowNode for a" arg1="ControlFlowNode for arg1, l:118 -> ControlFlowNode for a" arg1="ControlFlowNode for arg1, l:119 -> ControlFlowNode for a" arg1="ControlFlowNode for arg1, l:120 -> ControlFlowNode for a" - SINK2(b) #$ arg2="ControlFlowNode for arg2, l:117 -> ControlFlowNode for b" arg2="ControlFlowNode for arg2, l:120 -> ControlFlowNode for b" MISSING: arg2="ControlFlowNode for arg2, l:118 -> ControlFlowNode for b" arg2="ControlFlowNode for arg2, l:119 -> ControlFlowNode for b" - SINK3(c) #$ arg3="ControlFlowNode for arg3, l:117 -> ControlFlowNode for c" arg3="ControlFlowNode for arg3, l:119 -> ControlFlowNode for c" arg3="ControlFlowNode for arg3, l:120 -> ControlFlowNode for c" MISSING: arg3="ControlFlowNode for arg3, l:118 -> ControlFlowNode for c" + SINK1(a) #$ arg1="arg1, l:117 -> a" arg1="arg1, l:118 -> a" arg1="arg1, l:119 -> a" arg1="arg1, l:120 -> a" + SINK2(b) #$ arg2="arg2, l:117 -> b" arg2="arg2, l:120 -> b" MISSING: arg2="arg2, l:118 -> b" arg2="arg2, l:119 -> b" + SINK3(c) #$ arg3="arg3, l:117 -> c" arg3="arg3, l:119 -> c" arg3="arg3, l:120 -> c" MISSING: arg3="arg3, l:118 -> c" @expects(9) @@ -121,9 +121,9 @@ def test_multiple_kw_args(): def with_default_arguments(a=arg1, b=arg2, c=arg3): - SINK1(a) #$ arg1="ControlFlowNode for arg1, l:132 -> ControlFlowNode for a" MISSING:arg1="ControlFlowNode for arg1, l:123 -> ControlFlowNode for a" - SINK2(b) #$ arg2="ControlFlowNode for arg2, l:133 -> ControlFlowNode for b" MISSING: arg2="ControlFlowNode for arg2, l:123 -> ControlFlowNode for b" - SINK3(c) #$ arg3="ControlFlowNode for arg3, l:134 -> ControlFlowNode for c" MISSING: arg3="ControlFlowNode for arg3, l:123 -> ControlFlowNode for c" + SINK1(a) #$ arg1="arg1, l:132 -> a" MISSING:arg1="arg1, l:123 -> a" + SINK2(b) #$ arg2="arg2, l:133 -> b" MISSING: arg2="arg2, l:123 -> b" + SINK3(c) #$ arg3="arg3, l:134 -> c" MISSING: arg3="arg3, l:123 -> c" @expects(12) @@ -136,14 +136,14 @@ def test_default_arguments(): # Nested constructor pattern def grab_foo_bar_baz(foo, **kwargs): - SINK1(foo) #$ arg1="ControlFlowNode for arg1, l:160 -> ControlFlowNode for foo" + SINK1(foo) #$ arg1="arg1, l:160 -> foo" grab_bar_baz(**kwargs) # It is not possible to pass `bar` into `kwargs`, # since `bar` is a valid keyword argument. def grab_bar_baz(bar, **kwargs): - SINK2(bar) #$ arg2="ControlFlowNode for arg2, l:160 -> ControlFlowNode for bar" + SINK2(bar) #$ arg2="arg2, l:160 -> bar" try: SINK2_F(kwargs["bar"]) except: @@ -152,7 +152,7 @@ def grab_bar_baz(bar, **kwargs): def grab_baz(baz): - SINK3(baz) #$ arg3="ControlFlowNode for arg3, l:160 -> ControlFlowNode for baz" + SINK3(baz) #$ arg3="arg3, l:160 -> baz" @expects(4) @@ -163,14 +163,14 @@ def test_grab(): # All combinations def test_pos_pos(): def with_pos(a): - SINK1(a) #$ arg1="ControlFlowNode for arg1, l:168 -> ControlFlowNode for a" + SINK1(a) #$ arg1="arg1, l:168 -> a" with_pos(arg1) def test_pos_pos_only(): def with_pos_only(a, /): - SINK1(a) #$ arg1="ControlFlowNode for arg1, l:175 -> ControlFlowNode for a" + SINK1(a) #$ arg1="arg1, l:175 -> a" with_pos_only(arg1) @@ -178,34 +178,34 @@ def with_pos_only(a, /): def test_pos_star(): def with_star(*a): if len(a) > 0: - SINK1(a[0]) #$ arg1="ControlFlowNode for arg1, l:183 -> ControlFlowNode for Subscript" + SINK1(a[0]) #$ arg1="arg1, l:183 -> a[0]" with_star(arg1) def test_pos_kw(): def with_kw(a=""): - SINK1(a) #$ arg1="ControlFlowNode for arg1, l:190 -> ControlFlowNode for a" + SINK1(a) #$ arg1="arg1, l:190 -> a" with_kw(arg1) def test_kw_pos(): def with_pos(a): - SINK1(a) #$ arg1="ControlFlowNode for arg1, l:197 -> ControlFlowNode for a" + SINK1(a) #$ arg1="arg1, l:197 -> a" with_pos(a=arg1) def test_kw_kw(): def with_kw(a=""): - SINK1(a) #$ arg1="ControlFlowNode for arg1, l:204 -> ControlFlowNode for a" + SINK1(a) #$ arg1="arg1, l:204 -> a" with_kw(a=arg1) def test_kw_doublestar(): def with_doublestar(**a): - SINK1(a["a"]) #$ arg1="ControlFlowNode for arg1, l:211 -> ControlFlowNode for Subscript" + SINK1(a["a"]) #$ arg1="arg1, l:211 -> a['a']" with_doublestar(a=arg1) diff --git a/python/ql/test/experimental/dataflow/coverage/argumentRoutingTest.ql b/python/ql/test/experimental/dataflow/coverage/argumentRoutingTest.ql index 00cc3a49656a..8a2b9cf92350 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentRoutingTest.ql +++ b/python/ql/test/experimental/dataflow/coverage/argumentRoutingTest.ql @@ -1,7 +1,7 @@ import python import semmle.python.dataflow.new.DataFlow private import semmle.python.dataflow.new.internal.DataFlowPrivate as DataFlowPrivate -import experimental.dataflow.FlowTestUtil.FlowTest +import experimental.dataflow.TestUtil.FlowTest class Argument1RoutingTest extends FlowTest { Argument1RoutingTest() { this = "Argument1RoutingTest" } diff --git a/python/ql/test/experimental/dataflow/coverage/classes.py b/python/ql/test/experimental/dataflow/coverage/classes.py index 613019ce4b8e..eb850b8d8196 100644 --- a/python/ql/test/experimental/dataflow/coverage/classes.py +++ b/python/ql/test/experimental/dataflow/coverage/classes.py @@ -553,8 +553,8 @@ def test_length_hint(): # object.__getitem__(self, key) class With_getitem: def __getitem__(self, key): - SINK2(key) #$ arg2="ControlFlowNode for arg2, l:565 -> ControlFlowNode for key" - SINK1(self) #$ arg1="SSA variable with_getitem, l:563 -> ControlFlowNode for self" + SINK2(key) #$ arg2="arg2, l:565 -> key" + SINK1(self) #$ arg1="SSA variable with_getitem, l:563 -> self" OK() return "" @@ -568,9 +568,9 @@ def test_getitem(): # object.__setitem__(self, key, value) class With_setitem: def __setitem__(self, key, value): - SINK3(value) #$ arg3="ControlFlowNode for arg3, l:581 -> ControlFlowNode for value" - SINK2(key) #$ arg2="ControlFlowNode for arg2, l:581 -> ControlFlowNode for key" - SINK1(self) #$ arg1="SSA variable with_setitem, l:578 -> ControlFlowNode for self" + SINK3(value) #$ arg3="arg3, l:581 -> value" + SINK2(key) #$ arg2="arg2, l:581 -> key" + SINK1(self) #$ arg1="SSA variable with_setitem, l:578 -> self" OK() @@ -584,8 +584,8 @@ def test_setitem(): # object.__delitem__(self, key) class With_delitem: def __delitem__(self, key): - SINK2(key) #$ arg2="ControlFlowNode for arg2, l:595 -> ControlFlowNode for key" - SINK1(self) #$ arg1="SSA variable with_delitem, l:593 -> ControlFlowNode for self" + SINK2(key) #$ arg2="arg2, l:595 -> key" + SINK1(self) #$ arg1="SSA variable with_delitem, l:593 -> self" OK() @@ -655,8 +655,8 @@ def test_contains(): # object.__add__(self, other) class With_add: def __add__(self, other): - SINK2(other) #$ arg2="ControlFlowNode for arg2, l:667 -> ControlFlowNode for other" - SINK1(self) #$ arg1="SSA variable with_add, l:665 -> ControlFlowNode for self" + SINK2(other) #$ arg2="arg2, l:667 -> other" + SINK1(self) #$ arg1="SSA variable with_add, l:665 -> self" OK() return self @@ -670,8 +670,8 @@ def test_add(): # object.__sub__(self, other) class With_sub: def __sub__(self, other): - SINK2(other) #$ arg2="ControlFlowNode for arg2, l:682 -> ControlFlowNode for other" - SINK1(self) #$ arg1="SSA variable with_sub, l:680 -> ControlFlowNode for self" + SINK2(other) #$ arg2="arg2, l:682 -> other" + SINK1(self) #$ arg1="SSA variable with_sub, l:680 -> self" OK() return self @@ -685,8 +685,8 @@ def test_sub(): # object.__mul__(self, other) class With_mul: def __mul__(self, other): - SINK2(other) #$ arg2="ControlFlowNode for arg2, l:697 -> ControlFlowNode for other" - SINK1(self) #$ arg1="SSA variable with_mul, l:695 -> ControlFlowNode for self" + SINK2(other) #$ arg2="arg2, l:697 -> other" + SINK1(self) #$ arg1="SSA variable with_mul, l:695 -> self" OK() return self @@ -700,8 +700,8 @@ def test_mul(): # object.__matmul__(self, other) class With_matmul: def __matmul__(self, other): - SINK2(other) #$ arg2="ControlFlowNode for arg2, l:712 -> ControlFlowNode for other" - SINK1(self) #$ arg1="SSA variable with_matmul, l:710 -> ControlFlowNode for self" + SINK2(other) #$ arg2="arg2, l:712 -> other" + SINK1(self) #$ arg1="SSA variable with_matmul, l:710 -> self" OK() return self @@ -715,8 +715,8 @@ def test_matmul(): # object.__truediv__(self, other) class With_truediv: def __truediv__(self, other): - SINK2(other) #$ arg2="ControlFlowNode for arg2, l:727 -> ControlFlowNode for other" - SINK1(self) #$ arg1="SSA variable with_truediv, l:725 -> ControlFlowNode for self" + SINK2(other) #$ arg2="arg2, l:727 -> other" + SINK1(self) #$ arg1="SSA variable with_truediv, l:725 -> self" OK() return self @@ -730,8 +730,8 @@ def test_truediv(): # object.__floordiv__(self, other) class With_floordiv: def __floordiv__(self, other): - SINK2(other) #$ arg2="ControlFlowNode for arg2, l:742 -> ControlFlowNode for other" - SINK1(self) #$ arg1="SSA variable with_floordiv, l:740 -> ControlFlowNode for self" + SINK2(other) #$ arg2="arg2, l:742 -> other" + SINK1(self) #$ arg1="SSA variable with_floordiv, l:740 -> self" OK() return self @@ -745,8 +745,8 @@ def test_floordiv(): # object.__mod__(self, other) class With_mod: def __mod__(self, other): - SINK2(other) #$ arg2="ControlFlowNode for arg2, l:757 -> ControlFlowNode for other" - SINK1(self) #$ arg1="SSA variable with_mod, l:755 -> ControlFlowNode for self" + SINK2(other) #$ arg2="arg2, l:757 -> other" + SINK1(self) #$ arg1="SSA variable with_mod, l:755 -> self" OK() return self @@ -775,8 +775,8 @@ def test_divmod(): # object.__pow__(self, other[, modulo]) class With_pow: def __pow__(self, other): - SINK2(other) #$ arg2="ControlFlowNode for arg2, l:793 -> ControlFlowNode for other" - SINK1(self) #$ arg1="SSA variable with_pow, l:791 -> ControlFlowNode for self" + SINK2(other) #$ arg2="arg2, l:793 -> other" + SINK1(self) #$ arg1="SSA variable with_pow, l:791 -> self" OK() return self @@ -796,8 +796,8 @@ def test_pow_op(): # object.__lshift__(self, other) class With_lshift: def __lshift__(self, other): - SINK2(other) #$ arg2="ControlFlowNode for arg2, l:808 -> ControlFlowNode for other" - SINK1(self) #$ arg1="SSA variable with_lshift, l:806 -> ControlFlowNode for self" + SINK2(other) #$ arg2="arg2, l:808 -> other" + SINK1(self) #$ arg1="SSA variable with_lshift, l:806 -> self" OK() return self @@ -811,8 +811,8 @@ def test_lshift(): # object.__rshift__(self, other) class With_rshift: def __rshift__(self, other): - SINK2(other) #$ arg2="ControlFlowNode for arg2, l:823 -> ControlFlowNode for other" - SINK1(self) #$ arg1="SSA variable with_rshift, l:821 -> ControlFlowNode for self" + SINK2(other) #$ arg2="arg2, l:823 -> other" + SINK1(self) #$ arg1="SSA variable with_rshift, l:821 -> self" OK() return self @@ -826,8 +826,8 @@ def test_rshift(): # object.__and__(self, other) class With_and: def __and__(self, other): - SINK2(other) #$ arg2="ControlFlowNode for arg2, l:838 -> ControlFlowNode for other" - SINK1(self) #$ arg1="SSA variable with_and, l:836 -> ControlFlowNode for self" + SINK2(other) #$ arg2="arg2, l:838 -> other" + SINK1(self) #$ arg1="SSA variable with_and, l:836 -> self" OK() return self @@ -841,8 +841,8 @@ def test_and(): # object.__xor__(self, other) class With_xor: def __xor__(self, other): - SINK2(other) #$ arg2="ControlFlowNode for arg2, l:853 -> ControlFlowNode for other" - SINK1(self) #$ arg1="SSA variable with_xor, l:851 -> ControlFlowNode for self" + SINK2(other) #$ arg2="arg2, l:853 -> other" + SINK1(self) #$ arg1="SSA variable with_xor, l:851 -> self" OK() return self @@ -856,8 +856,8 @@ def test_xor(): # object.__or__(self, other) class With_or: def __or__(self, other): - SINK2(other) #$ arg2="ControlFlowNode for arg2, l:868 -> ControlFlowNode for other" - SINK1(self) #$ arg1="SSA variable with_or, l:866 -> ControlFlowNode for self" + SINK2(other) #$ arg2="arg2, l:868 -> other" + SINK1(self) #$ arg1="SSA variable with_or, l:866 -> self" OK() return self diff --git a/python/ql/test/experimental/dataflow/coverage/dataflowTest.ql b/python/ql/test/experimental/dataflow/coverage/dataflowTest.ql index c7b2b5bfe15a..76cabbfbbbf5 100644 --- a/python/ql/test/experimental/dataflow/coverage/dataflowTest.ql +++ b/python/ql/test/experimental/dataflow/coverage/dataflowTest.ql @@ -1,5 +1,5 @@ import python -import experimental.dataflow.FlowTestUtil.FlowTest +import experimental.dataflow.TestUtil.FlowTest import experimental.dataflow.testConfig class DataFlowTest extends FlowTest { diff --git a/python/ql/test/experimental/dataflow/coverage/datamodel.py b/python/ql/test/experimental/dataflow/coverage/datamodel.py index d6ab9bd3dcbc..0d921a2cb855 100644 --- a/python/ql/test/experimental/dataflow/coverage/datamodel.py +++ b/python/ql/test/experimental/dataflow/coverage/datamodel.py @@ -35,7 +35,7 @@ def SINK_F(x): def f(a, b): return a -SINK(f(SOURCE, 3)) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for f()" flow="ControlFlowNode for Str, l:13 -> ControlFlowNode for f()" +SINK(f(SOURCE, 3)) #$ flow="SOURCE -> f(..)" flow="'source', l:13 -> f(..)" # Instance methods # An instance method object combines a class, a class instance and any callable object (normally a user-defined function). @@ -68,18 +68,18 @@ async def coro(self, x): func_obj = c.method.__func__ # When an instance method object is called, the underlying function (__func__) is called, inserting the class instance (__self__) in front of the argument list. For instance, when C is a class which contains a definition for a function f(), and x is an instance of C, calling x.f(1) is equivalent to calling C.f(x, 1). -SINK(c.method(SOURCE, C)) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for Attribute()" flow="ControlFlowNode for SOURCE, l:38 -> ControlFlowNode for Attribute()" flow="ControlFlowNode for Str, l:13 -> ControlFlowNode for Attribute()" -SINK(C.method(c, SOURCE, C)) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for Attribute()" flow="ControlFlowNode for SOURCE, l:38 -> ControlFlowNode for Attribute()" flow="ControlFlowNode for SOURCE, l:71 -> ControlFlowNode for Attribute()" flow="ControlFlowNode for Str, l:13 -> ControlFlowNode for Attribute()" -SINK(func_obj(c, SOURCE, C)) +SINK(c.method(SOURCE, C)) #$ flow="SOURCE -> c.method(..)" flow="SOURCE, l:38 -> c.method(..)" flow="'source', l:13 -> c.method(..)" +SINK(C.method(c, SOURCE, C)) #$ flow="SOURCE -> C.method(..)" flow="SOURCE, l:38 -> C.method(..)" flow="SOURCE, l:71 -> C.method(..)" flow="'source', l:13 -> C.method(..)" +SINK(func_obj(c, SOURCE, C)) #$ MISSING: flow="SOURCE -> func_obj(..)" flow="SOURCE, l:38 -> func_obj(..)" flow="SOURCE, l:71 -> func_obj(..)" flow="SOURCE, l:72 -> func_obj(..)" flow="'source', l:13 -> func_obj()" # When an instance method object is created by retrieving a class method object from a class or instance, its __self__ attribute is the class itself, and its __func__ attribute is the function object underlying the class method. c_func_obj = C.classmethod.__func__ # When an instance method object is derived from a class method object, the “class instance” stored in __self__ will actually be the class itself, so that calling either x.f(1) or C.f(1) is equivalent to calling f(C,1) where f is the underlying function. -SINK(c.classmethod(SOURCE)) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for Attribute()" flow="ControlFlowNode for SOURCE, l:38 -> ControlFlowNode for Attribute()" flow="ControlFlowNode for SOURCE, l:71 -> ControlFlowNode for Attribute()" flow="ControlFlowNode for SOURCE, l:72 -> ControlFlowNode for Attribute()" flow="ControlFlowNode for SOURCE, l:73 -> ControlFlowNode for Attribute()" flow="ControlFlowNode for Str, l:13 -> ControlFlowNode for Attribute()" -SINK(C.classmethod(SOURCE)) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for Attribute()" flow="ControlFlowNode for SOURCE, l:38 -> ControlFlowNode for Attribute()" flow="ControlFlowNode for SOURCE, l:71 -> ControlFlowNode for Attribute()" flow="ControlFlowNode for SOURCE, l:72 -> ControlFlowNode for Attribute()" flow="ControlFlowNode for SOURCE, l:73 -> ControlFlowNode for Attribute()" flow="ControlFlowNode for SOURCE, l:80 -> ControlFlowNode for Attribute()" flow="ControlFlowNode for Str, l:13 -> ControlFlowNode for Attribute()" -SINK(c_func_obj(C, SOURCE)) +SINK(c.classmethod(SOURCE)) #$ flow="SOURCE -> c.classmethod(..)" flow="SOURCE, l:38 -> c.classmethod(..)" flow="SOURCE, l:71 -> c.classmethod(..)" flow="SOURCE, l:72 -> c.classmethod(..)" flow="SOURCE, l:73 -> c.classmethod(..)" flow="'source', l:13 -> c.classmethod(..)" +SINK(C.classmethod(SOURCE)) #$ flow="SOURCE -> C.classmethod(..)" flow="SOURCE, l:38 -> C.classmethod(..)" flow="SOURCE, l:71 -> C.classmethod(..)" flow="SOURCE, l:72 -> C.classmethod(..)" flow="SOURCE, l:73 -> C.classmethod(..)" flow="SOURCE, l:80 -> C.classmethod(..)" flow="'source', l:13 -> C.classmethod(..)" +SINK(c_func_obj(C, SOURCE)) #$ MISSING: flow="SOURCE -> c_func_obj(..)" flow="SOURCE, l:38 -> c_func_obj(..)" flow="SOURCE, l:71 -> c_func_obj(..)" flow="SOURCE, l:72 -> c_func_obj(..)" flow="SOURCE, l:73 -> c_func_obj(..)" flow="SOURCE, l:80 -> c_func_obj(..)" flow="SOURCE, l:81 -> c_func_obj(..)" flow="'source', l:13 -> c_func_obj()" # Generator functions # A function or method which uses the yield statement (see section The yield statement) is called a generator function. Such a function, when called, always returns an iterator object which can be used to execute the body of the function: calling the iterator’s iterator.__next__() method will cause the function to execute until it provides a value using the yield statement. When the function executes a return statement or falls off the end, a StopIteration exception is raised and the iterator will have reached the end of the set of values to be returned. @@ -156,4 +156,4 @@ def __init__(self): SINK(Customized.a) SINK_F(Customized.b) SINK(customized.a) -SINK(customized.b) #$ flow="ControlFlowNode for SOURCE, l:152 -> ControlFlowNode for Attribute" flow="ControlFlowNode for Str, l:13 -> ControlFlowNode for Attribute" +SINK(customized.b) #$ flow="SOURCE, l:152 -> customized.b" flow="'source', l:13 -> customized.b" diff --git a/python/ql/test/experimental/dataflow/coverage/maximalFlowTest.expected b/python/ql/test/experimental/dataflow/coverage/maximalFlowTest.expected deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/python/ql/test/experimental/dataflow/coverage/maximalFlowTest.ql b/python/ql/test/experimental/dataflow/coverage/maximalFlowTest.ql deleted file mode 100644 index ec171dcd9fd9..000000000000 --- a/python/ql/test/experimental/dataflow/coverage/maximalFlowTest.ql +++ /dev/null @@ -1 +0,0 @@ -import experimental.dataflow.FlowTestUtil.MaximalFlowTest diff --git a/python/ql/test/experimental/dataflow/coverage/test.py b/python/ql/test/experimental/dataflow/coverage/test.py index ab7b9f024050..616837a9d3b2 100644 --- a/python/ql/test/experimental/dataflow/coverage/test.py +++ b/python/ql/test/experimental/dataflow/coverage/test.py @@ -41,7 +41,7 @@ def SINK_F(x): def test_tuple_with_local_flow(): x = (NONSOURCE, SOURCE) y = x[1] - SINK(y) #$ flow="ControlFlowNode for SOURCE, l:42 -> ControlFlowNode for y" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for y" + SINK(y) #$ flow="SOURCE, l:42 -> y" flow="'source', l:20 -> y" def test_tuple_negative(): @@ -53,45 +53,45 @@ def test_tuple_negative(): # 6.2.1. Identifiers (Names) def test_names(): x = SOURCE - SINK(x) #$ flow="ControlFlowNode for SOURCE, l:55 -> ControlFlowNode for x" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for x" + SINK(x) #$ flow="SOURCE, l:55 -> x" flow="'source', l:20 -> x" # 6.2.2. Literals def test_string_literal(): x = "source" - SINK(x) #$ flow="ControlFlowNode for Str, l:61 -> ControlFlowNode for x" + SINK(x) #$ flow="'source', l:61 -> x" def test_bytes_literal(): x = b"source" - SINK(x) #$ flow="ControlFlowNode for Str, l:66 -> ControlFlowNode for x" + SINK(x) #$ flow="b'source', l:66 -> x" def test_integer_literal(): x = 42 - SINK(x) #$ flow="ControlFlowNode for IntegerLiteral, l:71 -> ControlFlowNode for x" + SINK(x) #$ flow="42, l:71 -> x" def test_floatnumber_literal(): x = 42.0 - SINK(x) #$ flow="ControlFlowNode for FloatLiteral, l:76 -> ControlFlowNode for x" + SINK(x) #$ flow="42.0, l:76 -> x" def test_imagnumber_literal(): x = 42j - SINK(x) #$ MISSING:flow="ControlFlowNode for FloatLiteral, l:81 -> ControlFlowNode for x" + SINK(x) #$ MISSING:flow="42j, l:81 -> x" # 6.2.3. Parenthesized forms def test_parenthesized_form(): x = (SOURCE) - SINK(x) #$ flow="ControlFlowNode for SOURCE, l:87 -> ControlFlowNode for x" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for x" + SINK(x) #$ flow="SOURCE, l:87 -> x" flow="'source', l:20 -> x" # 6.2.5. List displays def test_list_display(): x = [SOURCE] - SINK(x[0]) #$ flow="ControlFlowNode for SOURCE, l:93 -> ControlFlowNode for Subscript" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" + SINK(x[0]) #$ flow="SOURCE, l:93 -> x[0]" flow="'source', l:20 -> x[0]" def test_list_display_negative(): @@ -101,109 +101,109 @@ def test_list_display_negative(): def test_list_comprehension(): x = [SOURCE for y in [NONSOURCE]] - SINK(x[0]) #$ flow="ControlFlowNode for SOURCE, l:103 -> ControlFlowNode for Subscript" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" + SINK(x[0]) #$ flow="SOURCE, l:103 -> x[0]" flow="'source', l:20 -> x[0]" def test_list_comprehension_flow(): x = [y for y in [SOURCE]] - SINK(x[0]) #$ flow="ControlFlowNode for SOURCE, l:108 -> ControlFlowNode for Subscript" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" + SINK(x[0]) #$ flow="SOURCE, l:108 -> x[0]" flow="'source', l:20 -> x[0]" def test_list_comprehension_inflow(): l = [SOURCE] x = [y for y in l] - SINK(x[0]) #$ flow="ControlFlowNode for SOURCE, l:113 -> ControlFlowNode for Subscript" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" + SINK(x[0]) #$ flow="SOURCE, l:113 -> x[0]" flow="'source', l:20 -> x[0]" def test_nested_list_display(): x = [*[SOURCE]] - SINK(x[0]) #$ MISSING:flow="ControlFlowNode for SOURCE, l:119 -> ControlFlowNode for Subscript" MISSING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" + SINK(x[0]) #$ MISSING:flow="SOURCE, l:119 -> x[0]" MISSING:flow="'source', l:20 -> x[0]" # 6.2.6. Set displays def test_set_display(): x = {SOURCE} - SINK(x.pop()) #$ flow="ControlFlowNode for SOURCE, l:125 -> ControlFlowNode for Attribute()" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Attribute()" + SINK(x.pop()) #$ flow="SOURCE, l:125 -> x.pop()" flow="'source', l:20 -> x.pop()" def test_set_comprehension(): x = {SOURCE for y in [NONSOURCE]} - SINK(x.pop()) #$ flow="ControlFlowNode for SOURCE, l:130 -> ControlFlowNode for Attribute()" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Attribute()" + SINK(x.pop()) #$ flow="SOURCE, l:130 -> x.pop()" flow="'source', l:20 -> x.pop()" def test_set_comprehension_flow(): x = {y for y in [SOURCE]} - SINK(x.pop()) #$ flow="ControlFlowNode for SOURCE, l:135 -> ControlFlowNode for Attribute()" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Attribute()" + SINK(x.pop()) #$ flow="SOURCE, l:135 -> x.pop()" flow="'source', l:20 -> x.pop()" def test_set_comprehension_inflow(): l = {SOURCE} x = {y for y in l} - SINK(x.pop()) #$ flow="ControlFlowNode for SOURCE, l:140 -> ControlFlowNode for Attribute()" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Attribute()" + SINK(x.pop()) #$ flow="SOURCE, l:140 -> x.pop()" flow="'source', l:20 -> x.pop()" def test_nested_set_display(): x = {*{SOURCE}} - SINK(x.pop()) #$ MISSING:flow="ControlFlowNode for SOURCE, l:146 -> ControlFlowNode for Attribute()" MISSING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Attribute()" + SINK(x.pop()) #$ MISSING:flow="SOURCE, l:146 -> x.pop()" MISSING:flow="'source', l:20 -> x.pop()" # 6.2.7. Dictionary displays def test_dict_display(): x = {"s": SOURCE} - SINK(x["s"]) #$ flow="ControlFlowNode for SOURCE, l:152 -> ControlFlowNode for Subscript" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" + SINK(x["s"]) #$ flow="SOURCE, l:152 -> x['s']" flow="'source', l:20 -> x['s']" def test_dict_display_pop(): x = {"s": SOURCE} - SINK(x.pop("s")) #$ flow="ControlFlowNode for SOURCE, l:157 -> ControlFlowNode for Attribute()" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Attribute()" + SINK(x.pop("s")) #$ flow="SOURCE, l:157 -> x.pop(..)" flow="'source', l:20 -> x.pop(..)" def test_dict_comprehension(): x = {y: SOURCE for y in ["s"]} - SINK(x["s"]) #$ MISSING:flow="ControlFlowNode for SOURCE, l:152 -> ControlFlowNode for Subscript" MISING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" + SINK(x["s"]) #$ MISSING:flow="SOURCE, l:152 -> x['s']" MISING:flow="'source', l:20 -> x['s']" def test_dict_comprehension_pop(): x = {y: SOURCE for y in ["s"]} - SINK(x.pop("s")) #$ MISSING:flow="ControlFlowNode for SOURCE, l:167 -> ControlFlowNode for Attribute()" MISSING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Attribute()" + SINK(x.pop("s")) #$ MISSING:flow="SOURCE, l:167 -> x.pop()" MISSING:flow="'source', l:20 -> x.pop()" def test_nested_dict_display(): x = {**{"s": SOURCE}} - SINK(x["s"]) #$ MISSING:flow="ControlFlowNode for SOURCE, l:172 -> ControlFlowNode for Subscript" MISING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" + SINK(x["s"]) #$ MISSING:flow="SOURCE, l:172 -> x['s']" MISING:flow="'source', l:20 -> x['s']" def test_nested_dict_display_pop(): x = {**{"s": SOURCE}} - SINK(x.pop("s")) #$ MISSING:flow="ControlFlowNode for SOURCE, l:177 -> ControlFlowNode for Attribute()" MISSING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Attribute()" + SINK(x.pop("s")) #$ MISSING:flow="SOURCE, l:177 -> x.pop()" MISSING:flow="'source', l:20 -> x.pop()" # Nested comprehensions def test_nested_comprehension(): x = [y for z in [[SOURCE]] for y in z] - SINK(x[0]) #$ flow="ControlFlowNode for SOURCE, l:183 -> ControlFlowNode for Subscript" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" + SINK(x[0]) #$ flow="SOURCE, l:183 -> x[0]" flow="'source', l:20 -> x[0]" def test_nested_comprehension_deep_with_local_flow(): x = [y for v in [[[[SOURCE]]]] for u in v for z in u for y in z] - SINK(x[0]) #$ flow="ControlFlowNode for SOURCE, l:188 -> ControlFlowNode for Subscript" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" + SINK(x[0]) #$ flow="SOURCE, l:188 -> x[0]" flow="'source', l:20 -> x[0]" def test_nested_comprehension_dict(): d = {"s": [SOURCE]} x = [y for k, v in d.items() for y in v] - SINK(x[0]) #$ MISSING:flow="ControlFlowNode for SOURCE, l:193 -> ControlFlowNode for Subscript" MISING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" + SINK(x[0]) #$ MISSING:flow="SOURCE, l:193 -> x[0]" MISING:flow="'source', l:20 -> x[0]" def test_nested_comprehension_paren(): x = [y for y in (z for z in [SOURCE])] - SINK(x[0]) #$ flow="ControlFlowNode for SOURCE, l:199 -> ControlFlowNode for Subscript" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" + SINK(x[0]) #$ flow="SOURCE, l:199 -> x[0]" flow="'source', l:20 -> x[0]" # 6.2.8. Generator expressions def test_generator(): x = (SOURCE for y in [NONSOURCE]) - SINK([*x][0]) #$ MISSING:flow="ControlFlowNode for SOURCE, l:205 -> ControlFlowNode for Subscript" MISING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" + SINK([*x][0]) #$ MISSING:flow="SOURCE, l:205 -> List[0]" MISING:flow="'source', l:20 -> List[0]" # 6.2.9. Yield expressions @@ -213,7 +213,7 @@ def gen(x): def test_yield(): g = gen(SOURCE) - SINK(next(g)) #$ MISSING:flow="ControlFlowNode for SOURCE, l:215 -> ControlFlowNode for next()" MISING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for next()" + SINK(next(g)) #$ MISSING:flow="SOURCE, l:215 -> next()" MISING:flow="'source', l:20 -> next()" def gen_from(x): @@ -222,19 +222,19 @@ def gen_from(x): def test_yield_from(): g = gen_from(SOURCE) - SINK(next(g)) #$ MISSING:flow="ControlFlowNode for SOURCE, l:224 -> ControlFlowNode for next()" MISING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for next()" + SINK(next(g)) #$ MISSING:flow="SOURCE, l:224 -> next()" MISING:flow="'source', l:20 -> next()" # a statement rather than an expression, but related to generators def test_for(): for x in gen(SOURCE): - SINK(x) #$ MISSING:flow="ControlFlowNode for SOURCE, l:230 -> ControlFlowNode for x" MISING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for x" + SINK(x) #$ MISSING:flow="SOURCE, l:230 -> x" MISING:flow="'source', l:20 -> x" # 6.2.9.1. Generator-iterator methods def test___next__(): g = gen(SOURCE) - SINK(g.__next__()) #$ MISSING:flow="ControlFlowNode for SOURCE, l:236 -> ControlFlowNode for Attribute()" MISSING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Attribute()" + SINK(g.__next__()) #$ MISSING:flow="SOURCE, l:236 -> g.__next__()" MISSING:flow="'source', l:20 -> g.__next__()" def gen2(x): @@ -246,7 +246,7 @@ def gen2(x): def test_send(): g = gen2(NONSOURCE) n = next(g) - SINK(g.send(SOURCE)) #$ MISSING:flow="ControlFlowNode for SOURCE -> ControlFlowNode for Attribute()" MISSING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Attribute()" + SINK(g.send(SOURCE)) #$ MISSING:flow="SOURCE -> g.send()" MISSING:flow="'source', l:20 -> g.send()" def gen_ex(x): @@ -259,7 +259,7 @@ def gen_ex(x): def test_throw(): g = gen_ex(SOURCE) n = next(g) - SINK(g.throw(TypeError)) #$ MISSING:flow="ControlFlowNode for SOURCE, l:260 -> ControlFlowNode for Attribute()" MISSING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Attribute()" + SINK(g.throw(TypeError)) #$ MISSING:flow="SOURCE, l:260 -> g.throw()" MISSING:flow="'source', l:20 -> g.throw()" # no `test_close` as `close` involves no data flow @@ -280,7 +280,7 @@ def runa(a): async def atest___anext__(): g = agen(SOURCE) - SINK(await g.__anext__()) #$ MISSING:flow="ControlFlowNode for SOURCE, l:282 -> ControlFlowNode for Attribute()" MISSING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Attribute()" + SINK(await g.__anext__()) #$ MISSING:flow="SOURCE, l:282 -> g.__anext__()" MISSING:flow="'source', l:20 -> g.__anext__()" def test___anext__(): @@ -296,7 +296,7 @@ async def agen2(x): async def atest_asend(): g = agen2(NONSOURCE) n = await g.__anext__() - SINK(await g.asend(SOURCE)) #$ MISSING:flow="ControlFlowNode for SOURCE -> ControlFlowNode for Attribute()" MISSING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Attribute()" + SINK(await g.asend(SOURCE)) #$ MISSING:flow="SOURCE -> g.asend()" MISSING:flow="'source', l:20 -> g.asend()" def test_asend(): @@ -313,7 +313,7 @@ async def agen_ex(x): async def atest_athrow(): g = agen_ex(SOURCE) n = await g.__anext__() - SINK(await g.athrow(TypeError)) #$ MISSING:flow="ControlFlowNode for SOURCE, l:314 -> ControlFlowNode for Attribute()" MISSING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Attribute()" + SINK(await g.athrow(TypeError)) #$ MISSING:flow="SOURCE, l:314 -> g.athrow()" MISSING:flow="'source', l:20 -> g.athrow()" def test_athrow(): @@ -326,22 +326,22 @@ class C: def test_attribute_reference(): - SINK(C.a) #$ MISSING:flow="ControlFlowNode for SOURCE, l:325 -> ControlFlowNode for Attribute" MISSING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Attribute" + SINK(C.a) #$ MISSING:flow="SOURCE, l:325 -> C.a" MISSING:flow="'source', l:20 -> C.a" # overriding __getattr__ should be tested by the class coverage tests # 6.3.2. Subscriptions def test_subscription_tuple(): - SINK((SOURCE,)[0]) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for Subscript" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" + SINK((SOURCE,)[0]) #$ flow="SOURCE -> Tuple[0]" flow="'source', l:20 -> Tuple[0]" def test_subscription_list(): - SINK([SOURCE][0]) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for Subscript" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" + SINK([SOURCE][0]) #$ flow="SOURCE -> List[0]" flow="'source', l:20 -> List[0]" def test_subscription_mapping(): - SINK({"s": SOURCE}["s"]) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for Subscript" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" + SINK({"s": SOURCE}["s"]) #$ flow="SOURCE -> Dict['s']" flow="'source', l:20 -> Dict['s']" # overriding __getitem__ should be tested by the class coverage tests @@ -353,7 +353,7 @@ def test_subscription_mapping(): def test_slicing(): s = l[0:1:1] - SINK(s[0]) #$ MISSING:flow="ControlFlowNode for SOURCE -> ControlFlowNode for Subscript" MISSING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" + SINK(s[0]) #$ MISSING:flow="SOURCE -> s[0]" MISSING:flow="'source', l:20 -> s[0]" # The grammar seems to allow `l[0:1:1, 0:1]`, but the interpreter does not like it @@ -364,7 +364,7 @@ def second(a, b): def test_call_positional(): - SINK(second(NONSOURCE, SOURCE)) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for second()" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for second()" + SINK(second(NONSOURCE, SOURCE)) #$ flow="SOURCE -> second(..)" flow="'source', l:20 -> second(..)" def test_call_positional_negative(): @@ -372,15 +372,15 @@ def test_call_positional_negative(): def test_call_keyword(): - SINK(second(NONSOURCE, b=SOURCE)) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for second()" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for second()" + SINK(second(NONSOURCE, b=SOURCE)) #$ flow="SOURCE -> second(..)" flow="'source', l:20 -> second(..)" def test_call_unpack_iterable(): - SINK(second(NONSOURCE, *[SOURCE])) #$ MISSING:flow="ControlFlowNode for SOURCE -> ControlFlowNode for second()" MISING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for second()" + SINK(second(NONSOURCE, *[SOURCE])) #$ MISSING:flow="SOURCE -> second(..)" MISING:flow="'source', l:20 -> second(..)" def test_call_unpack_mapping(): - SINK(second(NONSOURCE, **{"b": SOURCE})) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for second()" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for second()" + SINK(second(NONSOURCE, **{"b": SOURCE})) #$ flow="SOURCE -> second(..)" flow="'source', l:20 -> second(..)" def f_extra_pos(a, *b): @@ -388,7 +388,7 @@ def f_extra_pos(a, *b): def test_call_extra_pos(): - SINK(f_extra_pos(NONSOURCE, SOURCE)) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for f_extra_pos()" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for f_extra_pos()" + SINK(f_extra_pos(NONSOURCE, SOURCE)) #$ flow="SOURCE -> f_extra_pos(..)" flow="'source', l:20 -> f_extra_pos(..)" def f_extra_keyword(a, **b): @@ -396,7 +396,7 @@ def f_extra_keyword(a, **b): def test_call_extra_keyword(): - SINK(f_extra_keyword(NONSOURCE, b=SOURCE)) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for f_extra_keyword()" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for f_extra_keyword()" + SINK(f_extra_keyword(NONSOURCE, b=SOURCE)) #$ flow="SOURCE -> f_extra_keyword(..)" flow="'source', l:20 -> f_extra_keyword(..)" # return the name of the first extra keyword argument @@ -406,18 +406,18 @@ def f_extra_keyword_flow(**a): # call the function with our source as the name of the keyword arguemnt def test_call_extra_keyword_flow(): - SINK(f_extra_keyword_flow(**{SOURCE: None})) #$ MISSING:flow="ControlFlowNode for SOURCE -> ControlFlowNode for f_extra_keyword()" MISSING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for f_extra_keyword()" + SINK(f_extra_keyword_flow(**{SOURCE: None})) #$ MISSING:flow="SOURCE -> f_extra_keyword(..)" MISSING:flow="'source', l:20 -> f_extra_keyword(..)" # 6.12. Assignment expressions def test_assignment_expression(): x = NONSOURCE - SINK(x := SOURCE) #$ MISSING:flow="ControlFlowNode for SOURCE -> ControlFlowNode for x" MISSING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for x" + SINK(x := SOURCE) #$ MISSING:flow="SOURCE -> x" MISSING:flow="'source', l:20 -> x" # 6.13. Conditional expressions def test_conditional_true(): - SINK(SOURCE if True else NONSOURCE) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for IfExp" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for IfExp" + SINK(SOURCE if True else NONSOURCE) #$ flow="SOURCE -> IfExp" flow="'source', l:20 -> IfExp" def test_conditional_true_guards(): @@ -425,7 +425,7 @@ def test_conditional_true_guards(): def test_conditional_false(): - SINK(NONSOURCE if False else SOURCE) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for IfExp" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for IfExp" + SINK(NONSOURCE if False else SOURCE) #$ flow="SOURCE -> IfExp" flow="'source', l:20 -> IfExp" def test_conditional_false_guards(): @@ -435,13 +435,13 @@ def test_conditional_false_guards(): # Condition is evaluated first, so x is SOURCE once chosen def test_conditional_evaluation_true(): x = NONSOURCE - SINK(x if (SOURCE == (x := SOURCE)) else NONSOURCE) #$ MISSING:flow="ControlFlowNode for SOURCE -> ControlFlowNode for IfExp" MISSING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for IfExp" + SINK(x if (SOURCE == (x := SOURCE)) else NONSOURCE) #$ MISSING:flow="SOURCE -> IfExp" MISSING:flow="'source', l:20 -> IfExp" # Condition is evaluated first, so x is SOURCE once chosen def test_conditional_evaluation_false(): x = NONSOURCE - SINK(NONSOURCE if (NONSOURCE == (x := SOURCE)) else x) #$ MISSING:flow="ControlFlowNode for SOURCE -> ControlFlowNode for IfExp" MISSING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for IfExp" + SINK(NONSOURCE if (NONSOURCE == (x := SOURCE)) else x) #$ MISSING:flow="SOURCE -> IfExp" MISSING:flow="'source', l:20 -> IfExp" # 6.14. Lambdas @@ -449,14 +449,14 @@ def test_lambda(): def f(x): return x - SINK(f(SOURCE)) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for f()" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for f()" + SINK(f(SOURCE)) #$ flow="SOURCE -> f(..)" flow="'source', l:20 -> f(..)" def test_lambda_positional(): def second(a, b): return b - SINK(second(NONSOURCE, SOURCE)) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for second()" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for second()" + SINK(second(NONSOURCE, SOURCE)) #$ flow="SOURCE -> second(..)" flow="'source', l:20 -> second(..)" def test_lambda_positional_negative(): @@ -470,50 +470,50 @@ def test_lambda_keyword(): def second(a, b): return b - SINK(second(NONSOURCE, b=SOURCE)) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for second()" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for second()" + SINK(second(NONSOURCE, b=SOURCE)) #$ flow="SOURCE -> second(..)" flow="'source', l:20 -> second(..)" def test_lambda_unpack_iterable(): def second(a, b): return b - SINK(second(NONSOURCE, *[SOURCE])) #$ MISSING:flow="ControlFlowNode for SOURCE -> ControlFlowNode for second()" MISSING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for second()" # Flow missing + SINK(second(NONSOURCE, *[SOURCE])) #$ MISSING:flow="SOURCE -> second(..)" MISSING:flow="'source', l:20 -> second(..)" # Flow missing def test_lambda_unpack_mapping(): def second(a, b): return b - SINK(second(NONSOURCE, **{"b": SOURCE})) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for second()" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for second()" + SINK(second(NONSOURCE, **{"b": SOURCE})) #$ flow="SOURCE -> second(..)" flow="'source', l:20 -> second(..)" def test_lambda_extra_pos(): f_extra_pos = lambda a, *b: b[0] - SINK(f_extra_pos(NONSOURCE, SOURCE)) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for f_extra_pos()" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for f_extra_pos()" + SINK(f_extra_pos(NONSOURCE, SOURCE)) #$ flow="SOURCE -> f_extra_pos(..)" flow="'source', l:20 -> f_extra_pos(..)" def test_lambda_extra_keyword(): f_extra_keyword = lambda a, **b: b["b"] - SINK(f_extra_keyword(NONSOURCE, b=SOURCE)) #$ flow="ControlFlowNode for SOURCE -> ControlFlowNode for f_extra_keyword()" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for f_extra_keyword()" + SINK(f_extra_keyword(NONSOURCE, b=SOURCE)) #$ flow="SOURCE -> f_extra_keyword(..)" flow="'source', l:20 -> f_extra_keyword(..)" # call the function with our source as the name of the keyword argument def test_lambda_extra_keyword_flow(): # return the name of the first extra keyword argument f_extra_keyword_flow = lambda **a: [*a][0] - SINK(f_extra_keyword_flow(**{SOURCE: None})) #$ MISSING:flow="ControlFlowNode for SOURCE -> ControlFlowNode for f_extra_keyword()" MISSING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for f_extra_keyword()" + SINK(f_extra_keyword_flow(**{SOURCE: None})) #$ MISSING:flow="SOURCE -> f_extra_keyword(..)" MISSING:flow="'source', l:20 -> f_extra_keyword(..)" @expects(4) def test_swap(): a = SOURCE b = NONSOURCE - SINK(a) #$ flow="ControlFlowNode for SOURCE, l:509 -> ControlFlowNode for a" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for a" + SINK(a) #$ flow="SOURCE, l:509 -> a" flow="'source', l:20 -> a" SINK_F(b) a, b = b, a SINK_F(a) - SINK(b) #$ flow="ControlFlowNode for SOURCE, l:509 -> ControlFlowNode for b" flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for b" + SINK(b) #$ flow="SOURCE, l:509 -> b" flow="'source', l:20 -> b" def test_deep_callgraph(): @@ -538,7 +538,7 @@ def f6(arg): return f5(arg) x = f6(SOURCE) - SINK(x) #$ MISSING:flow="ControlFlowNode for SOURCE, l:540 -> ControlFlowNode for x" MISING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for x" + SINK(x) #$ MISSING:flow="SOURCE, l:540 -> x" MISING:flow="'source', l:20 -> x" @expects(2) @@ -547,7 +547,7 @@ def test_dynamic_tuple_creation_1(): tup += (SOURCE,) tup += (NONSOURCE,) - SINK(tup[0]) #$ MISSING:flow="ControlFlowNode for SOURCE, l:547 -> ControlFlowNode for Subscript" MISING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" + SINK(tup[0]) #$ MISSING:flow="SOURCE, l:547 -> tup[0]" MISING:flow="'source', l:20 -> tup[0]" SINK_F(tup[1]) @@ -557,7 +557,7 @@ def test_dynamic_tuple_creation_2(): tup += (SOURCE,) tup += (NONSOURCE,) - SINK(tup[0]) #$ MISSING:flow="ControlFlowNode for SOURCE, l:557 -> ControlFlowNode for Subscript" MISING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" + SINK(tup[0]) #$ MISSING:flow="SOURCE, l:557 -> tup[0]" MISING:flow="'source', l:20 -> tup[0]" SINK_F(tup[1]) @@ -567,7 +567,7 @@ def test_dynamic_tuple_creation_3(): tup2 = (NONSOURCE,) tup = tup1 + tup2 - SINK(tup[0]) #$ MISSING:flow="ControlFlowNode for SOURCE, l:566 -> ControlFlowNode for Subscript" MISING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" + SINK(tup[0]) #$ MISSING:flow="SOURCE, l:566 -> tup[0]" MISING:flow="'source', l:20 -> tup[0]" SINK_F(tup[1]) @@ -578,5 +578,5 @@ def test_dynamic_tuple_creation_4(): for item in [SOURCE, NONSOURCE]: tup += (item,) - SINK(tup[0]) #$ MISSING:flow="ControlFlowNode for SOURCE, l:578 -> ControlFlowNode for Subscript" MISING:flow="ControlFlowNode for Str, l:20 -> ControlFlowNode for Subscript" + SINK(tup[0]) #$ MISSING:flow="SOURCE, l:578 -> tup[0]" MISING:flow="'source', l:20 -> tup[0]" SINK_F(tup[1]) diff --git a/python/ql/test/experimental/dataflow/tainttracking/TestTaintLib.qll b/python/ql/test/experimental/dataflow/tainttracking/TestTaintLib.qll index 6d6ee56ad0ee..618fa1cfd2af 100644 --- a/python/ql/test/experimental/dataflow/tainttracking/TestTaintLib.qll +++ b/python/ql/test/experimental/dataflow/tainttracking/TestTaintLib.qll @@ -1,6 +1,7 @@ import python import semmle.python.dataflow.new.TaintTracking import semmle.python.dataflow.new.DataFlow +import experimental.dataflow.TestUtil.PrintNode class TestTaintTrackingConfiguration extends TaintTracking::Configuration { TestTaintTrackingConfiguration() { this = "TestTaintTrackingConfiguration" } @@ -18,31 +19,6 @@ class TestTaintTrackingConfiguration extends TaintTracking::Configuration { } } -private string repr(Expr e) { - not e instanceof Num and - not e instanceof StrConst and - not e instanceof Subscript and - not e instanceof Call and - not e instanceof Attribute and - result = e.toString() - or - result = e.(Num).getN() - or - result = - e.(StrConst).getPrefix() + e.(StrConst).getText() + - e.(StrConst).getPrefix().regexpReplaceAll("[a-zA-Z]+", "") - or - result = repr(e.(Subscript).getObject()) + "[" + repr(e.(Subscript).getIndex()) + "]" - or - ( - if exists(e.(Call).getAnArg()) or exists(e.(Call).getANamedArg()) - then result = repr(e.(Call).getFunc()) + "(..)" - else result = repr(e.(Call).getFunc()) + "()" - ) - or - result = repr(e.(Attribute).getObject()) + "." + e.(Attribute).getName() -} - query predicate test_taint(string arg_location, string test_res, string scope_name, string repr) { exists(Call call, Expr arg, boolean expected_taint, boolean has_taint | // only consider files that are extracted as part of the test @@ -69,6 +45,6 @@ query predicate test_taint(string arg_location, string test_res, string scope_na arg_location = arg.getLocation().toString() and test_res = test_res and scope_name = call.getScope().getName() and - repr = repr(arg) + repr = prettyExp(arg) ) } From 737f4dff09471818ceffbde8ea35cf4de20a2af3 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 24 Nov 2020 10:57:57 +0100 Subject: [PATCH 06/16] Python: update test annotations --- python/ql/test/experimental/dataflow/basic/test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/test/experimental/dataflow/basic/test.py b/python/ql/test/experimental/dataflow/basic/test.py index d0a54a570eb5..b850aa0d99c8 100644 --- a/python/ql/test/experimental/dataflow/basic/test.py +++ b/python/ql/test/experimental/dataflow/basic/test.py @@ -1,4 +1,4 @@ -def obfuscated_id(x): #$ step="FunctionExpr -> GSSA Variable obfuscated_id" +def obfuscated_id(x): #$ step="FunctionExpr -> GSSA Variable obfuscated_id" step="x -> SSA variable x" y = x #$ step="x -> SSA variable y" step="SSA variable x, l:1 -> x" z = y #$ step="y -> SSA variable z" step="SSA variable y, l:2 -> y" return z #$ flow="42, l:6 -> z" step="SSA variable z, l:3 -> z" From 80dcb8da4ac477e59161fac77d450caa03bca982 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 24 Nov 2020 11:55:28 +0100 Subject: [PATCH 07/16] Python: annotate missing flow --- .../experimental/dataflow/coverage/classes.py | 270 +++++++++--------- 1 file changed, 135 insertions(+), 135 deletions(-) diff --git a/python/ql/test/experimental/dataflow/coverage/classes.py b/python/ql/test/experimental/dataflow/coverage/classes.py index eb850b8d8196..fd8a45bc6090 100644 --- a/python/ql/test/experimental/dataflow/coverage/classes.py +++ b/python/ql/test/experimental/dataflow/coverage/classes.py @@ -40,7 +40,7 @@ def OK(): # object.__new__(cls[, ...]) class With_new: def __new__(cls): - SINK1(cls) # Flow not found + SINK1(cls) #$ MISSING: arg1="With_new, l:41 -> cls" OK() # Call not found return super().__new__(cls) @@ -52,7 +52,7 @@ def test_new(): # object.__init__(self[, ...]) class With_init: def __init__(self): - SINK1(self) + SINK1(self) #$ MISSING: arg1="with_init, l:60 -> self" OK() @@ -63,7 +63,7 @@ def test_init(): # object.__del__(self) class With_del: def __del__(self): - SINK1(self) # Flow not found + SINK1(self) #$ MISSING: arg1="with_del, l:71 -> self" OK() # Call not found @@ -75,7 +75,7 @@ def test_del(): # object.__repr__(self) class With_repr: def __repr__(self): - SINK1(self) # Flow not found + SINK1(self) #$ MISSING: arg1="with_repr, l:84 -> self" OK() # Call not found return "With_repr()" @@ -88,7 +88,7 @@ def test_repr(): # object.__str__(self) class With_str: def __str__(self): - SINK1(self) # Flow not found + SINK1(self) #$ MISSING: arg1="with_str, l:97 -> self" OK() # Call not found return "Awesome" @@ -101,7 +101,7 @@ def test_str(): # object.__bytes__(self) class With_bytes: def __bytes__(self): - SINK1(self) # Flow not found + SINK1(self) #$ MISSING: arg1="with_bytes, l:110 -> self" OK() # Call not found return b"Awesome" @@ -114,8 +114,8 @@ def test_bytes(): # object.__format__(self, format_spec) class With_format: def __format__(self, format_spec): - SINK2(format_spec) # Flow not found - SINK1(self) # Flow not found + SINK2(format_spec) #$ MISSING: arg2="arg2, l:125 -> format_spec" + SINK1(self) #$ MISSING: arg1="with_format, l:124 -> self" OK() # Call not found return "Awesome" @@ -139,8 +139,8 @@ def test_format_fstr(): # object.__lt__(self, other) class With_lt: def __lt__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found + SINK2(other) #$ MISSING: arg2="arg2, l:150 -> other" + SINK1(self) #$ MISSING: arg1="with_lt, l:149 -> self" OK() # Call not found return "" @@ -154,8 +154,8 @@ def test_lt(): # object.__le__(self, other) class With_le: def __le__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found + SINK2(other) #$ MISSING: arg2="arg2, l:165 -> other" + SINK1(self) #$ MISSING: arg1="with_le, l:164 -> self" OK() # Call not found return "" @@ -169,8 +169,8 @@ def test_le(): # object.__eq__(self, other) class With_eq: def __eq__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found + SINK2(other) #$ MISSING: arg2="with_eq, l:180 -> other" + SINK1(self) #$ MISSING: arg1="with_eq, l:179 -> self" OK() # Call not found return "" @@ -183,8 +183,8 @@ def test_eq(): # object.__ne__(self, other) class With_ne: def __ne__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found + SINK2(other) #$ MISSING: arg2="with_ne, l:194 -> other" + SINK1(self) #$ MISSING: arg1="with_ne, l:193 -> self" OK() # Call not found return "" @@ -197,8 +197,8 @@ def test_ne(): # object.__gt__(self, other) class With_gt: def __gt__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found + SINK2(other) #$ MISSING: arg2="arg2, l:208 -> other" + SINK1(self) #$ MISSING: arg1="with_gt, l:207 -> self" OK() # Call not found return "" @@ -212,8 +212,8 @@ def test_gt(): # object.__ge__(self, other) class With_ge: def __ge__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found + SINK2(other) #$ MISSING: arg2="arg2, l:223 -> other" + SINK1(self) #$ MISSING: arg1="with_ge, l:222 -> self" OK() # Call not found return "" @@ -227,7 +227,7 @@ def test_ge(): # object.__hash__(self) class With_hash: def __hash__(self): - SINK1(self) # Flow not found + SINK1(self) #$ MISSING: arg1="with_hash, l:236 -> self" arg1="with_hash, l:241 -> self" arg1="with_hash, l:246 -> self" arg1="with_hash, l:251 -> self" OK() # Call not found return 0 @@ -255,7 +255,7 @@ def test_hash_dict(): # object.__bool__(self) class With_bool: def __bool__(self): - SINK1(self) # Flow not found + SINK1(self) #$ MISSING: arg1="with_bool, l:264 -> self" arg1="with_bool, l:269 -> self" OK() # Call not found return True @@ -275,8 +275,8 @@ def test_bool_if(): # object.__getattr__(self, name) class With_getattr: def __getattr__(self, name): - SINK2(name) # Flow not found - SINK1(self) # Flow not found + SINK2(name) #$ MISSING: arg2="with_getattr.arg2, l:286 -> name" + SINK1(self) #$ MISSING: arg1="with_getattr, l:285 -> self" OK() # Call not found return "" @@ -289,8 +289,8 @@ def test_getattr(): # object.__getattribute__(self, name) class With_getattribute: def __getattribute__(self, name): - SINK2(name) # Flow not found - SINK1(self) # Flow not found + SINK2(name) #$ MISSING: arg2="arg2, l:300 -> name" + SINK1(self) #$ MISSING: arg1="with_getattribute, l:299 -> self" OK() # Call not found return "" @@ -303,9 +303,9 @@ def test_getattribute(): # object.__setattr__(self, name, value) class With_setattr: def __setattr__(self, name, value): - SINK3(value) # Flow not found - SINK2(name) # Flow not found - SINK1(self) # Flow not found + SINK3(value) #$ MISSING: arg3="arg3, l:314 -> value" + SINK2(name) #$ MISSING: arg2="arg2, l:315 -> name" + SINK1(self) #$ MISSING: arg1="with_setattr, l:313 -> self" OK() # Call not found @@ -318,8 +318,8 @@ def test_setattr(): # object.__delattr__(self, name) class With_delattr: def __delattr__(self, name): - SINK2(name) # Flow not found - SINK1(self) # Flow not found + SINK2(name) #$ MISSING: arg2="arg2, l:328 -> name" + SINK1(self) #$ MISSING: arg1="with_delattr, l:327 -> self" OK() # Call not found @@ -331,7 +331,7 @@ def test_delattr(): # object.__dir__(self) class With_dir: def __dir__(self): - SINK1(self) # Flow not found + SINK1(self) #$ MISSING: arg1="with_dir, l:340 -> self" OK() # Call not found return [] @@ -350,8 +350,8 @@ class Owner: class With_get: def __get__(self, instance, owner=None): SINK3(owner) # Flow not testsed, use class `Owner` as source to test - SINK2(instance) # Flow not found - SINK1(self) # Flow not found + SINK2(instance) #$ MISSING: arg2="arg2, l:365 -> instance" + SINK1(self) #$ MISSING: arg1="with_get, l:363 -> self" OK() # Call not found return "" @@ -369,9 +369,9 @@ class arg3: # object.__set__(self, instance, value) class With_set: def __set__(self, instance, value): - SINK3(value) # Flow not found - SINK2(instance) # Flow not found - SINK1(self) # Flow not found + SINK3(value) #$ MISSING: arg3="arg3, l:382 -> value" + SINK2(instance) #$ MISSING: arg2="arg2, l:381 -> instance" + SINK1(self) #$ MISSING: arg1="with_set, l:379 -> self" OK() # Call not found @@ -386,8 +386,8 @@ def test_set(): # object.__delete__(self, instance) class With_delete: def __delete__(self, instance): - SINK2(instance) # Flow not found - SINK1(self) # Flow not found + SINK2(instance) #$ MISSING: arg2="arg2, l:397 -> instance" + SINK1(self) #$ MISSING: arg1="with_delete, l:395 -> self" OK() # Call not found @@ -401,9 +401,9 @@ def test_delete(): # object.__set_name__(self, owner, name) class With_set_name: def __set_name__(self, owner, name): - SINK3(name) # Flow not found - SINK2(owner) # Flow not found - SINK1(self) # Flow not found + SINK3(name) #$ MISSING: arg3="arg3, l:412 -> name" + SINK2(owner) #$ MISSING: arg2="arg2, l:412 -> owner" + SINK1(self) #$ MISSING: arg1="with_set_name, l:411 -> self" OK() # Call not found @@ -412,7 +412,7 @@ def test_set_name(): type("arg2", (object,), dict(arg3=with_set_name)) -# 3.3.2.4. __slots__ // We are not testing the suppression of -weakref_ and _dict_ here +# 3.3.2.4. __slots__ // We are not testing the suppression of __weakref__ and __dict__ here # object.__slots__ # __weakref__ # __dict__ @@ -421,7 +421,7 @@ def test_set_name(): # classmethod object.__init_subclass__(cls) class With_init_subclass: def __init_subclass__(cls): - SINK1(cls) # Flow not found + SINK1(cls) #$ MISSING: arg1="Tuple[0], l:429 -> cls" OK() # Call not found @@ -441,7 +441,7 @@ class With_prepare(type): def __prepare__(name, bases, **kwds): SINK3(kwds) # Flow not tested SINK2(bases) # Flow not tested - SINK1(name) # Flow not found + SINK1(name) #$ MISSING: arg1="arg1, l:450 -> name" OK() # Call not found return kwds @@ -455,8 +455,8 @@ class arg1(metaclass=With_prepare): # class.__instancecheck__(self, instance) class With_instancecheck: def __instancecheck__(self, instance): - SINK2(instance) # Flow not found - SINK1(self) # Flow not found + SINK2(instance) #$ MISSING: arg2="arg2, l:466 -> instance" + SINK1(self) #$ MISSING: arg1="with_instancecheck, l:465 -> self" OK() # Call not found return True @@ -470,8 +470,8 @@ def test_instancecheck(): # class.__subclasscheck__(self, subclass) class With_subclasscheck: def __subclasscheck__(self, subclass): - SINK2(subclass) # Flow not found - SINK1(self) # Flow not found + SINK2(subclass) #$ MISSING: arg2="arg2, l:481 -> subclass" + SINK1(self) #$ MISSING: arg1="with_subclasscheck, l:480 -> self" OK() # Call not found return True @@ -486,8 +486,8 @@ def test_subclasscheck(): # classmethod object.__class_getitem__(cls, key) class With_class_getitem: def __class_getitem__(cls, key): - SINK2(key) # Flow not found - SINK1(cls) # Flow not found + SINK2(key) #$ MISSING: arg2="arg2, l:496 -> key" + SINK1(cls) #$ MISSING: arg1="With_class_getitem, l:487 -> cls" OK() # Call not found return object @@ -501,7 +501,7 @@ def test_class_getitem(): # object.__call__(self[, args...]) class With_call: def __call__(self): - SINK1(self) # Flow not found + SINK1(self) #$ MISSING: arg1="with_call, l:509 -> self" OK() # Call not found @@ -514,7 +514,7 @@ def test_call(): # object.__len__(self) class With_len: def __len__(self): - SINK1(self) # Flow not found + SINK1(self) #$ MISSING: arg1="with_len, l:523 -> self" arg1="with_len, l:528 -> self" arg1="with_len, l:533 -> self" OK() # Call not found return 0 @@ -538,7 +538,7 @@ def test_len_if(): # object.__length_hint__(self) class With_length_hint: def __length_hint__(self): - SINK1(self) # Flow not found + SINK1(self) #$ MISSING: arg1="with_length_hint, l:549 -> self" OK() # Call not found return 0 @@ -598,8 +598,8 @@ def test_delitem(): # object.__missing__(self, key) class With_missing(dict): def __missing__(self, key): - SINK2(key) # Flow not found - SINK1(self) # Flow not found + SINK2(key) #$ MISSING: arg2="arg2, l:609 -> key" + SINK1(self) #$ MISSING: arg1="with_missing, l:608 -> self" OK() # Call not found return "" @@ -613,7 +613,7 @@ def test_missing(): # object.__iter__(self) class With_iter: def __iter__(self): - SINK1(self) # Flow not found + SINK1(self) #$ MISSING: arg1="with_iter, l:622 -> self" OK() # Call not found return [].__iter__() @@ -626,7 +626,7 @@ def test_iter(): # object.__reversed__(self) class With_reversed: def __reversed__(self): - SINK1(self) # Flow not found + SINK1(self) #$ MISSING: arg1="with_reversed, l:635 -> self" OK() # Call not found return [].__iter__ @@ -639,8 +639,8 @@ def test_reversed(): # object.__contains__(self, item) class With_contains: def __contains__(self, item): - SINK2(item) # Flow not found - SINK1(self) # Flow not found + SINK2(item) #$ MISSING: arg2="arg2, l:650 -> item" + SINK1(self) #$ MISSING: arg1="with_contains, l:649 -> self" OK() # Call not found return True @@ -760,8 +760,8 @@ def test_mod(): # object.__divmod__(self, other) class With_divmod: def __divmod__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found + SINK2(other) #$ MISSING: arg2="arg2, l:771 -> other" + SINK1(self) #$ MISSING: arg1="with_divmod, l:770 -> self" OK() # Call not found return self @@ -871,8 +871,8 @@ def test_or(): # object.__radd__(self, other) class With_radd: def __radd__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found + SINK2(other) #$ MISSING: arg2="arg2, l:882 -> other" + SINK1(self) #$ MISSING: arg1="with_radd, l:881 -> self" OK() # Call not found return self @@ -886,8 +886,8 @@ def test_radd(): # object.__rsub__(self, other) class With_rsub: def __rsub__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found + SINK2(other) #$ MISSING: arg2="arg2, l:897 -> other" + SINK1(self) #$ MISSING: arg1="with_rsub, l:896 -> self" OK() # Call not found return self @@ -901,8 +901,8 @@ def test_rsub(): # object.__rmul__(self, other) class With_rmul: def __rmul__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found + SINK2(other) #$ MISSING: arg2="arg2, l:912 -> other" + SINK1(self) #$ MISSING: arg1="with_rmul, l:911 -> self" OK() # Call not found return self @@ -916,8 +916,8 @@ def test_rmul(): # object.__rmatmul__(self, other) class With_rmatmul: def __rmatmul__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found + SINK2(other) #$ MISSING: arg2="arg2, l:927 -> other" + SINK1(self) #$ MISSING: arg1="with_rmatmul, l:926 -> self" OK() # Call not found return self @@ -931,8 +931,8 @@ def test_rmatmul(): # object.__rtruediv__(self, other) class With_rtruediv: def __rtruediv__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found + SINK2(other) #$ MISSING: arg2="arg2, l:942 -> other" + SINK1(self) #$ MISSING: arg1="with_rtruediv, l:941 -> self" OK() # Call not found return self @@ -946,8 +946,8 @@ def test_rtruediv(): # object.__rfloordiv__(self, other) class With_rfloordiv: def __rfloordiv__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found + SINK2(other) #$ MISSING: arg2="arg2, l:957 -> other" + SINK1(self) #$ MISSING: arg1="with_rfloordiv, l:956 -> self" OK() # Call not found return self @@ -961,8 +961,8 @@ def test_rfloordiv(): # object.__rmod__(self, other) class With_rmod: def __rmod__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found + SINK2(other) #$ MISSING: arg2="arg2, l:972 -> other" + SINK1(self) #$ MISSING: arg1="with_rmod, l:971 -> self" OK() # Call not found return self @@ -976,8 +976,8 @@ def test_rmod(): # object.__rdivmod__(self, other) class With_rdivmod: def __rdivmod__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found + SINK2(other) #$ MISSING: arg2="arg2, l:987 -> other" + SINK1(self) #$ MISSING: arg1="with_rdivmod, l:986 -> self" OK() # Call not found return self @@ -991,8 +991,8 @@ def test_rdivmod(): # object.__rpow__(self, other[, modulo]) class With_rpow: def __rpow__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found + SINK2(other) #$ MISSING: arg2="arg2, l:1002 -> other" arg2="arg2, l:1008 -> other" + SINK1(self) #$ MISSING: arg1="with_rpow, l:1001 -> self" arg1="with_rpow, l:1007 -> self" OK() # Call not found return self @@ -1012,8 +1012,8 @@ def test_rpow_op(): # object.__rlshift__(self, other) class With_rlshift: def __rlshift__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found + SINK2(other) #$ MISSING: arg2="arg2, l:1023 -> other" + SINK1(self) #$ MISSING: arg1="with_rlshift, l:1022 -> self" OK() # Call not found return self @@ -1027,8 +1027,8 @@ def test_rlshift(): # object.__rrshift__(self, other) class With_rrshift: def __rrshift__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found + SINK2(other) #$ MISSING: arg2="arg2, l:1038 -> other" + SINK1(self) #$ MISSING: arg1="with_rrshift, l:1037 -> self" OK() # Call not found return self @@ -1042,8 +1042,8 @@ def test_rrshift(): # object.__rand__(self, other) class With_rand: def __rand__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found + SINK2(other) #$ MISSING: arg2="arg2, l:1053 -> other" + SINK1(self) #$ MISSING: arg1="with_rand, l:1052 -> self" OK() # Call not found return self @@ -1057,8 +1057,8 @@ def test_rand(): # object.__rxor__(self, other) class With_rxor: def __rxor__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found + SINK2(other) #$ MISSING: arg2="arg2, l:1068 -> other" + SINK1(self) #$ MISSING: arg1="with_rxor, l:1067 -> self" OK() # Call not found return self @@ -1072,8 +1072,8 @@ def test_rxor(): # object.__ror__(self, other) class With_ror: def __ror__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found + SINK2(other) #$ MISSING: arg2="arg2, l:1083 -> other" + SINK1(self) #$ MISSING: arg1="with_ror, l:1082 -> self" OK() # Call not found return self @@ -1087,8 +1087,8 @@ def test_ror(): # object.__iadd__(self, other) class With_iadd: def __iadd__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found + SINK2(other) #$ MISSING: arg2="arg2, l:1098 -> other" + SINK1(self) #$ MISSING: arg1="with_iadd, l:1097 -> self" OK() # Call not found return self @@ -1102,8 +1102,8 @@ def test_iadd(): # object.__isub__(self, other) class With_isub: def __isub__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found + SINK2(other) #$ MISSING: arg2="arg2, l:1113 -> other" + SINK1(self) #$ MISSING: arg1="with_isub, l:1112 -> self" OK() # Call not found return self @@ -1117,8 +1117,8 @@ def test_isub(): # object.__imul__(self, other) class With_imul: def __imul__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found + SINK2(other) #$ MISSING: arg2="arg2, l:1128 -> other" + SINK1(self) #$ MISSING: arg1="with_imul, l:1127 -> self" OK() # Call not found return self @@ -1132,8 +1132,8 @@ def test_imul(): # object.__imatmul__(self, other) class With_imatmul: def __imatmul__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found + SINK2(other) #$ MISSING: arg2="arg2, l:1143 -> other" + SINK1(self) #$ MISSING: arg1="with_imatmul, l:1142 -> self" OK() # Call not found return self @@ -1147,8 +1147,8 @@ def test_imatmul(): # object.__itruediv__(self, other) class With_itruediv: def __itruediv__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found + SINK2(other) #$ MISSING: arg2="arg2, l:1158 -> other" + SINK1(self) #$ MISSING: arg1="with_itruediv, l:1157 -> self" OK() # Call not found return self @@ -1162,8 +1162,8 @@ def test_itruediv(): # object.__ifloordiv__(self, other) class With_ifloordiv: def __ifloordiv__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found + SINK2(other) #$ MISSING: arg2="arg2, l:1173 -> other" + SINK1(self) #$ MISSING: arg1="with_ifloordiv, l:172 -> self" OK() # Call not found return self @@ -1177,8 +1177,8 @@ def test_ifloordiv(): # object.__imod__(self, other) class With_imod: def __imod__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found + SINK2(other) #$ MISSING: arg2="arg2, l:1188 -> other" + SINK1(self) #$ MISSING: arg1="with_imod, l:1187 -> self" OK() # Call not found return self @@ -1192,8 +1192,8 @@ def test_imod(): # object.__ipow__(self, other[, modulo]) class With_ipow: def __ipow__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found + SINK2(other) #$ MISSING: arg2="arg2, l:1203 -> other" + SINK1(self) #$ MISSING: arg1="with_ipow, l:1202 -> self" OK() # Call not found return self @@ -1207,8 +1207,8 @@ def test_ipow(): # object.__ilshift__(self, other) class With_ilshift: def __ilshift__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found + SINK2(other) #$ MISSING: arg2="arg2, l:1218 -> other" + SINK1(self) #$ MISSING: arg1="with_ilshift, l:1217 -> self" OK() # Call not found return self @@ -1222,8 +1222,8 @@ def test_ilshift(): # object.__irshift__(self, other) class With_irshift: def __irshift__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found + SINK2(other) #$ MISSING: arg2="arg2, l:1233 -> other" + SINK1(self) #$ MISSING: arg1="with_irshift, l:1232 -> self" OK() # Call not found return self @@ -1237,8 +1237,8 @@ def test_irshift(): # object.__iand__(self, other) class With_iand: def __iand__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found + SINK2(other) #$ MISSING: arg2="arg2, l:1248 -> other" + SINK1(self) #$ MISSING: arg1="with_iand, l:1247 -> self" OK() # Call not found return self @@ -1252,8 +1252,8 @@ def test_iand(): # object.__ixor__(self, other) class With_ixor: def __ixor__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found + SINK2(other) #$ MISSING: arg2="arg2, l:1263 -> other" + SINK1(self) #$ MISSING: arg1="with_ixor, l:1262 -> self" OK() # Call not found return self @@ -1267,8 +1267,8 @@ def test_ixor(): # object.__ior__(self, other) class With_ior: def __ior__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found + SINK2(other) #$ MISSING: arg2="arg2, l:1278 -> other" + SINK1(self) #$ MISSING: arg1="with_ior, l:1277 -> self" OK() # Call not found return self @@ -1282,7 +1282,7 @@ def test_ior(): # object.__neg__(self) class With_neg: def __neg__(self): - SINK1(self) # Flow not found + SINK1(self) #$ MISSING: arg1="with_neg, l:1291 -> self" OK() # Call not found return self @@ -1295,7 +1295,7 @@ def test_neg(): # object.__pos__(self) class With_pos: def __pos__(self): - SINK1(self) # Flow not found + SINK1(self) #$ MISSING: arg1="with_pos, l:1303 -> self" OK() # Call not found return self @@ -1308,7 +1308,7 @@ def test_pos(): # object.__abs__(self) class With_abs: def __abs__(self): - SINK1(self) # Flow not found + SINK1(self) #$ MISSING: arg1="with_abs, l:1317 -> self" OK() # Call not found return self @@ -1321,7 +1321,7 @@ def test_abs(): # object.__invert__(self) class With_invert: def __invert__(self): - SINK1(self) # Flow not found + SINK1(self) #$ MISSING: arg1="with_invert, l:1330 -> self" OK() # Call not found return self @@ -1334,7 +1334,7 @@ def test_invert(): # object.__complex__(self) class With_complex: def __complex__(self): - SINK1(self) # Flow not found + SINK1(self) #$ MISSING: arg1="with_complex, l:1343 -> self" OK() # Call not found return 0j @@ -1347,7 +1347,7 @@ def test_complex(): # object.__int__(self) class With_int: def __int__(self): - SINK1(self) # Flow not found + SINK1(self) #$ MISSING: arg1="with_int, l:1356 -> self" OK() # Call not found return 0 @@ -1360,7 +1360,7 @@ def test_int(): # object.__float__(self) class With_float: def __float__(self): - SINK1(self) # Flow not found + SINK1(self) #$ MISSING: arg1="with_float, l:1369 -> self" OK() # Call not found return 0.0 @@ -1373,7 +1373,7 @@ def test_float(): # object.__index__(self) class With_index: def __index__(self): - SINK1(self) # Flow not found + SINK1(self) #$ MISSING: arg1="with_index, l:1384 -> self" arg1="with_index, l:1389 -> self" arg1="with_index, l:1394 -> self" arg1="with_index, l:1399 -> self" arg1="with_index, l:1404 -> self" arg1="with_index, l:1409 -> self" arg1="with_index, l:1414 -> self" arg1="with_index, l:1419 -> self" OK() # Call not found return 0 @@ -1423,7 +1423,7 @@ def test_index_complex(): # object.__round__(self[, ndigits]) class With_round: def __round__(self): - SINK1(self) # Flow not found + SINK1(self) #$ MISSING: arg1="with_round, l:1432 -> self" OK() # Call not found return 0 @@ -1436,7 +1436,7 @@ def test_round(): # object.__trunc__(self) class With_trunc: def __trunc__(self): - SINK1(self) # Flow not found + SINK1(self) #$ MISSING: arg1="with_trunc, l:1445 -> self" OK() # Call not found return 0 @@ -1451,7 +1451,7 @@ def test_trunc(): # object.__floor__(self) class With_floor: def __floor__(self): - SINK1(self) # Flow not found + SINK1(self) #$ MISSING: arg1="with_floor, l:1460 -> self" OK() # Call not found return 0 @@ -1466,7 +1466,7 @@ def test_floor(): # object.__ceil__(self) class With_ceil: def __ceil__(self): - SINK1(self) # Flow not found + SINK1(self) #$ MISSING: arg1="with_ceil, l:147 -> self" OK() # Call not found return 0 @@ -1482,7 +1482,7 @@ def test_ceil(): # object.__enter__(self) class With_enter: def __enter__(self): - SINK1(self) # Flow not found + SINK1(self) #$ MISSING: arg1=".0, l:1494 -> self" OK() # Call not found return @@ -1504,7 +1504,7 @@ def __exit__(self, exc_type, exc_value, traceback): SINK4(traceback) # Flow not tested SINK3(exc_value) # Flow not tested SINK2(exc_type) # Flow not tested - SINK1(self) # Flow not found + SINK1(self) #$ MISSING: arg1=".0, l:1513 -> self" OK() # Call not found return @@ -1519,7 +1519,7 @@ def test_exit(): # object.__await__(self) class With_await: def __await__(self): - SINK1(self) # Flow not found + SINK1(self) #$ MISSING: arg1="with_await, l:1528 -> self" OK() # Call not found return (yield from asyncio.coroutine(lambda: "")()) @@ -1538,7 +1538,7 @@ async def atest_await(): # object.__aiter__(self) class With_aiter: def __aiter__(self): - SINK1(self) # Flow not found + SINK1(self) #$ MISSING: arg1="with_aiter, l:1550 -> self" OK() # Call not found return self @@ -1558,7 +1558,7 @@ def __aiter__(self): return self async def __anext__(self): - SINK1(self) # Flow not found + SINK1(self) #$ MISSING: arg1="with_anext, l:1567 -> self" OK() # Call not found raise StopAsyncIteration @@ -1573,7 +1573,7 @@ async def atest_anext(): # object.__aenter__(self) class With_aenter: async def __aenter__(self): - SINK1(self) # Flow not found + SINK1(self) #$ MISSING: arg1="with_aenter, l:1584 -> self" OK() # Call not found async def __aexit__(self, exc_type, exc_value, traceback): @@ -1595,7 +1595,7 @@ async def __aexit__(self, exc_type, exc_value, traceback): SINK4(traceback) # Flow not tested SINK3(exc_value) # Flow not tested SINK2(exc_type) # Flow not tested - SINK1(self) # Flow not found + SINK1(self) #$ MISSING: arg1="with_aexit, l:1603 -> self" OK() # Call not found From 42fa3bdb8191b2e3d506c7dc3e731bb3aaad8536 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 19 Jan 2021 09:13:17 +0100 Subject: [PATCH 08/16] Python: Only consider the closest SOURCE (in use-use flow) a source --- .../dataflow/coverage/dataflow.expected | 114 ---------------- .../dataflow/coverage/datamodel.py | 16 +-- .../experimental/dataflow/coverage/test.py | 122 +++++++++--------- .../dataflow/fieldflow/dataflow.expected | 36 ------ .../test/experimental/dataflow/testConfig.qll | 4 +- 5 files changed, 72 insertions(+), 220 deletions(-) diff --git a/python/ql/test/experimental/dataflow/coverage/dataflow.expected b/python/ql/test/experimental/dataflow/coverage/dataflow.expected index dc0859554086..3bb58f506187 100644 --- a/python/ql/test/experimental/dataflow/coverage/dataflow.expected +++ b/python/ql/test/experimental/dataflow/coverage/dataflow.expected @@ -1,68 +1,13 @@ edges -| datamodel.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module datamodel | datamodel.py:152:14:152:19 | ControlFlowNode for SOURCE | -| datamodel.py:13:1:13:6 | GSSA Variable SOURCE | datamodel.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module datamodel | -| datamodel.py:13:10:13:17 | ControlFlowNode for Str | datamodel.py:13:1:13:6 | GSSA Variable SOURCE | -| datamodel.py:13:10:13:17 | ControlFlowNode for Str | datamodel.py:38:8:38:13 | ControlFlowNode for SOURCE | -| datamodel.py:13:10:13:17 | ControlFlowNode for Str | datamodel.py:71:15:71:20 | ControlFlowNode for SOURCE | -| datamodel.py:13:10:13:17 | ControlFlowNode for Str | datamodel.py:72:18:72:23 | ControlFlowNode for SOURCE | -| datamodel.py:13:10:13:17 | ControlFlowNode for Str | datamodel.py:80:20:80:25 | ControlFlowNode for SOURCE | -| datamodel.py:13:10:13:17 | ControlFlowNode for Str | datamodel.py:81:20:81:25 | ControlFlowNode for SOURCE | | datamodel.py:38:8:38:13 | ControlFlowNode for SOURCE | datamodel.py:38:6:38:17 | ControlFlowNode for f() | -| datamodel.py:38:8:38:13 | ControlFlowNode for SOURCE | datamodel.py:71:15:71:20 | ControlFlowNode for SOURCE | -| datamodel.py:38:8:38:13 | ControlFlowNode for SOURCE | datamodel.py:72:18:72:23 | ControlFlowNode for SOURCE | -| datamodel.py:38:8:38:13 | ControlFlowNode for SOURCE | datamodel.py:80:20:80:25 | ControlFlowNode for SOURCE | -| datamodel.py:38:8:38:13 | ControlFlowNode for SOURCE | datamodel.py:81:20:81:25 | ControlFlowNode for SOURCE | | datamodel.py:71:15:71:20 | ControlFlowNode for SOURCE | datamodel.py:71:6:71:24 | ControlFlowNode for Attribute() | -| datamodel.py:71:15:71:20 | ControlFlowNode for SOURCE | datamodel.py:72:18:72:23 | ControlFlowNode for SOURCE | -| datamodel.py:71:15:71:20 | ControlFlowNode for SOURCE | datamodel.py:80:20:80:25 | ControlFlowNode for SOURCE | -| datamodel.py:71:15:71:20 | ControlFlowNode for SOURCE | datamodel.py:81:20:81:25 | ControlFlowNode for SOURCE | | datamodel.py:72:18:72:23 | ControlFlowNode for SOURCE | datamodel.py:72:6:72:27 | ControlFlowNode for Attribute() | -| datamodel.py:72:18:72:23 | ControlFlowNode for SOURCE | datamodel.py:80:20:80:25 | ControlFlowNode for SOURCE | -| datamodel.py:72:18:72:23 | ControlFlowNode for SOURCE | datamodel.py:81:20:81:25 | ControlFlowNode for SOURCE | -| datamodel.py:73:18:73:23 | ControlFlowNode for SOURCE | datamodel.py:80:20:80:25 | ControlFlowNode for SOURCE | -| datamodel.py:73:18:73:23 | ControlFlowNode for SOURCE | datamodel.py:81:20:81:25 | ControlFlowNode for SOURCE | | datamodel.py:80:20:80:25 | ControlFlowNode for SOURCE | datamodel.py:80:6:80:26 | ControlFlowNode for Attribute() | -| datamodel.py:80:20:80:25 | ControlFlowNode for SOURCE | datamodel.py:81:20:81:25 | ControlFlowNode for SOURCE | | datamodel.py:81:20:81:25 | ControlFlowNode for SOURCE | datamodel.py:81:6:81:26 | ControlFlowNode for Attribute() | | datamodel.py:152:5:152:8 | [post store] ControlFlowNode for self [Attribute b] | datamodel.py:155:14:155:25 | ControlFlowNode for Customized() [Attribute b] | | datamodel.py:152:14:152:19 | ControlFlowNode for SOURCE | datamodel.py:152:5:152:8 | [post store] ControlFlowNode for self [Attribute b] | | datamodel.py:155:14:155:25 | ControlFlowNode for Customized() [Attribute b] | datamodel.py:159:6:159:15 | ControlFlowNode for customized [Attribute b] | | datamodel.py:159:6:159:15 | ControlFlowNode for customized [Attribute b] | datamodel.py:159:6:159:17 | ControlFlowNode for Attribute | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:42:21:42:26 | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:55:9:55:14 | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:87:10:87:15 | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:93:10:93:15 | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:103:10:103:15 | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:108:22:108:27 | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:113:10:113:15 | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:125:10:125:15 | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:130:10:130:15 | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:135:22:135:27 | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:140:10:140:15 | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:152:15:152:20 | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:157:15:157:20 | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:183:23:183:28 | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:188:25:188:30 | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:199:34:199:39 | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:336:11:336:16 | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:340:11:340:16 | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:344:16:344:21 | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:367:28:367:33 | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:375:30:375:35 | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:383:36:383:41 | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:391:33:391:38 | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:399:39:399:44 | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:420:10:420:15 | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:428:34:428:39 | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:452:12:452:17 | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:459:28:459:33 | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:473:30:473:35 | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:487:36:487:41 | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:492:33:492:38 | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:497:39:497:44 | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:509:9:509:14 | ControlFlowNode for SOURCE | -| test.py:20:1:20:6 | GSSA Variable SOURCE | test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | -| test.py:20:10:20:17 | ControlFlowNode for Str | test.py:20:1:20:6 | GSSA Variable SOURCE | | test.py:42:10:42:26 | ControlFlowNode for Tuple [Tuple element at index 1] | test.py:43:9:43:9 | ControlFlowNode for x [Tuple element at index 1] | | test.py:42:21:42:26 | ControlFlowNode for SOURCE | test.py:42:10:42:26 | ControlFlowNode for Tuple [Tuple element at index 1] | | test.py:43:9:43:9 | ControlFlowNode for x [Tuple element at index 1] | test.py:43:9:43:12 | ControlFlowNode for Subscript | @@ -180,16 +125,12 @@ edges | test.py:509:9:509:14 | ControlFlowNode for SOURCE | test.py:511:10:511:10 | ControlFlowNode for a | | test.py:509:9:509:14 | ControlFlowNode for SOURCE | test.py:516:10:516:10 | ControlFlowNode for b | nodes -| datamodel.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module datamodel | semmle.label | ModuleVariableNode for Global Variable SOURCE in Module datamodel | -| datamodel.py:13:1:13:6 | GSSA Variable SOURCE | semmle.label | GSSA Variable SOURCE | -| datamodel.py:13:10:13:17 | ControlFlowNode for Str | semmle.label | ControlFlowNode for Str | | datamodel.py:38:6:38:17 | ControlFlowNode for f() | semmle.label | ControlFlowNode for f() | | datamodel.py:38:8:38:13 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | | datamodel.py:71:6:71:24 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | datamodel.py:71:15:71:20 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | | datamodel.py:72:6:72:27 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | datamodel.py:72:18:72:23 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | -| datamodel.py:73:18:73:23 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | | datamodel.py:80:6:80:26 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | datamodel.py:80:20:80:25 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | | datamodel.py:81:6:81:26 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | @@ -199,9 +140,6 @@ nodes | datamodel.py:155:14:155:25 | ControlFlowNode for Customized() [Attribute b] | semmle.label | ControlFlowNode for Customized() [Attribute b] | | datamodel.py:159:6:159:15 | ControlFlowNode for customized [Attribute b] | semmle.label | ControlFlowNode for customized [Attribute b] | | datamodel.py:159:6:159:17 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | semmle.label | ModuleVariableNode for Global Variable SOURCE in Module test | -| test.py:20:1:20:6 | GSSA Variable SOURCE | semmle.label | GSSA Variable SOURCE | -| test.py:20:10:20:17 | ControlFlowNode for Str | semmle.label | ControlFlowNode for Str | | test.py:42:10:42:26 | ControlFlowNode for Tuple [Tuple element at index 1] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 1] | | test.py:42:21:42:26 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | | test.py:43:9:43:9 | ControlFlowNode for x [Tuple element at index 1] | semmle.label | ControlFlowNode for x [Tuple element at index 1] | @@ -356,99 +294,47 @@ nodes | test.py:511:10:511:10 | ControlFlowNode for a | semmle.label | ControlFlowNode for a | | test.py:516:10:516:10 | ControlFlowNode for b | semmle.label | ControlFlowNode for b | #select -| datamodel.py:38:6:38:17 | ControlFlowNode for f() | datamodel.py:13:10:13:17 | ControlFlowNode for Str | datamodel.py:38:6:38:17 | ControlFlowNode for f() | Flow found | | datamodel.py:38:6:38:17 | ControlFlowNode for f() | datamodel.py:38:8:38:13 | ControlFlowNode for SOURCE | datamodel.py:38:6:38:17 | ControlFlowNode for f() | Flow found | -| datamodel.py:71:6:71:24 | ControlFlowNode for Attribute() | datamodel.py:13:10:13:17 | ControlFlowNode for Str | datamodel.py:71:6:71:24 | ControlFlowNode for Attribute() | Flow found | -| datamodel.py:71:6:71:24 | ControlFlowNode for Attribute() | datamodel.py:38:8:38:13 | ControlFlowNode for SOURCE | datamodel.py:71:6:71:24 | ControlFlowNode for Attribute() | Flow found | | datamodel.py:71:6:71:24 | ControlFlowNode for Attribute() | datamodel.py:71:15:71:20 | ControlFlowNode for SOURCE | datamodel.py:71:6:71:24 | ControlFlowNode for Attribute() | Flow found | -| datamodel.py:72:6:72:27 | ControlFlowNode for Attribute() | datamodel.py:13:10:13:17 | ControlFlowNode for Str | datamodel.py:72:6:72:27 | ControlFlowNode for Attribute() | Flow found | -| datamodel.py:72:6:72:27 | ControlFlowNode for Attribute() | datamodel.py:38:8:38:13 | ControlFlowNode for SOURCE | datamodel.py:72:6:72:27 | ControlFlowNode for Attribute() | Flow found | -| datamodel.py:72:6:72:27 | ControlFlowNode for Attribute() | datamodel.py:71:15:71:20 | ControlFlowNode for SOURCE | datamodel.py:72:6:72:27 | ControlFlowNode for Attribute() | Flow found | | datamodel.py:72:6:72:27 | ControlFlowNode for Attribute() | datamodel.py:72:18:72:23 | ControlFlowNode for SOURCE | datamodel.py:72:6:72:27 | ControlFlowNode for Attribute() | Flow found | -| datamodel.py:80:6:80:26 | ControlFlowNode for Attribute() | datamodel.py:13:10:13:17 | ControlFlowNode for Str | datamodel.py:80:6:80:26 | ControlFlowNode for Attribute() | Flow found | -| datamodel.py:80:6:80:26 | ControlFlowNode for Attribute() | datamodel.py:38:8:38:13 | ControlFlowNode for SOURCE | datamodel.py:80:6:80:26 | ControlFlowNode for Attribute() | Flow found | -| datamodel.py:80:6:80:26 | ControlFlowNode for Attribute() | datamodel.py:71:15:71:20 | ControlFlowNode for SOURCE | datamodel.py:80:6:80:26 | ControlFlowNode for Attribute() | Flow found | -| datamodel.py:80:6:80:26 | ControlFlowNode for Attribute() | datamodel.py:72:18:72:23 | ControlFlowNode for SOURCE | datamodel.py:80:6:80:26 | ControlFlowNode for Attribute() | Flow found | -| datamodel.py:80:6:80:26 | ControlFlowNode for Attribute() | datamodel.py:73:18:73:23 | ControlFlowNode for SOURCE | datamodel.py:80:6:80:26 | ControlFlowNode for Attribute() | Flow found | | datamodel.py:80:6:80:26 | ControlFlowNode for Attribute() | datamodel.py:80:20:80:25 | ControlFlowNode for SOURCE | datamodel.py:80:6:80:26 | ControlFlowNode for Attribute() | Flow found | -| datamodel.py:81:6:81:26 | ControlFlowNode for Attribute() | datamodel.py:13:10:13:17 | ControlFlowNode for Str | datamodel.py:81:6:81:26 | ControlFlowNode for Attribute() | Flow found | -| datamodel.py:81:6:81:26 | ControlFlowNode for Attribute() | datamodel.py:38:8:38:13 | ControlFlowNode for SOURCE | datamodel.py:81:6:81:26 | ControlFlowNode for Attribute() | Flow found | -| datamodel.py:81:6:81:26 | ControlFlowNode for Attribute() | datamodel.py:71:15:71:20 | ControlFlowNode for SOURCE | datamodel.py:81:6:81:26 | ControlFlowNode for Attribute() | Flow found | -| datamodel.py:81:6:81:26 | ControlFlowNode for Attribute() | datamodel.py:72:18:72:23 | ControlFlowNode for SOURCE | datamodel.py:81:6:81:26 | ControlFlowNode for Attribute() | Flow found | -| datamodel.py:81:6:81:26 | ControlFlowNode for Attribute() | datamodel.py:73:18:73:23 | ControlFlowNode for SOURCE | datamodel.py:81:6:81:26 | ControlFlowNode for Attribute() | Flow found | -| datamodel.py:81:6:81:26 | ControlFlowNode for Attribute() | datamodel.py:80:20:80:25 | ControlFlowNode for SOURCE | datamodel.py:81:6:81:26 | ControlFlowNode for Attribute() | Flow found | | datamodel.py:81:6:81:26 | ControlFlowNode for Attribute() | datamodel.py:81:20:81:25 | ControlFlowNode for SOURCE | datamodel.py:81:6:81:26 | ControlFlowNode for Attribute() | Flow found | -| datamodel.py:159:6:159:17 | ControlFlowNode for Attribute | datamodel.py:13:10:13:17 | ControlFlowNode for Str | datamodel.py:159:6:159:17 | ControlFlowNode for Attribute | Flow found | | datamodel.py:159:6:159:17 | ControlFlowNode for Attribute | datamodel.py:152:14:152:19 | ControlFlowNode for SOURCE | datamodel.py:159:6:159:17 | ControlFlowNode for Attribute | Flow found | -| test.py:44:10:44:10 | ControlFlowNode for y | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:44:10:44:10 | ControlFlowNode for y | Flow found | | test.py:44:10:44:10 | ControlFlowNode for y | test.py:42:21:42:26 | ControlFlowNode for SOURCE | test.py:44:10:44:10 | ControlFlowNode for y | Flow found | -| test.py:56:10:56:10 | ControlFlowNode for x | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:56:10:56:10 | ControlFlowNode for x | Flow found | | test.py:56:10:56:10 | ControlFlowNode for x | test.py:55:9:55:14 | ControlFlowNode for SOURCE | test.py:56:10:56:10 | ControlFlowNode for x | Flow found | | test.py:62:10:62:10 | ControlFlowNode for x | test.py:61:9:61:16 | ControlFlowNode for Str | test.py:62:10:62:10 | ControlFlowNode for x | Flow found | | test.py:67:10:67:10 | ControlFlowNode for x | test.py:66:9:66:17 | ControlFlowNode for Str | test.py:67:10:67:10 | ControlFlowNode for x | Flow found | | test.py:72:10:72:10 | ControlFlowNode for x | test.py:71:9:71:10 | ControlFlowNode for IntegerLiteral | test.py:72:10:72:10 | ControlFlowNode for x | Flow found | | test.py:77:10:77:10 | ControlFlowNode for x | test.py:76:9:76:12 | ControlFlowNode for FloatLiteral | test.py:77:10:77:10 | ControlFlowNode for x | Flow found | -| test.py:88:10:88:10 | ControlFlowNode for x | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:88:10:88:10 | ControlFlowNode for x | Flow found | | test.py:88:10:88:10 | ControlFlowNode for x | test.py:87:10:87:15 | ControlFlowNode for SOURCE | test.py:88:10:88:10 | ControlFlowNode for x | Flow found | -| test.py:94:10:94:13 | ControlFlowNode for Subscript | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:94:10:94:13 | ControlFlowNode for Subscript | Flow found | | test.py:94:10:94:13 | ControlFlowNode for Subscript | test.py:93:10:93:15 | ControlFlowNode for SOURCE | test.py:94:10:94:13 | ControlFlowNode for Subscript | Flow found | -| test.py:104:10:104:13 | ControlFlowNode for Subscript | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:104:10:104:13 | ControlFlowNode for Subscript | Flow found | | test.py:104:10:104:13 | ControlFlowNode for Subscript | test.py:103:10:103:15 | ControlFlowNode for SOURCE | test.py:104:10:104:13 | ControlFlowNode for Subscript | Flow found | -| test.py:109:10:109:13 | ControlFlowNode for Subscript | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:109:10:109:13 | ControlFlowNode for Subscript | Flow found | | test.py:109:10:109:13 | ControlFlowNode for Subscript | test.py:108:22:108:27 | ControlFlowNode for SOURCE | test.py:109:10:109:13 | ControlFlowNode for Subscript | Flow found | -| test.py:115:10:115:13 | ControlFlowNode for Subscript | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:115:10:115:13 | ControlFlowNode for Subscript | Flow found | | test.py:115:10:115:13 | ControlFlowNode for Subscript | test.py:113:10:113:15 | ControlFlowNode for SOURCE | test.py:115:10:115:13 | ControlFlowNode for Subscript | Flow found | -| test.py:126:10:126:16 | ControlFlowNode for Attribute() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:126:10:126:16 | ControlFlowNode for Attribute() | Flow found | | test.py:126:10:126:16 | ControlFlowNode for Attribute() | test.py:125:10:125:15 | ControlFlowNode for SOURCE | test.py:126:10:126:16 | ControlFlowNode for Attribute() | Flow found | -| test.py:131:10:131:16 | ControlFlowNode for Attribute() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:131:10:131:16 | ControlFlowNode for Attribute() | Flow found | | test.py:131:10:131:16 | ControlFlowNode for Attribute() | test.py:130:10:130:15 | ControlFlowNode for SOURCE | test.py:131:10:131:16 | ControlFlowNode for Attribute() | Flow found | -| test.py:136:10:136:16 | ControlFlowNode for Attribute() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:136:10:136:16 | ControlFlowNode for Attribute() | Flow found | | test.py:136:10:136:16 | ControlFlowNode for Attribute() | test.py:135:22:135:27 | ControlFlowNode for SOURCE | test.py:136:10:136:16 | ControlFlowNode for Attribute() | Flow found | -| test.py:142:10:142:16 | ControlFlowNode for Attribute() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:142:10:142:16 | ControlFlowNode for Attribute() | Flow found | | test.py:142:10:142:16 | ControlFlowNode for Attribute() | test.py:140:10:140:15 | ControlFlowNode for SOURCE | test.py:142:10:142:16 | ControlFlowNode for Attribute() | Flow found | -| test.py:153:10:153:15 | ControlFlowNode for Subscript | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:153:10:153:15 | ControlFlowNode for Subscript | Flow found | | test.py:153:10:153:15 | ControlFlowNode for Subscript | test.py:152:15:152:20 | ControlFlowNode for SOURCE | test.py:153:10:153:15 | ControlFlowNode for Subscript | Flow found | -| test.py:158:10:158:19 | ControlFlowNode for Attribute() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:158:10:158:19 | ControlFlowNode for Attribute() | Flow found | | test.py:158:10:158:19 | ControlFlowNode for Attribute() | test.py:157:15:157:20 | ControlFlowNode for SOURCE | test.py:158:10:158:19 | ControlFlowNode for Attribute() | Flow found | -| test.py:184:10:184:13 | ControlFlowNode for Subscript | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:184:10:184:13 | ControlFlowNode for Subscript | Flow found | | test.py:184:10:184:13 | ControlFlowNode for Subscript | test.py:183:23:183:28 | ControlFlowNode for SOURCE | test.py:184:10:184:13 | ControlFlowNode for Subscript | Flow found | -| test.py:189:10:189:13 | ControlFlowNode for Subscript | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:189:10:189:13 | ControlFlowNode for Subscript | Flow found | | test.py:189:10:189:13 | ControlFlowNode for Subscript | test.py:188:25:188:30 | ControlFlowNode for SOURCE | test.py:189:10:189:13 | ControlFlowNode for Subscript | Flow found | -| test.py:200:10:200:13 | ControlFlowNode for Subscript | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:200:10:200:13 | ControlFlowNode for Subscript | Flow found | | test.py:200:10:200:13 | ControlFlowNode for Subscript | test.py:199:34:199:39 | ControlFlowNode for SOURCE | test.py:200:10:200:13 | ControlFlowNode for Subscript | Flow found | -| test.py:336:10:336:21 | ControlFlowNode for Subscript | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:336:10:336:21 | ControlFlowNode for Subscript | Flow found | | test.py:336:10:336:21 | ControlFlowNode for Subscript | test.py:336:11:336:16 | ControlFlowNode for SOURCE | test.py:336:10:336:21 | ControlFlowNode for Subscript | Flow found | -| test.py:340:10:340:20 | ControlFlowNode for Subscript | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:340:10:340:20 | ControlFlowNode for Subscript | Flow found | | test.py:340:10:340:20 | ControlFlowNode for Subscript | test.py:340:11:340:16 | ControlFlowNode for SOURCE | test.py:340:10:340:20 | ControlFlowNode for Subscript | Flow found | -| test.py:344:10:344:27 | ControlFlowNode for Subscript | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:344:10:344:27 | ControlFlowNode for Subscript | Flow found | | test.py:344:10:344:27 | ControlFlowNode for Subscript | test.py:344:16:344:21 | ControlFlowNode for SOURCE | test.py:344:10:344:27 | ControlFlowNode for Subscript | Flow found | -| test.py:367:10:367:34 | ControlFlowNode for second() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:367:10:367:34 | ControlFlowNode for second() | Flow found | | test.py:367:10:367:34 | ControlFlowNode for second() | test.py:367:28:367:33 | ControlFlowNode for SOURCE | test.py:367:10:367:34 | ControlFlowNode for second() | Flow found | -| test.py:375:10:375:36 | ControlFlowNode for second() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:375:10:375:36 | ControlFlowNode for second() | Flow found | | test.py:375:10:375:36 | ControlFlowNode for second() | test.py:375:30:375:35 | ControlFlowNode for SOURCE | test.py:375:10:375:36 | ControlFlowNode for second() | Flow found | -| test.py:383:10:383:43 | ControlFlowNode for second() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:383:10:383:43 | ControlFlowNode for second() | Flow found | | test.py:383:10:383:43 | ControlFlowNode for second() | test.py:383:36:383:41 | ControlFlowNode for SOURCE | test.py:383:10:383:43 | ControlFlowNode for second() | Flow found | -| test.py:391:10:391:39 | ControlFlowNode for f_extra_pos() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:391:10:391:39 | ControlFlowNode for f_extra_pos() | Flow found | | test.py:391:10:391:39 | ControlFlowNode for f_extra_pos() | test.py:391:33:391:38 | ControlFlowNode for SOURCE | test.py:391:10:391:39 | ControlFlowNode for f_extra_pos() | Flow found | -| test.py:399:10:399:45 | ControlFlowNode for f_extra_keyword() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:399:10:399:45 | ControlFlowNode for f_extra_keyword() | Flow found | | test.py:399:10:399:45 | ControlFlowNode for f_extra_keyword() | test.py:399:39:399:44 | ControlFlowNode for SOURCE | test.py:399:10:399:45 | ControlFlowNode for f_extra_keyword() | Flow found | -| test.py:420:10:420:38 | ControlFlowNode for IfExp | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:420:10:420:38 | ControlFlowNode for IfExp | Flow found | | test.py:420:10:420:38 | ControlFlowNode for IfExp | test.py:420:10:420:15 | ControlFlowNode for SOURCE | test.py:420:10:420:38 | ControlFlowNode for IfExp | Flow found | -| test.py:428:10:428:39 | ControlFlowNode for IfExp | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:428:10:428:39 | ControlFlowNode for IfExp | Flow found | | test.py:428:10:428:39 | ControlFlowNode for IfExp | test.py:428:34:428:39 | ControlFlowNode for SOURCE | test.py:428:10:428:39 | ControlFlowNode for IfExp | Flow found | -| test.py:452:10:452:18 | ControlFlowNode for f() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:452:10:452:18 | ControlFlowNode for f() | Flow found | | test.py:452:10:452:18 | ControlFlowNode for f() | test.py:452:12:452:17 | ControlFlowNode for SOURCE | test.py:452:10:452:18 | ControlFlowNode for f() | Flow found | -| test.py:459:10:459:34 | ControlFlowNode for second() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:459:10:459:34 | ControlFlowNode for second() | Flow found | | test.py:459:10:459:34 | ControlFlowNode for second() | test.py:459:28:459:33 | ControlFlowNode for SOURCE | test.py:459:10:459:34 | ControlFlowNode for second() | Flow found | -| test.py:473:10:473:36 | ControlFlowNode for second() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:473:10:473:36 | ControlFlowNode for second() | Flow found | | test.py:473:10:473:36 | ControlFlowNode for second() | test.py:473:30:473:35 | ControlFlowNode for SOURCE | test.py:473:10:473:36 | ControlFlowNode for second() | Flow found | -| test.py:487:10:487:43 | ControlFlowNode for second() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:487:10:487:43 | ControlFlowNode for second() | Flow found | | test.py:487:10:487:43 | ControlFlowNode for second() | test.py:487:36:487:41 | ControlFlowNode for SOURCE | test.py:487:10:487:43 | ControlFlowNode for second() | Flow found | -| test.py:492:10:492:39 | ControlFlowNode for f_extra_pos() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:492:10:492:39 | ControlFlowNode for f_extra_pos() | Flow found | | test.py:492:10:492:39 | ControlFlowNode for f_extra_pos() | test.py:492:33:492:38 | ControlFlowNode for SOURCE | test.py:492:10:492:39 | ControlFlowNode for f_extra_pos() | Flow found | -| test.py:497:10:497:45 | ControlFlowNode for f_extra_keyword() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:497:10:497:45 | ControlFlowNode for f_extra_keyword() | Flow found | | test.py:497:10:497:45 | ControlFlowNode for f_extra_keyword() | test.py:497:39:497:44 | ControlFlowNode for SOURCE | test.py:497:10:497:45 | ControlFlowNode for f_extra_keyword() | Flow found | -| test.py:511:10:511:10 | ControlFlowNode for a | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:511:10:511:10 | ControlFlowNode for a | Flow found | | test.py:511:10:511:10 | ControlFlowNode for a | test.py:509:9:509:14 | ControlFlowNode for SOURCE | test.py:511:10:511:10 | ControlFlowNode for a | Flow found | -| test.py:516:10:516:10 | ControlFlowNode for b | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:516:10:516:10 | ControlFlowNode for b | Flow found | | test.py:516:10:516:10 | ControlFlowNode for b | test.py:509:9:509:14 | ControlFlowNode for SOURCE | test.py:516:10:516:10 | ControlFlowNode for b | Flow found | diff --git a/python/ql/test/experimental/dataflow/coverage/datamodel.py b/python/ql/test/experimental/dataflow/coverage/datamodel.py index 0d921a2cb855..3f11593dbd19 100644 --- a/python/ql/test/experimental/dataflow/coverage/datamodel.py +++ b/python/ql/test/experimental/dataflow/coverage/datamodel.py @@ -35,7 +35,7 @@ def SINK_F(x): def f(a, b): return a -SINK(f(SOURCE, 3)) #$ flow="SOURCE -> f(..)" flow="'source', l:13 -> f(..)" +SINK(f(SOURCE, 3)) #$ flow="SOURCE -> f(..)" # Instance methods # An instance method object combines a class, a class instance and any callable object (normally a user-defined function). @@ -68,18 +68,18 @@ async def coro(self, x): func_obj = c.method.__func__ # When an instance method object is called, the underlying function (__func__) is called, inserting the class instance (__self__) in front of the argument list. For instance, when C is a class which contains a definition for a function f(), and x is an instance of C, calling x.f(1) is equivalent to calling C.f(x, 1). -SINK(c.method(SOURCE, C)) #$ flow="SOURCE -> c.method(..)" flow="SOURCE, l:38 -> c.method(..)" flow="'source', l:13 -> c.method(..)" -SINK(C.method(c, SOURCE, C)) #$ flow="SOURCE -> C.method(..)" flow="SOURCE, l:38 -> C.method(..)" flow="SOURCE, l:71 -> C.method(..)" flow="'source', l:13 -> C.method(..)" -SINK(func_obj(c, SOURCE, C)) #$ MISSING: flow="SOURCE -> func_obj(..)" flow="SOURCE, l:38 -> func_obj(..)" flow="SOURCE, l:71 -> func_obj(..)" flow="SOURCE, l:72 -> func_obj(..)" flow="'source', l:13 -> func_obj()" +SINK(c.method(SOURCE, C)) #$ flow="SOURCE -> c.method(..)" +SINK(C.method(c, SOURCE, C)) #$ flow="SOURCE -> C.method(..)" +SINK(func_obj(c, SOURCE, C)) #$ MISSING: flow="SOURCE -> func_obj(..)" # When an instance method object is created by retrieving a class method object from a class or instance, its __self__ attribute is the class itself, and its __func__ attribute is the function object underlying the class method. c_func_obj = C.classmethod.__func__ # When an instance method object is derived from a class method object, the “class instance” stored in __self__ will actually be the class itself, so that calling either x.f(1) or C.f(1) is equivalent to calling f(C,1) where f is the underlying function. -SINK(c.classmethod(SOURCE)) #$ flow="SOURCE -> c.classmethod(..)" flow="SOURCE, l:38 -> c.classmethod(..)" flow="SOURCE, l:71 -> c.classmethod(..)" flow="SOURCE, l:72 -> c.classmethod(..)" flow="SOURCE, l:73 -> c.classmethod(..)" flow="'source', l:13 -> c.classmethod(..)" -SINK(C.classmethod(SOURCE)) #$ flow="SOURCE -> C.classmethod(..)" flow="SOURCE, l:38 -> C.classmethod(..)" flow="SOURCE, l:71 -> C.classmethod(..)" flow="SOURCE, l:72 -> C.classmethod(..)" flow="SOURCE, l:73 -> C.classmethod(..)" flow="SOURCE, l:80 -> C.classmethod(..)" flow="'source', l:13 -> C.classmethod(..)" -SINK(c_func_obj(C, SOURCE)) #$ MISSING: flow="SOURCE -> c_func_obj(..)" flow="SOURCE, l:38 -> c_func_obj(..)" flow="SOURCE, l:71 -> c_func_obj(..)" flow="SOURCE, l:72 -> c_func_obj(..)" flow="SOURCE, l:73 -> c_func_obj(..)" flow="SOURCE, l:80 -> c_func_obj(..)" flow="SOURCE, l:81 -> c_func_obj(..)" flow="'source', l:13 -> c_func_obj()" +SINK(c.classmethod(SOURCE)) #$ flow="SOURCE -> c.classmethod(..)" +SINK(C.classmethod(SOURCE)) #$ flow="SOURCE -> C.classmethod(..)" +SINK(c_func_obj(C, SOURCE)) #$ MISSING: flow="SOURCE -> c_func_obj(..)" # Generator functions # A function or method which uses the yield statement (see section The yield statement) is called a generator function. Such a function, when called, always returns an iterator object which can be used to execute the body of the function: calling the iterator’s iterator.__next__() method will cause the function to execute until it provides a value using the yield statement. When the function executes a return statement or falls off the end, a StopIteration exception is raised and the iterator will have reached the end of the set of values to be returned. @@ -156,4 +156,4 @@ def __init__(self): SINK(Customized.a) SINK_F(Customized.b) SINK(customized.a) -SINK(customized.b) #$ flow="SOURCE, l:152 -> customized.b" flow="'source', l:13 -> customized.b" +SINK(customized.b) #$ flow="SOURCE, l:152 -> customized.b" diff --git a/python/ql/test/experimental/dataflow/coverage/test.py b/python/ql/test/experimental/dataflow/coverage/test.py index 616837a9d3b2..2a1f7dca58c3 100644 --- a/python/ql/test/experimental/dataflow/coverage/test.py +++ b/python/ql/test/experimental/dataflow/coverage/test.py @@ -41,7 +41,7 @@ def SINK_F(x): def test_tuple_with_local_flow(): x = (NONSOURCE, SOURCE) y = x[1] - SINK(y) #$ flow="SOURCE, l:42 -> y" flow="'source', l:20 -> y" + SINK(y) #$ flow="SOURCE, l:42 -> y" def test_tuple_negative(): @@ -53,13 +53,13 @@ def test_tuple_negative(): # 6.2.1. Identifiers (Names) def test_names(): x = SOURCE - SINK(x) #$ flow="SOURCE, l:55 -> x" flow="'source', l:20 -> x" + SINK(x) #$ flow="SOURCE, l:55 -> x" # 6.2.2. Literals def test_string_literal(): x = "source" - SINK(x) #$ flow="'source', l:61 -> x" + SINK(x) #$ flow="'source', l:61 -> x" def test_bytes_literal(): @@ -85,13 +85,13 @@ def test_imagnumber_literal(): # 6.2.3. Parenthesized forms def test_parenthesized_form(): x = (SOURCE) - SINK(x) #$ flow="SOURCE, l:87 -> x" flow="'source', l:20 -> x" + SINK(x) #$ flow="SOURCE, l:87 -> x" # 6.2.5. List displays def test_list_display(): x = [SOURCE] - SINK(x[0]) #$ flow="SOURCE, l:93 -> x[0]" flow="'source', l:20 -> x[0]" + SINK(x[0]) #$ flow="SOURCE, l:93 -> x[0]" def test_list_display_negative(): @@ -101,109 +101,109 @@ def test_list_display_negative(): def test_list_comprehension(): x = [SOURCE for y in [NONSOURCE]] - SINK(x[0]) #$ flow="SOURCE, l:103 -> x[0]" flow="'source', l:20 -> x[0]" + SINK(x[0]) #$ flow="SOURCE, l:103 -> x[0]" def test_list_comprehension_flow(): x = [y for y in [SOURCE]] - SINK(x[0]) #$ flow="SOURCE, l:108 -> x[0]" flow="'source', l:20 -> x[0]" + SINK(x[0]) #$ flow="SOURCE, l:108 -> x[0]" def test_list_comprehension_inflow(): l = [SOURCE] x = [y for y in l] - SINK(x[0]) #$ flow="SOURCE, l:113 -> x[0]" flow="'source', l:20 -> x[0]" + SINK(x[0]) #$ flow="SOURCE, l:113 -> x[0]" def test_nested_list_display(): x = [*[SOURCE]] - SINK(x[0]) #$ MISSING:flow="SOURCE, l:119 -> x[0]" MISSING:flow="'source', l:20 -> x[0]" + SINK(x[0]) #$ MISSING:flow="SOURCE, l:119 -> x[0]" # 6.2.6. Set displays def test_set_display(): x = {SOURCE} - SINK(x.pop()) #$ flow="SOURCE, l:125 -> x.pop()" flow="'source', l:20 -> x.pop()" + SINK(x.pop()) #$ flow="SOURCE, l:125 -> x.pop()" def test_set_comprehension(): x = {SOURCE for y in [NONSOURCE]} - SINK(x.pop()) #$ flow="SOURCE, l:130 -> x.pop()" flow="'source', l:20 -> x.pop()" + SINK(x.pop()) #$ flow="SOURCE, l:130 -> x.pop()" def test_set_comprehension_flow(): x = {y for y in [SOURCE]} - SINK(x.pop()) #$ flow="SOURCE, l:135 -> x.pop()" flow="'source', l:20 -> x.pop()" + SINK(x.pop()) #$ flow="SOURCE, l:135 -> x.pop()" def test_set_comprehension_inflow(): l = {SOURCE} x = {y for y in l} - SINK(x.pop()) #$ flow="SOURCE, l:140 -> x.pop()" flow="'source', l:20 -> x.pop()" + SINK(x.pop()) #$ flow="SOURCE, l:140 -> x.pop()" def test_nested_set_display(): x = {*{SOURCE}} - SINK(x.pop()) #$ MISSING:flow="SOURCE, l:146 -> x.pop()" MISSING:flow="'source', l:20 -> x.pop()" + SINK(x.pop()) #$ MISSING:flow="SOURCE, l:146 -> x.pop()" # 6.2.7. Dictionary displays def test_dict_display(): x = {"s": SOURCE} - SINK(x["s"]) #$ flow="SOURCE, l:152 -> x['s']" flow="'source', l:20 -> x['s']" + SINK(x["s"]) #$ flow="SOURCE, l:152 -> x['s']" def test_dict_display_pop(): x = {"s": SOURCE} - SINK(x.pop("s")) #$ flow="SOURCE, l:157 -> x.pop(..)" flow="'source', l:20 -> x.pop(..)" + SINK(x.pop("s")) #$ flow="SOURCE, l:157 -> x.pop(..)" def test_dict_comprehension(): x = {y: SOURCE for y in ["s"]} - SINK(x["s"]) #$ MISSING:flow="SOURCE, l:152 -> x['s']" MISING:flow="'source', l:20 -> x['s']" + SINK(x["s"]) #$ MISSING:flow="SOURCE, l:152 -> x['s']" def test_dict_comprehension_pop(): x = {y: SOURCE for y in ["s"]} - SINK(x.pop("s")) #$ MISSING:flow="SOURCE, l:167 -> x.pop()" MISSING:flow="'source', l:20 -> x.pop()" + SINK(x.pop("s")) #$ MISSING:flow="SOURCE, l:167 -> x.pop()" def test_nested_dict_display(): x = {**{"s": SOURCE}} - SINK(x["s"]) #$ MISSING:flow="SOURCE, l:172 -> x['s']" MISING:flow="'source', l:20 -> x['s']" + SINK(x["s"]) #$ MISSING:flow="SOURCE, l:172 -> x['s']" def test_nested_dict_display_pop(): x = {**{"s": SOURCE}} - SINK(x.pop("s")) #$ MISSING:flow="SOURCE, l:177 -> x.pop()" MISSING:flow="'source', l:20 -> x.pop()" + SINK(x.pop("s")) #$ MISSING:flow="SOURCE, l:177 -> x.pop()" # Nested comprehensions def test_nested_comprehension(): x = [y for z in [[SOURCE]] for y in z] - SINK(x[0]) #$ flow="SOURCE, l:183 -> x[0]" flow="'source', l:20 -> x[0]" + SINK(x[0]) #$ flow="SOURCE, l:183 -> x[0]" def test_nested_comprehension_deep_with_local_flow(): x = [y for v in [[[[SOURCE]]]] for u in v for z in u for y in z] - SINK(x[0]) #$ flow="SOURCE, l:188 -> x[0]" flow="'source', l:20 -> x[0]" + SINK(x[0]) #$ flow="SOURCE, l:188 -> x[0]" def test_nested_comprehension_dict(): d = {"s": [SOURCE]} x = [y for k, v in d.items() for y in v] - SINK(x[0]) #$ MISSING:flow="SOURCE, l:193 -> x[0]" MISING:flow="'source', l:20 -> x[0]" + SINK(x[0]) #$ MISSING:flow="SOURCE, l:193 -> x[0]" def test_nested_comprehension_paren(): x = [y for y in (z for z in [SOURCE])] - SINK(x[0]) #$ flow="SOURCE, l:199 -> x[0]" flow="'source', l:20 -> x[0]" + SINK(x[0]) #$ flow="SOURCE, l:199 -> x[0]" # 6.2.8. Generator expressions def test_generator(): x = (SOURCE for y in [NONSOURCE]) - SINK([*x][0]) #$ MISSING:flow="SOURCE, l:205 -> List[0]" MISING:flow="'source', l:20 -> List[0]" + SINK([*x][0]) #$ MISSING:flow="SOURCE, l:205 -> List[0]" # 6.2.9. Yield expressions @@ -213,7 +213,7 @@ def gen(x): def test_yield(): g = gen(SOURCE) - SINK(next(g)) #$ MISSING:flow="SOURCE, l:215 -> next()" MISING:flow="'source', l:20 -> next()" + SINK(next(g)) #$ MISSING:flow="SOURCE, l:215 -> next()" def gen_from(x): @@ -222,19 +222,19 @@ def gen_from(x): def test_yield_from(): g = gen_from(SOURCE) - SINK(next(g)) #$ MISSING:flow="SOURCE, l:224 -> next()" MISING:flow="'source', l:20 -> next()" + SINK(next(g)) #$ MISSING:flow="SOURCE, l:224 -> next()" # a statement rather than an expression, but related to generators def test_for(): for x in gen(SOURCE): - SINK(x) #$ MISSING:flow="SOURCE, l:230 -> x" MISING:flow="'source', l:20 -> x" + SINK(x) #$ MISSING:flow="SOURCE, l:230 -> x" # 6.2.9.1. Generator-iterator methods def test___next__(): g = gen(SOURCE) - SINK(g.__next__()) #$ MISSING:flow="SOURCE, l:236 -> g.__next__()" MISSING:flow="'source', l:20 -> g.__next__()" + SINK(g.__next__()) #$ MISSING:flow="SOURCE, l:236 -> g.__next__()" def gen2(x): @@ -246,7 +246,7 @@ def gen2(x): def test_send(): g = gen2(NONSOURCE) n = next(g) - SINK(g.send(SOURCE)) #$ MISSING:flow="SOURCE -> g.send()" MISSING:flow="'source', l:20 -> g.send()" + SINK(g.send(SOURCE)) #$ MISSING:flow="SOURCE -> g.send()" def gen_ex(x): @@ -259,7 +259,7 @@ def gen_ex(x): def test_throw(): g = gen_ex(SOURCE) n = next(g) - SINK(g.throw(TypeError)) #$ MISSING:flow="SOURCE, l:260 -> g.throw()" MISSING:flow="'source', l:20 -> g.throw()" + SINK(g.throw(TypeError)) #$ MISSING:flow="SOURCE, l:260 -> g.throw()" # no `test_close` as `close` involves no data flow @@ -280,7 +280,7 @@ def runa(a): async def atest___anext__(): g = agen(SOURCE) - SINK(await g.__anext__()) #$ MISSING:flow="SOURCE, l:282 -> g.__anext__()" MISSING:flow="'source', l:20 -> g.__anext__()" + SINK(await g.__anext__()) #$ MISSING:flow="SOURCE, l:282 -> g.__anext__()" def test___anext__(): @@ -296,7 +296,7 @@ async def agen2(x): async def atest_asend(): g = agen2(NONSOURCE) n = await g.__anext__() - SINK(await g.asend(SOURCE)) #$ MISSING:flow="SOURCE -> g.asend()" MISSING:flow="'source', l:20 -> g.asend()" + SINK(await g.asend(SOURCE)) #$ MISSING:flow="SOURCE -> g.asend()" def test_asend(): @@ -313,7 +313,7 @@ async def agen_ex(x): async def atest_athrow(): g = agen_ex(SOURCE) n = await g.__anext__() - SINK(await g.athrow(TypeError)) #$ MISSING:flow="SOURCE, l:314 -> g.athrow()" MISSING:flow="'source', l:20 -> g.athrow()" + SINK(await g.athrow(TypeError)) #$ MISSING:flow="SOURCE, l:314 -> g.athrow()" def test_athrow(): @@ -326,22 +326,22 @@ class C: def test_attribute_reference(): - SINK(C.a) #$ MISSING:flow="SOURCE, l:325 -> C.a" MISSING:flow="'source', l:20 -> C.a" + SINK(C.a) #$ MISSING:flow="SOURCE, l:325 -> C.a" # overriding __getattr__ should be tested by the class coverage tests # 6.3.2. Subscriptions def test_subscription_tuple(): - SINK((SOURCE,)[0]) #$ flow="SOURCE -> Tuple[0]" flow="'source', l:20 -> Tuple[0]" + SINK((SOURCE,)[0]) #$ flow="SOURCE -> Tuple[0]" def test_subscription_list(): - SINK([SOURCE][0]) #$ flow="SOURCE -> List[0]" flow="'source', l:20 -> List[0]" + SINK([SOURCE][0]) #$ flow="SOURCE -> List[0]" def test_subscription_mapping(): - SINK({"s": SOURCE}["s"]) #$ flow="SOURCE -> Dict['s']" flow="'source', l:20 -> Dict['s']" + SINK({"s": SOURCE}["s"]) #$ flow="SOURCE -> Dict['s']" # overriding __getitem__ should be tested by the class coverage tests @@ -353,7 +353,7 @@ def test_subscription_mapping(): def test_slicing(): s = l[0:1:1] - SINK(s[0]) #$ MISSING:flow="SOURCE -> s[0]" MISSING:flow="'source', l:20 -> s[0]" + SINK(s[0]) #$ MISSING:flow="SOURCE -> s[0]" # The grammar seems to allow `l[0:1:1, 0:1]`, but the interpreter does not like it @@ -364,7 +364,7 @@ def second(a, b): def test_call_positional(): - SINK(second(NONSOURCE, SOURCE)) #$ flow="SOURCE -> second(..)" flow="'source', l:20 -> second(..)" + SINK(second(NONSOURCE, SOURCE)) #$ flow="SOURCE -> second(..)" def test_call_positional_negative(): @@ -372,7 +372,7 @@ def test_call_positional_negative(): def test_call_keyword(): - SINK(second(NONSOURCE, b=SOURCE)) #$ flow="SOURCE -> second(..)" flow="'source', l:20 -> second(..)" + SINK(second(NONSOURCE, b=SOURCE)) #$ flow="SOURCE -> second(..)" def test_call_unpack_iterable(): @@ -380,7 +380,7 @@ def test_call_unpack_iterable(): def test_call_unpack_mapping(): - SINK(second(NONSOURCE, **{"b": SOURCE})) #$ flow="SOURCE -> second(..)" flow="'source', l:20 -> second(..)" + SINK(second(NONSOURCE, **{"b": SOURCE})) #$ flow="SOURCE -> second(..)" def f_extra_pos(a, *b): @@ -388,7 +388,7 @@ def f_extra_pos(a, *b): def test_call_extra_pos(): - SINK(f_extra_pos(NONSOURCE, SOURCE)) #$ flow="SOURCE -> f_extra_pos(..)" flow="'source', l:20 -> f_extra_pos(..)" + SINK(f_extra_pos(NONSOURCE, SOURCE)) #$ flow="SOURCE -> f_extra_pos(..)" def f_extra_keyword(a, **b): @@ -396,7 +396,7 @@ def f_extra_keyword(a, **b): def test_call_extra_keyword(): - SINK(f_extra_keyword(NONSOURCE, b=SOURCE)) #$ flow="SOURCE -> f_extra_keyword(..)" flow="'source', l:20 -> f_extra_keyword(..)" + SINK(f_extra_keyword(NONSOURCE, b=SOURCE)) #$ flow="SOURCE -> f_extra_keyword(..)" # return the name of the first extra keyword argument @@ -406,18 +406,18 @@ def f_extra_keyword_flow(**a): # call the function with our source as the name of the keyword arguemnt def test_call_extra_keyword_flow(): - SINK(f_extra_keyword_flow(**{SOURCE: None})) #$ MISSING:flow="SOURCE -> f_extra_keyword(..)" MISSING:flow="'source', l:20 -> f_extra_keyword(..)" + SINK(f_extra_keyword_flow(**{SOURCE: None})) #$ MISSING:flow="SOURCE -> f_extra_keyword(..)" # 6.12. Assignment expressions def test_assignment_expression(): x = NONSOURCE - SINK(x := SOURCE) #$ MISSING:flow="SOURCE -> x" MISSING:flow="'source', l:20 -> x" + SINK(x := SOURCE) #$ MISSING:flow="SOURCE -> x" # 6.13. Conditional expressions def test_conditional_true(): - SINK(SOURCE if True else NONSOURCE) #$ flow="SOURCE -> IfExp" flow="'source', l:20 -> IfExp" + SINK(SOURCE if True else NONSOURCE) #$ flow="SOURCE -> IfExp" def test_conditional_true_guards(): @@ -425,7 +425,7 @@ def test_conditional_true_guards(): def test_conditional_false(): - SINK(NONSOURCE if False else SOURCE) #$ flow="SOURCE -> IfExp" flow="'source', l:20 -> IfExp" + SINK(NONSOURCE if False else SOURCE) #$ flow="SOURCE -> IfExp" def test_conditional_false_guards(): @@ -435,13 +435,13 @@ def test_conditional_false_guards(): # Condition is evaluated first, so x is SOURCE once chosen def test_conditional_evaluation_true(): x = NONSOURCE - SINK(x if (SOURCE == (x := SOURCE)) else NONSOURCE) #$ MISSING:flow="SOURCE -> IfExp" MISSING:flow="'source', l:20 -> IfExp" + SINK(x if (SOURCE == (x := SOURCE)) else NONSOURCE) #$ MISSING:flow="SOURCE -> IfExp" # Condition is evaluated first, so x is SOURCE once chosen def test_conditional_evaluation_false(): x = NONSOURCE - SINK(NONSOURCE if (NONSOURCE == (x := SOURCE)) else x) #$ MISSING:flow="SOURCE -> IfExp" MISSING:flow="'source', l:20 -> IfExp" + SINK(NONSOURCE if (NONSOURCE == (x := SOURCE)) else x) #$ MISSING:flow="SOURCE -> IfExp" # 6.14. Lambdas @@ -449,14 +449,14 @@ def test_lambda(): def f(x): return x - SINK(f(SOURCE)) #$ flow="SOURCE -> f(..)" flow="'source', l:20 -> f(..)" + SINK(f(SOURCE)) #$ flow="SOURCE -> f(..)" def test_lambda_positional(): def second(a, b): return b - SINK(second(NONSOURCE, SOURCE)) #$ flow="SOURCE -> second(..)" flow="'source', l:20 -> second(..)" + SINK(second(NONSOURCE, SOURCE)) #$ flow="SOURCE -> second(..)" def test_lambda_positional_negative(): @@ -470,50 +470,50 @@ def test_lambda_keyword(): def second(a, b): return b - SINK(second(NONSOURCE, b=SOURCE)) #$ flow="SOURCE -> second(..)" flow="'source', l:20 -> second(..)" + SINK(second(NONSOURCE, b=SOURCE)) #$ flow="SOURCE -> second(..)" def test_lambda_unpack_iterable(): def second(a, b): return b - SINK(second(NONSOURCE, *[SOURCE])) #$ MISSING:flow="SOURCE -> second(..)" MISSING:flow="'source', l:20 -> second(..)" # Flow missing + SINK(second(NONSOURCE, *[SOURCE])) #$ MISSING:flow="SOURCE -> second(..)" # Flow missing def test_lambda_unpack_mapping(): def second(a, b): return b - SINK(second(NONSOURCE, **{"b": SOURCE})) #$ flow="SOURCE -> second(..)" flow="'source', l:20 -> second(..)" + SINK(second(NONSOURCE, **{"b": SOURCE})) #$ flow="SOURCE -> second(..)" def test_lambda_extra_pos(): f_extra_pos = lambda a, *b: b[0] - SINK(f_extra_pos(NONSOURCE, SOURCE)) #$ flow="SOURCE -> f_extra_pos(..)" flow="'source', l:20 -> f_extra_pos(..)" + SINK(f_extra_pos(NONSOURCE, SOURCE)) #$ flow="SOURCE -> f_extra_pos(..)" def test_lambda_extra_keyword(): f_extra_keyword = lambda a, **b: b["b"] - SINK(f_extra_keyword(NONSOURCE, b=SOURCE)) #$ flow="SOURCE -> f_extra_keyword(..)" flow="'source', l:20 -> f_extra_keyword(..)" + SINK(f_extra_keyword(NONSOURCE, b=SOURCE)) #$ flow="SOURCE -> f_extra_keyword(..)" # call the function with our source as the name of the keyword argument def test_lambda_extra_keyword_flow(): # return the name of the first extra keyword argument f_extra_keyword_flow = lambda **a: [*a][0] - SINK(f_extra_keyword_flow(**{SOURCE: None})) #$ MISSING:flow="SOURCE -> f_extra_keyword(..)" MISSING:flow="'source', l:20 -> f_extra_keyword(..)" + SINK(f_extra_keyword_flow(**{SOURCE: None})) #$ MISSING:flow="SOURCE -> f_extra_keyword(..)" @expects(4) def test_swap(): a = SOURCE b = NONSOURCE - SINK(a) #$ flow="SOURCE, l:509 -> a" flow="'source', l:20 -> a" + SINK(a) #$ flow="SOURCE, l:509 -> a" SINK_F(b) a, b = b, a SINK_F(a) - SINK(b) #$ flow="SOURCE, l:509 -> b" flow="'source', l:20 -> b" + SINK(b) #$ flow="SOURCE, l:509 -> b" def test_deep_callgraph(): @@ -538,7 +538,7 @@ def f6(arg): return f5(arg) x = f6(SOURCE) - SINK(x) #$ MISSING:flow="SOURCE, l:540 -> x" MISING:flow="'source', l:20 -> x" + SINK(x) #$ MISSING:flow="SOURCE, l:540 -> x" @expects(2) diff --git a/python/ql/test/experimental/dataflow/fieldflow/dataflow.expected b/python/ql/test/experimental/dataflow/fieldflow/dataflow.expected index 168ff7e66ce4..2301e52f08f4 100644 --- a/python/ql/test/experimental/dataflow/fieldflow/dataflow.expected +++ b/python/ql/test/experimental/dataflow/fieldflow/dataflow.expected @@ -1,34 +1,17 @@ edges | examples.py:27:8:27:12 | [post arg] ControlFlowNode for myobj [Attribute foo] | examples.py:28:6:28:10 | ControlFlowNode for myobj [Attribute foo] | | examples.py:27:15:27:20 | ControlFlowNode for SOURCE | examples.py:27:8:27:12 | [post arg] ControlFlowNode for myobj [Attribute foo] | -| examples.py:27:15:27:20 | ControlFlowNode for SOURCE | examples.py:35:13:35:13 | ControlFlowNode for x | -| examples.py:27:15:27:20 | ControlFlowNode for SOURCE | examples.py:49:13:49:18 | ControlFlowNode for SOURCE | -| examples.py:27:15:27:20 | ControlFlowNode for SOURCE | examples.py:59:29:59:34 | ControlFlowNode for SOURCE | | examples.py:28:6:28:10 | ControlFlowNode for myobj [Attribute foo] | examples.py:28:6:28:14 | ControlFlowNode for Attribute | | examples.py:31:5:31:10 | ControlFlowNode for SOURCE | examples.py:35:13:35:13 | ControlFlowNode for x | -| examples.py:31:5:31:10 | ControlFlowNode for SOURCE | examples.py:49:13:49:18 | ControlFlowNode for SOURCE | -| examples.py:31:5:31:10 | ControlFlowNode for SOURCE | examples.py:59:29:59:34 | ControlFlowNode for SOURCE | | examples.py:35:1:35:1 | [post read] ControlFlowNode for a [Attribute obj, Attribute foo] | examples.py:37:6:37:6 | ControlFlowNode for a [Attribute obj, Attribute foo] | | examples.py:35:1:35:5 | [post store] ControlFlowNode for Attribute [Attribute foo] | examples.py:35:1:35:1 | [post read] ControlFlowNode for a [Attribute obj, Attribute foo] | | examples.py:35:13:35:13 | ControlFlowNode for x | examples.py:35:1:35:5 | [post store] ControlFlowNode for Attribute [Attribute foo] | | examples.py:37:6:37:6 | ControlFlowNode for a [Attribute obj, Attribute foo] | examples.py:37:6:37:10 | ControlFlowNode for Attribute [Attribute foo] | | examples.py:37:6:37:10 | ControlFlowNode for Attribute [Attribute foo] | examples.py:37:6:37:14 | ControlFlowNode for Attribute | -| examples.py:40:5:40:10 | ControlFlowNode for SOURCE | examples.py:49:13:49:18 | ControlFlowNode for SOURCE | -| examples.py:40:5:40:10 | ControlFlowNode for SOURCE | examples.py:59:29:59:34 | ControlFlowNode for SOURCE | | examples.py:49:7:49:19 | ControlFlowNode for MyObj() [Attribute foo] | examples.py:50:6:50:8 | ControlFlowNode for obj [Attribute foo] | | examples.py:49:13:49:18 | ControlFlowNode for SOURCE | examples.py:49:7:49:19 | ControlFlowNode for MyObj() [Attribute foo] | -| examples.py:49:13:49:18 | ControlFlowNode for SOURCE | examples.py:59:29:59:34 | ControlFlowNode for SOURCE | | examples.py:50:6:50:8 | ControlFlowNode for obj [Attribute foo] | examples.py:50:6:50:12 | ControlFlowNode for Attribute | | examples.py:59:29:59:34 | ControlFlowNode for SOURCE | examples.py:59:6:59:35 | ControlFlowNode for fields_with_local_flow() | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:49:19:49:24 | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:56:18:56:23 | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:61:9:61:14 | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:71:9:71:14 | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:81:17:81:22 | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:86:21:86:26 | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:97:33:97:38 | ControlFlowNode for SOURCE | -| test.py:3:1:3:6 | GSSA Variable SOURCE | test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | -| test.py:3:10:3:17 | ControlFlowNode for Str | test.py:3:1:3:6 | GSSA Variable SOURCE | | test.py:49:12:49:16 | [post arg] ControlFlowNode for myobj [Attribute foo] | test.py:50:10:50:14 | ControlFlowNode for myobj [Attribute foo] | | test.py:49:19:49:24 | ControlFlowNode for SOURCE | test.py:49:12:49:16 | [post arg] ControlFlowNode for myobj [Attribute foo] | | test.py:50:10:50:14 | ControlFlowNode for myobj [Attribute foo] | test.py:50:10:50:18 | ControlFlowNode for Attribute | @@ -66,16 +49,12 @@ nodes | examples.py:37:6:37:6 | ControlFlowNode for a [Attribute obj, Attribute foo] | semmle.label | ControlFlowNode for a [Attribute obj, Attribute foo] | | examples.py:37:6:37:10 | ControlFlowNode for Attribute [Attribute foo] | semmle.label | ControlFlowNode for Attribute [Attribute foo] | | examples.py:37:6:37:14 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| examples.py:40:5:40:10 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | | examples.py:49:7:49:19 | ControlFlowNode for MyObj() [Attribute foo] | semmle.label | ControlFlowNode for MyObj() [Attribute foo] | | examples.py:49:13:49:18 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | | examples.py:50:6:50:8 | ControlFlowNode for obj [Attribute foo] | semmle.label | ControlFlowNode for obj [Attribute foo] | | examples.py:50:6:50:12 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | | examples.py:59:6:59:35 | ControlFlowNode for fields_with_local_flow() | semmle.label | ControlFlowNode for fields_with_local_flow() | | examples.py:59:29:59:34 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | -| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | semmle.label | ModuleVariableNode for Global Variable SOURCE in Module test | -| test.py:3:1:3:6 | GSSA Variable SOURCE | semmle.label | GSSA Variable SOURCE | -| test.py:3:10:3:17 | ControlFlowNode for Str | semmle.label | ControlFlowNode for Str | | test.py:49:12:49:16 | [post arg] ControlFlowNode for myobj [Attribute foo] | semmle.label | [post arg] ControlFlowNode for myobj [Attribute foo] | | test.py:49:19:49:24 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | | test.py:50:10:50:14 | ControlFlowNode for myobj [Attribute foo] | semmle.label | ControlFlowNode for myobj [Attribute foo] | @@ -110,28 +89,13 @@ nodes | test.py:97:33:97:38 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | #select | examples.py:28:6:28:14 | ControlFlowNode for Attribute | examples.py:27:15:27:20 | ControlFlowNode for SOURCE | examples.py:28:6:28:14 | ControlFlowNode for Attribute | Flow found | -| examples.py:37:6:37:14 | ControlFlowNode for Attribute | examples.py:27:15:27:20 | ControlFlowNode for SOURCE | examples.py:37:6:37:14 | ControlFlowNode for Attribute | Flow found | | examples.py:37:6:37:14 | ControlFlowNode for Attribute | examples.py:31:5:31:10 | ControlFlowNode for SOURCE | examples.py:37:6:37:14 | ControlFlowNode for Attribute | Flow found | -| examples.py:50:6:50:12 | ControlFlowNode for Attribute | examples.py:27:15:27:20 | ControlFlowNode for SOURCE | examples.py:50:6:50:12 | ControlFlowNode for Attribute | Flow found | -| examples.py:50:6:50:12 | ControlFlowNode for Attribute | examples.py:31:5:31:10 | ControlFlowNode for SOURCE | examples.py:50:6:50:12 | ControlFlowNode for Attribute | Flow found | -| examples.py:50:6:50:12 | ControlFlowNode for Attribute | examples.py:40:5:40:10 | ControlFlowNode for SOURCE | examples.py:50:6:50:12 | ControlFlowNode for Attribute | Flow found | | examples.py:50:6:50:12 | ControlFlowNode for Attribute | examples.py:49:13:49:18 | ControlFlowNode for SOURCE | examples.py:50:6:50:12 | ControlFlowNode for Attribute | Flow found | -| examples.py:59:6:59:35 | ControlFlowNode for fields_with_local_flow() | examples.py:27:15:27:20 | ControlFlowNode for SOURCE | examples.py:59:6:59:35 | ControlFlowNode for fields_with_local_flow() | Flow found | -| examples.py:59:6:59:35 | ControlFlowNode for fields_with_local_flow() | examples.py:31:5:31:10 | ControlFlowNode for SOURCE | examples.py:59:6:59:35 | ControlFlowNode for fields_with_local_flow() | Flow found | -| examples.py:59:6:59:35 | ControlFlowNode for fields_with_local_flow() | examples.py:40:5:40:10 | ControlFlowNode for SOURCE | examples.py:59:6:59:35 | ControlFlowNode for fields_with_local_flow() | Flow found | -| examples.py:59:6:59:35 | ControlFlowNode for fields_with_local_flow() | examples.py:49:13:49:18 | ControlFlowNode for SOURCE | examples.py:59:6:59:35 | ControlFlowNode for fields_with_local_flow() | Flow found | | examples.py:59:6:59:35 | ControlFlowNode for fields_with_local_flow() | examples.py:59:29:59:34 | ControlFlowNode for SOURCE | examples.py:59:6:59:35 | ControlFlowNode for fields_with_local_flow() | Flow found | -| test.py:50:10:50:18 | ControlFlowNode for Attribute | test.py:3:10:3:17 | ControlFlowNode for Str | test.py:50:10:50:18 | ControlFlowNode for Attribute | Flow found | | test.py:50:10:50:18 | ControlFlowNode for Attribute | test.py:49:19:49:24 | ControlFlowNode for SOURCE | test.py:50:10:50:18 | ControlFlowNode for Attribute | Flow found | -| test.py:57:10:57:18 | ControlFlowNode for Attribute | test.py:3:10:3:17 | ControlFlowNode for Str | test.py:57:10:57:18 | ControlFlowNode for Attribute | Flow found | | test.py:57:10:57:18 | ControlFlowNode for Attribute | test.py:56:18:56:23 | ControlFlowNode for SOURCE | test.py:57:10:57:18 | ControlFlowNode for Attribute | Flow found | -| test.py:67:10:67:18 | ControlFlowNode for Attribute | test.py:3:10:3:17 | ControlFlowNode for Str | test.py:67:10:67:18 | ControlFlowNode for Attribute | Flow found | | test.py:67:10:67:18 | ControlFlowNode for Attribute | test.py:61:9:61:14 | ControlFlowNode for SOURCE | test.py:67:10:67:18 | ControlFlowNode for Attribute | Flow found | -| test.py:77:10:77:18 | ControlFlowNode for Attribute | test.py:3:10:3:17 | ControlFlowNode for Str | test.py:77:10:77:18 | ControlFlowNode for Attribute | Flow found | | test.py:77:10:77:18 | ControlFlowNode for Attribute | test.py:71:9:71:14 | ControlFlowNode for SOURCE | test.py:77:10:77:18 | ControlFlowNode for Attribute | Flow found | -| test.py:82:10:82:16 | ControlFlowNode for Attribute | test.py:3:10:3:17 | ControlFlowNode for Str | test.py:82:10:82:16 | ControlFlowNode for Attribute | Flow found | | test.py:82:10:82:16 | ControlFlowNode for Attribute | test.py:81:17:81:22 | ControlFlowNode for SOURCE | test.py:82:10:82:16 | ControlFlowNode for Attribute | Flow found | -| test.py:87:10:87:16 | ControlFlowNode for Attribute | test.py:3:10:3:17 | ControlFlowNode for Str | test.py:87:10:87:16 | ControlFlowNode for Attribute | Flow found | | test.py:87:10:87:16 | ControlFlowNode for Attribute | test.py:86:21:86:26 | ControlFlowNode for SOURCE | test.py:87:10:87:16 | ControlFlowNode for Attribute | Flow found | -| test.py:97:10:97:39 | ControlFlowNode for fields_with_local_flow() | test.py:3:10:3:17 | ControlFlowNode for Str | test.py:97:10:97:39 | ControlFlowNode for fields_with_local_flow() | Flow found | | test.py:97:10:97:39 | ControlFlowNode for fields_with_local_flow() | test.py:97:33:97:38 | ControlFlowNode for SOURCE | test.py:97:10:97:39 | ControlFlowNode for fields_with_local_flow() | Flow found | diff --git a/python/ql/test/experimental/dataflow/testConfig.qll b/python/ql/test/experimental/dataflow/testConfig.qll index 43fdb48876f4..90bd1d47978a 100644 --- a/python/ql/test/experimental/dataflow/testConfig.qll +++ b/python/ql/test/experimental/dataflow/testConfig.qll @@ -44,5 +44,7 @@ class TestConfiguration extends DataFlow::Configuration { ) } - override int explorationLimit() { result = 4 } + override predicate isBarrierIn(DataFlow::Node node) { this.isSource(node) } + + override int explorationLimit() { result = 5 } } From 77da4b0106beaacebff7d9de3f8c30b292e7a8d3 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 19 Jan 2021 17:05:42 +0100 Subject: [PATCH 09/16] Python: Remove absolute line numbers - Use relative line numbers in flow test - Elide line numbers in routing test (new concept) --- .../dataflow/TestUtil/FlowTest.qll | 13 +- .../dataflow/TestUtil/RoutingTest.qll | 35 + .../test/experimental/dataflow/basic/test.py | 8 +- .../dataflow/coverage/argumentPassing.py | 92 +-- .../dataflow/coverage/argumentRoutingTest.ql | 16 +- .../experimental/dataflow/coverage/classes.py | 688 +++++++++--------- .../dataflow/coverage/datamodel.py | 6 +- .../experimental/dataflow/coverage/test.py | 64 +- 8 files changed, 482 insertions(+), 440 deletions(-) create mode 100644 python/ql/test/experimental/dataflow/TestUtil/RoutingTest.qll diff --git a/python/ql/test/experimental/dataflow/TestUtil/FlowTest.qll b/python/ql/test/experimental/dataflow/TestUtil/FlowTest.qll index edb24373386c..f6985bf4a1e9 100644 --- a/python/ql/test/experimental/dataflow/TestUtil/FlowTest.qll +++ b/python/ql/test/experimental/dataflow/TestUtil/FlowTest.qll @@ -26,8 +26,15 @@ abstract class FlowTest extends InlineExpectationsTest { pragma[inline] private string lineStr(DataFlow::Node fromNode, DataFlow::Node toNode) { - if fromNode.getLocation().getStartLine() = toNode.getLocation().getStartLine() - then result = "" - else result = ", l:" + fromNode.getLocation().getStartLine() + exists(int delta | + delta = fromNode.getLocation().getStartLine() - toNode.getLocation().getStartLine() + | + if delta = 0 + then result = "" + else + if delta > 0 + then result = ", l:+" + delta.toString() + else result = ", l:" + delta.toString() + ) } } diff --git a/python/ql/test/experimental/dataflow/TestUtil/RoutingTest.qll b/python/ql/test/experimental/dataflow/TestUtil/RoutingTest.qll new file mode 100644 index 000000000000..eb685cc3ac17 --- /dev/null +++ b/python/ql/test/experimental/dataflow/TestUtil/RoutingTest.qll @@ -0,0 +1,35 @@ +import python +import semmle.python.dataflow.new.DataFlow +import TestUtilities.InlineExpectationsTest +import experimental.dataflow.TestUtil.PrintNode + +/** + * A routing test is designed to test that vlues are routed to the + * correct arguments of the correct functions. It is assumed that + * the functions tested sink their arguments sequentially, that is + * `SINK1(arg1)`, etc. + */ +abstract class RoutingTest extends InlineExpectationsTest { + bindingset[this] + RoutingTest() { any() } + + abstract string flowTag(); + + abstract predicate relevantFlow(DataFlow::Node fromNode, DataFlow::Node toNode); + + override string getARelevantTag() { result in ["func", this.flowTag()] } + + override predicate hasActualResult(Location location, string element, string tag, string value) { + exists(DataFlow::Node fromNode, DataFlow::Node toNode | this.relevantFlow(fromNode, toNode) | + location = fromNode.getLocation() and + element = fromNode.toString() and + ( + tag = this.flowTag() and + value = "\"" + prettyNode(fromNode).replaceAll("\"", "'") + "\"" + or + tag = "func" and + value = toNode.getEnclosingCallable().getCallableValue().getScope().getQualifiedName() // TODO: More robust pretty printing? + ) + ) + } +} diff --git a/python/ql/test/experimental/dataflow/basic/test.py b/python/ql/test/experimental/dataflow/basic/test.py index b850aa0d99c8..7ea19e9d4d0a 100644 --- a/python/ql/test/experimental/dataflow/basic/test.py +++ b/python/ql/test/experimental/dataflow/basic/test.py @@ -1,7 +1,7 @@ def obfuscated_id(x): #$ step="FunctionExpr -> GSSA Variable obfuscated_id" step="x -> SSA variable x" - y = x #$ step="x -> SSA variable y" step="SSA variable x, l:1 -> x" - z = y #$ step="y -> SSA variable z" step="SSA variable y, l:2 -> y" - return z #$ flow="42, l:6 -> z" step="SSA variable z, l:3 -> z" + y = x #$ step="x -> SSA variable y" step="SSA variable x, l:-1 -> x" + z = y #$ step="y -> SSA variable z" step="SSA variable y, l:-1 -> y" + return z #$ flow="42, l:+2 -> z" step="SSA variable z, l:-1 -> z" a = 42 #$ step="42 -> GSSA Variable a" -b = obfuscated_id(a) #$ flow="42, l:6 -> GSSA Variable b" flow="FunctionExpr, l:1 -> obfuscated_id" step="obfuscated_id(..) -> GSSA Variable b" step="GSSA Variable obfuscated_id, l:1 -> obfuscated_id" step="GSSA Variable a, l:6 -> a" +b = obfuscated_id(a) #$ flow="42, l:-1 -> GSSA Variable b" flow="FunctionExpr, l:-6 -> obfuscated_id" step="obfuscated_id(..) -> GSSA Variable b" step="GSSA Variable obfuscated_id, l:-6 -> obfuscated_id" step="GSSA Variable a, l:-1 -> a" diff --git a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py index 6de4d56ad137..67650c149d3c 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py +++ b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py @@ -72,78 +72,78 @@ def argument_passing( f, **g, ): - SINK1(a) #$ arg1="arg1, l:89 -> a" arg1="arg1, l:94 -> a" - SINK2(b) #$ arg2="arg2, l:94 -> b" MISSING:arg2="arg2, l:89 -> b" - SINK3(c) #$ arg3="arg3, l:94 -> c" MISSING: arg3="arg3, l:89 -> c" - SINK4(d) #$ MISSING: arg4="arg4, l:89 -> d" - SINK5(e) #$ MISSING: arg5="arg5, l:89 -> e" - SINK6(f) #$ MISSING: arg6="arg6, l:89 -> f" + SINK1(a) + SINK2(b) + SINK3(c) + SINK4(d) + SINK5(e) + SINK6(f) try: - SINK7(g["g"]) #$ arg7="arg7, l:89 -> g['g']" + SINK7(g["g"]) except: print("OK") @expects(7) def test_argument_passing1(): - argument_passing(arg1, *(arg2, arg3, arg4), e=arg5, **{"f": arg6, "g": arg7}) + argument_passing(arg1, *(arg2, arg3, arg4), e=arg5, **{"f": arg6, "g": arg7}) #$ arg1="arg1" arg7="arg7" func=argument_passing MISSING: arg2="arg2" arg3="arg3 arg4="arg4" arg5="arg5" arg6="arg6" @expects(7) def test_argument_passing2(): - argument_passing(arg1, arg2, arg3, f=arg6) + argument_passing(arg1, arg2, arg3, f=arg6) #$ arg1="arg1" arg2="arg2" arg3="arg3" func=argument_passing def with_pos_only(a, /, b): - SINK1(a) #$ arg1="arg1, l:104 -> a" arg1="arg1, l:105 -> a" arg1="arg1, l:106 -> a" - SINK2(b) #$ arg2="arg2, l:104 -> b" arg2="arg2, l:105 -> b" MISSING: arg2="arg2, l:106 -> b" + SINK1(a) + SINK2(b) @expects(6) def test_pos_only(): - with_pos_only(arg1, arg2) - with_pos_only(arg1, b=arg2) - with_pos_only(arg1, *(arg2,)) + with_pos_only(arg1, arg2) #$ arg1="arg1" arg2="arg2" func=with_pos_only + with_pos_only(arg1, b=arg2) #$ arg1="arg1" arg2="arg2" func=with_pos_only + with_pos_only(arg1, *(arg2,)) #$ arg1="arg1" func=with_pos_only MISSING: arg2="arg2" def with_multiple_kw_args(a, b, c): - SINK1(a) #$ arg1="arg1, l:117 -> a" arg1="arg1, l:118 -> a" arg1="arg1, l:119 -> a" arg1="arg1, l:120 -> a" - SINK2(b) #$ arg2="arg2, l:117 -> b" arg2="arg2, l:120 -> b" MISSING: arg2="arg2, l:118 -> b" arg2="arg2, l:119 -> b" - SINK3(c) #$ arg3="arg3, l:117 -> c" arg3="arg3, l:119 -> c" arg3="arg3, l:120 -> c" MISSING: arg3="arg3, l:118 -> c" + SINK1(a) + SINK2(b) + SINK3(c) @expects(9) def test_multiple_kw_args(): - with_multiple_kw_args(b=arg2, c=arg3, a=arg1) - with_multiple_kw_args(arg1, *(arg2,), arg3) - with_multiple_kw_args(arg1, **{"c": arg3}, b=arg2) - with_multiple_kw_args(**{"b": arg2}, **{"c": arg3}, **{"a": arg1}) + with_multiple_kw_args(b=arg2, c=arg3, a=arg1) #$ arg1="arg1" arg2="arg2" arg3="arg3" func=with_multiple_kw_args + with_multiple_kw_args(arg1, *(arg2,), arg3) #$ arg1="arg1" func=with_multiple_kw_args MISSING: arg2="arg2" arg3="arg3" + with_multiple_kw_args(arg1, **{"c": arg3}, b=arg2) #$ arg1="arg1" arg3="arg3" func=with_multiple_kw_args MISSING: arg2="arg2" + with_multiple_kw_args(**{"b": arg2}, **{"c": arg3}, **{"a": arg1}) #$ arg1="arg1" arg2="arg2" arg3="arg3" func=with_multiple_kw_args -def with_default_arguments(a=arg1, b=arg2, c=arg3): - SINK1(a) #$ arg1="arg1, l:132 -> a" MISSING:arg1="arg1, l:123 -> a" - SINK2(b) #$ arg2="arg2, l:133 -> b" MISSING: arg2="arg2, l:123 -> b" - SINK3(c) #$ arg3="arg3, l:134 -> c" MISSING: arg3="arg3, l:123 -> c" +def with_default_arguments(a=arg1, b=arg2, c=arg3): # Need a mechanism to test default arguments + SINK1(a) + SINK2(b) + SINK3(c) @expects(12) def test_default_arguments(): with_default_arguments() - with_default_arguments(arg1) - with_default_arguments(b=arg2) - with_default_arguments(**{"c": arg3}) + with_default_arguments(arg1) #$ arg1="arg1" func=with_default_arguments + with_default_arguments(b=arg2) #$ arg2="arg2" func=with_default_arguments + with_default_arguments(**{"c": arg3}) #$ arg3="arg3" func=with_default_arguments # Nested constructor pattern def grab_foo_bar_baz(foo, **kwargs): - SINK1(foo) #$ arg1="arg1, l:160 -> foo" + SINK1(foo) grab_bar_baz(**kwargs) # It is not possible to pass `bar` into `kwargs`, # since `bar` is a valid keyword argument. def grab_bar_baz(bar, **kwargs): - SINK2(bar) #$ arg2="arg2, l:160 -> bar" + SINK2(bar) try: SINK2_F(kwargs["bar"]) except: @@ -152,60 +152,60 @@ def grab_bar_baz(bar, **kwargs): def grab_baz(baz): - SINK3(baz) #$ arg3="arg3, l:160 -> baz" + SINK3(baz) @expects(4) def test_grab(): - grab_foo_bar_baz(baz=arg3, bar=arg2, foo=arg1) + grab_foo_bar_baz(baz=arg3, bar=arg2, foo=arg1) #$ arg1="arg1" arg2="arg2" arg3="arg3" func=grab_foo_bar_baz func=grab_bar_baz func=grab_baz # All combinations def test_pos_pos(): def with_pos(a): - SINK1(a) #$ arg1="arg1, l:168 -> a" + SINK1(a) - with_pos(arg1) + with_pos(arg1) #$ arg1="arg1" func=test_pos_pos.with_pos def test_pos_pos_only(): def with_pos_only(a, /): - SINK1(a) #$ arg1="arg1, l:175 -> a" + SINK1(a) - with_pos_only(arg1) + with_pos_only(arg1) #$ arg1="arg1" func=test_pos_pos_only.with_pos_only def test_pos_star(): def with_star(*a): if len(a) > 0: - SINK1(a[0]) #$ arg1="arg1, l:183 -> a[0]" + SINK1(a[0]) - with_star(arg1) + with_star(arg1) #$ arg1="arg1" func=test_pos_star.with_star def test_pos_kw(): def with_kw(a=""): - SINK1(a) #$ arg1="arg1, l:190 -> a" + SINK1(a) - with_kw(arg1) + with_kw(arg1) #$ arg1="arg1" func=test_pos_kw.with_kw def test_kw_pos(): def with_pos(a): - SINK1(a) #$ arg1="arg1, l:197 -> a" + SINK1(a) - with_pos(a=arg1) + with_pos(a=arg1) #$ arg1="arg1" func=test_kw_pos.with_pos def test_kw_kw(): def with_kw(a=""): - SINK1(a) #$ arg1="arg1, l:204 -> a" + SINK1(a) - with_kw(a=arg1) + with_kw(a=arg1) #$ arg1="arg1" func=test_kw_kw.with_kw def test_kw_doublestar(): def with_doublestar(**a): - SINK1(a["a"]) #$ arg1="arg1, l:211 -> a['a']" + SINK1(a["a"]) - with_doublestar(a=arg1) + with_doublestar(a=arg1) #$ arg1="arg1" func=test_kw_doublestar.with_doublestar diff --git a/python/ql/test/experimental/dataflow/coverage/argumentRoutingTest.ql b/python/ql/test/experimental/dataflow/coverage/argumentRoutingTest.ql index 8a2b9cf92350..51963055f560 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentRoutingTest.ql +++ b/python/ql/test/experimental/dataflow/coverage/argumentRoutingTest.ql @@ -1,9 +1,9 @@ import python import semmle.python.dataflow.new.DataFlow private import semmle.python.dataflow.new.internal.DataFlowPrivate as DataFlowPrivate -import experimental.dataflow.TestUtil.FlowTest +import experimental.dataflow.TestUtil.RoutingTest -class Argument1RoutingTest extends FlowTest { +class Argument1RoutingTest extends RoutingTest { Argument1RoutingTest() { this = "Argument1RoutingTest" } override string flowTag() { result = "arg1" } @@ -46,7 +46,7 @@ class Argument1RoutingConfig extends DataFlow::Configuration { override predicate isBarrierIn(DataFlow::Node node) { isSource(node) } } -class Argument2RoutingTest extends FlowTest { +class Argument2RoutingTest extends RoutingTest { Argument2RoutingTest() { this = "Argument2RoutingTest" } override string flowTag() { result = "arg2" } @@ -82,7 +82,7 @@ class Argument2RoutingConfig extends DataFlow::Configuration { override predicate isBarrierIn(DataFlow::Node node) { isSource(node) } } -class Argument3RoutingTest extends FlowTest { +class Argument3RoutingTest extends RoutingTest { Argument3RoutingTest() { this = "Argument3RoutingTest" } override string flowTag() { result = "arg3" } @@ -118,7 +118,7 @@ class Argument3RoutingConfig extends DataFlow::Configuration { override predicate isBarrierIn(DataFlow::Node node) { isSource(node) } } -class Argument4RoutingTest extends FlowTest { +class Argument4RoutingTest extends RoutingTest { Argument4RoutingTest() { this = "Argument4RoutingTest" } override string flowTag() { result = "arg4" } @@ -154,7 +154,7 @@ class Argument4RoutingConfig extends DataFlow::Configuration { override predicate isBarrierIn(DataFlow::Node node) { isSource(node) } } -class Argument5RoutingTest extends FlowTest { +class Argument5RoutingTest extends RoutingTest { Argument5RoutingTest() { this = "Argument5RoutingTest" } override string flowTag() { result = "arg5" } @@ -190,7 +190,7 @@ class Argument5RoutingConfig extends DataFlow::Configuration { override predicate isBarrierIn(DataFlow::Node node) { isSource(node) } } -class Argument6RoutingTest extends FlowTest { +class Argument6RoutingTest extends RoutingTest { Argument6RoutingTest() { this = "Argument6RoutingTest" } override string flowTag() { result = "arg6" } @@ -226,7 +226,7 @@ class Argument6RoutingConfig extends DataFlow::Configuration { override predicate isBarrierIn(DataFlow::Node node) { isSource(node) } } -class Argument7RoutingTest extends FlowTest { +class Argument7RoutingTest extends RoutingTest { Argument7RoutingTest() { this = "Argument7RoutingTest" } override string flowTag() { result = "arg7" } diff --git a/python/ql/test/experimental/dataflow/coverage/classes.py b/python/ql/test/experimental/dataflow/coverage/classes.py index fd8a45bc6090..654297d31452 100644 --- a/python/ql/test/experimental/dataflow/coverage/classes.py +++ b/python/ql/test/experimental/dataflow/coverage/classes.py @@ -38,9 +38,9 @@ def OK(): # object.__new__(cls[, ...]) -class With_new: +class With_new: #$ MISSING: arg1="With_new" func=With_new.__new__ def __new__(cls): - SINK1(cls) #$ MISSING: arg1="With_new, l:41 -> cls" + SINK1(cls) OK() # Call not found return super().__new__(cls) @@ -52,221 +52,221 @@ def test_new(): # object.__init__(self[, ...]) class With_init: def __init__(self): - SINK1(self) #$ MISSING: arg1="with_init, l:60 -> self" + SINK1(self) OK() def test_init(): - with_init = With_init() + with_init = With_init() #$ MISSING: arg1="SSA variable with_init" func=With_init.__init__ # object.__del__(self) class With_del: def __del__(self): - SINK1(self) #$ MISSING: arg1="with_del, l:71 -> self" + SINK1(self) OK() # Call not found def test_del(): - with_del = With_del() + with_del = With_del() #$ MISSING: arg1="SSA variable with_del" func=With_del.__del__ del with_del # object.__repr__(self) class With_repr: def __repr__(self): - SINK1(self) #$ MISSING: arg1="with_repr, l:84 -> self" + SINK1(self) OK() # Call not found return "With_repr()" def test_repr(): - with_repr = With_repr() + with_repr = With_repr() #$ MISSING: arg1="SSA variable with_repr" func=With_repr.__repr__ repr(with_repr) # object.__str__(self) class With_str: def __str__(self): - SINK1(self) #$ MISSING: arg1="with_str, l:97 -> self" + SINK1(self) OK() # Call not found return "Awesome" def test_str(): - with_str = With_str() + with_str = With_str() #$ MISSING: arg1="SSA variable with_str" func=With_str.__str__ str(with_str) # object.__bytes__(self) class With_bytes: def __bytes__(self): - SINK1(self) #$ MISSING: arg1="with_bytes, l:110 -> self" + SINK1(self) OK() # Call not found return b"Awesome" def test_bytes(): - with_bytes = With_bytes() + with_bytes = With_bytes() #$ MISSING: arg1="SSA variable with_bytes" func=With_bytes.__bytes__ bytes(with_bytes) # object.__format__(self, format_spec) class With_format: def __format__(self, format_spec): - SINK2(format_spec) #$ MISSING: arg2="arg2, l:125 -> format_spec" - SINK1(self) #$ MISSING: arg1="with_format, l:124 -> self" + SINK2(format_spec) + SINK1(self) OK() # Call not found return "Awesome" def test_format(): - with_format = With_format() - arg2 = "" + with_format = With_format() #$ MISSING: arg1="SSA variable with_format" func=With_format.__format__ + arg2 = "" #$ MISSING: arg2="arg2" func=With_format.__format__ format(with_format, arg2) def test_format_str(): - with_format = With_format() + with_format = With_format() #$ MISSING: arg1="SSA variable with_format" func=With_format.__format__ "{0}".format(with_format) def test_format_fstr(): - with_format = With_format() + with_format = With_format() #$ MISSING: arg1="SSA variable with_format" func=With_format.__format__ f"{with_format}" # object.__lt__(self, other) class With_lt: def __lt__(self, other): - SINK2(other) #$ MISSING: arg2="arg2, l:150 -> other" - SINK1(self) #$ MISSING: arg1="with_lt, l:149 -> self" + SINK2(other) + SINK1(self) OK() # Call not found return "" def test_lt(): - with_lt = With_lt() - arg2 = with_lt + with_lt = With_lt() #$ MISSING: arg1="SSA variable with_lt" func=With_lt.__lt__ + arg2 = with_lt #$ MISSING: arg2="arg2" func=With_lt.__lt__ with_lt < arg2 # object.__le__(self, other) class With_le: def __le__(self, other): - SINK2(other) #$ MISSING: arg2="arg2, l:165 -> other" - SINK1(self) #$ MISSING: arg1="with_le, l:164 -> self" + SINK2(other) + SINK1(self) OK() # Call not found return "" def test_le(): - with_le = With_le() - arg2 = with_le + with_le = With_le() #$ MISSING: arg1="SSA variable with_le" func=With_le.__le__ + arg2 = with_le #$ MISSING: arg2="arg2" func=With_le.__le__ with_le <= arg2 # object.__eq__(self, other) class With_eq: def __eq__(self, other): - SINK2(other) #$ MISSING: arg2="with_eq, l:180 -> other" - SINK1(self) #$ MISSING: arg1="with_eq, l:179 -> self" + SINK2(other) + SINK1(self) OK() # Call not found return "" def test_eq(): - with_eq = With_eq() - with_eq == with_eq + with_eq = With_eq() #$ MISSING: arg1="SSA variable with_eq" func=With_eq.__eq__ + with_eq == with_eq #$ MISSING: arg2="with_eq" func=With_eq.__eq__ # object.__ne__(self, other) class With_ne: def __ne__(self, other): - SINK2(other) #$ MISSING: arg2="with_ne, l:194 -> other" - SINK1(self) #$ MISSING: arg1="with_ne, l:193 -> self" + SINK2(other) + SINK1(self) OK() # Call not found return "" def test_ne(): - with_ne = With_ne() - with_ne != with_ne + with_ne = With_ne() #$ MISSING: arg1="SSA variable with_ne" func=With_ne.__ne__ + with_ne != with_ne #$ MISSING: arg2="with_ne" func=With_ne.__ne__ # object.__gt__(self, other) class With_gt: def __gt__(self, other): - SINK2(other) #$ MISSING: arg2="arg2, l:208 -> other" - SINK1(self) #$ MISSING: arg1="with_gt, l:207 -> self" + SINK2(other) + SINK1(self) OK() # Call not found return "" def test_gt(): - with_gt = With_gt() - arg2 = with_gt + with_gt = With_gt() #$ MISSING: arg1="SSA variable with_gt" func=With_gt.__gt__ + arg2 = with_gt #$ MISSING: arg2="arg2" func=With_gt.__gt__ with_gt > arg2 # object.__ge__(self, other) class With_ge: def __ge__(self, other): - SINK2(other) #$ MISSING: arg2="arg2, l:223 -> other" - SINK1(self) #$ MISSING: arg1="with_ge, l:222 -> self" + SINK2(other) + SINK1(self) OK() # Call not found return "" def test_ge(): - with_ge = With_ge() - arg2 = with_ge + with_ge = With_ge() #$ MISSING: arg1="SSA variable with_ge" func=With_ge.__ge__ + arg2 = with_ge #$ MISSING: arg2="arg2" func=With_ge.__ge__ with_ge >= arg2 # object.__hash__(self) class With_hash: def __hash__(self): - SINK1(self) #$ MISSING: arg1="with_hash, l:236 -> self" arg1="with_hash, l:241 -> self" arg1="with_hash, l:246 -> self" arg1="with_hash, l:251 -> self" + SINK1(self) OK() # Call not found return 0 def test_hash(): - with_hash = With_hash() + with_hash = With_hash() #$ MISSING: arg1="SSA variable with_hash" func=With_hash.__hash__ hash(with_hash) def test_hash_set(): - with_hash = With_hash() + with_hash = With_hash() #$ MISSING: arg1="SSA variable with_hash" func=With_hash.__hash__ len(set([with_hash])) def test_hash_frozenset(): - with_hash = With_hash() + with_hash = With_hash() #$ MISSING: arg1="SSA variable with_hash" func=With_hash.__hash__ len(frozenset([with_hash])) def test_hash_dict(): - with_hash = With_hash() + with_hash = With_hash() #$ MISSING: arg1="SSA variable with_hash" func=With_hash.__hash__ len(dict({with_hash: 0})) # object.__bool__(self) class With_bool: def __bool__(self): - SINK1(self) #$ MISSING: arg1="with_bool, l:264 -> self" arg1="with_bool, l:269 -> self" + SINK1(self) OK() # Call not found return True def test_bool(): - with_bool = With_bool() + with_bool = With_bool() #$ MISSING: arg1="SSA variable with_bool" func=With_bool.__bool__ bool(with_bool) def test_bool_if(): - with_bool = With_bool() + with_bool = With_bool() #$ MISSING: arg1="SSA variable with_bool" func=With_bool.__bool__ if with_bool: pass @@ -275,69 +275,69 @@ def test_bool_if(): # object.__getattr__(self, name) class With_getattr: def __getattr__(self, name): - SINK2(name) #$ MISSING: arg2="with_getattr.arg2, l:286 -> name" - SINK1(self) #$ MISSING: arg1="with_getattr, l:285 -> self" + SINK2(name) + SINK1(self) OK() # Call not found return "" def test_getattr(): - with_getattr = With_getattr() - with_getattr.arg2 + with_getattr = With_getattr() #$ MISSING: arg1="SSA variable with_getattr" func=With_getattr.__getattr__ + with_getattr.arg2 #$ MISSING: arg2="with_getattr.arg2" func=With_getattr.__getattr__ # object.__getattribute__(self, name) class With_getattribute: def __getattribute__(self, name): - SINK2(name) #$ MISSING: arg2="arg2, l:300 -> name" - SINK1(self) #$ MISSING: arg1="with_getattribute, l:299 -> self" + SINK2(name) + SINK1(self) OK() # Call not found return "" def test_getattribute(): - with_getattribute = With_getattribute() - with_getattribute.arg2 + with_getattribute = With_getattribute() #$ MISSING: arg1="SSA variable with_getattribute" func=With_getattribute.__getattribute__ + with_getattribute.arg2 #$ MISSING: arg2="arg2" func=With_getattribute.__getattribute__ # object.__setattr__(self, name, value) class With_setattr: def __setattr__(self, name, value): - SINK3(value) #$ MISSING: arg3="arg3, l:314 -> value" - SINK2(name) #$ MISSING: arg2="arg2, l:315 -> name" - SINK1(self) #$ MISSING: arg1="with_setattr, l:313 -> self" + SINK3(value) + SINK2(name) + SINK1(self) OK() # Call not found def test_setattr(): - with_setattr = With_setattr() - arg3 = "" - with_setattr.arg2 = arg3 + with_setattr = With_setattr() #$ MISSING: arg1="SSA variable with_setattr" func=With_setattr.__setattr__ + arg3 = "" #$ MISSING: arg3="arg3" func=With_setattr.__setattr__ + with_setattr.arg2 = arg3 #$ MISSING: arg2="arg2" func=With_setattr.__setattr__ # object.__delattr__(self, name) class With_delattr: def __delattr__(self, name): - SINK2(name) #$ MISSING: arg2="arg2, l:328 -> name" - SINK1(self) #$ MISSING: arg1="with_delattr, l:327 -> self" + SINK2(name) + SINK1(self) OK() # Call not found def test_delattr(): - with_delattr = With_delattr() - del with_delattr.arg2 + with_delattr = With_delattr() #$ MISSING: arg1="SSA variable with_delattr" func=With_delattr.__delattr__ + del with_delattr.arg2 #$ MISSING: arg2="arg2" func=With_delattr.__delattr__ # object.__dir__(self) class With_dir: def __dir__(self): - SINK1(self) #$ MISSING: arg1="with_dir, l:340 -> self" + SINK1(self) OK() # Call not found return [] def test_dir(): - with_dir = With_dir() + with_dir = With_dir() #$ MISSING: arg1="SSA variable with_dir" func=With_dir.__dir__ dir(with_dir) @@ -350,8 +350,8 @@ class Owner: class With_get: def __get__(self, instance, owner=None): SINK3(owner) # Flow not testsed, use class `Owner` as source to test - SINK2(instance) #$ MISSING: arg2="arg2, l:365 -> instance" - SINK1(self) #$ MISSING: arg1="with_get, l:363 -> self" + SINK2(instance) + SINK1(self) OK() # Call not found return "" @@ -360,56 +360,56 @@ def test_get(): class arg3: pass - with_get = With_get() + with_get = With_get() #$ MISSING: arg1="SSA variable with_get" func=With_get.__get__ arg3.attr = with_get - arg2 = arg3() + arg2 = arg3() #$ MISSING: arg2="arg2" func=With_get.__get__ arg2.attr # object.__set__(self, instance, value) class With_set: def __set__(self, instance, value): - SINK3(value) #$ MISSING: arg3="arg3, l:382 -> value" - SINK2(instance) #$ MISSING: arg2="arg2, l:381 -> instance" - SINK1(self) #$ MISSING: arg1="with_set, l:379 -> self" + SINK3(value) + SINK2(instance) + SINK1(self) OK() # Call not found def test_set(): - with_set = With_set() + with_set = With_set() #$ MISSING: arg1="SSA variable with_set" func=With_set.__set__ Owner.attr = with_set - arg2 = Owner() - arg3 = "" + arg2 = Owner() #$ MISSING: arg2="arg2" func=With_set.__set__ + arg3 = "" #$ MISSING: arg3="arg3" func=With_set.__set__ arg2.attr = arg3 # object.__delete__(self, instance) class With_delete: def __delete__(self, instance): - SINK2(instance) #$ MISSING: arg2="arg2, l:397 -> instance" - SINK1(self) #$ MISSING: arg1="with_delete, l:395 -> self" + SINK2(instance) + SINK1(self) OK() # Call not found def test_delete(): - with_delete = With_delete() + with_delete = With_delete() #$ MISSING: arg1="SSA variable with_delete" func=With_delete.__delete__ Owner.attr = with_delete - arg2 = Owner() + arg2 = Owner() #$ MISSING: arg2="arg2" func=With_delete.__delete__ del arg2.attr # object.__set_name__(self, owner, name) class With_set_name: def __set_name__(self, owner, name): - SINK3(name) #$ MISSING: arg3="arg3, l:412 -> name" - SINK2(owner) #$ MISSING: arg2="arg2, l:412 -> owner" - SINK1(self) #$ MISSING: arg1="with_set_name, l:411 -> self" + SINK3(name) + SINK2(owner) + SINK1(self) OK() # Call not found def test_set_name(): - with_set_name = With_set_name() - type("arg2", (object,), dict(arg3=with_set_name)) + with_set_name = With_set_name() #$ MISSING: arg1="SSA variable with_set_name" func=With_set_name.__set_name__ + type("arg2", (object,), dict(arg3=with_set_name)) #$ MISSING: arg2="arg2" arg3="arg3" func=With_set_name.__set_name__ # 3.3.2.4. __slots__ // We are not testing the suppression of __weakref__ and __dict__ here @@ -455,45 +455,45 @@ class arg1(metaclass=With_prepare): # class.__instancecheck__(self, instance) class With_instancecheck: def __instancecheck__(self, instance): - SINK2(instance) #$ MISSING: arg2="arg2, l:466 -> instance" - SINK1(self) #$ MISSING: arg1="with_instancecheck, l:465 -> self" + SINK2(instance) + SINK1(self) OK() # Call not found return True def test_instancecheck(): - with_instancecheck = With_instancecheck() - arg2 = "" + with_instancecheck = With_instancecheck() #$ MISSING: arg1="SSA variable with_instancecheck" func=With_instancecheck.__instancecheck__ + arg2 = "" #$ MISSING: arg2="arg2" func=With_instancecheck.__instancecheck__ isinstance(arg2, with_instancecheck) # class.__subclasscheck__(self, subclass) class With_subclasscheck: def __subclasscheck__(self, subclass): - SINK2(subclass) #$ MISSING: arg2="arg2, l:481 -> subclass" - SINK1(self) #$ MISSING: arg1="with_subclasscheck, l:480 -> self" + SINK2(subclass) + SINK1(self) OK() # Call not found return True def test_subclasscheck(): - with_subclasscheck = With_subclasscheck() - arg2 = object + with_subclasscheck = With_subclasscheck() #$ MISSING: arg1="SSA variable with_subclasscheck" func=With_subclasscheck.__subclasscheck__ + arg2 = object #$ MISSING: arg2="arg2" func=With_subclasscheck.__subclasscheck__ issubclass(arg2, with_subclasscheck) # 3.3.5. Emulating generic types # classmethod object.__class_getitem__(cls, key) -class With_class_getitem: +class With_class_getitem: #$ MISSING: arg1="With_class_getitem" func=With_class_getitem.__class_getitem__ def __class_getitem__(cls, key): - SINK2(key) #$ MISSING: arg2="arg2, l:496 -> key" - SINK1(cls) #$ MISSING: arg1="With_class_getitem, l:487 -> cls" + SINK2(key) + SINK1(cls) OK() # Call not found return object def test_class_getitem(): - arg2 = int + arg2 = int #$ MISSING: arg2="arg2" func=With_class_getitem.__class_getitem__ with_class_getitem = With_class_getitem[arg2]() @@ -501,12 +501,12 @@ def test_class_getitem(): # object.__call__(self[, args...]) class With_call: def __call__(self): - SINK1(self) #$ MISSING: arg1="with_call, l:509 -> self" + SINK1(self) OK() # Call not found def test_call(): - with_call = With_call() + with_call = With_call() #$ MISSING: arg1="SSA variable with_call" func=With_call.__call__ with_call() @@ -514,23 +514,23 @@ def test_call(): # object.__len__(self) class With_len: def __len__(self): - SINK1(self) #$ MISSING: arg1="with_len, l:523 -> self" arg1="with_len, l:528 -> self" arg1="with_len, l:533 -> self" + SINK1(self) OK() # Call not found return 0 def test_len(): - with_len = With_len() + with_len = With_len() #$ MISSING: arg1="SSA variable with_len" func=With_len.__len__ len(with_len) def test_len_bool(): - with_len = With_len() + with_len = With_len() #$ MISSING: arg1="SSA variable with_len" func=With_len.__len__ bool(with_len) def test_len_if(): - with_len = With_len() + with_len = With_len() #$ MISSING: arg1="SSA variable with_len" func=With_len.__len__ if with_len: pass @@ -538,7 +538,7 @@ def test_len_if(): # object.__length_hint__(self) class With_length_hint: def __length_hint__(self): - SINK1(self) #$ MISSING: arg1="with_length_hint, l:549 -> self" + SINK1(self) OK() # Call not found return 0 @@ -546,108 +546,108 @@ def __length_hint__(self): def test_length_hint(): import operator - with_length_hint = With_length_hint() + with_length_hint = With_length_hint() #$ MISSING: arg1="SSA variable with_length_hint" func=With_length_hint.__length_hint__ operator.length_hint(with_length_hint) # object.__getitem__(self, key) class With_getitem: def __getitem__(self, key): - SINK2(key) #$ arg2="arg2, l:565 -> key" - SINK1(self) #$ arg1="SSA variable with_getitem, l:563 -> self" + SINK2(key) + SINK1(self) OK() return "" def test_getitem(): - with_getitem = With_getitem() + with_getitem = With_getitem() #$ arg1="SSA variable with_getitem" func=With_getitem.__getitem__ arg2 = 0 - with_getitem[arg2] + with_getitem[arg2] #$ arg2="arg2" func=With_getitem.__getitem__ # object.__setitem__(self, key, value) class With_setitem: def __setitem__(self, key, value): - SINK3(value) #$ arg3="arg3, l:581 -> value" - SINK2(key) #$ arg2="arg2, l:581 -> key" - SINK1(self) #$ arg1="SSA variable with_setitem, l:578 -> self" + SINK3(value) + SINK2(key) + SINK1(self) OK() def test_setitem(): - with_setitem = With_setitem() + with_setitem = With_setitem() #$ arg1="SSA variable with_setitem" func=With_setitem.__setitem__ arg2 = 0 arg3 = "" - with_setitem[arg2] = arg3 + with_setitem[arg2] = arg3 #$ arg2="arg2" arg3="arg3" func=With_setitem.__setitem__ # object.__delitem__(self, key) class With_delitem: def __delitem__(self, key): - SINK2(key) #$ arg2="arg2, l:595 -> key" - SINK1(self) #$ arg1="SSA variable with_delitem, l:593 -> self" + SINK2(key) + SINK1(self) OK() def test_delitem(): - with_delitem = With_delitem() + with_delitem = With_delitem() #$ arg1="SSA variable with_delitem" func=With_delitem.__delitem__ arg2 = 0 - del with_delitem[arg2] + del with_delitem[arg2] #$ arg2="arg2" func=With_delitem.__delitem__ # object.__missing__(self, key) class With_missing(dict): def __missing__(self, key): - SINK2(key) #$ MISSING: arg2="arg2, l:609 -> key" - SINK1(self) #$ MISSING: arg1="with_missing, l:608 -> self" + SINK2(key) + SINK1(self) OK() # Call not found return "" def test_missing(): - with_missing = With_missing() - arg2 = 0 + with_missing = With_missing() #$ MISSING: arg1="SSA variable with_missing" func=With_missing.__missing__ + arg2 = 0 #$ MISSING: arg2="arg2" func=With_missing.__missing__ with_missing[arg2] # object.__iter__(self) class With_iter: def __iter__(self): - SINK1(self) #$ MISSING: arg1="with_iter, l:622 -> self" + SINK1(self) OK() # Call not found return [].__iter__() def test_iter(): - with_iter = With_iter() + with_iter = With_iter() #$ MISSING: arg1="SSA variable with_iter" func=With_iter.__iter__ [x for x in with_iter] # object.__reversed__(self) class With_reversed: def __reversed__(self): - SINK1(self) #$ MISSING: arg1="with_reversed, l:635 -> self" + SINK1(self) OK() # Call not found return [].__iter__ def test_reversed(): - with_reversed = With_reversed() + with_reversed = With_reversed() #$ MISSING: arg1="SSA variable with_reversed" func=With_reversed.__reversed__ reversed(with_reversed) # object.__contains__(self, item) class With_contains: def __contains__(self, item): - SINK2(item) #$ MISSING: arg2="arg2, l:650 -> item" - SINK1(self) #$ MISSING: arg1="with_contains, l:649 -> self" + SINK2(item) + SINK1(self) OK() # Call not found return True def test_contains(): - with_contains = With_contains() - arg2 = 0 + with_contains = With_contains() #$ MISSING: arg1="SSA variable with_contains" func=With_contains.__contains__ + arg2 = 0 #$ MISSING: arg2="arg2" func=With_contains.__contains__ arg2 in with_contains @@ -655,725 +655,725 @@ def test_contains(): # object.__add__(self, other) class With_add: def __add__(self, other): - SINK2(other) #$ arg2="arg2, l:667 -> other" - SINK1(self) #$ arg1="SSA variable with_add, l:665 -> self" + SINK2(other) + SINK1(self) OK() return self def test_add(): - with_add = With_add() + with_add = With_add() #$ arg1="SSA variable with_add" func=With_add.__add__ arg2 = with_add - with_add + arg2 + with_add + arg2 #$ arg2="arg2" func=With_add.__add__ # object.__sub__(self, other) class With_sub: def __sub__(self, other): - SINK2(other) #$ arg2="arg2, l:682 -> other" - SINK1(self) #$ arg1="SSA variable with_sub, l:680 -> self" + SINK2(other) + SINK1(self) OK() return self def test_sub(): - with_sub = With_sub() + with_sub = With_sub() #$ arg1="SSA variable with_sub" func=With_sub.__sub__ arg2 = with_sub - with_sub - arg2 + with_sub - arg2 #$ arg2="arg2" func=With_sub.__sub__ # object.__mul__(self, other) class With_mul: def __mul__(self, other): - SINK2(other) #$ arg2="arg2, l:697 -> other" - SINK1(self) #$ arg1="SSA variable with_mul, l:695 -> self" + SINK2(other) + SINK1(self) OK() return self def test_mul(): - with_mul = With_mul() + with_mul = With_mul() #$ arg1="SSA variable with_mul" func=With_mul.__mul__ arg2 = with_mul - with_mul * arg2 + with_mul * arg2 #$ arg2="arg2" func=With_mul.__mul__ # object.__matmul__(self, other) class With_matmul: def __matmul__(self, other): - SINK2(other) #$ arg2="arg2, l:712 -> other" - SINK1(self) #$ arg1="SSA variable with_matmul, l:710 -> self" + SINK2(other) + SINK1(self) OK() return self def test_matmul(): - with_matmul = With_matmul() + with_matmul = With_matmul() #$ arg1="SSA variable with_matmul" func=With_matmul.__matmul__ arg2 = with_matmul - with_matmul @ arg2 + with_matmul @ arg2 #$ arg2="arg2" func=With_matmul.__matmul__ # object.__truediv__(self, other) class With_truediv: def __truediv__(self, other): - SINK2(other) #$ arg2="arg2, l:727 -> other" - SINK1(self) #$ arg1="SSA variable with_truediv, l:725 -> self" + SINK2(other) + SINK1(self) OK() return self def test_truediv(): - with_truediv = With_truediv() + with_truediv = With_truediv() #$ arg1="SSA variable with_truediv" func=With_truediv.__truediv__ arg2 = with_truediv - with_truediv / arg2 + with_truediv / arg2 #$ arg2="arg2" func=With_truediv.__truediv__ # object.__floordiv__(self, other) class With_floordiv: def __floordiv__(self, other): - SINK2(other) #$ arg2="arg2, l:742 -> other" - SINK1(self) #$ arg1="SSA variable with_floordiv, l:740 -> self" + SINK2(other) + SINK1(self) OK() return self def test_floordiv(): - with_floordiv = With_floordiv() + with_floordiv = With_floordiv() #$ arg1="SSA variable with_floordiv" func=With_floordiv.__floordiv__ arg2 = with_floordiv - with_floordiv // arg2 + with_floordiv // arg2 #$ arg2="arg2" func=With_floordiv.__floordiv__ # object.__mod__(self, other) class With_mod: def __mod__(self, other): - SINK2(other) #$ arg2="arg2, l:757 -> other" - SINK1(self) #$ arg1="SSA variable with_mod, l:755 -> self" + SINK2(other) + SINK1(self) OK() return self def test_mod(): - with_mod = With_mod() + with_mod = With_mod() #$ arg1="SSA variable with_mod" func=With_mod.__mod__ arg2 = with_mod - with_mod % arg2 + with_mod % arg2 #$ arg2="arg2" func=With_mod.__mod__ # object.__divmod__(self, other) class With_divmod: def __divmod__(self, other): - SINK2(other) #$ MISSING: arg2="arg2, l:771 -> other" - SINK1(self) #$ MISSING: arg1="with_divmod, l:770 -> self" + SINK2(other) + SINK1(self) OK() # Call not found return self def test_divmod(): - with_divmod = With_divmod() - arg2 = With_divmod + with_divmod = With_divmod() #$ MISSING: arg1="SSA variable with_divmod" func=With_divmod.__divmod__ + arg2 = With_divmod #$ MISSING: arg2="arg2" func=With_divmod.__divmod__ divmod(with_divmod, arg2) # object.__pow__(self, other[, modulo]) class With_pow: def __pow__(self, other): - SINK2(other) #$ arg2="arg2, l:793 -> other" - SINK1(self) #$ arg1="SSA variable with_pow, l:791 -> self" + SINK2(other) + SINK1(self) OK() return self def test_pow(): - with_pow = With_pow() + with_pow = With_pow() #$ MISSING: arg1="SSA variable with_pow" func=With_pow.__pow__ arg2 = with_pow - pow(with_pow, arg2) # Call not found + pow(with_pow, arg2) #$ MISSING: arg2="arg2" func=With_pow.__pow__ def test_pow_op(): - with_pow = With_pow() + with_pow = With_pow() #$ arg1="SSA variable with_pow" func=With_pow.__pow__ arg2 = with_pow - with_pow ** arg2 + with_pow ** arg2 #$ arg2="arg2" func=With_pow.__pow__ # object.__lshift__(self, other) class With_lshift: def __lshift__(self, other): - SINK2(other) #$ arg2="arg2, l:808 -> other" - SINK1(self) #$ arg1="SSA variable with_lshift, l:806 -> self" + SINK2(other) + SINK1(self) OK() return self def test_lshift(): - with_lshift = With_lshift() + with_lshift = With_lshift() #$ arg1="SSA variable with_lshift" func=With_lshift.__lshift__ arg2 = with_lshift - with_lshift << arg2 + with_lshift << arg2 #$ arg2="arg2" func=With_lshift.__lshift__ # object.__rshift__(self, other) class With_rshift: def __rshift__(self, other): - SINK2(other) #$ arg2="arg2, l:823 -> other" - SINK1(self) #$ arg1="SSA variable with_rshift, l:821 -> self" + SINK2(other) + SINK1(self) OK() return self def test_rshift(): - with_rshift = With_rshift() + with_rshift = With_rshift() #$ arg1="SSA variable with_rshift" func=With_rshift.__rshift__ arg2 = with_rshift - with_rshift >> arg2 + with_rshift >> arg2 #$ arg2="arg2" func=With_rshift.__rshift__ # object.__and__(self, other) class With_and: def __and__(self, other): - SINK2(other) #$ arg2="arg2, l:838 -> other" - SINK1(self) #$ arg1="SSA variable with_and, l:836 -> self" + SINK2(other) + SINK1(self) OK() return self def test_and(): - with_and = With_and() + with_and = With_and() #$ arg1="SSA variable with_and" func=With_and.__and__ arg2 = with_and - with_and & arg2 + with_and & arg2 #$ arg2="arg2" func=With_and.__and__ # object.__xor__(self, other) class With_xor: def __xor__(self, other): - SINK2(other) #$ arg2="arg2, l:853 -> other" - SINK1(self) #$ arg1="SSA variable with_xor, l:851 -> self" + SINK2(other) + SINK1(self) OK() return self def test_xor(): - with_xor = With_xor() + with_xor = With_xor() #$ arg1="SSA variable with_xor" func=With_xor.__xor__ arg2 = with_xor - with_xor ^ arg2 + with_xor ^ arg2 #$ arg2="arg2" func=With_xor.__xor__ # object.__or__(self, other) class With_or: def __or__(self, other): - SINK2(other) #$ arg2="arg2, l:868 -> other" - SINK1(self) #$ arg1="SSA variable with_or, l:866 -> self" + SINK2(other) + SINK1(self) OK() return self def test_or(): - with_or = With_or() + with_or = With_or() #$ arg1="SSA variable with_or" func=With_or.__or__ arg2 = with_or - with_or | arg2 + with_or | arg2 #$ arg2="arg2" func=With_or.__or__ # object.__radd__(self, other) class With_radd: def __radd__(self, other): SINK2(other) #$ MISSING: arg2="arg2, l:882 -> other" - SINK1(self) #$ MISSING: arg1="with_radd, l:881 -> self" + SINK1(self) OK() # Call not found return self def test_radd(): - with_radd = With_radd() - arg2 = "" + with_radd = With_radd() #$ MISSING: arg1="SSA variable with_radd" func=With_radd.__radd__ + arg2 = "" #$ MISSING: arg2="arg2" func=With_radd.__radd__ arg2 + with_radd # object.__rsub__(self, other) class With_rsub: def __rsub__(self, other): - SINK2(other) #$ MISSING: arg2="arg2, l:897 -> other" - SINK1(self) #$ MISSING: arg1="with_rsub, l:896 -> self" + SINK2(other) + SINK1(self) OK() # Call not found return self def test_rsub(): - with_rsub = With_rsub() - arg2 = "" + with_rsub = With_rsub() #$ MISSING: arg1="SSA variable with_rsub" func=With_rsub.__rsub__ + arg2 = "" #$ MISSING: arg2="arg2" func=With_rsub.__rsub__ arg2 - with_rsub # object.__rmul__(self, other) class With_rmul: def __rmul__(self, other): - SINK2(other) #$ MISSING: arg2="arg2, l:912 -> other" - SINK1(self) #$ MISSING: arg1="with_rmul, l:911 -> self" + SINK2(other) + SINK1(self) OK() # Call not found return self def test_rmul(): - with_rmul = With_rmul() - arg2 = "" + with_rmul = With_rmul() #$ MISSING: arg1="SSA variable with_rmul" func=With_rmul.__rmul__ + arg2 = "" #$ MISSING: arg2="arg2" func=With_rmul.__rmul__ arg2 * with_rmul # object.__rmatmul__(self, other) class With_rmatmul: def __rmatmul__(self, other): - SINK2(other) #$ MISSING: arg2="arg2, l:927 -> other" - SINK1(self) #$ MISSING: arg1="with_rmatmul, l:926 -> self" + SINK2(other) + SINK1(self) OK() # Call not found return self def test_rmatmul(): - with_rmatmul = With_rmatmul() - arg2 = "" + with_rmatmul = With_rmatmul() #$ MISSING: arg1="SSA variable with_rmatmul" func=With_rmatmul.__rmatmul__ + arg2 = "" #$ MISSING: arg2="arg2" func=With_rmatmul.__rmatmul__ arg2 @ with_rmatmul # object.__rtruediv__(self, other) class With_rtruediv: def __rtruediv__(self, other): - SINK2(other) #$ MISSING: arg2="arg2, l:942 -> other" - SINK1(self) #$ MISSING: arg1="with_rtruediv, l:941 -> self" + SINK2(other) + SINK1(self) OK() # Call not found return self def test_rtruediv(): - with_rtruediv = With_rtruediv() - arg2 = "" + with_rtruediv = With_rtruediv() #$ MISSING: arg1="SSA variable with_rtruediv" func=With_rtruediv.__rtruediv__ + arg2 = "" #$ MISSING: arg2="arg2" func=With_rtruediv.__rtruediv__ arg2 / with_rtruediv # object.__rfloordiv__(self, other) class With_rfloordiv: def __rfloordiv__(self, other): - SINK2(other) #$ MISSING: arg2="arg2, l:957 -> other" - SINK1(self) #$ MISSING: arg1="with_rfloordiv, l:956 -> self" + SINK2(other) + SINK1(self) OK() # Call not found return self def test_rfloordiv(): - with_rfloordiv = With_rfloordiv() - arg2 = "" + with_rfloordiv = With_rfloordiv() #$ MISSING: arg1="SSA variable with_rfloordiv" func=With_rfloordiv.__rfloordiv__ + arg2 = "" #$ MISSING: arg2="arg2" func=With_rfloordiv.__rfloordiv__ arg2 // with_rfloordiv # object.__rmod__(self, other) class With_rmod: def __rmod__(self, other): - SINK2(other) #$ MISSING: arg2="arg2, l:972 -> other" - SINK1(self) #$ MISSING: arg1="with_rmod, l:971 -> self" + SINK2(other) + SINK1(self) OK() # Call not found return self def test_rmod(): - with_rmod = With_rmod() - arg2 = {} + with_rmod = With_rmod() #$ MISSING: arg1="SSA variable with_rmod" func=With_rmod.__rmod__ + arg2 = {} #$ MISSING: arg2="arg2" func=With_rmod.__rmod__ arg2 % with_rmod # object.__rdivmod__(self, other) class With_rdivmod: def __rdivmod__(self, other): - SINK2(other) #$ MISSING: arg2="arg2, l:987 -> other" - SINK1(self) #$ MISSING: arg1="with_rdivmod, l:986 -> self" + SINK2(other) + SINK1(self) OK() # Call not found return self def test_rdivmod(): - with_rdivmod = With_rdivmod() - arg2 = "" + with_rdivmod = With_rdivmod() #$ MISSING: arg1="SSA variable with_rdivmod" func=With_rdivmod.__rdivmod__ + arg2 = "" #$ MISSING: arg2="arg2" func=With_rdivmod.__rdivmod__ divmod(arg2, with_rdivmod) # object.__rpow__(self, other[, modulo]) class With_rpow: def __rpow__(self, other): - SINK2(other) #$ MISSING: arg2="arg2, l:1002 -> other" arg2="arg2, l:1008 -> other" - SINK1(self) #$ MISSING: arg1="with_rpow, l:1001 -> self" arg1="with_rpow, l:1007 -> self" + SINK2(other) + SINK1(self) OK() # Call not found return self def test_rpow(): - with_rpow = With_rpow() - arg2 = "" + with_rpow = With_rpow() #$ MISSING: arg1="SSA variable with_rpow" func=With_rpow.__rpow__ + arg2 = "" #$ MISSING: arg2="arg2" func=With_rpow.__rpow__ pow(arg2, with_rpow) def test_rpow_op(): - with_rpow = With_rpow() - arg2 = "" + with_rpow = With_rpow() #$ MISSING: arg1="SSA variable with_rpow" func=With_rpow.__rpow__ + arg2 = "" #$ MISSING: arg2="arg2" func=With_rpow.__rpow__ arg2 ** with_rpow # object.__rlshift__(self, other) class With_rlshift: def __rlshift__(self, other): - SINK2(other) #$ MISSING: arg2="arg2, l:1023 -> other" - SINK1(self) #$ MISSING: arg1="with_rlshift, l:1022 -> self" + SINK2(other) + SINK1(self) OK() # Call not found return self def test_rlshift(): - with_rlshift = With_rlshift() - arg2 = "" + with_rlshift = With_rlshift() #$ MISSING: arg1="SSA variable with_rlshift" func=With_rlshift.__rlshift__ + arg2 = "" #$ MISSING: arg2="arg2" func=With_rlshift.__rlshift__ arg2 << with_rlshift # object.__rrshift__(self, other) class With_rrshift: def __rrshift__(self, other): - SINK2(other) #$ MISSING: arg2="arg2, l:1038 -> other" - SINK1(self) #$ MISSING: arg1="with_rrshift, l:1037 -> self" + SINK2(other) + SINK1(self) OK() # Call not found return self def test_rrshift(): - with_rrshift = With_rrshift() - arg2 = "" + with_rrshift = With_rrshift() #$ MISSING: arg1="SSA variable with_rrshift" func=With_rrshift.__rrshift__ + arg2 = "" #$ MISSING: arg2="arg2" func=With_rrshift.__rrshift__ arg2 >> with_rrshift # object.__rand__(self, other) class With_rand: def __rand__(self, other): - SINK2(other) #$ MISSING: arg2="arg2, l:1053 -> other" - SINK1(self) #$ MISSING: arg1="with_rand, l:1052 -> self" + SINK2(other) + SINK1(self) OK() # Call not found return self def test_rand(): - with_rand = With_rand() - arg2 = "" + with_rand = With_rand() #$ MISSING: arg1="SSA variable with_rand" func=With_rand.__rand__ + arg2 = "" #$ MISSING: arg2="arg2" func=With_rand.__rand__ arg2 & with_rand # object.__rxor__(self, other) class With_rxor: def __rxor__(self, other): - SINK2(other) #$ MISSING: arg2="arg2, l:1068 -> other" - SINK1(self) #$ MISSING: arg1="with_rxor, l:1067 -> self" + SINK2(other) + SINK1(self) OK() # Call not found return self def test_rxor(): - with_rxor = With_rxor() - arg2 = "" + with_rxor = With_rxor() #$ MISSING: arg1="SSA variable with_rxor" func=With_rxor.__rxor__ + arg2 = "" #$ MISSING: arg2="arg2" func=With_rxor.__rxor__ arg2 ^ with_rxor # object.__ror__(self, other) class With_ror: def __ror__(self, other): - SINK2(other) #$ MISSING: arg2="arg2, l:1083 -> other" - SINK1(self) #$ MISSING: arg1="with_ror, l:1082 -> self" + SINK2(other) + SINK1(self) OK() # Call not found return self def test_ror(): - with_ror = With_ror() - arg2 = "" + with_ror = With_ror() #$ MISSING: arg1="SSA variable with_ror" func=With_ror.__ror__ + arg2 = "" #$ MISSING: arg2="arg2" func=With_ror.__ror__ arg2 | with_ror # object.__iadd__(self, other) class With_iadd: def __iadd__(self, other): - SINK2(other) #$ MISSING: arg2="arg2, l:1098 -> other" - SINK1(self) #$ MISSING: arg1="with_iadd, l:1097 -> self" + SINK2(other) + SINK1(self) OK() # Call not found return self def test_iadd(): - with_iadd = With_iadd() - arg2 = with_iadd + with_iadd = With_iadd() #$ MISSING: arg1="SSA variable with_iadd" func=With_iadd.__iadd__ + arg2 = with_iadd #$ MISSING: arg2="arg2" func=With_iadd.__iadd__ with_iadd += arg2 # object.__isub__(self, other) class With_isub: def __isub__(self, other): - SINK2(other) #$ MISSING: arg2="arg2, l:1113 -> other" - SINK1(self) #$ MISSING: arg1="with_isub, l:1112 -> self" + SINK2(other) + SINK1(self) OK() # Call not found return self def test_isub(): - with_isub = With_isub() - arg2 = with_isub + with_isub = With_isub() #$ MISSING: arg1="SSA variable with_isub" func=With_isub.__isub__ + arg2 = with_isub #$ MISSING: arg2="arg2" func=With_isub.__isub__ with_isub -= arg2 # object.__imul__(self, other) class With_imul: def __imul__(self, other): - SINK2(other) #$ MISSING: arg2="arg2, l:1128 -> other" - SINK1(self) #$ MISSING: arg1="with_imul, l:1127 -> self" + SINK2(other) + SINK1(self) OK() # Call not found return self def test_imul(): - with_imul = With_imul() - arg2 = with_imul + with_imul = With_imul() #$ MISSING: arg1="SSA variable with_imul" func=With_imul.__imul__ + arg2 = with_imul #$ MISSING: arg2="arg2" func=With_imul.__imul__ with_imul *= arg2 # object.__imatmul__(self, other) class With_imatmul: def __imatmul__(self, other): - SINK2(other) #$ MISSING: arg2="arg2, l:1143 -> other" - SINK1(self) #$ MISSING: arg1="with_imatmul, l:1142 -> self" + SINK2(other) + SINK1(self) OK() # Call not found return self def test_imatmul(): - with_imatmul = With_imatmul() - arg2 = with_imatmul + with_imatmul = With_imatmul() #$ MISSING: arg1="SSA variable with_imatmul" func=With_imatmul.__imatmul__ + arg2 = with_imatmul #$ MISSING: arg2="arg2" func=With_imatmul.__imatmul__ with_imatmul @= arg2 # object.__itruediv__(self, other) class With_itruediv: def __itruediv__(self, other): - SINK2(other) #$ MISSING: arg2="arg2, l:1158 -> other" - SINK1(self) #$ MISSING: arg1="with_itruediv, l:1157 -> self" + SINK2(other) + SINK1(self) OK() # Call not found return self def test_itruediv(): - with_itruediv = With_itruediv() - arg2 = with_itruediv + with_itruediv = With_itruediv() #$ MISSING: arg1="SSA variable with_itruediv" func=With_itruediv.__itruediv__ + arg2 = with_itruediv #$ MISSING: arg2="arg2" func=With_itruediv.__itruediv__ with_itruediv /= arg2 # object.__ifloordiv__(self, other) class With_ifloordiv: def __ifloordiv__(self, other): - SINK2(other) #$ MISSING: arg2="arg2, l:1173 -> other" - SINK1(self) #$ MISSING: arg1="with_ifloordiv, l:172 -> self" + SINK2(other) + SINK1(self) OK() # Call not found return self def test_ifloordiv(): - with_ifloordiv = With_ifloordiv() - arg2 = with_ifloordiv + with_ifloordiv = With_ifloordiv() #$ MISSING: arg1="SSA variable with_ifloordiv" func=With_ifloordiv.__ifloordiv__ + arg2 = with_ifloordiv #$ MISSING: arg2="arg2" func=With_ifloordiv.__ifloordiv__ with_ifloordiv //= arg2 # object.__imod__(self, other) class With_imod: def __imod__(self, other): - SINK2(other) #$ MISSING: arg2="arg2, l:1188 -> other" - SINK1(self) #$ MISSING: arg1="with_imod, l:1187 -> self" + SINK2(other) + SINK1(self) OK() # Call not found return self def test_imod(): - with_imod = With_imod() - arg2 = with_imod + with_imod = With_imod() #$ MISSING: arg1="SSA variable with_imod" func=With_imod.__imod__ + arg2 = with_imod #$ MISSING: arg2="arg2" func=With_imod.__imod__ with_imod %= arg2 # object.__ipow__(self, other[, modulo]) class With_ipow: def __ipow__(self, other): - SINK2(other) #$ MISSING: arg2="arg2, l:1203 -> other" - SINK1(self) #$ MISSING: arg1="with_ipow, l:1202 -> self" + SINK2(other) + SINK1(self) OK() # Call not found return self def test_ipow(): - with_ipow = With_ipow() - arg2 = with_ipow + with_ipow = With_ipow() #$ MISSING: arg1="SSA variable with_ipow" func=With_ipow.__ipow__ + arg2 = with_ipow #$ MISSING: arg2="arg2" func=With_ipow.__ipow__ with_ipow **= arg2 # object.__ilshift__(self, other) class With_ilshift: def __ilshift__(self, other): - SINK2(other) #$ MISSING: arg2="arg2, l:1218 -> other" - SINK1(self) #$ MISSING: arg1="with_ilshift, l:1217 -> self" + SINK2(other) + SINK1(self) OK() # Call not found return self def test_ilshift(): - with_ilshift = With_ilshift() - arg2 = with_ilshift + with_ilshift = With_ilshift() #$ MISSING: arg1="SSA variable with_ilshift" func=With_ilshift.__ilshift__ + arg2 = with_ilshift #$ MISSING: arg2="arg2" func=With_ilshift.__ilshift__ with_ilshift <<= arg2 # object.__irshift__(self, other) class With_irshift: def __irshift__(self, other): - SINK2(other) #$ MISSING: arg2="arg2, l:1233 -> other" - SINK1(self) #$ MISSING: arg1="with_irshift, l:1232 -> self" + SINK2(other) + SINK1(self) OK() # Call not found return self def test_irshift(): - with_irshift = With_irshift() - arg2 = with_irshift + with_irshift = With_irshift() #$ MISSING: arg1="SSA variable with_irshift" func=With_irshift.__irshift__ + arg2 = with_irshift #$ MISSING: arg2="arg2" func=With_irshift.__irshift__ with_irshift >>= arg2 # object.__iand__(self, other) class With_iand: def __iand__(self, other): - SINK2(other) #$ MISSING: arg2="arg2, l:1248 -> other" - SINK1(self) #$ MISSING: arg1="with_iand, l:1247 -> self" + SINK2(other) + SINK1(self) OK() # Call not found return self def test_iand(): - with_iand = With_iand() - arg2 = with_iand + with_iand = With_iand() #$ MISSING: arg1="SSA variable with_iand" func=With_iand.__iand__ + arg2 = with_iand #$ MISSING: arg2="arg2" func=With_iand.__iand__ with_iand &= arg2 # object.__ixor__(self, other) class With_ixor: def __ixor__(self, other): - SINK2(other) #$ MISSING: arg2="arg2, l:1263 -> other" - SINK1(self) #$ MISSING: arg1="with_ixor, l:1262 -> self" + SINK2(other) + SINK1(self) OK() # Call not found return self def test_ixor(): - with_ixor = With_ixor() - arg2 = with_ixor + with_ixor = With_ixor() #$ MISSING: arg1="SSA variable with_ixor" func=With_ixor.__ixor__ + arg2 = with_ixor #$ MISSING: arg2="arg2" func=With_ixor.__ixor__ with_ixor ^= arg2 # object.__ior__(self, other) class With_ior: def __ior__(self, other): - SINK2(other) #$ MISSING: arg2="arg2, l:1278 -> other" - SINK1(self) #$ MISSING: arg1="with_ior, l:1277 -> self" + SINK2(other) + SINK1(self) OK() # Call not found return self def test_ior(): - with_ior = With_ior() - arg2 = with_ior + with_ior = With_ior() #$ MISSING: arg1="SSA variable with_ior" func=With_ior.__ior__ + arg2 = with_ior #$ MISSING: arg2="arg2" func=With_ior.__ior__ with_ior |= arg2 # object.__neg__(self) class With_neg: def __neg__(self): - SINK1(self) #$ MISSING: arg1="with_neg, l:1291 -> self" + SINK1(self) OK() # Call not found return self def test_neg(): - with_neg = With_neg() + with_neg = With_neg() #$ MISSING: arg1="SSA variable with_neg" func=With_neg.__neg__ -with_neg # object.__pos__(self) class With_pos: def __pos__(self): - SINK1(self) #$ MISSING: arg1="with_pos, l:1303 -> self" + SINK1(self) OK() # Call not found return self def test_pos(): - with_pos = With_pos() + with_pos = With_pos() #$ MISSING: arg1="SSA variable with_pos" func=With_pos.__pos__ +with_pos # object.__abs__(self) class With_abs: def __abs__(self): - SINK1(self) #$ MISSING: arg1="with_abs, l:1317 -> self" + SINK1(self) OK() # Call not found return self def test_abs(): - with_abs = With_abs() + with_abs = With_abs() #$ MISSING: arg1="SSA variable with_abs" func=With_abs.__abs__ abs(with_abs) # object.__invert__(self) class With_invert: def __invert__(self): - SINK1(self) #$ MISSING: arg1="with_invert, l:1330 -> self" + SINK1(self) OK() # Call not found return self def test_invert(): - with_invert = With_invert() + with_invert = With_invert() #$ MISSING: arg1="SSA variable with_invert" func=With_invert.__invert__ ~with_invert # object.__complex__(self) class With_complex: def __complex__(self): - SINK1(self) #$ MISSING: arg1="with_complex, l:1343 -> self" + SINK1(self) OK() # Call not found return 0j def test_complex(): - with_complex = With_complex() + with_complex = With_complex() #$ MISSING: arg1="SSA variable with_complex" func=With_complex.__complex__ complex(with_complex) # object.__int__(self) class With_int: def __int__(self): - SINK1(self) #$ MISSING: arg1="with_int, l:1356 -> self" + SINK1(self) OK() # Call not found return 0 def test_int(): - with_int = With_int() + with_int = With_int() #$ MISSING: arg1="SSA variable with_int" func=With_int.__int__ int(with_int) # object.__float__(self) class With_float: def __float__(self): - SINK1(self) #$ MISSING: arg1="with_float, l:1369 -> self" + SINK1(self) OK() # Call not found return 0.0 def test_float(): - with_float = With_float() + with_float = With_float() #$ MISSING: arg1="SSA variable with_float" func=With_float.__float__ float(with_float) # object.__index__(self) class With_index: def __index__(self): - SINK1(self) #$ MISSING: arg1="with_index, l:1384 -> self" arg1="with_index, l:1389 -> self" arg1="with_index, l:1394 -> self" arg1="with_index, l:1399 -> self" arg1="with_index, l:1404 -> self" arg1="with_index, l:1409 -> self" arg1="with_index, l:1414 -> self" arg1="with_index, l:1419 -> self" + SINK1(self) OK() # Call not found return 0 @@ -1381,68 +1381,68 @@ def __index__(self): def test_index(): import operator - with_index = With_index() + with_index = With_index() #$ MISSING: arg1="SSA variable with_index" func=With_index.__index__ operator.index(with_index) def test_index_slicing(): - with_index = With_index() + with_index = With_index() #$ MISSING: arg1="SSA variable with_index" func=With_index.__index__ [0][with_index:1] def test_index_bin(): - with_index = With_index() + with_index = With_index() #$ MISSING: arg1="SSA variable with_index" func=With_index.__index__ bin(with_index) def test_index_hex(): - with_index = With_index() + with_index = With_index() #$ MISSING: arg1="SSA variable with_index" func=With_index.__index__ hex(with_index) def test_index_oct(): - with_index = With_index() + with_index = With_index() #$ MISSING: arg1="SSA variable with_index" func=With_index.__index__ oct(with_index) def test_index_int(): - with_index = With_index() + with_index = With_index() #$ MISSING: arg1="SSA variable with_index" func=With_index.__index__ int(with_index) def test_index_float(): - with_index = With_index() + with_index = With_index() #$ MISSING: arg1="SSA variable with_index" func=With_index.__index__ float(with_index) def test_index_complex(): - with_index = With_index() + with_index = With_index() #$ MISSING: arg1="SSA variable with_index" func=With_index.__index__ complex(with_index) # object.__round__(self[, ndigits]) class With_round: def __round__(self): - SINK1(self) #$ MISSING: arg1="with_round, l:1432 -> self" + SINK1(self) OK() # Call not found return 0 def test_round(): - with_round = With_round() + with_round = With_round() #$ MISSING: arg1="SSA variable with_round" func=With_round.__round__ round(with_round) # object.__trunc__(self) class With_trunc: def __trunc__(self): - SINK1(self) #$ MISSING: arg1="with_trunc, l:1445 -> self" + SINK1(self) OK() # Call not found return 0 def test_trunc(): - with_trunc = With_trunc() + with_trunc = With_trunc() #$ MISSING: arg1="SSA variable with_trunc" func=With_trunc.__trunc__ import math math.trunc(with_trunc) @@ -1451,13 +1451,13 @@ def test_trunc(): # object.__floor__(self) class With_floor: def __floor__(self): - SINK1(self) #$ MISSING: arg1="with_floor, l:1460 -> self" + SINK1(self) OK() # Call not found return 0 def test_floor(): - with_floor = With_floor() + with_floor = With_floor() #$ MISSING: arg1="SSA variable with_floor" func=With_floor.__floor__ import math math.floor(with_floor) @@ -1466,13 +1466,13 @@ def test_floor(): # object.__ceil__(self) class With_ceil: def __ceil__(self): - SINK1(self) #$ MISSING: arg1="with_ceil, l:147 -> self" + SINK1(self) OK() # Call not found return 0 def test_ceil(): - with_ceil = With_ceil() + with_ceil = With_ceil() #$ MISSING: arg1="SSA variable with_ceil" func=With_ceil.__ceil__ import math math.ceil(with_ceil) @@ -1482,7 +1482,7 @@ def test_ceil(): # object.__enter__(self) class With_enter: def __enter__(self): - SINK1(self) #$ MISSING: arg1=".0, l:1494 -> self" + SINK1(self) OK() # Call not found return @@ -1504,7 +1504,7 @@ def __exit__(self, exc_type, exc_value, traceback): SINK4(traceback) # Flow not tested SINK3(exc_value) # Flow not tested SINK2(exc_type) # Flow not tested - SINK1(self) #$ MISSING: arg1=".0, l:1513 -> self" + SINK1(self) OK() # Call not found return @@ -1519,13 +1519,13 @@ def test_exit(): # object.__await__(self) class With_await: def __await__(self): - SINK1(self) #$ MISSING: arg1="with_await, l:1528 -> self" + SINK1(self) OK() # Call not found return (yield from asyncio.coroutine(lambda: "")()) async def atest_await(): - with_await = With_await() + with_await = With_await() #$ MISSING: arg1="SSA variable with_await" func=With_await.__await__ await (with_await) @@ -1538,7 +1538,7 @@ async def atest_await(): # object.__aiter__(self) class With_aiter: def __aiter__(self): - SINK1(self) #$ MISSING: arg1="with_aiter, l:1550 -> self" + SINK1(self) OK() # Call not found return self @@ -1547,7 +1547,7 @@ async def __anext__(self): async def atest_aiter(): - with_aiter = With_aiter() + with_aiter = With_aiter() #$ MISSING: arg1="SSA variable with_aiter" func=With_aiter.__aiter__ async for x in with_aiter: pass @@ -1558,13 +1558,13 @@ def __aiter__(self): return self async def __anext__(self): - SINK1(self) #$ MISSING: arg1="with_anext, l:1567 -> self" + SINK1(self) OK() # Call not found raise StopAsyncIteration async def atest_anext(): - with_anext = With_anext() + with_anext = With_anext() #$ MISSING: arg1="SSA variable with_anext" func=With_anext.__anext__ async for x in with_anext: pass @@ -1573,7 +1573,7 @@ async def atest_anext(): # object.__aenter__(self) class With_aenter: async def __aenter__(self): - SINK1(self) #$ MISSING: arg1="with_aenter, l:1584 -> self" + SINK1(self) OK() # Call not found async def __aexit__(self, exc_type, exc_value, traceback): @@ -1581,7 +1581,7 @@ async def __aexit__(self, exc_type, exc_value, traceback): async def atest_aenter(): - with_aenter = With_aenter() + with_aenter = With_aenter() #$ MISSING: arg1="SSA variable with_aenter" func=With_aenter.__aenter__ async with with_aenter: pass @@ -1595,11 +1595,11 @@ async def __aexit__(self, exc_type, exc_value, traceback): SINK4(traceback) # Flow not tested SINK3(exc_value) # Flow not tested SINK2(exc_type) # Flow not tested - SINK1(self) #$ MISSING: arg1="with_aexit, l:1603 -> self" + SINK1(self) OK() # Call not found async def atest_aexit(): - with_aexit = With_aexit() + with_aexit = With_aexit() #$ MISSING: arg1="SSA variable with_aexit" func=With_aexit.__aexit__ async with with_aexit: pass diff --git a/python/ql/test/experimental/dataflow/coverage/datamodel.py b/python/ql/test/experimental/dataflow/coverage/datamodel.py index 3f11593dbd19..6c20ed60755e 100644 --- a/python/ql/test/experimental/dataflow/coverage/datamodel.py +++ b/python/ql/test/experimental/dataflow/coverage/datamodel.py @@ -153,7 +153,7 @@ def __init__(self): # testing __new__ and __init__ customized = Customized() -SINK(Customized.a) +SINK(Customized.a) #$ MISSING:flow="SOURCE, l:-8 -> customized.a" SINK_F(Customized.b) -SINK(customized.a) -SINK(customized.b) #$ flow="SOURCE, l:152 -> customized.b" +SINK(customized.a) #$ MISSING:flow="SOURCE, l:-10 -> customized.a" +SINK(customized.b) #$ flow="SOURCE, l:-7 -> customized.b" diff --git a/python/ql/test/experimental/dataflow/coverage/test.py b/python/ql/test/experimental/dataflow/coverage/test.py index 2a1f7dca58c3..eb33273cd4e7 100644 --- a/python/ql/test/experimental/dataflow/coverage/test.py +++ b/python/ql/test/experimental/dataflow/coverage/test.py @@ -41,7 +41,7 @@ def SINK_F(x): def test_tuple_with_local_flow(): x = (NONSOURCE, SOURCE) y = x[1] - SINK(y) #$ flow="SOURCE, l:42 -> y" + SINK(y) #$ flow="SOURCE, l:-2 -> y" def test_tuple_negative(): @@ -53,45 +53,45 @@ def test_tuple_negative(): # 6.2.1. Identifiers (Names) def test_names(): x = SOURCE - SINK(x) #$ flow="SOURCE, l:55 -> x" + SINK(x) #$ flow="SOURCE, l:-1 -> x" # 6.2.2. Literals def test_string_literal(): x = "source" - SINK(x) #$ flow="'source', l:61 -> x" + SINK(x) #$ flow="'source', l:-1 -> x" def test_bytes_literal(): x = b"source" - SINK(x) #$ flow="b'source', l:66 -> x" + SINK(x) #$ flow="b'source', l:-1 -> x" def test_integer_literal(): x = 42 - SINK(x) #$ flow="42, l:71 -> x" + SINK(x) #$ flow="42, l:-1 -> x" def test_floatnumber_literal(): x = 42.0 - SINK(x) #$ flow="42.0, l:76 -> x" + SINK(x) #$ flow="42.0, l:-1 -> x" def test_imagnumber_literal(): x = 42j - SINK(x) #$ MISSING:flow="42j, l:81 -> x" + SINK(x) #$ MISSING:flow="42j, l:-1 -> x" # 6.2.3. Parenthesized forms def test_parenthesized_form(): x = (SOURCE) - SINK(x) #$ flow="SOURCE, l:87 -> x" + SINK(x) #$ flow="SOURCE, l:-1 -> x" # 6.2.5. List displays def test_list_display(): x = [SOURCE] - SINK(x[0]) #$ flow="SOURCE, l:93 -> x[0]" + SINK(x[0]) #$ flow="SOURCE, l:-1 -> x[0]" def test_list_display_negative(): @@ -101,103 +101,103 @@ def test_list_display_negative(): def test_list_comprehension(): x = [SOURCE for y in [NONSOURCE]] - SINK(x[0]) #$ flow="SOURCE, l:103 -> x[0]" + SINK(x[0]) #$ flow="SOURCE, l:-1 -> x[0]" def test_list_comprehension_flow(): x = [y for y in [SOURCE]] - SINK(x[0]) #$ flow="SOURCE, l:108 -> x[0]" + SINK(x[0]) #$ flow="SOURCE, l:-1 -> x[0]" def test_list_comprehension_inflow(): l = [SOURCE] x = [y for y in l] - SINK(x[0]) #$ flow="SOURCE, l:113 -> x[0]" + SINK(x[0]) #$ flow="SOURCE, l:-2 -> x[0]" def test_nested_list_display(): x = [*[SOURCE]] - SINK(x[0]) #$ MISSING:flow="SOURCE, l:119 -> x[0]" + SINK(x[0]) #$ MISSING:flow="SOURCE, l:-1 -> x[0]" # 6.2.6. Set displays def test_set_display(): x = {SOURCE} - SINK(x.pop()) #$ flow="SOURCE, l:125 -> x.pop()" + SINK(x.pop()) #$ flow="SOURCE, l:-1 -> x.pop()" def test_set_comprehension(): x = {SOURCE for y in [NONSOURCE]} - SINK(x.pop()) #$ flow="SOURCE, l:130 -> x.pop()" + SINK(x.pop()) #$ flow="SOURCE, l:-1 -> x.pop()" def test_set_comprehension_flow(): x = {y for y in [SOURCE]} - SINK(x.pop()) #$ flow="SOURCE, l:135 -> x.pop()" + SINK(x.pop()) #$ flow="SOURCE, l:-1 -> x.pop()" def test_set_comprehension_inflow(): l = {SOURCE} x = {y for y in l} - SINK(x.pop()) #$ flow="SOURCE, l:140 -> x.pop()" + SINK(x.pop()) #$ flow="SOURCE, l:-2 -> x.pop()" def test_nested_set_display(): x = {*{SOURCE}} - SINK(x.pop()) #$ MISSING:flow="SOURCE, l:146 -> x.pop()" + SINK(x.pop()) #$ MISSING:flow="SOURCE, l:-1 -> x.pop()" # 6.2.7. Dictionary displays def test_dict_display(): x = {"s": SOURCE} - SINK(x["s"]) #$ flow="SOURCE, l:152 -> x['s']" + SINK(x["s"]) #$ flow="SOURCE, l:-1 -> x['s']" def test_dict_display_pop(): x = {"s": SOURCE} - SINK(x.pop("s")) #$ flow="SOURCE, l:157 -> x.pop(..)" + SINK(x.pop("s")) #$ flow="SOURCE, l:-1 -> x.pop(..)" def test_dict_comprehension(): x = {y: SOURCE for y in ["s"]} - SINK(x["s"]) #$ MISSING:flow="SOURCE, l:152 -> x['s']" + SINK(x["s"]) #$ MISSING:flow="SOURCE, l:-1 -> x['s']" def test_dict_comprehension_pop(): x = {y: SOURCE for y in ["s"]} - SINK(x.pop("s")) #$ MISSING:flow="SOURCE, l:167 -> x.pop()" + SINK(x.pop("s")) #$ MISSING:flow="SOURCE, l:-1 -> x.pop()" def test_nested_dict_display(): x = {**{"s": SOURCE}} - SINK(x["s"]) #$ MISSING:flow="SOURCE, l:172 -> x['s']" + SINK(x["s"]) #$ MISSING:flow="SOURCE, l:-1 -> x['s']" def test_nested_dict_display_pop(): x = {**{"s": SOURCE}} - SINK(x.pop("s")) #$ MISSING:flow="SOURCE, l:177 -> x.pop()" + SINK(x.pop("s")) #$ MISSING:flow="SOURCE, l:-1 -> x.pop()" # Nested comprehensions def test_nested_comprehension(): x = [y for z in [[SOURCE]] for y in z] - SINK(x[0]) #$ flow="SOURCE, l:183 -> x[0]" + SINK(x[0]) #$ flow="SOURCE, l:-1 -> x[0]" def test_nested_comprehension_deep_with_local_flow(): x = [y for v in [[[[SOURCE]]]] for u in v for z in u for y in z] - SINK(x[0]) #$ flow="SOURCE, l:188 -> x[0]" + SINK(x[0]) #$ flow="SOURCE, l:-1 -> x[0]" def test_nested_comprehension_dict(): d = {"s": [SOURCE]} x = [y for k, v in d.items() for y in v] - SINK(x[0]) #$ MISSING:flow="SOURCE, l:193 -> x[0]" + SINK(x[0]) #$ MISSING:flow="SOURCE, l:-1 -> x[0]" def test_nested_comprehension_paren(): x = [y for y in (z for z in [SOURCE])] - SINK(x[0]) #$ flow="SOURCE, l:199 -> x[0]" + SINK(x[0]) #$ flow="SOURCE, l:-1 -> x[0]" # 6.2.8. Generator expressions @@ -228,7 +228,7 @@ def test_yield_from(): # a statement rather than an expression, but related to generators def test_for(): for x in gen(SOURCE): - SINK(x) #$ MISSING:flow="SOURCE, l:230 -> x" + SINK(x) #$ MISSING:flow="SOURCE, l:-1 -> x" # 6.2.9.1. Generator-iterator methods @@ -508,12 +508,12 @@ def test_lambda_extra_keyword_flow(): def test_swap(): a = SOURCE b = NONSOURCE - SINK(a) #$ flow="SOURCE, l:509 -> a" + SINK(a) #$ flow="SOURCE, l:-2 -> a" SINK_F(b) a, b = b, a SINK_F(a) - SINK(b) #$ flow="SOURCE, l:509 -> b" + SINK(b) #$ flow="SOURCE, l:-7 -> b" def test_deep_callgraph(): @@ -538,7 +538,7 @@ def f6(arg): return f5(arg) x = f6(SOURCE) - SINK(x) #$ MISSING:flow="SOURCE, l:540 -> x" + SINK(x) #$ MISSING:flow="SOURCE, l:-1 -> x" @expects(2) From 69913c053e359caa4824f6ba58ed91817f955536 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 19 Jan 2021 18:10:22 +0100 Subject: [PATCH 10/16] Python: relative line numbers in MISSING-annotations --- .../experimental/dataflow/coverage/classes.py | 6 ++--- .../experimental/dataflow/coverage/test.py | 26 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/python/ql/test/experimental/dataflow/coverage/classes.py b/python/ql/test/experimental/dataflow/coverage/classes.py index 654297d31452..d9586f4997fd 100644 --- a/python/ql/test/experimental/dataflow/coverage/classes.py +++ b/python/ql/test/experimental/dataflow/coverage/classes.py @@ -421,7 +421,7 @@ def test_set_name(): # classmethod object.__init_subclass__(cls) class With_init_subclass: def __init_subclass__(cls): - SINK1(cls) #$ MISSING: arg1="Tuple[0], l:429 -> cls" + SINK1(cls) #$ MISSING: arg1="Tuple[0], l:+5 -> cls" OK() # Call not found @@ -441,7 +441,7 @@ class With_prepare(type): def __prepare__(name, bases, **kwds): SINK3(kwds) # Flow not tested SINK2(bases) # Flow not tested - SINK1(name) #$ MISSING: arg1="arg1, l:450 -> name" + SINK1(name) #$ MISSING: arg1="arg1, l:+6 -> name" OK() # Call not found return kwds @@ -871,7 +871,7 @@ def test_or(): # object.__radd__(self, other) class With_radd: def __radd__(self, other): - SINK2(other) #$ MISSING: arg2="arg2, l:882 -> other" + SINK2(other) #$ MISSING: arg2="arg2, l:+8 -> other" SINK1(self) OK() # Call not found return self diff --git a/python/ql/test/experimental/dataflow/coverage/test.py b/python/ql/test/experimental/dataflow/coverage/test.py index eb33273cd4e7..a37b63215a25 100644 --- a/python/ql/test/experimental/dataflow/coverage/test.py +++ b/python/ql/test/experimental/dataflow/coverage/test.py @@ -203,7 +203,7 @@ def test_nested_comprehension_paren(): # 6.2.8. Generator expressions def test_generator(): x = (SOURCE for y in [NONSOURCE]) - SINK([*x][0]) #$ MISSING:flow="SOURCE, l:205 -> List[0]" + SINK([*x][0]) #$ MISSING:flow="SOURCE, l:-1 -> List[0]" # 6.2.9. Yield expressions @@ -213,7 +213,7 @@ def gen(x): def test_yield(): g = gen(SOURCE) - SINK(next(g)) #$ MISSING:flow="SOURCE, l:215 -> next()" + SINK(next(g)) #$ MISSING:flow="SOURCE, l:-1 -> next()" def gen_from(x): @@ -222,7 +222,7 @@ def gen_from(x): def test_yield_from(): g = gen_from(SOURCE) - SINK(next(g)) #$ MISSING:flow="SOURCE, l:224 -> next()" + SINK(next(g)) #$ MISSING:flow="SOURCE, l:-1 -> next()" # a statement rather than an expression, but related to generators @@ -234,7 +234,7 @@ def test_for(): # 6.2.9.1. Generator-iterator methods def test___next__(): g = gen(SOURCE) - SINK(g.__next__()) #$ MISSING:flow="SOURCE, l:236 -> g.__next__()" + SINK(g.__next__()) #$ MISSING:flow="SOURCE, l:-1 -> g.__next__()" def gen2(x): @@ -259,7 +259,7 @@ def gen_ex(x): def test_throw(): g = gen_ex(SOURCE) n = next(g) - SINK(g.throw(TypeError)) #$ MISSING:flow="SOURCE, l:260 -> g.throw()" + SINK(g.throw(TypeError)) #$ MISSING:flow="SOURCE, l:-2 -> g.throw()" # no `test_close` as `close` involves no data flow @@ -280,7 +280,7 @@ def runa(a): async def atest___anext__(): g = agen(SOURCE) - SINK(await g.__anext__()) #$ MISSING:flow="SOURCE, l:282 -> g.__anext__()" + SINK(await g.__anext__()) #$ MISSING:flow="SOURCE, l:-1 -> g.__anext__()" def test___anext__(): @@ -313,7 +313,7 @@ async def agen_ex(x): async def atest_athrow(): g = agen_ex(SOURCE) n = await g.__anext__() - SINK(await g.athrow(TypeError)) #$ MISSING:flow="SOURCE, l:314 -> g.athrow()" + SINK(await g.athrow(TypeError)) #$ MISSING:flow="SOURCE, l:-2 -> g.athrow()" def test_athrow(): @@ -326,7 +326,7 @@ class C: def test_attribute_reference(): - SINK(C.a) #$ MISSING:flow="SOURCE, l:325 -> C.a" + SINK(C.a) #$ MISSING:flow="SOURCE, l:-4 -> C.a" # overriding __getattr__ should be tested by the class coverage tests @@ -376,7 +376,7 @@ def test_call_keyword(): def test_call_unpack_iterable(): - SINK(second(NONSOURCE, *[SOURCE])) #$ MISSING:flow="SOURCE -> second(..)" MISING:flow="'source', l:20 -> second(..)" + SINK(second(NONSOURCE, *[SOURCE])) #$ MISSING:flow="SOURCE -> second(..)" def test_call_unpack_mapping(): @@ -547,7 +547,7 @@ def test_dynamic_tuple_creation_1(): tup += (SOURCE,) tup += (NONSOURCE,) - SINK(tup[0]) #$ MISSING:flow="SOURCE, l:547 -> tup[0]" MISING:flow="'source', l:20 -> tup[0]" + SINK(tup[0]) #$ MISSING:flow="SOURCE, l:-3 -> tup[0]" SINK_F(tup[1]) @@ -557,7 +557,7 @@ def test_dynamic_tuple_creation_2(): tup += (SOURCE,) tup += (NONSOURCE,) - SINK(tup[0]) #$ MISSING:flow="SOURCE, l:557 -> tup[0]" MISING:flow="'source', l:20 -> tup[0]" + SINK(tup[0]) #$ MISSING:flow="SOURCE, l:-3 -> tup[0]" SINK_F(tup[1]) @@ -567,7 +567,7 @@ def test_dynamic_tuple_creation_3(): tup2 = (NONSOURCE,) tup = tup1 + tup2 - SINK(tup[0]) #$ MISSING:flow="SOURCE, l:566 -> tup[0]" MISING:flow="'source', l:20 -> tup[0]" + SINK(tup[0]) #$ MISSING:flow="SOURCE, l:-4 -> tup[0]" SINK_F(tup[1]) @@ -578,5 +578,5 @@ def test_dynamic_tuple_creation_4(): for item in [SOURCE, NONSOURCE]: tup += (item,) - SINK(tup[0]) #$ MISSING:flow="SOURCE, l:578 -> tup[0]" MISING:flow="'source', l:20 -> tup[0]" + SINK(tup[0]) #$ MISSING:flow="SOURCE, l:-3 -> tup[0]" SINK_F(tup[1]) From ae38bbe03b35eb74eb699d46de5c19e62b57aedf Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 19 Jan 2021 18:19:11 +0100 Subject: [PATCH 11/16] Python: Fearlessly adding another test in the middle of the file. --- .../ql/test/experimental/dataflow/coverage/argumentPassing.py | 2 +- python/ql/test/experimental/dataflow/coverage/test.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py index 67650c149d3c..db19860a9019 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py +++ b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py @@ -112,7 +112,7 @@ def with_multiple_kw_args(a, b, c): SINK3(c) -@expects(9) +@expects(12) def test_multiple_kw_args(): with_multiple_kw_args(b=arg2, c=arg3, a=arg1) #$ arg1="arg1" arg2="arg2" arg3="arg3" func=with_multiple_kw_args with_multiple_kw_args(arg1, *(arg2,), arg3) #$ arg1="arg1" func=with_multiple_kw_args MISSING: arg2="arg2" arg3="arg3" diff --git a/python/ql/test/experimental/dataflow/coverage/test.py b/python/ql/test/experimental/dataflow/coverage/test.py index a37b63215a25..691d1f160975 100644 --- a/python/ql/test/experimental/dataflow/coverage/test.py +++ b/python/ql/test/experimental/dataflow/coverage/test.py @@ -325,9 +325,11 @@ class C: a = SOURCE +@expects(2) def test_attribute_reference(): SINK(C.a) #$ MISSING:flow="SOURCE, l:-4 -> C.a" - + c = C() + SINK(c.a) #$ MISSING:flow="SOURCE, l:-6 -> c.a" # overriding __getattr__ should be tested by the class coverage tests From 8e126603b3594ee036c1339be0814c623173d0bc Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 19 Jan 2021 18:21:27 +0100 Subject: [PATCH 12/16] Python: Remember that old style tests still needs updated expectations. --- .../dataflow/coverage/dataflow.expected | 186 +++++++++--------- 1 file changed, 93 insertions(+), 93 deletions(-) diff --git a/python/ql/test/experimental/dataflow/coverage/dataflow.expected b/python/ql/test/experimental/dataflow/coverage/dataflow.expected index 3bb58f506187..83d1799cceb7 100644 --- a/python/ql/test/experimental/dataflow/coverage/dataflow.expected +++ b/python/ql/test/experimental/dataflow/coverage/dataflow.expected @@ -95,35 +95,35 @@ edges | test.py:199:33:199:40 | ControlFlowNode for List [List element] | test.py:199:28:199:28 | SSA variable z | | test.py:199:34:199:39 | ControlFlowNode for SOURCE | test.py:199:33:199:40 | ControlFlowNode for List [List element] | | test.py:200:10:200:10 | ControlFlowNode for x [List element] | test.py:200:10:200:13 | ControlFlowNode for Subscript | -| test.py:336:11:336:16 | ControlFlowNode for SOURCE | test.py:336:11:336:17 | ControlFlowNode for Tuple [Tuple element at index 0] | -| test.py:336:11:336:17 | ControlFlowNode for Tuple [Tuple element at index 0] | test.py:336:10:336:21 | ControlFlowNode for Subscript | -| test.py:340:10:340:17 | ControlFlowNode for List [List element] | test.py:340:10:340:20 | ControlFlowNode for Subscript | -| test.py:340:11:340:16 | ControlFlowNode for SOURCE | test.py:340:10:340:17 | ControlFlowNode for List [List element] | -| test.py:344:10:344:22 | ControlFlowNode for Dict [Dictionary element at key s] | test.py:344:10:344:27 | ControlFlowNode for Subscript | -| test.py:344:16:344:21 | ControlFlowNode for SOURCE | test.py:344:10:344:22 | ControlFlowNode for Dict [Dictionary element at key s] | -| test.py:367:28:367:33 | ControlFlowNode for SOURCE | test.py:367:10:367:34 | ControlFlowNode for second() | -| test.py:375:30:375:35 | ControlFlowNode for SOURCE | test.py:375:10:375:36 | ControlFlowNode for second() | -| test.py:383:10:383:43 | KwUnpacked b | test.py:383:10:383:43 | ControlFlowNode for second() | -| test.py:383:30:383:42 | ControlFlowNode for Dict [Dictionary element at key b] | test.py:383:10:383:43 | KwUnpacked b | -| test.py:383:36:383:41 | ControlFlowNode for SOURCE | test.py:383:30:383:42 | ControlFlowNode for Dict [Dictionary element at key b] | -| test.py:391:10:391:39 | PosOverflowNode for f_extra_pos() [Tuple element at index 0] | test.py:391:10:391:39 | ControlFlowNode for f_extra_pos() | -| test.py:391:33:391:38 | ControlFlowNode for SOURCE | test.py:391:10:391:39 | PosOverflowNode for f_extra_pos() [Tuple element at index 0] | -| test.py:399:10:399:45 | KwOverflowNode for f_extra_keyword() [Dictionary element at key b] | test.py:399:10:399:45 | ControlFlowNode for f_extra_keyword() | -| test.py:399:39:399:44 | ControlFlowNode for SOURCE | test.py:399:10:399:45 | KwOverflowNode for f_extra_keyword() [Dictionary element at key b] | -| test.py:420:10:420:15 | ControlFlowNode for SOURCE | test.py:420:10:420:38 | ControlFlowNode for IfExp | -| test.py:428:34:428:39 | ControlFlowNode for SOURCE | test.py:428:10:428:39 | ControlFlowNode for IfExp | -| test.py:452:12:452:17 | ControlFlowNode for SOURCE | test.py:452:10:452:18 | ControlFlowNode for f() | -| test.py:459:28:459:33 | ControlFlowNode for SOURCE | test.py:459:10:459:34 | ControlFlowNode for second() | -| test.py:473:30:473:35 | ControlFlowNode for SOURCE | test.py:473:10:473:36 | ControlFlowNode for second() | -| test.py:487:10:487:43 | KwUnpacked b | test.py:487:10:487:43 | ControlFlowNode for second() | -| test.py:487:30:487:42 | ControlFlowNode for Dict [Dictionary element at key b] | test.py:487:10:487:43 | KwUnpacked b | -| test.py:487:36:487:41 | ControlFlowNode for SOURCE | test.py:487:30:487:42 | ControlFlowNode for Dict [Dictionary element at key b] | -| test.py:492:10:492:39 | PosOverflowNode for f_extra_pos() [Tuple element at index 0] | test.py:492:10:492:39 | ControlFlowNode for f_extra_pos() | -| test.py:492:33:492:38 | ControlFlowNode for SOURCE | test.py:492:10:492:39 | PosOverflowNode for f_extra_pos() [Tuple element at index 0] | -| test.py:497:10:497:45 | KwOverflowNode for f_extra_keyword() [Dictionary element at key b] | test.py:497:10:497:45 | ControlFlowNode for f_extra_keyword() | -| test.py:497:39:497:44 | ControlFlowNode for SOURCE | test.py:497:10:497:45 | KwOverflowNode for f_extra_keyword() [Dictionary element at key b] | -| test.py:509:9:509:14 | ControlFlowNode for SOURCE | test.py:511:10:511:10 | ControlFlowNode for a | -| test.py:509:9:509:14 | ControlFlowNode for SOURCE | test.py:516:10:516:10 | ControlFlowNode for b | +| test.py:338:11:338:16 | ControlFlowNode for SOURCE | test.py:338:11:338:17 | ControlFlowNode for Tuple [Tuple element at index 0] | +| test.py:338:11:338:17 | ControlFlowNode for Tuple [Tuple element at index 0] | test.py:338:10:338:21 | ControlFlowNode for Subscript | +| test.py:342:10:342:17 | ControlFlowNode for List [List element] | test.py:342:10:342:20 | ControlFlowNode for Subscript | +| test.py:342:11:342:16 | ControlFlowNode for SOURCE | test.py:342:10:342:17 | ControlFlowNode for List [List element] | +| test.py:346:10:346:22 | ControlFlowNode for Dict [Dictionary element at key s] | test.py:346:10:346:27 | ControlFlowNode for Subscript | +| test.py:346:16:346:21 | ControlFlowNode for SOURCE | test.py:346:10:346:22 | ControlFlowNode for Dict [Dictionary element at key s] | +| test.py:369:28:369:33 | ControlFlowNode for SOURCE | test.py:369:10:369:34 | ControlFlowNode for second() | +| test.py:377:30:377:35 | ControlFlowNode for SOURCE | test.py:377:10:377:36 | ControlFlowNode for second() | +| test.py:385:10:385:43 | KwUnpacked b | test.py:385:10:385:43 | ControlFlowNode for second() | +| test.py:385:30:385:42 | ControlFlowNode for Dict [Dictionary element at key b] | test.py:385:10:385:43 | KwUnpacked b | +| test.py:385:36:385:41 | ControlFlowNode for SOURCE | test.py:385:30:385:42 | ControlFlowNode for Dict [Dictionary element at key b] | +| test.py:393:10:393:39 | PosOverflowNode for f_extra_pos() [Tuple element at index 0] | test.py:393:10:393:39 | ControlFlowNode for f_extra_pos() | +| test.py:393:33:393:38 | ControlFlowNode for SOURCE | test.py:393:10:393:39 | PosOverflowNode for f_extra_pos() [Tuple element at index 0] | +| test.py:401:10:401:45 | KwOverflowNode for f_extra_keyword() [Dictionary element at key b] | test.py:401:10:401:45 | ControlFlowNode for f_extra_keyword() | +| test.py:401:39:401:44 | ControlFlowNode for SOURCE | test.py:401:10:401:45 | KwOverflowNode for f_extra_keyword() [Dictionary element at key b] | +| test.py:422:10:422:15 | ControlFlowNode for SOURCE | test.py:422:10:422:38 | ControlFlowNode for IfExp | +| test.py:430:34:430:39 | ControlFlowNode for SOURCE | test.py:430:10:430:39 | ControlFlowNode for IfExp | +| test.py:454:12:454:17 | ControlFlowNode for SOURCE | test.py:454:10:454:18 | ControlFlowNode for f() | +| test.py:461:28:461:33 | ControlFlowNode for SOURCE | test.py:461:10:461:34 | ControlFlowNode for second() | +| test.py:475:30:475:35 | ControlFlowNode for SOURCE | test.py:475:10:475:36 | ControlFlowNode for second() | +| test.py:489:10:489:43 | KwUnpacked b | test.py:489:10:489:43 | ControlFlowNode for second() | +| test.py:489:30:489:42 | ControlFlowNode for Dict [Dictionary element at key b] | test.py:489:10:489:43 | KwUnpacked b | +| test.py:489:36:489:41 | ControlFlowNode for SOURCE | test.py:489:30:489:42 | ControlFlowNode for Dict [Dictionary element at key b] | +| test.py:494:10:494:39 | PosOverflowNode for f_extra_pos() [Tuple element at index 0] | test.py:494:10:494:39 | ControlFlowNode for f_extra_pos() | +| test.py:494:33:494:38 | ControlFlowNode for SOURCE | test.py:494:10:494:39 | PosOverflowNode for f_extra_pos() [Tuple element at index 0] | +| test.py:499:10:499:45 | KwOverflowNode for f_extra_keyword() [Dictionary element at key b] | test.py:499:10:499:45 | ControlFlowNode for f_extra_keyword() | +| test.py:499:39:499:44 | ControlFlowNode for SOURCE | test.py:499:10:499:45 | KwOverflowNode for f_extra_keyword() [Dictionary element at key b] | +| test.py:511:9:511:14 | ControlFlowNode for SOURCE | test.py:513:10:513:10 | ControlFlowNode for a | +| test.py:511:9:511:14 | ControlFlowNode for SOURCE | test.py:518:10:518:10 | ControlFlowNode for b | nodes | datamodel.py:38:6:38:17 | ControlFlowNode for f() | semmle.label | ControlFlowNode for f() | | datamodel.py:38:8:38:13 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | @@ -247,52 +247,52 @@ nodes | test.py:199:34:199:39 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | | test.py:200:10:200:10 | ControlFlowNode for x [List element] | semmle.label | ControlFlowNode for x [List element] | | test.py:200:10:200:13 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | -| test.py:336:10:336:21 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | -| test.py:336:11:336:16 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | -| test.py:336:11:336:17 | ControlFlowNode for Tuple [Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0] | -| test.py:340:10:340:17 | ControlFlowNode for List [List element] | semmle.label | ControlFlowNode for List [List element] | -| test.py:340:10:340:20 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | -| test.py:340:11:340:16 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | -| test.py:344:10:344:22 | ControlFlowNode for Dict [Dictionary element at key s] | semmle.label | ControlFlowNode for Dict [Dictionary element at key s] | -| test.py:344:10:344:27 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | -| test.py:344:16:344:21 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | -| test.py:367:10:367:34 | ControlFlowNode for second() | semmle.label | ControlFlowNode for second() | -| test.py:367:28:367:33 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | -| test.py:375:10:375:36 | ControlFlowNode for second() | semmle.label | ControlFlowNode for second() | -| test.py:375:30:375:35 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | -| test.py:383:10:383:43 | ControlFlowNode for second() | semmle.label | ControlFlowNode for second() | -| test.py:383:10:383:43 | KwUnpacked b | semmle.label | KwUnpacked b | -| test.py:383:30:383:42 | ControlFlowNode for Dict [Dictionary element at key b] | semmle.label | ControlFlowNode for Dict [Dictionary element at key b] | -| test.py:383:36:383:41 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | -| test.py:391:10:391:39 | ControlFlowNode for f_extra_pos() | semmle.label | ControlFlowNode for f_extra_pos() | -| test.py:391:10:391:39 | PosOverflowNode for f_extra_pos() [Tuple element at index 0] | semmle.label | PosOverflowNode for f_extra_pos() [Tuple element at index 0] | -| test.py:391:33:391:38 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | -| test.py:399:10:399:45 | ControlFlowNode for f_extra_keyword() | semmle.label | ControlFlowNode for f_extra_keyword() | -| test.py:399:10:399:45 | KwOverflowNode for f_extra_keyword() [Dictionary element at key b] | semmle.label | KwOverflowNode for f_extra_keyword() [Dictionary element at key b] | -| test.py:399:39:399:44 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | -| test.py:420:10:420:15 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | -| test.py:420:10:420:38 | ControlFlowNode for IfExp | semmle.label | ControlFlowNode for IfExp | -| test.py:428:10:428:39 | ControlFlowNode for IfExp | semmle.label | ControlFlowNode for IfExp | -| test.py:428:34:428:39 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | -| test.py:452:10:452:18 | ControlFlowNode for f() | semmle.label | ControlFlowNode for f() | -| test.py:452:12:452:17 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | -| test.py:459:10:459:34 | ControlFlowNode for second() | semmle.label | ControlFlowNode for second() | -| test.py:459:28:459:33 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | -| test.py:473:10:473:36 | ControlFlowNode for second() | semmle.label | ControlFlowNode for second() | -| test.py:473:30:473:35 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | -| test.py:487:10:487:43 | ControlFlowNode for second() | semmle.label | ControlFlowNode for second() | -| test.py:487:10:487:43 | KwUnpacked b | semmle.label | KwUnpacked b | -| test.py:487:30:487:42 | ControlFlowNode for Dict [Dictionary element at key b] | semmle.label | ControlFlowNode for Dict [Dictionary element at key b] | -| test.py:487:36:487:41 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | -| test.py:492:10:492:39 | ControlFlowNode for f_extra_pos() | semmle.label | ControlFlowNode for f_extra_pos() | -| test.py:492:10:492:39 | PosOverflowNode for f_extra_pos() [Tuple element at index 0] | semmle.label | PosOverflowNode for f_extra_pos() [Tuple element at index 0] | -| test.py:492:33:492:38 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | -| test.py:497:10:497:45 | ControlFlowNode for f_extra_keyword() | semmle.label | ControlFlowNode for f_extra_keyword() | -| test.py:497:10:497:45 | KwOverflowNode for f_extra_keyword() [Dictionary element at key b] | semmle.label | KwOverflowNode for f_extra_keyword() [Dictionary element at key b] | -| test.py:497:39:497:44 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | -| test.py:509:9:509:14 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | -| test.py:511:10:511:10 | ControlFlowNode for a | semmle.label | ControlFlowNode for a | -| test.py:516:10:516:10 | ControlFlowNode for b | semmle.label | ControlFlowNode for b | +| test.py:338:10:338:21 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | +| test.py:338:11:338:16 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | +| test.py:338:11:338:17 | ControlFlowNode for Tuple [Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0] | +| test.py:342:10:342:17 | ControlFlowNode for List [List element] | semmle.label | ControlFlowNode for List [List element] | +| test.py:342:10:342:20 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | +| test.py:342:11:342:16 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | +| test.py:346:10:346:22 | ControlFlowNode for Dict [Dictionary element at key s] | semmle.label | ControlFlowNode for Dict [Dictionary element at key s] | +| test.py:346:10:346:27 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | +| test.py:346:16:346:21 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | +| test.py:369:10:369:34 | ControlFlowNode for second() | semmle.label | ControlFlowNode for second() | +| test.py:369:28:369:33 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | +| test.py:377:10:377:36 | ControlFlowNode for second() | semmle.label | ControlFlowNode for second() | +| test.py:377:30:377:35 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | +| test.py:385:10:385:43 | ControlFlowNode for second() | semmle.label | ControlFlowNode for second() | +| test.py:385:10:385:43 | KwUnpacked b | semmle.label | KwUnpacked b | +| test.py:385:30:385:42 | ControlFlowNode for Dict [Dictionary element at key b] | semmle.label | ControlFlowNode for Dict [Dictionary element at key b] | +| test.py:385:36:385:41 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | +| test.py:393:10:393:39 | ControlFlowNode for f_extra_pos() | semmle.label | ControlFlowNode for f_extra_pos() | +| test.py:393:10:393:39 | PosOverflowNode for f_extra_pos() [Tuple element at index 0] | semmle.label | PosOverflowNode for f_extra_pos() [Tuple element at index 0] | +| test.py:393:33:393:38 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | +| test.py:401:10:401:45 | ControlFlowNode for f_extra_keyword() | semmle.label | ControlFlowNode for f_extra_keyword() | +| test.py:401:10:401:45 | KwOverflowNode for f_extra_keyword() [Dictionary element at key b] | semmle.label | KwOverflowNode for f_extra_keyword() [Dictionary element at key b] | +| test.py:401:39:401:44 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | +| test.py:422:10:422:15 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | +| test.py:422:10:422:38 | ControlFlowNode for IfExp | semmle.label | ControlFlowNode for IfExp | +| test.py:430:10:430:39 | ControlFlowNode for IfExp | semmle.label | ControlFlowNode for IfExp | +| test.py:430:34:430:39 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | +| test.py:454:10:454:18 | ControlFlowNode for f() | semmle.label | ControlFlowNode for f() | +| test.py:454:12:454:17 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | +| test.py:461:10:461:34 | ControlFlowNode for second() | semmle.label | ControlFlowNode for second() | +| test.py:461:28:461:33 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | +| test.py:475:10:475:36 | ControlFlowNode for second() | semmle.label | ControlFlowNode for second() | +| test.py:475:30:475:35 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | +| test.py:489:10:489:43 | ControlFlowNode for second() | semmle.label | ControlFlowNode for second() | +| test.py:489:10:489:43 | KwUnpacked b | semmle.label | KwUnpacked b | +| test.py:489:30:489:42 | ControlFlowNode for Dict [Dictionary element at key b] | semmle.label | ControlFlowNode for Dict [Dictionary element at key b] | +| test.py:489:36:489:41 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | +| test.py:494:10:494:39 | ControlFlowNode for f_extra_pos() | semmle.label | ControlFlowNode for f_extra_pos() | +| test.py:494:10:494:39 | PosOverflowNode for f_extra_pos() [Tuple element at index 0] | semmle.label | PosOverflowNode for f_extra_pos() [Tuple element at index 0] | +| test.py:494:33:494:38 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | +| test.py:499:10:499:45 | ControlFlowNode for f_extra_keyword() | semmle.label | ControlFlowNode for f_extra_keyword() | +| test.py:499:10:499:45 | KwOverflowNode for f_extra_keyword() [Dictionary element at key b] | semmle.label | KwOverflowNode for f_extra_keyword() [Dictionary element at key b] | +| test.py:499:39:499:44 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | +| test.py:511:9:511:14 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | +| test.py:513:10:513:10 | ControlFlowNode for a | semmle.label | ControlFlowNode for a | +| test.py:518:10:518:10 | ControlFlowNode for b | semmle.label | ControlFlowNode for b | #select | datamodel.py:38:6:38:17 | ControlFlowNode for f() | datamodel.py:38:8:38:13 | ControlFlowNode for SOURCE | datamodel.py:38:6:38:17 | ControlFlowNode for f() | Flow found | | datamodel.py:71:6:71:24 | ControlFlowNode for Attribute() | datamodel.py:71:15:71:20 | ControlFlowNode for SOURCE | datamodel.py:71:6:71:24 | ControlFlowNode for Attribute() | Flow found | @@ -320,21 +320,21 @@ nodes | test.py:184:10:184:13 | ControlFlowNode for Subscript | test.py:183:23:183:28 | ControlFlowNode for SOURCE | test.py:184:10:184:13 | ControlFlowNode for Subscript | Flow found | | test.py:189:10:189:13 | ControlFlowNode for Subscript | test.py:188:25:188:30 | ControlFlowNode for SOURCE | test.py:189:10:189:13 | ControlFlowNode for Subscript | Flow found | | test.py:200:10:200:13 | ControlFlowNode for Subscript | test.py:199:34:199:39 | ControlFlowNode for SOURCE | test.py:200:10:200:13 | ControlFlowNode for Subscript | Flow found | -| test.py:336:10:336:21 | ControlFlowNode for Subscript | test.py:336:11:336:16 | ControlFlowNode for SOURCE | test.py:336:10:336:21 | ControlFlowNode for Subscript | Flow found | -| test.py:340:10:340:20 | ControlFlowNode for Subscript | test.py:340:11:340:16 | ControlFlowNode for SOURCE | test.py:340:10:340:20 | ControlFlowNode for Subscript | Flow found | -| test.py:344:10:344:27 | ControlFlowNode for Subscript | test.py:344:16:344:21 | ControlFlowNode for SOURCE | test.py:344:10:344:27 | ControlFlowNode for Subscript | Flow found | -| test.py:367:10:367:34 | ControlFlowNode for second() | test.py:367:28:367:33 | ControlFlowNode for SOURCE | test.py:367:10:367:34 | ControlFlowNode for second() | Flow found | -| test.py:375:10:375:36 | ControlFlowNode for second() | test.py:375:30:375:35 | ControlFlowNode for SOURCE | test.py:375:10:375:36 | ControlFlowNode for second() | Flow found | -| test.py:383:10:383:43 | ControlFlowNode for second() | test.py:383:36:383:41 | ControlFlowNode for SOURCE | test.py:383:10:383:43 | ControlFlowNode for second() | Flow found | -| test.py:391:10:391:39 | ControlFlowNode for f_extra_pos() | test.py:391:33:391:38 | ControlFlowNode for SOURCE | test.py:391:10:391:39 | ControlFlowNode for f_extra_pos() | Flow found | -| test.py:399:10:399:45 | ControlFlowNode for f_extra_keyword() | test.py:399:39:399:44 | ControlFlowNode for SOURCE | test.py:399:10:399:45 | ControlFlowNode for f_extra_keyword() | Flow found | -| test.py:420:10:420:38 | ControlFlowNode for IfExp | test.py:420:10:420:15 | ControlFlowNode for SOURCE | test.py:420:10:420:38 | ControlFlowNode for IfExp | Flow found | -| test.py:428:10:428:39 | ControlFlowNode for IfExp | test.py:428:34:428:39 | ControlFlowNode for SOURCE | test.py:428:10:428:39 | ControlFlowNode for IfExp | Flow found | -| test.py:452:10:452:18 | ControlFlowNode for f() | test.py:452:12:452:17 | ControlFlowNode for SOURCE | test.py:452:10:452:18 | ControlFlowNode for f() | Flow found | -| test.py:459:10:459:34 | ControlFlowNode for second() | test.py:459:28:459:33 | ControlFlowNode for SOURCE | test.py:459:10:459:34 | ControlFlowNode for second() | Flow found | -| test.py:473:10:473:36 | ControlFlowNode for second() | test.py:473:30:473:35 | ControlFlowNode for SOURCE | test.py:473:10:473:36 | ControlFlowNode for second() | Flow found | -| test.py:487:10:487:43 | ControlFlowNode for second() | test.py:487:36:487:41 | ControlFlowNode for SOURCE | test.py:487:10:487:43 | ControlFlowNode for second() | Flow found | -| test.py:492:10:492:39 | ControlFlowNode for f_extra_pos() | test.py:492:33:492:38 | ControlFlowNode for SOURCE | test.py:492:10:492:39 | ControlFlowNode for f_extra_pos() | Flow found | -| test.py:497:10:497:45 | ControlFlowNode for f_extra_keyword() | test.py:497:39:497:44 | ControlFlowNode for SOURCE | test.py:497:10:497:45 | ControlFlowNode for f_extra_keyword() | Flow found | -| test.py:511:10:511:10 | ControlFlowNode for a | test.py:509:9:509:14 | ControlFlowNode for SOURCE | test.py:511:10:511:10 | ControlFlowNode for a | Flow found | -| test.py:516:10:516:10 | ControlFlowNode for b | test.py:509:9:509:14 | ControlFlowNode for SOURCE | test.py:516:10:516:10 | ControlFlowNode for b | Flow found | +| test.py:338:10:338:21 | ControlFlowNode for Subscript | test.py:338:11:338:16 | ControlFlowNode for SOURCE | test.py:338:10:338:21 | ControlFlowNode for Subscript | Flow found | +| test.py:342:10:342:20 | ControlFlowNode for Subscript | test.py:342:11:342:16 | ControlFlowNode for SOURCE | test.py:342:10:342:20 | ControlFlowNode for Subscript | Flow found | +| test.py:346:10:346:27 | ControlFlowNode for Subscript | test.py:346:16:346:21 | ControlFlowNode for SOURCE | test.py:346:10:346:27 | ControlFlowNode for Subscript | Flow found | +| test.py:369:10:369:34 | ControlFlowNode for second() | test.py:369:28:369:33 | ControlFlowNode for SOURCE | test.py:369:10:369:34 | ControlFlowNode for second() | Flow found | +| test.py:377:10:377:36 | ControlFlowNode for second() | test.py:377:30:377:35 | ControlFlowNode for SOURCE | test.py:377:10:377:36 | ControlFlowNode for second() | Flow found | +| test.py:385:10:385:43 | ControlFlowNode for second() | test.py:385:36:385:41 | ControlFlowNode for SOURCE | test.py:385:10:385:43 | ControlFlowNode for second() | Flow found | +| test.py:393:10:393:39 | ControlFlowNode for f_extra_pos() | test.py:393:33:393:38 | ControlFlowNode for SOURCE | test.py:393:10:393:39 | ControlFlowNode for f_extra_pos() | Flow found | +| test.py:401:10:401:45 | ControlFlowNode for f_extra_keyword() | test.py:401:39:401:44 | ControlFlowNode for SOURCE | test.py:401:10:401:45 | ControlFlowNode for f_extra_keyword() | Flow found | +| test.py:422:10:422:38 | ControlFlowNode for IfExp | test.py:422:10:422:15 | ControlFlowNode for SOURCE | test.py:422:10:422:38 | ControlFlowNode for IfExp | Flow found | +| test.py:430:10:430:39 | ControlFlowNode for IfExp | test.py:430:34:430:39 | ControlFlowNode for SOURCE | test.py:430:10:430:39 | ControlFlowNode for IfExp | Flow found | +| test.py:454:10:454:18 | ControlFlowNode for f() | test.py:454:12:454:17 | ControlFlowNode for SOURCE | test.py:454:10:454:18 | ControlFlowNode for f() | Flow found | +| test.py:461:10:461:34 | ControlFlowNode for second() | test.py:461:28:461:33 | ControlFlowNode for SOURCE | test.py:461:10:461:34 | ControlFlowNode for second() | Flow found | +| test.py:475:10:475:36 | ControlFlowNode for second() | test.py:475:30:475:35 | ControlFlowNode for SOURCE | test.py:475:10:475:36 | ControlFlowNode for second() | Flow found | +| test.py:489:10:489:43 | ControlFlowNode for second() | test.py:489:36:489:41 | ControlFlowNode for SOURCE | test.py:489:10:489:43 | ControlFlowNode for second() | Flow found | +| test.py:494:10:494:39 | ControlFlowNode for f_extra_pos() | test.py:494:33:494:38 | ControlFlowNode for SOURCE | test.py:494:10:494:39 | ControlFlowNode for f_extra_pos() | Flow found | +| test.py:499:10:499:45 | ControlFlowNode for f_extra_keyword() | test.py:499:39:499:44 | ControlFlowNode for SOURCE | test.py:499:10:499:45 | ControlFlowNode for f_extra_keyword() | Flow found | +| test.py:513:10:513:10 | ControlFlowNode for a | test.py:511:9:511:14 | ControlFlowNode for SOURCE | test.py:513:10:513:10 | ControlFlowNode for a | Flow found | +| test.py:518:10:518:10 | ControlFlowNode for b | test.py:511:9:511:14 | ControlFlowNode for SOURCE | test.py:518:10:518:10 | ControlFlowNode for b | Flow found | From 3fc085ff38cae5de0ce9b9d776c670aed1fe9376 Mon Sep 17 00:00:00 2001 From: yoff Date: Wed, 20 Jan 2021 16:11:40 +0100 Subject: [PATCH 13/16] Update python/ql/test/experimental/dataflow/TestUtil/RoutingTest.qll Co-authored-by: Rasmus Wriedt Larsen --- python/ql/test/experimental/dataflow/TestUtil/RoutingTest.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/test/experimental/dataflow/TestUtil/RoutingTest.qll b/python/ql/test/experimental/dataflow/TestUtil/RoutingTest.qll index eb685cc3ac17..8224a510ef19 100644 --- a/python/ql/test/experimental/dataflow/TestUtil/RoutingTest.qll +++ b/python/ql/test/experimental/dataflow/TestUtil/RoutingTest.qll @@ -4,7 +4,7 @@ import TestUtilities.InlineExpectationsTest import experimental.dataflow.TestUtil.PrintNode /** - * A routing test is designed to test that vlues are routed to the + * A routing test is designed to test that values are routed to the * correct arguments of the correct functions. It is assumed that * the functions tested sink their arguments sequentially, that is * `SINK1(arg1)`, etc. From 2409a7899bc16854377f65b99c1c5bf2eb4627bf Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Wed, 20 Jan 2021 20:18:40 +0100 Subject: [PATCH 14/16] Python: Remove func tag in some situations. Also make ArgumentNode public --- .../dataflow/new/internal/DataFlowPrivate.qll | 11 ----------- .../dataflow/new/internal/DataFlowPublic.qll | 11 +++++++++++ .../dataflow/TestUtil/RoutingTest.qll | 13 ++++++++++++- .../dataflow/coverage/argumentPassing.py | 18 +++++++++--------- .../experimental/dataflow/coverage/test.py | 2 +- 5 files changed, 33 insertions(+), 22 deletions(-) diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index 4842b670cbd4..570c0396037c 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -703,17 +703,6 @@ class SpecialCall extends DataFlowCall, TSpecialCall { } } -/** A data flow node that represents a call argument. */ -class ArgumentNode extends Node { - ArgumentNode() { this = any(DataFlowCall c).getArg(_) } - - /** Holds if this argument occurs at the given position in the given call. */ - predicate argumentOf(DataFlowCall call, int pos) { this = call.getArg(pos) } - - /** Gets the call in which this node is an argument. */ - final DataFlowCall getCall() { this.argumentOf(result, _) } -} - /** Gets a viable run-time target for the call `call`. */ DataFlowCallable viableCallable(DataFlowCall call) { result = call.getCallable() } diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll index 4d49806fe12e..edb550872f54 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll @@ -193,6 +193,17 @@ class ParameterNode extends CfgNode { Parameter getParameter() { result = def.getParameter() } } +/** A data flow node that represents a call argument. */ +class ArgumentNode extends Node { + ArgumentNode() { this = any(DataFlowCall c).getArg(_) } + + /** Holds if this argument occurs at the given position in the given call. */ + predicate argumentOf(DataFlowCall call, int pos) { this = call.getArg(pos) } + + /** Gets the call in which this node is an argument. */ + final DataFlowCall getCall() { this.argumentOf(result, _) } +} + /** * A node associated with an object after an operation that might have * changed its state. diff --git a/python/ql/test/experimental/dataflow/TestUtil/RoutingTest.qll b/python/ql/test/experimental/dataflow/TestUtil/RoutingTest.qll index 8224a510ef19..05fd7241c412 100644 --- a/python/ql/test/experimental/dataflow/TestUtil/RoutingTest.qll +++ b/python/ql/test/experimental/dataflow/TestUtil/RoutingTest.qll @@ -28,8 +28,19 @@ abstract class RoutingTest extends InlineExpectationsTest { value = "\"" + prettyNode(fromNode).replaceAll("\"", "'") + "\"" or tag = "func" and - value = toNode.getEnclosingCallable().getCallableValue().getScope().getQualifiedName() // TODO: More robust pretty printing? + not fromFunc(fromNode) = toFunc(toNode) and + value = toFunc(toNode) ) ) } + + pragma[inline] + private string fromFunc(DataFlow::ArgumentNode fromNode) { + result = fromNode.getCall().getNode().(CallNode).getFunction().getNode().(Name).getId() + } + + pragma[inline] + private string toFunc(DataFlow::Node toNode) { + result = toNode.getEnclosingCallable().getCallableValue().getScope().getQualifiedName() // TODO: More robust pretty printing? + } } diff --git a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py index db19860a9019..56b4b2a66a3c 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py +++ b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py @@ -91,7 +91,7 @@ def test_argument_passing1(): @expects(7) def test_argument_passing2(): - argument_passing(arg1, arg2, arg3, f=arg6) #$ arg1="arg1" arg2="arg2" arg3="arg3" func=argument_passing + argument_passing(arg1, arg2, arg3, f=arg6) #$ arg1="arg1" arg2="arg2" arg3="arg3" def with_pos_only(a, /, b): @@ -101,9 +101,9 @@ def with_pos_only(a, /, b): @expects(6) def test_pos_only(): - with_pos_only(arg1, arg2) #$ arg1="arg1" arg2="arg2" func=with_pos_only - with_pos_only(arg1, b=arg2) #$ arg1="arg1" arg2="arg2" func=with_pos_only - with_pos_only(arg1, *(arg2,)) #$ arg1="arg1" func=with_pos_only MISSING: arg2="arg2" + with_pos_only(arg1, arg2) #$ arg1="arg1" arg2="arg2" + with_pos_only(arg1, b=arg2) #$ arg1="arg1" arg2="arg2" + with_pos_only(arg1, *(arg2,)) #$ arg1="arg1" MISSING: arg2="arg2" def with_multiple_kw_args(a, b, c): @@ -114,8 +114,8 @@ def with_multiple_kw_args(a, b, c): @expects(12) def test_multiple_kw_args(): - with_multiple_kw_args(b=arg2, c=arg3, a=arg1) #$ arg1="arg1" arg2="arg2" arg3="arg3" func=with_multiple_kw_args - with_multiple_kw_args(arg1, *(arg2,), arg3) #$ arg1="arg1" func=with_multiple_kw_args MISSING: arg2="arg2" arg3="arg3" + with_multiple_kw_args(b=arg2, c=arg3, a=arg1) #$ arg1="arg1" arg2="arg2" arg3="arg3" + with_multiple_kw_args(arg1, *(arg2,), arg3) #$ arg1="arg1" MISSING: arg2="arg2" arg3="arg3" with_multiple_kw_args(arg1, **{"c": arg3}, b=arg2) #$ arg1="arg1" arg3="arg3" func=with_multiple_kw_args MISSING: arg2="arg2" with_multiple_kw_args(**{"b": arg2}, **{"c": arg3}, **{"a": arg1}) #$ arg1="arg1" arg2="arg2" arg3="arg3" func=with_multiple_kw_args @@ -129,8 +129,8 @@ def with_default_arguments(a=arg1, b=arg2, c=arg3): # Need a mechanism to test @expects(12) def test_default_arguments(): with_default_arguments() - with_default_arguments(arg1) #$ arg1="arg1" func=with_default_arguments - with_default_arguments(b=arg2) #$ arg2="arg2" func=with_default_arguments + with_default_arguments(arg1) #$ arg1="arg1" + with_default_arguments(b=arg2) #$ arg2="arg2" with_default_arguments(**{"c": arg3}) #$ arg3="arg3" func=with_default_arguments @@ -157,7 +157,7 @@ def grab_baz(baz): @expects(4) def test_grab(): - grab_foo_bar_baz(baz=arg3, bar=arg2, foo=arg1) #$ arg1="arg1" arg2="arg2" arg3="arg3" func=grab_foo_bar_baz func=grab_bar_baz func=grab_baz + grab_foo_bar_baz(baz=arg3, bar=arg2, foo=arg1) #$ arg1="arg1" arg2="arg2" arg3="arg3" func=grab_bar_baz func=grab_baz # All combinations diff --git a/python/ql/test/experimental/dataflow/coverage/test.py b/python/ql/test/experimental/dataflow/coverage/test.py index bc328a6d9a67..9b55a7c02d7b 100644 --- a/python/ql/test/experimental/dataflow/coverage/test.py +++ b/python/ql/test/experimental/dataflow/coverage/test.py @@ -590,4 +590,4 @@ def return_from_inner_scope(x): return SOURCE def test_return_from_inner_scope(): - SINK(return_from_inner_scope([])) + SINK(return_from_inner_scope([])) #$ flow="SOURCE, l:-3 -> return_from_inner_scope(..)" From 419449fb8a3d6a9eec0088fb6e3a5c9372052276 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Wed, 20 Jan 2021 20:33:04 +0100 Subject: [PATCH 15/16] Python: default value for argN --- .../dataflow/TestUtil/RoutingTest.qll | 11 +- .../dataflow/coverage/argumentPassing.py | 40 +++--- .../experimental/dataflow/coverage/classes.py | 130 +++++++++--------- 3 files changed, 93 insertions(+), 88 deletions(-) diff --git a/python/ql/test/experimental/dataflow/TestUtil/RoutingTest.qll b/python/ql/test/experimental/dataflow/TestUtil/RoutingTest.qll index 05fd7241c412..03f4f8056eb5 100644 --- a/python/ql/test/experimental/dataflow/TestUtil/RoutingTest.qll +++ b/python/ql/test/experimental/dataflow/TestUtil/RoutingTest.qll @@ -25,15 +25,20 @@ abstract class RoutingTest extends InlineExpectationsTest { element = fromNode.toString() and ( tag = this.flowTag() and - value = "\"" + prettyNode(fromNode).replaceAll("\"", "'") + "\"" + if "\"" + tag + "\"" = fromValue(fromNode) then value = "" else value = fromValue(fromNode) or tag = "func" and - not fromFunc(fromNode) = toFunc(toNode) and - value = toFunc(toNode) + value = toFunc(toNode) and + not value = fromFunc(fromNode) ) ) } + pragma[inline] + private string fromValue(DataFlow::Node fromNode) { + result = "\"" + prettyNode(fromNode).replaceAll("\"", "'") + "\"" + } + pragma[inline] private string fromFunc(DataFlow::ArgumentNode fromNode) { result = fromNode.getCall().getNode().(CallNode).getFunction().getNode().(Name).getId() diff --git a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py index 56b4b2a66a3c..cbbac6c0d68a 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py +++ b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py @@ -86,12 +86,12 @@ def argument_passing( @expects(7) def test_argument_passing1(): - argument_passing(arg1, *(arg2, arg3, arg4), e=arg5, **{"f": arg6, "g": arg7}) #$ arg1="arg1" arg7="arg7" func=argument_passing MISSING: arg2="arg2" arg3="arg3 arg4="arg4" arg5="arg5" arg6="arg6" + argument_passing(arg1, *(arg2, arg3, arg4), e=arg5, **{"f": arg6, "g": arg7}) #$ arg1 arg7 func=argument_passing MISSING: arg2 arg3="arg3 arg4 arg5 arg6 @expects(7) def test_argument_passing2(): - argument_passing(arg1, arg2, arg3, f=arg6) #$ arg1="arg1" arg2="arg2" arg3="arg3" + argument_passing(arg1, arg2, arg3, f=arg6) #$ arg1 arg2 arg3 def with_pos_only(a, /, b): @@ -101,9 +101,9 @@ def with_pos_only(a, /, b): @expects(6) def test_pos_only(): - with_pos_only(arg1, arg2) #$ arg1="arg1" arg2="arg2" - with_pos_only(arg1, b=arg2) #$ arg1="arg1" arg2="arg2" - with_pos_only(arg1, *(arg2,)) #$ arg1="arg1" MISSING: arg2="arg2" + with_pos_only(arg1, arg2) #$ arg1 arg2 + with_pos_only(arg1, b=arg2) #$ arg1 arg2 + with_pos_only(arg1, *(arg2,)) #$ arg1 MISSING: arg2 def with_multiple_kw_args(a, b, c): @@ -114,10 +114,10 @@ def with_multiple_kw_args(a, b, c): @expects(12) def test_multiple_kw_args(): - with_multiple_kw_args(b=arg2, c=arg3, a=arg1) #$ arg1="arg1" arg2="arg2" arg3="arg3" - with_multiple_kw_args(arg1, *(arg2,), arg3) #$ arg1="arg1" MISSING: arg2="arg2" arg3="arg3" - with_multiple_kw_args(arg1, **{"c": arg3}, b=arg2) #$ arg1="arg1" arg3="arg3" func=with_multiple_kw_args MISSING: arg2="arg2" - with_multiple_kw_args(**{"b": arg2}, **{"c": arg3}, **{"a": arg1}) #$ arg1="arg1" arg2="arg2" arg3="arg3" func=with_multiple_kw_args + with_multiple_kw_args(b=arg2, c=arg3, a=arg1) #$ arg1 arg2 arg3 + with_multiple_kw_args(arg1, *(arg2,), arg3) #$ arg1 MISSING: arg2 arg3 + with_multiple_kw_args(arg1, **{"c": arg3}, b=arg2) #$ arg1 arg3 func=with_multiple_kw_args MISSING: arg2 + with_multiple_kw_args(**{"b": arg2}, **{"c": arg3}, **{"a": arg1}) #$ arg1 arg2 arg3 func=with_multiple_kw_args def with_default_arguments(a=arg1, b=arg2, c=arg3): # Need a mechanism to test default arguments @@ -129,9 +129,9 @@ def with_default_arguments(a=arg1, b=arg2, c=arg3): # Need a mechanism to test @expects(12) def test_default_arguments(): with_default_arguments() - with_default_arguments(arg1) #$ arg1="arg1" - with_default_arguments(b=arg2) #$ arg2="arg2" - with_default_arguments(**{"c": arg3}) #$ arg3="arg3" func=with_default_arguments + with_default_arguments(arg1) #$ arg1 + with_default_arguments(b=arg2) #$ arg2 + with_default_arguments(**{"c": arg3}) #$ arg3 func=with_default_arguments # Nested constructor pattern @@ -157,7 +157,7 @@ def grab_baz(baz): @expects(4) def test_grab(): - grab_foo_bar_baz(baz=arg3, bar=arg2, foo=arg1) #$ arg1="arg1" arg2="arg2" arg3="arg3" func=grab_bar_baz func=grab_baz + grab_foo_bar_baz(baz=arg3, bar=arg2, foo=arg1) #$ arg1 arg2 arg3 func=grab_bar_baz func=grab_baz # All combinations @@ -165,14 +165,14 @@ def test_pos_pos(): def with_pos(a): SINK1(a) - with_pos(arg1) #$ arg1="arg1" func=test_pos_pos.with_pos + with_pos(arg1) #$ arg1 func=test_pos_pos.with_pos def test_pos_pos_only(): def with_pos_only(a, /): SINK1(a) - with_pos_only(arg1) #$ arg1="arg1" func=test_pos_pos_only.with_pos_only + with_pos_only(arg1) #$ arg1 func=test_pos_pos_only.with_pos_only def test_pos_star(): @@ -180,32 +180,32 @@ def with_star(*a): if len(a) > 0: SINK1(a[0]) - with_star(arg1) #$ arg1="arg1" func=test_pos_star.with_star + with_star(arg1) #$ arg1 func=test_pos_star.with_star def test_pos_kw(): def with_kw(a=""): SINK1(a) - with_kw(arg1) #$ arg1="arg1" func=test_pos_kw.with_kw + with_kw(arg1) #$ arg1 func=test_pos_kw.with_kw def test_kw_pos(): def with_pos(a): SINK1(a) - with_pos(a=arg1) #$ arg1="arg1" func=test_kw_pos.with_pos + with_pos(a=arg1) #$ arg1 func=test_kw_pos.with_pos def test_kw_kw(): def with_kw(a=""): SINK1(a) - with_kw(a=arg1) #$ arg1="arg1" func=test_kw_kw.with_kw + with_kw(a=arg1) #$ arg1 func=test_kw_kw.with_kw def test_kw_doublestar(): def with_doublestar(**a): SINK1(a["a"]) - with_doublestar(a=arg1) #$ arg1="arg1" func=test_kw_doublestar.with_doublestar + with_doublestar(a=arg1) #$ arg1 func=test_kw_doublestar.with_doublestar diff --git a/python/ql/test/experimental/dataflow/coverage/classes.py b/python/ql/test/experimental/dataflow/coverage/classes.py index d9586f4997fd..cf55681c40a3 100644 --- a/python/ql/test/experimental/dataflow/coverage/classes.py +++ b/python/ql/test/experimental/dataflow/coverage/classes.py @@ -122,7 +122,7 @@ def __format__(self, format_spec): def test_format(): with_format = With_format() #$ MISSING: arg1="SSA variable with_format" func=With_format.__format__ - arg2 = "" #$ MISSING: arg2="arg2" func=With_format.__format__ + arg2 = "" #$ MISSING: arg2 func=With_format.__format__ format(with_format, arg2) @@ -147,7 +147,7 @@ def __lt__(self, other): def test_lt(): with_lt = With_lt() #$ MISSING: arg1="SSA variable with_lt" func=With_lt.__lt__ - arg2 = with_lt #$ MISSING: arg2="arg2" func=With_lt.__lt__ + arg2 = with_lt #$ MISSING: arg2 func=With_lt.__lt__ with_lt < arg2 @@ -162,7 +162,7 @@ def __le__(self, other): def test_le(): with_le = With_le() #$ MISSING: arg1="SSA variable with_le" func=With_le.__le__ - arg2 = with_le #$ MISSING: arg2="arg2" func=With_le.__le__ + arg2 = with_le #$ MISSING: arg2 func=With_le.__le__ with_le <= arg2 @@ -205,7 +205,7 @@ def __gt__(self, other): def test_gt(): with_gt = With_gt() #$ MISSING: arg1="SSA variable with_gt" func=With_gt.__gt__ - arg2 = with_gt #$ MISSING: arg2="arg2" func=With_gt.__gt__ + arg2 = with_gt #$ MISSING: arg2 func=With_gt.__gt__ with_gt > arg2 @@ -220,7 +220,7 @@ def __ge__(self, other): def test_ge(): with_ge = With_ge() #$ MISSING: arg1="SSA variable with_ge" func=With_ge.__ge__ - arg2 = with_ge #$ MISSING: arg2="arg2" func=With_ge.__ge__ + arg2 = with_ge #$ MISSING: arg2 func=With_ge.__ge__ with_ge >= arg2 @@ -297,7 +297,7 @@ def __getattribute__(self, name): def test_getattribute(): with_getattribute = With_getattribute() #$ MISSING: arg1="SSA variable with_getattribute" func=With_getattribute.__getattribute__ - with_getattribute.arg2 #$ MISSING: arg2="arg2" func=With_getattribute.__getattribute__ + with_getattribute.arg2 #$ MISSING: arg2 func=With_getattribute.__getattribute__ # object.__setattr__(self, name, value) @@ -311,8 +311,8 @@ def __setattr__(self, name, value): def test_setattr(): with_setattr = With_setattr() #$ MISSING: arg1="SSA variable with_setattr" func=With_setattr.__setattr__ - arg3 = "" #$ MISSING: arg3="arg3" func=With_setattr.__setattr__ - with_setattr.arg2 = arg3 #$ MISSING: arg2="arg2" func=With_setattr.__setattr__ + arg3 = "" #$ MISSING: arg3 func=With_setattr.__setattr__ + with_setattr.arg2 = arg3 #$ MISSING: arg2 func=With_setattr.__setattr__ # object.__delattr__(self, name) @@ -325,7 +325,7 @@ def __delattr__(self, name): def test_delattr(): with_delattr = With_delattr() #$ MISSING: arg1="SSA variable with_delattr" func=With_delattr.__delattr__ - del with_delattr.arg2 #$ MISSING: arg2="arg2" func=With_delattr.__delattr__ + del with_delattr.arg2 #$ MISSING: arg2 func=With_delattr.__delattr__ # object.__dir__(self) @@ -362,7 +362,7 @@ class arg3: with_get = With_get() #$ MISSING: arg1="SSA variable with_get" func=With_get.__get__ arg3.attr = with_get - arg2 = arg3() #$ MISSING: arg2="arg2" func=With_get.__get__ + arg2 = arg3() #$ MISSING: arg2 func=With_get.__get__ arg2.attr @@ -378,8 +378,8 @@ def __set__(self, instance, value): def test_set(): with_set = With_set() #$ MISSING: arg1="SSA variable with_set" func=With_set.__set__ Owner.attr = with_set - arg2 = Owner() #$ MISSING: arg2="arg2" func=With_set.__set__ - arg3 = "" #$ MISSING: arg3="arg3" func=With_set.__set__ + arg2 = Owner() #$ MISSING: arg2 func=With_set.__set__ + arg3 = "" #$ MISSING: arg3 func=With_set.__set__ arg2.attr = arg3 @@ -394,7 +394,7 @@ def __delete__(self, instance): def test_delete(): with_delete = With_delete() #$ MISSING: arg1="SSA variable with_delete" func=With_delete.__delete__ Owner.attr = with_delete - arg2 = Owner() #$ MISSING: arg2="arg2" func=With_delete.__delete__ + arg2 = Owner() #$ MISSING: arg2 func=With_delete.__delete__ del arg2.attr @@ -409,7 +409,7 @@ def __set_name__(self, owner, name): def test_set_name(): with_set_name = With_set_name() #$ MISSING: arg1="SSA variable with_set_name" func=With_set_name.__set_name__ - type("arg2", (object,), dict(arg3=with_set_name)) #$ MISSING: arg2="arg2" arg3="arg3" func=With_set_name.__set_name__ + type("arg2", (object,), dict(arg3=with_set_name)) #$ MISSING: arg2 arg3 func=With_set_name.__set_name__ # 3.3.2.4. __slots__ // We are not testing the suppression of __weakref__ and __dict__ here @@ -463,7 +463,7 @@ def __instancecheck__(self, instance): def test_instancecheck(): with_instancecheck = With_instancecheck() #$ MISSING: arg1="SSA variable with_instancecheck" func=With_instancecheck.__instancecheck__ - arg2 = "" #$ MISSING: arg2="arg2" func=With_instancecheck.__instancecheck__ + arg2 = "" #$ MISSING: arg2 func=With_instancecheck.__instancecheck__ isinstance(arg2, with_instancecheck) @@ -478,7 +478,7 @@ def __subclasscheck__(self, subclass): def test_subclasscheck(): with_subclasscheck = With_subclasscheck() #$ MISSING: arg1="SSA variable with_subclasscheck" func=With_subclasscheck.__subclasscheck__ - arg2 = object #$ MISSING: arg2="arg2" func=With_subclasscheck.__subclasscheck__ + arg2 = object #$ MISSING: arg2 func=With_subclasscheck.__subclasscheck__ issubclass(arg2, with_subclasscheck) @@ -493,7 +493,7 @@ def __class_getitem__(cls, key): def test_class_getitem(): - arg2 = int #$ MISSING: arg2="arg2" func=With_class_getitem.__class_getitem__ + arg2 = int #$ MISSING: arg2 func=With_class_getitem.__class_getitem__ with_class_getitem = With_class_getitem[arg2]() @@ -562,7 +562,7 @@ def __getitem__(self, key): def test_getitem(): with_getitem = With_getitem() #$ arg1="SSA variable with_getitem" func=With_getitem.__getitem__ arg2 = 0 - with_getitem[arg2] #$ arg2="arg2" func=With_getitem.__getitem__ + with_getitem[arg2] #$ arg2 func=With_getitem.__getitem__ # object.__setitem__(self, key, value) @@ -578,7 +578,7 @@ def test_setitem(): with_setitem = With_setitem() #$ arg1="SSA variable with_setitem" func=With_setitem.__setitem__ arg2 = 0 arg3 = "" - with_setitem[arg2] = arg3 #$ arg2="arg2" arg3="arg3" func=With_setitem.__setitem__ + with_setitem[arg2] = arg3 #$ arg2 arg3 func=With_setitem.__setitem__ # object.__delitem__(self, key) @@ -592,7 +592,7 @@ def __delitem__(self, key): def test_delitem(): with_delitem = With_delitem() #$ arg1="SSA variable with_delitem" func=With_delitem.__delitem__ arg2 = 0 - del with_delitem[arg2] #$ arg2="arg2" func=With_delitem.__delitem__ + del with_delitem[arg2] #$ arg2 func=With_delitem.__delitem__ # object.__missing__(self, key) @@ -606,7 +606,7 @@ def __missing__(self, key): def test_missing(): with_missing = With_missing() #$ MISSING: arg1="SSA variable with_missing" func=With_missing.__missing__ - arg2 = 0 #$ MISSING: arg2="arg2" func=With_missing.__missing__ + arg2 = 0 #$ MISSING: arg2 func=With_missing.__missing__ with_missing[arg2] @@ -647,7 +647,7 @@ def __contains__(self, item): def test_contains(): with_contains = With_contains() #$ MISSING: arg1="SSA variable with_contains" func=With_contains.__contains__ - arg2 = 0 #$ MISSING: arg2="arg2" func=With_contains.__contains__ + arg2 = 0 #$ MISSING: arg2 func=With_contains.__contains__ arg2 in with_contains @@ -664,7 +664,7 @@ def __add__(self, other): def test_add(): with_add = With_add() #$ arg1="SSA variable with_add" func=With_add.__add__ arg2 = with_add - with_add + arg2 #$ arg2="arg2" func=With_add.__add__ + with_add + arg2 #$ arg2 func=With_add.__add__ # object.__sub__(self, other) @@ -679,7 +679,7 @@ def __sub__(self, other): def test_sub(): with_sub = With_sub() #$ arg1="SSA variable with_sub" func=With_sub.__sub__ arg2 = with_sub - with_sub - arg2 #$ arg2="arg2" func=With_sub.__sub__ + with_sub - arg2 #$ arg2 func=With_sub.__sub__ # object.__mul__(self, other) @@ -694,7 +694,7 @@ def __mul__(self, other): def test_mul(): with_mul = With_mul() #$ arg1="SSA variable with_mul" func=With_mul.__mul__ arg2 = with_mul - with_mul * arg2 #$ arg2="arg2" func=With_mul.__mul__ + with_mul * arg2 #$ arg2 func=With_mul.__mul__ # object.__matmul__(self, other) @@ -709,7 +709,7 @@ def __matmul__(self, other): def test_matmul(): with_matmul = With_matmul() #$ arg1="SSA variable with_matmul" func=With_matmul.__matmul__ arg2 = with_matmul - with_matmul @ arg2 #$ arg2="arg2" func=With_matmul.__matmul__ + with_matmul @ arg2 #$ arg2 func=With_matmul.__matmul__ # object.__truediv__(self, other) @@ -724,7 +724,7 @@ def __truediv__(self, other): def test_truediv(): with_truediv = With_truediv() #$ arg1="SSA variable with_truediv" func=With_truediv.__truediv__ arg2 = with_truediv - with_truediv / arg2 #$ arg2="arg2" func=With_truediv.__truediv__ + with_truediv / arg2 #$ arg2 func=With_truediv.__truediv__ # object.__floordiv__(self, other) @@ -739,7 +739,7 @@ def __floordiv__(self, other): def test_floordiv(): with_floordiv = With_floordiv() #$ arg1="SSA variable with_floordiv" func=With_floordiv.__floordiv__ arg2 = with_floordiv - with_floordiv // arg2 #$ arg2="arg2" func=With_floordiv.__floordiv__ + with_floordiv // arg2 #$ arg2 func=With_floordiv.__floordiv__ # object.__mod__(self, other) @@ -754,7 +754,7 @@ def __mod__(self, other): def test_mod(): with_mod = With_mod() #$ arg1="SSA variable with_mod" func=With_mod.__mod__ arg2 = with_mod - with_mod % arg2 #$ arg2="arg2" func=With_mod.__mod__ + with_mod % arg2 #$ arg2 func=With_mod.__mod__ # object.__divmod__(self, other) @@ -768,7 +768,7 @@ def __divmod__(self, other): def test_divmod(): with_divmod = With_divmod() #$ MISSING: arg1="SSA variable with_divmod" func=With_divmod.__divmod__ - arg2 = With_divmod #$ MISSING: arg2="arg2" func=With_divmod.__divmod__ + arg2 = With_divmod #$ MISSING: arg2 func=With_divmod.__divmod__ divmod(with_divmod, arg2) @@ -784,13 +784,13 @@ def __pow__(self, other): def test_pow(): with_pow = With_pow() #$ MISSING: arg1="SSA variable with_pow" func=With_pow.__pow__ arg2 = with_pow - pow(with_pow, arg2) #$ MISSING: arg2="arg2" func=With_pow.__pow__ + pow(with_pow, arg2) #$ MISSING: arg2 func=With_pow.__pow__ def test_pow_op(): with_pow = With_pow() #$ arg1="SSA variable with_pow" func=With_pow.__pow__ arg2 = with_pow - with_pow ** arg2 #$ arg2="arg2" func=With_pow.__pow__ + with_pow ** arg2 #$ arg2 func=With_pow.__pow__ # object.__lshift__(self, other) @@ -805,7 +805,7 @@ def __lshift__(self, other): def test_lshift(): with_lshift = With_lshift() #$ arg1="SSA variable with_lshift" func=With_lshift.__lshift__ arg2 = with_lshift - with_lshift << arg2 #$ arg2="arg2" func=With_lshift.__lshift__ + with_lshift << arg2 #$ arg2 func=With_lshift.__lshift__ # object.__rshift__(self, other) @@ -820,7 +820,7 @@ def __rshift__(self, other): def test_rshift(): with_rshift = With_rshift() #$ arg1="SSA variable with_rshift" func=With_rshift.__rshift__ arg2 = with_rshift - with_rshift >> arg2 #$ arg2="arg2" func=With_rshift.__rshift__ + with_rshift >> arg2 #$ arg2 func=With_rshift.__rshift__ # object.__and__(self, other) @@ -835,7 +835,7 @@ def __and__(self, other): def test_and(): with_and = With_and() #$ arg1="SSA variable with_and" func=With_and.__and__ arg2 = with_and - with_and & arg2 #$ arg2="arg2" func=With_and.__and__ + with_and & arg2 #$ arg2 func=With_and.__and__ # object.__xor__(self, other) @@ -850,7 +850,7 @@ def __xor__(self, other): def test_xor(): with_xor = With_xor() #$ arg1="SSA variable with_xor" func=With_xor.__xor__ arg2 = with_xor - with_xor ^ arg2 #$ arg2="arg2" func=With_xor.__xor__ + with_xor ^ arg2 #$ arg2 func=With_xor.__xor__ # object.__or__(self, other) @@ -865,7 +865,7 @@ def __or__(self, other): def test_or(): with_or = With_or() #$ arg1="SSA variable with_or" func=With_or.__or__ arg2 = with_or - with_or | arg2 #$ arg2="arg2" func=With_or.__or__ + with_or | arg2 #$ arg2 func=With_or.__or__ # object.__radd__(self, other) @@ -879,7 +879,7 @@ def __radd__(self, other): def test_radd(): with_radd = With_radd() #$ MISSING: arg1="SSA variable with_radd" func=With_radd.__radd__ - arg2 = "" #$ MISSING: arg2="arg2" func=With_radd.__radd__ + arg2 = "" #$ MISSING: arg2 func=With_radd.__radd__ arg2 + with_radd @@ -894,7 +894,7 @@ def __rsub__(self, other): def test_rsub(): with_rsub = With_rsub() #$ MISSING: arg1="SSA variable with_rsub" func=With_rsub.__rsub__ - arg2 = "" #$ MISSING: arg2="arg2" func=With_rsub.__rsub__ + arg2 = "" #$ MISSING: arg2 func=With_rsub.__rsub__ arg2 - with_rsub @@ -909,7 +909,7 @@ def __rmul__(self, other): def test_rmul(): with_rmul = With_rmul() #$ MISSING: arg1="SSA variable with_rmul" func=With_rmul.__rmul__ - arg2 = "" #$ MISSING: arg2="arg2" func=With_rmul.__rmul__ + arg2 = "" #$ MISSING: arg2 func=With_rmul.__rmul__ arg2 * with_rmul @@ -924,7 +924,7 @@ def __rmatmul__(self, other): def test_rmatmul(): with_rmatmul = With_rmatmul() #$ MISSING: arg1="SSA variable with_rmatmul" func=With_rmatmul.__rmatmul__ - arg2 = "" #$ MISSING: arg2="arg2" func=With_rmatmul.__rmatmul__ + arg2 = "" #$ MISSING: arg2 func=With_rmatmul.__rmatmul__ arg2 @ with_rmatmul @@ -939,7 +939,7 @@ def __rtruediv__(self, other): def test_rtruediv(): with_rtruediv = With_rtruediv() #$ MISSING: arg1="SSA variable with_rtruediv" func=With_rtruediv.__rtruediv__ - arg2 = "" #$ MISSING: arg2="arg2" func=With_rtruediv.__rtruediv__ + arg2 = "" #$ MISSING: arg2 func=With_rtruediv.__rtruediv__ arg2 / with_rtruediv @@ -954,7 +954,7 @@ def __rfloordiv__(self, other): def test_rfloordiv(): with_rfloordiv = With_rfloordiv() #$ MISSING: arg1="SSA variable with_rfloordiv" func=With_rfloordiv.__rfloordiv__ - arg2 = "" #$ MISSING: arg2="arg2" func=With_rfloordiv.__rfloordiv__ + arg2 = "" #$ MISSING: arg2 func=With_rfloordiv.__rfloordiv__ arg2 // with_rfloordiv @@ -969,7 +969,7 @@ def __rmod__(self, other): def test_rmod(): with_rmod = With_rmod() #$ MISSING: arg1="SSA variable with_rmod" func=With_rmod.__rmod__ - arg2 = {} #$ MISSING: arg2="arg2" func=With_rmod.__rmod__ + arg2 = {} #$ MISSING: arg2 func=With_rmod.__rmod__ arg2 % with_rmod @@ -984,7 +984,7 @@ def __rdivmod__(self, other): def test_rdivmod(): with_rdivmod = With_rdivmod() #$ MISSING: arg1="SSA variable with_rdivmod" func=With_rdivmod.__rdivmod__ - arg2 = "" #$ MISSING: arg2="arg2" func=With_rdivmod.__rdivmod__ + arg2 = "" #$ MISSING: arg2 func=With_rdivmod.__rdivmod__ divmod(arg2, with_rdivmod) @@ -999,13 +999,13 @@ def __rpow__(self, other): def test_rpow(): with_rpow = With_rpow() #$ MISSING: arg1="SSA variable with_rpow" func=With_rpow.__rpow__ - arg2 = "" #$ MISSING: arg2="arg2" func=With_rpow.__rpow__ + arg2 = "" #$ MISSING: arg2 func=With_rpow.__rpow__ pow(arg2, with_rpow) def test_rpow_op(): with_rpow = With_rpow() #$ MISSING: arg1="SSA variable with_rpow" func=With_rpow.__rpow__ - arg2 = "" #$ MISSING: arg2="arg2" func=With_rpow.__rpow__ + arg2 = "" #$ MISSING: arg2 func=With_rpow.__rpow__ arg2 ** with_rpow @@ -1020,7 +1020,7 @@ def __rlshift__(self, other): def test_rlshift(): with_rlshift = With_rlshift() #$ MISSING: arg1="SSA variable with_rlshift" func=With_rlshift.__rlshift__ - arg2 = "" #$ MISSING: arg2="arg2" func=With_rlshift.__rlshift__ + arg2 = "" #$ MISSING: arg2 func=With_rlshift.__rlshift__ arg2 << with_rlshift @@ -1035,7 +1035,7 @@ def __rrshift__(self, other): def test_rrshift(): with_rrshift = With_rrshift() #$ MISSING: arg1="SSA variable with_rrshift" func=With_rrshift.__rrshift__ - arg2 = "" #$ MISSING: arg2="arg2" func=With_rrshift.__rrshift__ + arg2 = "" #$ MISSING: arg2 func=With_rrshift.__rrshift__ arg2 >> with_rrshift @@ -1050,7 +1050,7 @@ def __rand__(self, other): def test_rand(): with_rand = With_rand() #$ MISSING: arg1="SSA variable with_rand" func=With_rand.__rand__ - arg2 = "" #$ MISSING: arg2="arg2" func=With_rand.__rand__ + arg2 = "" #$ MISSING: arg2 func=With_rand.__rand__ arg2 & with_rand @@ -1065,7 +1065,7 @@ def __rxor__(self, other): def test_rxor(): with_rxor = With_rxor() #$ MISSING: arg1="SSA variable with_rxor" func=With_rxor.__rxor__ - arg2 = "" #$ MISSING: arg2="arg2" func=With_rxor.__rxor__ + arg2 = "" #$ MISSING: arg2 func=With_rxor.__rxor__ arg2 ^ with_rxor @@ -1080,7 +1080,7 @@ def __ror__(self, other): def test_ror(): with_ror = With_ror() #$ MISSING: arg1="SSA variable with_ror" func=With_ror.__ror__ - arg2 = "" #$ MISSING: arg2="arg2" func=With_ror.__ror__ + arg2 = "" #$ MISSING: arg2 func=With_ror.__ror__ arg2 | with_ror @@ -1095,7 +1095,7 @@ def __iadd__(self, other): def test_iadd(): with_iadd = With_iadd() #$ MISSING: arg1="SSA variable with_iadd" func=With_iadd.__iadd__ - arg2 = with_iadd #$ MISSING: arg2="arg2" func=With_iadd.__iadd__ + arg2 = with_iadd #$ MISSING: arg2 func=With_iadd.__iadd__ with_iadd += arg2 @@ -1110,7 +1110,7 @@ def __isub__(self, other): def test_isub(): with_isub = With_isub() #$ MISSING: arg1="SSA variable with_isub" func=With_isub.__isub__ - arg2 = with_isub #$ MISSING: arg2="arg2" func=With_isub.__isub__ + arg2 = with_isub #$ MISSING: arg2 func=With_isub.__isub__ with_isub -= arg2 @@ -1125,7 +1125,7 @@ def __imul__(self, other): def test_imul(): with_imul = With_imul() #$ MISSING: arg1="SSA variable with_imul" func=With_imul.__imul__ - arg2 = with_imul #$ MISSING: arg2="arg2" func=With_imul.__imul__ + arg2 = with_imul #$ MISSING: arg2 func=With_imul.__imul__ with_imul *= arg2 @@ -1140,7 +1140,7 @@ def __imatmul__(self, other): def test_imatmul(): with_imatmul = With_imatmul() #$ MISSING: arg1="SSA variable with_imatmul" func=With_imatmul.__imatmul__ - arg2 = with_imatmul #$ MISSING: arg2="arg2" func=With_imatmul.__imatmul__ + arg2 = with_imatmul #$ MISSING: arg2 func=With_imatmul.__imatmul__ with_imatmul @= arg2 @@ -1155,7 +1155,7 @@ def __itruediv__(self, other): def test_itruediv(): with_itruediv = With_itruediv() #$ MISSING: arg1="SSA variable with_itruediv" func=With_itruediv.__itruediv__ - arg2 = with_itruediv #$ MISSING: arg2="arg2" func=With_itruediv.__itruediv__ + arg2 = with_itruediv #$ MISSING: arg2 func=With_itruediv.__itruediv__ with_itruediv /= arg2 @@ -1170,7 +1170,7 @@ def __ifloordiv__(self, other): def test_ifloordiv(): with_ifloordiv = With_ifloordiv() #$ MISSING: arg1="SSA variable with_ifloordiv" func=With_ifloordiv.__ifloordiv__ - arg2 = with_ifloordiv #$ MISSING: arg2="arg2" func=With_ifloordiv.__ifloordiv__ + arg2 = with_ifloordiv #$ MISSING: arg2 func=With_ifloordiv.__ifloordiv__ with_ifloordiv //= arg2 @@ -1185,7 +1185,7 @@ def __imod__(self, other): def test_imod(): with_imod = With_imod() #$ MISSING: arg1="SSA variable with_imod" func=With_imod.__imod__ - arg2 = with_imod #$ MISSING: arg2="arg2" func=With_imod.__imod__ + arg2 = with_imod #$ MISSING: arg2 func=With_imod.__imod__ with_imod %= arg2 @@ -1200,7 +1200,7 @@ def __ipow__(self, other): def test_ipow(): with_ipow = With_ipow() #$ MISSING: arg1="SSA variable with_ipow" func=With_ipow.__ipow__ - arg2 = with_ipow #$ MISSING: arg2="arg2" func=With_ipow.__ipow__ + arg2 = with_ipow #$ MISSING: arg2 func=With_ipow.__ipow__ with_ipow **= arg2 @@ -1215,7 +1215,7 @@ def __ilshift__(self, other): def test_ilshift(): with_ilshift = With_ilshift() #$ MISSING: arg1="SSA variable with_ilshift" func=With_ilshift.__ilshift__ - arg2 = with_ilshift #$ MISSING: arg2="arg2" func=With_ilshift.__ilshift__ + arg2 = with_ilshift #$ MISSING: arg2 func=With_ilshift.__ilshift__ with_ilshift <<= arg2 @@ -1230,7 +1230,7 @@ def __irshift__(self, other): def test_irshift(): with_irshift = With_irshift() #$ MISSING: arg1="SSA variable with_irshift" func=With_irshift.__irshift__ - arg2 = with_irshift #$ MISSING: arg2="arg2" func=With_irshift.__irshift__ + arg2 = with_irshift #$ MISSING: arg2 func=With_irshift.__irshift__ with_irshift >>= arg2 @@ -1245,7 +1245,7 @@ def __iand__(self, other): def test_iand(): with_iand = With_iand() #$ MISSING: arg1="SSA variable with_iand" func=With_iand.__iand__ - arg2 = with_iand #$ MISSING: arg2="arg2" func=With_iand.__iand__ + arg2 = with_iand #$ MISSING: arg2 func=With_iand.__iand__ with_iand &= arg2 @@ -1260,7 +1260,7 @@ def __ixor__(self, other): def test_ixor(): with_ixor = With_ixor() #$ MISSING: arg1="SSA variable with_ixor" func=With_ixor.__ixor__ - arg2 = with_ixor #$ MISSING: arg2="arg2" func=With_ixor.__ixor__ + arg2 = with_ixor #$ MISSING: arg2 func=With_ixor.__ixor__ with_ixor ^= arg2 @@ -1275,7 +1275,7 @@ def __ior__(self, other): def test_ior(): with_ior = With_ior() #$ MISSING: arg1="SSA variable with_ior" func=With_ior.__ior__ - arg2 = with_ior #$ MISSING: arg2="arg2" func=With_ior.__ior__ + arg2 = with_ior #$ MISSING: arg2 func=With_ior.__ior__ with_ior |= arg2 From e786be06aef074639e3bc56e8f8465bd30813c06 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Thu, 21 Jan 2021 12:40:35 +0100 Subject: [PATCH 16/16] Python: Fix broken references --- .../ql/test/experimental/dataflow/TestUtil/MaximalFlowTest.qll | 2 +- python/ql/test/experimental/dataflow/callGraphConfig.qll | 2 +- .../ql/test/experimental/dataflow/coverage/classesCallGraph.ql | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/python/ql/test/experimental/dataflow/TestUtil/MaximalFlowTest.qll b/python/ql/test/experimental/dataflow/TestUtil/MaximalFlowTest.qll index eb84d197c69a..4956aecadc26 100644 --- a/python/ql/test/experimental/dataflow/TestUtil/MaximalFlowTest.qll +++ b/python/ql/test/experimental/dataflow/TestUtil/MaximalFlowTest.qll @@ -35,7 +35,7 @@ class MaximalFlowsConfig extends DataFlow::Configuration { override predicate isSink(DataFlow::Node node) { exists(node.getLocation().getFile().getRelativePath()) and not any(CallNode c).getArg(_) = node.asCfgNode() and - not node instanceof ArgumentNode and + not node instanceof DataFlow::ArgumentNode and not node.asCfgNode().(NameNode).getId().matches("SINK%") and not exists(DataFlow::Node succ | DataFlow::localFlowStep(node, succ)) } diff --git a/python/ql/test/experimental/dataflow/callGraphConfig.qll b/python/ql/test/experimental/dataflow/callGraphConfig.qll index c2846192e4de..ceb39bafcd6a 100644 --- a/python/ql/test/experimental/dataflow/callGraphConfig.qll +++ b/python/ql/test/experimental/dataflow/callGraphConfig.qll @@ -11,7 +11,7 @@ class CallGraphConfig extends DataFlow::Configuration { override predicate isSource(DataFlow::Node node) { node instanceof DataFlowPrivate::ReturnNode or - node instanceof DataFlowPrivate::ArgumentNode + node instanceof DataFlow::ArgumentNode } override predicate isSink(DataFlow::Node node) { diff --git a/python/ql/test/experimental/dataflow/coverage/classesCallGraph.ql b/python/ql/test/experimental/dataflow/coverage/classesCallGraph.ql index 3c74e722b3d3..1f8edfc1c791 100644 --- a/python/ql/test/experimental/dataflow/coverage/classesCallGraph.ql +++ b/python/ql/test/experimental/dataflow/coverage/classesCallGraph.ql @@ -11,7 +11,7 @@ class CallGraphConfig extends DataFlow::Configuration { node instanceof DataFlowPrivate::ReturnNode or // These sources should allow for the non-standard call syntax - node instanceof DataFlowPrivate::ArgumentNode + node instanceof DataFlow::ArgumentNode } override predicate isSink(DataFlow::Node node) {