From 823ed447df465beee6ca6d7fb5d6f410d2708c35 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Thu, 12 Nov 2020 21:57:29 +0100 Subject: [PATCH 001/343] 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 00000000000..9f0762f6488 --- /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 00000000000..c2c180627ec --- /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 00000000000..792aa2b848d --- /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 00000000000..e69de29bb2d 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 00000000000..6e57f26cd0f --- /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 00000000000..e69de29bb2d 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 00000000000..ec171dcd9fd --- /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 416467d9dc9..e97068a041c 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 00000000000..e69de29bb2d 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 00000000000..c7b2b5bfe15 --- /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 f5f3680dd55..d6ab9bd3dcb 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 @@ c = C() 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 @@ SINK(func_obj(c, SOURCE, C)) 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 @@ customized = Customized() 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 00000000000..e69de29bb2d 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 00000000000..ec171dcd9fd --- /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 cddb88f5ccb..ab7b9f02405 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 @@ l = [SOURCE] 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 test_deep_callgraph(): 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 002/343] 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 c1efdd1d28f..38f3123fab5 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 test_pos_pos_only(): 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 00000000000..5dfe0963387 --- /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 00000000000..5b8e80cad2a --- /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 003/343] 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 38f3123fab5..7f1a832bf61 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 5dfe0963387..5624d283462 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 5b8e80cad2a..00cc3a49656 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 004/343] 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 5624d283462..e69de29bb2d 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 1977998ab64..613019ce4b8 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 3b5ff7386202e5036f78a4881464d7130fd0a6b8 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 5 Nov 2020 15:37:21 +0000 Subject: [PATCH 005/343] JS: Introduce API::InvokeNode to simplify reasoning about calls --- .../ql/src/semmle/javascript/ApiGraphs.qll | 62 ++++++++++++++++++- 1 file changed, 59 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/ApiGraphs.qll b/javascript/ql/src/semmle/javascript/ApiGraphs.qll index e3d627c3da7..5b54509dae4 100644 --- a/javascript/ql/src/semmle/javascript/ApiGraphs.qll +++ b/javascript/ql/src/semmle/javascript/ApiGraphs.qll @@ -54,17 +54,17 @@ module API { /** * Gets a call to the function represented by this API component. */ - DataFlow::CallNode getACall() { result = getReturn().getAnImmediateUse() } + CallNode getACall() { result = getReturn().getAnImmediateUse() } /** * Gets a `new` call to the function represented by this API component. */ - DataFlow::NewNode getAnInstantiation() { result = getInstance().getAnImmediateUse() } + NewNode getAnInstantiation() { result = getInstance().getAnImmediateUse() } /** * Gets an invocation (with our without `new`) to the function represented by this API component. */ - DataFlow::InvokeNode getAnInvocation() { result = getACall() or result = getAnInstantiation() } + InvokeNode getAnInvocation() { result = getACall() or result = getAnInstantiation() } /** * Gets a data-flow node corresponding to the right-hand side of a definition of the API @@ -114,11 +114,17 @@ module API { * For example, if this node represents a use of some class `A`, then there might be a node * representing instances of `A`, typically corresponding to expressions `new A()` at the * source level. + * + * This predicate may have multiple results when there are multiple constructor calls invoking this API component. + * Consider using `getAnInstantiation()` if there is a need to distingiush between individual constructor calls. */ Node getInstance() { result = getASuccessor(Label::instance()) } /** * Gets a node representing the `i`th parameter of the function represented by this node. + * + * This predicate may have multiple results when there are multiple invocations of this API component. + * Consider using `getAnInvocation()` if there is a need to distingiush between individual calls. */ bindingset[i] Node getParameter(int i) { result = getASuccessor(Label::parameter(i)) } @@ -133,6 +139,9 @@ module API { /** * Gets a node representing the last parameter of the function represented by this node. + * + * This predicate may have multiple results when there are multiple invocations of this API component. + * Consider using `getAnInvocation()` if there is a need to distingiush between individual calls. */ Node getLastParameter() { result = getParameter(getNumParameter() - 1) } @@ -144,6 +153,10 @@ module API { /** * Gets a node representing a parameter or the receiver of the function represented by this * node. + * + * This predicate may result in a mix of parameters from different call sites in cases where + * there are multiple invocations of this API component. + * Consider using `getAnInvocation()` if there is a need to distingiush between individual calls. */ Node getAParameter() { result = getASuccessor(Label::parameterByStringIndex(_)) or @@ -152,6 +165,9 @@ module API { /** * Gets a node representing the result of the function represented by this node. + * + * This predicate may have multiple results when there are multiple invocations of this API component. + * Consider using `getACall()` if there is a need to distingiush between individual calls. */ Node getReturn() { result = getASuccessor(Label::return()) } @@ -787,6 +803,46 @@ module API { } import Label as EdgeLabel + + /** + * An `InvokeNode` that is connected to the API graph. + * + * Can be used to reason about calls to an external API in which the correlation between + * parameters and/or return values must be retained. + * + * The member predicates `getParameter`, `getReturn`, and `getInstance` mimic the corresponding + * predicates from `API::Node`. These are guaranteed to exist and be unique to this call. + */ + class InvokeNode extends DataFlow::InvokeNode { + API::Node callee; + + InvokeNode() { this = callee.getReturn().getAnImmediateUse() or this = callee.getInstance().getAnImmediateUse() } + + /** Gets the API node for the `i`th parameter of this invocation. */ + Node getParameter(int i) { + result = callee.getParameter(i) and + result.getARhs() = getArgument(i) + } + + /** Gets the API node a parameter of this invocation. */ + Node getAParameter() { + result = getParameter(_) + } + + /** Gets the API node for the return value of this call. */ + Node getReturn() { result.getAnImmediateUse() = this } + + /** Gets the API node for the object constructed by this invocation. */ + Node getInstance() { result.getAnImmediateUse() = this } + } + + /** A call connected to the API graph. */ + class CallNode extends InvokeNode, DataFlow::CallNode { + } + + /** A `new` call connected to the API graph. */ + class NewNode extends InvokeNode, DataFlow::NewNode { + } } private module Label { From ac00e028555a3cbda95c828c079e829485d92d66 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 11 Nov 2020 15:49:26 +0000 Subject: [PATCH 006/343] JS: Add API::Node.getAValueReachingRhs --- javascript/ql/src/semmle/javascript/ApiGraphs.qll | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/ApiGraphs.qll b/javascript/ql/src/semmle/javascript/ApiGraphs.qll index 5b54509dae4..58b08c5bf91 100644 --- a/javascript/ql/src/semmle/javascript/ApiGraphs.qll +++ b/javascript/ql/src/semmle/javascript/ApiGraphs.qll @@ -82,6 +82,12 @@ module API { */ DataFlow::Node getARhs() { Impl::rhs(this, result) } + /** + * Gets a data-flow node that may interprocedurally flow to the right-hand side of a definition + * of the API component represented by this node. + */ + DataFlow::Node getAValueReachingRhs() { result = Impl::trackDefNode(getARhs()) } + /** * Gets a node representing member `m` of this API component. * @@ -825,9 +831,10 @@ module API { } /** Gets the API node a parameter of this invocation. */ - Node getAParameter() { - result = getParameter(_) - } + Node getAParameter() { result = getParameter(_) } + + /** Gets the API node for the last parameter of this invocation. */ + Node getLastParameter() { result = getParameter(getNumArgument() - 1) } /** Gets the API node for the return value of this call. */ Node getReturn() { result.getAnImmediateUse() = this } From b6b8a55b371006033d6151ee4b30951ddfec2a3a Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 23 Nov 2020 16:16:50 +0000 Subject: [PATCH 007/343] JS: Add test case --- .../ql/test/ApiGraphs/call-nodes/index.js | 4 +++ .../test/ApiGraphs/call-nodes/test.expected | 3 +++ .../ql/test/ApiGraphs/call-nodes/test.ql | 25 +++++++++++++++++++ 3 files changed, 32 insertions(+) create mode 100644 javascript/ql/test/ApiGraphs/call-nodes/index.js create mode 100644 javascript/ql/test/ApiGraphs/call-nodes/test.expected create mode 100644 javascript/ql/test/ApiGraphs/call-nodes/test.ql diff --git a/javascript/ql/test/ApiGraphs/call-nodes/index.js b/javascript/ql/test/ApiGraphs/call-nodes/index.js new file mode 100644 index 00000000000..999af64c90b --- /dev/null +++ b/javascript/ql/test/ApiGraphs/call-nodes/index.js @@ -0,0 +1,4 @@ +import { foo } from 'mylibrary'; + +foo({ value: 1 }, { value: 1 }); +foo({ value: 2 }, { value: 2 }); diff --git a/javascript/ql/test/ApiGraphs/call-nodes/test.expected b/javascript/ql/test/ApiGraphs/call-nodes/test.expected new file mode 100644 index 00000000000..9b8eb28bbef --- /dev/null +++ b/javascript/ql/test/ApiGraphs/call-nodes/test.expected @@ -0,0 +1,3 @@ +ERROR: Could not resolve predicate getArgument/1 (/Users/asger/git/code/ql/javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll:716,60-71) +ERROR: Could not resolve predicate getParameter/1 (/Users/asger/git/code/ql/javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll:719,40-52) +ERROR: Could not resolve type API::MethodCallNode (/Users/asger/git/code/ql/javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll:705,51-70) diff --git a/javascript/ql/test/ApiGraphs/call-nodes/test.ql b/javascript/ql/test/ApiGraphs/call-nodes/test.ql new file mode 100644 index 00000000000..97cfc6aeeba --- /dev/null +++ b/javascript/ql/test/ApiGraphs/call-nodes/test.ql @@ -0,0 +1,25 @@ +import javascript + +class FooCall extends API::CallNode { + FooCall() { + this = API::moduleImport("mylibrary").getMember("foo").getACall() + } + + DataFlow::Node getFirst() { + result = getParameter(0).getMember("value").getARhs() + } + + DataFlow::Node getSecond() { + result = getParameter(1).getMember("value").getARhs() + } +} + +query predicate values(FooCall call, int first, int second) { + first = call.getFirst().getIntValue() and + second = call.getSecond().getIntValue() +} + +query predicate mismatch(FooCall call, string msg) { + call.getFirst().getIntValue() != call.getSecond().getIntValue() and + msg = "mismatching parameter indices found for call" +} From c146e044ca9a15fa391a95a13da888a4fd7713f2 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 23 Nov 2020 16:17:00 +0000 Subject: [PATCH 008/343] JS: Update NoSQL model --- .../semmle/javascript/frameworks/NoSQL.qll | 26 +++++++------------ 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll b/javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll index 31671cbc423..a202b557268 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll @@ -62,22 +62,20 @@ private module MongoDB { } /** A call to a MongoDB query method. */ - private class QueryCall extends DatabaseAccess, DataFlow::CallNode { + private class QueryCall extends DatabaseAccess, API::CallNode { int queryArgIdx; - API::Node callee; QueryCall() { exists(string method | CollectionMethodSignatures::interpretsArgumentAsQuery(method, queryArgIdx) and - callee = getACollection().getMember(method) - ) and - this = callee.getACall() + this = getACollection().getMember(method).getACall() + ) } override DataFlow::Node getAQueryArgument() { result = getArgument(queryArgIdx) } DataFlow::Node getACodeOperator() { - result = getADollarWhereProperty(callee.getParameter(queryArgIdx)) + result = getADollarWhereProperty(getParameter(queryArgIdx)) } } @@ -670,14 +668,12 @@ private module Minimongo { } /** A call to a Minimongo query method. */ - private class QueryCall extends DatabaseAccess, DataFlow::MethodCallNode { + private class QueryCall extends DatabaseAccess, API::CallNode { int queryArgIdx; - API::Node callee; QueryCall() { exists(string m | - callee = API::moduleImport("minimongo").getAMember().getReturn().getAMember().getMember(m) and - this = callee.getACall() and + this = API::moduleImport("minimongo").getAMember().getReturn().getAMember().getMember(m).getACall() and CollectionMethodSignatures::interpretsArgumentAsQuery(m, queryArgIdx) ) } @@ -685,7 +681,7 @@ private module Minimongo { override DataFlow::Node getAQueryArgument() { result = getArgument(queryArgIdx) } DataFlow::Node getACodeOperator() { - result = getADollarWhereProperty(callee.getParameter(queryArgIdx)) + result = getADollarWhereProperty(getParameter(queryArgIdx)) } } @@ -706,14 +702,12 @@ private module Minimongo { */ private module MarsDB { /** A call to a MarsDB query method. */ - private class QueryCall extends DatabaseAccess, DataFlow::MethodCallNode { + private class QueryCall extends DatabaseAccess, API::MethodCallNode { int queryArgIdx; - API::Node callee; QueryCall() { exists(string m | - callee = API::moduleImport("marsdb").getMember("Collection").getInstance().getMember(m) and - this = callee.getACall() and + this = API::moduleImport("marsdb").getMember("Collection").getInstance().getMember(m).getACall() and // implements parts of the Minimongo interface Minimongo::CollectionMethodSignatures::interpretsArgumentAsQuery(m, queryArgIdx) ) @@ -722,7 +716,7 @@ private module MarsDB { override DataFlow::Node getAQueryArgument() { result = getArgument(queryArgIdx) } DataFlow::Node getACodeOperator() { - result = getADollarWhereProperty(callee.getParameter(queryArgIdx)) + result = getADollarWhereProperty(getParameter(queryArgIdx)) } } From 85f0a627c40a14e359e506317d3e4044510e054f Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 23 Nov 2020 16:17:22 +0000 Subject: [PATCH 009/343] JS: Autoformat --- javascript/ql/src/semmle/javascript/ApiGraphs.qll | 11 ++++++----- .../ql/src/semmle/javascript/frameworks/NoSQL.qll | 11 +++++++++-- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/ApiGraphs.qll b/javascript/ql/src/semmle/javascript/ApiGraphs.qll index 58b08c5bf91..0e919b62e64 100644 --- a/javascript/ql/src/semmle/javascript/ApiGraphs.qll +++ b/javascript/ql/src/semmle/javascript/ApiGraphs.qll @@ -822,7 +822,10 @@ module API { class InvokeNode extends DataFlow::InvokeNode { API::Node callee; - InvokeNode() { this = callee.getReturn().getAnImmediateUse() or this = callee.getInstance().getAnImmediateUse() } + InvokeNode() { + this = callee.getReturn().getAnImmediateUse() or + this = callee.getInstance().getAnImmediateUse() + } /** Gets the API node for the `i`th parameter of this invocation. */ Node getParameter(int i) { @@ -844,12 +847,10 @@ module API { } /** A call connected to the API graph. */ - class CallNode extends InvokeNode, DataFlow::CallNode { - } + class CallNode extends InvokeNode, DataFlow::CallNode { } /** A `new` call connected to the API graph. */ - class NewNode extends InvokeNode, DataFlow::NewNode { - } + class NewNode extends InvokeNode, DataFlow::NewNode { } } private module Label { diff --git a/javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll b/javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll index a202b557268..a78b937018e 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll @@ -673,7 +673,13 @@ private module Minimongo { QueryCall() { exists(string m | - this = API::moduleImport("minimongo").getAMember().getReturn().getAMember().getMember(m).getACall() and + this = + API::moduleImport("minimongo") + .getAMember() + .getReturn() + .getAMember() + .getMember(m) + .getACall() and CollectionMethodSignatures::interpretsArgumentAsQuery(m, queryArgIdx) ) } @@ -707,7 +713,8 @@ private module MarsDB { QueryCall() { exists(string m | - this = API::moduleImport("marsdb").getMember("Collection").getInstance().getMember(m).getACall() and + this = + API::moduleImport("marsdb").getMember("Collection").getInstance().getMember(m).getACall() and // implements parts of the Minimongo interface Minimongo::CollectionMethodSignatures::interpretsArgumentAsQuery(m, queryArgIdx) ) From d3412bb0ecb52900a3c7249250b5b4a72adea702 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 23 Nov 2020 21:18:53 +0000 Subject: [PATCH 010/343] JS: Fix typo in NoSQL model --- javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll | 2 +- javascript/ql/test/ApiGraphs/call-nodes/test.expected | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll b/javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll index a78b937018e..88b1879bdb2 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll @@ -708,7 +708,7 @@ private module Minimongo { */ private module MarsDB { /** A call to a MarsDB query method. */ - private class QueryCall extends DatabaseAccess, API::MethodCallNode { + private class QueryCall extends DatabaseAccess, API::CallNode { int queryArgIdx; QueryCall() { diff --git a/javascript/ql/test/ApiGraphs/call-nodes/test.expected b/javascript/ql/test/ApiGraphs/call-nodes/test.expected index 9b8eb28bbef..5d70524cdd0 100644 --- a/javascript/ql/test/ApiGraphs/call-nodes/test.expected +++ b/javascript/ql/test/ApiGraphs/call-nodes/test.expected @@ -1,3 +1,4 @@ -ERROR: Could not resolve predicate getArgument/1 (/Users/asger/git/code/ql/javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll:716,60-71) -ERROR: Could not resolve predicate getParameter/1 (/Users/asger/git/code/ql/javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll:719,40-52) -ERROR: Could not resolve type API::MethodCallNode (/Users/asger/git/code/ql/javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll:705,51-70) +values +| index.js:3:1:3:31 | foo({ v ... e: 1 }) | 1 | 1 | +| index.js:4:1:4:31 | foo({ v ... e: 2 }) | 2 | 2 | +mismatch From ac6d4aac9d5377f382c7b4e438aa72115e487dcc Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 23 Nov 2020 21:20:38 +0000 Subject: [PATCH 011/343] Apply suggestions from code review Co-authored-by: Max Schaefer <54907921+max-schaefer@users.noreply.github.com> --- javascript/ql/src/semmle/javascript/ApiGraphs.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/ApiGraphs.qll b/javascript/ql/src/semmle/javascript/ApiGraphs.qll index 0e919b62e64..6c9faff38e8 100644 --- a/javascript/ql/src/semmle/javascript/ApiGraphs.qll +++ b/javascript/ql/src/semmle/javascript/ApiGraphs.qll @@ -122,7 +122,7 @@ module API { * source level. * * This predicate may have multiple results when there are multiple constructor calls invoking this API component. - * Consider using `getAnInstantiation()` if there is a need to distingiush between individual constructor calls. + * Consider using `getAnInstantiation()` if there is a need to distinguish between individual constructor calls. */ Node getInstance() { result = getASuccessor(Label::instance()) } @@ -833,7 +833,7 @@ module API { result.getARhs() = getArgument(i) } - /** Gets the API node a parameter of this invocation. */ + /** Gets the API node for a parameter of this invocation. */ Node getAParameter() { result = getParameter(_) } /** Gets the API node for the last parameter of this invocation. */ From a19304a4a068ac9ac5b6bcea16295ff3df34e61c Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 24 Nov 2020 02:17:38 +0100 Subject: [PATCH 012/343] 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 9f0762f6488..edb24373386 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 792aa2b848d..eb84d197c69 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 00000000000..84f97d3f6ff --- /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 6e57f26cd0f..6dca0190156 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 ec171dcd9fd..618dae382f1 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 e97068a041c..d0a54a570eb 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 7f1a832bf61..6de4d56ad13 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 test_pos_pos_only(): 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 00cc3a49656..8a2b9cf9235 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 613019ce4b8..eb850b8d819 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 c7b2b5bfe15..76cabbfbbbf 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 d6ab9bd3dcb..0d921a2cb85 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 @@ c = C() 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 @@ customized = Customized() 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 e69de29bb2d..00000000000 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 ec171dcd9fd..00000000000 --- 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 ab7b9f02405..616837a9d3b 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 @@ l = [SOURCE] 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 test_deep_callgraph(): 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 6d6ee56ad0e..618fa1cfd2a 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 013/343] 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 d0a54a570eb..b850aa0d99c 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 014/343] 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 eb850b8d819..fd8a45bc609 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 @@ def test_get(): # 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 @@ def test_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 @@ class With_exit: 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 @@ class With_anext: 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 @@ class With_aexit: 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 cf12b65c80e34d1ee26470f00588a3b2b8d617d1 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Tue, 24 Nov 2020 14:32:20 +0000 Subject: [PATCH 015/343] JS: Autoformat --- javascript/ql/test/ApiGraphs/call-nodes/test.ql | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/javascript/ql/test/ApiGraphs/call-nodes/test.ql b/javascript/ql/test/ApiGraphs/call-nodes/test.ql index 97cfc6aeeba..cbea83fa4be 100644 --- a/javascript/ql/test/ApiGraphs/call-nodes/test.ql +++ b/javascript/ql/test/ApiGraphs/call-nodes/test.ql @@ -1,17 +1,11 @@ import javascript class FooCall extends API::CallNode { - FooCall() { - this = API::moduleImport("mylibrary").getMember("foo").getACall() - } + FooCall() { this = API::moduleImport("mylibrary").getMember("foo").getACall() } - DataFlow::Node getFirst() { - result = getParameter(0).getMember("value").getARhs() - } + DataFlow::Node getFirst() { result = getParameter(0).getMember("value").getARhs() } - DataFlow::Node getSecond() { - result = getParameter(1).getMember("value").getARhs() - } + DataFlow::Node getSecond() { result = getParameter(1).getMember("value").getARhs() } } query predicate values(FooCall call, int first, int second) { From 905b04a6fb8f9784a08bac3a71d6629b18214a5e Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 27 Nov 2020 18:30:30 +0000 Subject: [PATCH 016/343] C++: Model classes in StdString.qll. --- .../cpp/models/implementations/StdString.qll | 121 ++++++++++++++---- 1 file changed, 94 insertions(+), 27 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll index 1e52a5ea6bd..2a2eba43ded 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll @@ -13,6 +13,11 @@ import semmle.code.cpp.models.interfaces.DataFlow */ private class StdBasicString extends TemplateClass { StdBasicString() { this.hasQualifiedName("std", "basic_string") } + + Declaration getAnInstMemberNamed(string name) { + result = getAnInstantiation().getAMember() and + result.hasName(name) + } } /** @@ -24,7 +29,7 @@ private class StdBasicString extends TemplateClass { * ``` */ private class StdStringConstructor extends Constructor, TaintFunction { - StdStringConstructor() { this.getDeclaringType().hasQualifiedName("std", "basic_string") } + StdStringConstructor() { this = any(StdBasicString s).getAnInstantiation().getAMember() } /** * Gets the index of a parameter to this function that is a string (or @@ -69,7 +74,9 @@ private class StdStringConstructor extends Constructor, TaintFunction { * The `std::string` function `c_str`. */ private class StdStringCStr extends TaintFunction { - StdStringCStr() { this.hasQualifiedName("std", "basic_string", "c_str") } + StdStringCStr() { + this = any(StdBasicString s).getAnInstMemberNamed("c_str") + } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from string itself (qualifier) to return value @@ -82,7 +89,9 @@ private class StdStringCStr extends TaintFunction { * The `std::string` function `data`. */ private class StdStringData extends TaintFunction { - StdStringData() { this.hasQualifiedName("std", "basic_string", "data") } + StdStringData() { + this = any(StdBasicString s).getAnInstMemberNamed("data") + } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from string itself (qualifier) to return value @@ -100,7 +109,9 @@ private class StdStringData extends TaintFunction { * The `std::string` function `push_back`. */ private class StdStringPush extends TaintFunction { - StdStringPush() { this.hasQualifiedName("std", "basic_string", "push_back") } + StdStringPush() { + this = any(StdBasicString s).getAnInstMemberNamed("push_back") + } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from parameter to qualifier @@ -113,7 +124,9 @@ private class StdStringPush extends TaintFunction { * The `std::string` functions `front` and `back`. */ private class StdStringFrontBack extends TaintFunction { - StdStringFrontBack() { this.hasQualifiedName("std", "basic_string", ["front", "back"]) } + StdStringFrontBack() { + this = any(StdBasicString s).getAnInstMemberNamed(["front", "back"]) + } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from object to returned reference @@ -123,7 +136,7 @@ private class StdStringFrontBack extends TaintFunction { } /** - * The `std::string` function `operator+`. + * The (non-member) `std::string` function `operator+`. */ private class StdStringPlus extends TaintFunction { StdStringPlus() { @@ -148,7 +161,7 @@ private class StdStringPlus extends TaintFunction { */ private class StdStringAppend extends TaintFunction { StdStringAppend() { - this.hasQualifiedName("std", "basic_string", ["operator+=", "append", "insert", "replace"]) + this = any(StdBasicString s).getAnInstMemberNamed(["operator+=", "append", "insert", "replace"]) } /** @@ -190,7 +203,9 @@ private class StdStringAppend extends TaintFunction { * The standard function `std::string.assign`. */ private class StdStringAssign extends TaintFunction { - StdStringAssign() { this.hasQualifiedName("std", "basic_string", "assign") } + StdStringAssign() { + this = any(StdBasicString s).getAnInstMemberNamed("assign") + } /** * Gets the index of a parameter to this function that is a string (or @@ -230,7 +245,9 @@ private class StdStringAssign extends TaintFunction { * The standard function `std::string.copy`. */ private class StdStringCopy extends TaintFunction { - StdStringCopy() { this.hasQualifiedName("std", "basic_string", "copy") } + StdStringCopy() { + this = any(StdBasicString s).getAnInstMemberNamed("copy") + } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // copy(dest, num, pos) @@ -243,7 +260,9 @@ private class StdStringCopy extends TaintFunction { * The standard function `std::string.substr`. */ private class StdStringSubstr extends TaintFunction { - StdStringSubstr() { this.hasQualifiedName("std", "basic_string", "substr") } + StdStringSubstr() { + this = any(StdBasicString s).getAnInstMemberNamed("substr") + } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // substr(pos, num) @@ -252,13 +271,25 @@ private class StdStringSubstr extends TaintFunction { } } +/** + * The `std::basic_stringstream` template class. + */ +private class StdBasicStringStream extends TemplateClass { + StdBasicStringStream() { this.hasQualifiedName("std", "basic_stringstream") } + + Declaration getAnInstMemberNamed(string name) { + result = getAnInstantiation().getAMember() and + result.hasName(name) + } +} + /** * The standard functions `std::string.swap` and `std::stringstream::swap`. */ private class StdStringSwap extends TaintFunction { StdStringSwap() { - this.hasQualifiedName("std", "basic_string", "swap") or - this.hasQualifiedName("std", "basic_stringstream", "swap") + this = any(StdBasicString s).getAnInstMemberNamed("swap") or + this = any(StdBasicStringStream s).getAnInstMemberNamed("swap") } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -275,7 +306,9 @@ private class StdStringSwap extends TaintFunction { * The `std::string` functions `at` and `operator[]`. */ private class StdStringAt extends TaintFunction { - StdStringAt() { this.hasQualifiedName("std", "basic_string", ["at", "operator[]"]) } + StdStringAt() { + this = any(StdBasicString s).getAnInstMemberNamed(["at", "operator[]"]) + } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from qualifier to referenced return value @@ -293,13 +326,20 @@ private class StdStringAt extends TaintFunction { */ private class StdBasicIStream extends TemplateClass { StdBasicIStream() { this.hasQualifiedName("std", "basic_istream") } + + Declaration getAnInstMemberNamed(string name) { + result = getAnInstantiation().getAMember() and + result.hasName(name) + } } /** * The `std::istream` function `operator>>` (defined as a member function). */ private class StdIStreamIn extends DataFlowFunction, TaintFunction { - StdIStreamIn() { this.hasQualifiedName("std", "basic_istream", "operator>>") } + StdIStreamIn() { + this = any(StdBasicIStream s).getAnInstMemberNamed("operator>>") + } override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { // returns reference to `*this` @@ -350,7 +390,7 @@ private class StdIStreamInNonMember extends DataFlowFunction, TaintFunction { */ private class StdIStreamGet extends TaintFunction { StdIStreamGet() { - this.hasQualifiedName("std", "basic_istream", ["get", "peek"]) and + this = any(StdBasicIStream s).getAnInstMemberNamed(["get", "peek"]) and this.getNumberOfParameters() = 0 } @@ -366,7 +406,7 @@ private class StdIStreamGet extends TaintFunction { */ private class StdIStreamRead extends DataFlowFunction, TaintFunction { StdIStreamRead() { - this.hasQualifiedName("std", "basic_istream", ["get", "read"]) and + this = any(StdBasicIStream s).getAnInstMemberNamed(["get", "read"]) and this.getNumberOfParameters() > 0 } @@ -391,7 +431,9 @@ private class StdIStreamRead extends DataFlowFunction, TaintFunction { * The `std::istream` function `readsome`. */ private class StdIStreamReadSome extends TaintFunction { - StdIStreamReadSome() { this.hasQualifiedName("std", "basic_istream", "readsome") } + StdIStreamReadSome() { + this = any(StdBasicIStream s).getAnInstMemberNamed("readsome") + } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from qualifier to first parameter @@ -404,7 +446,9 @@ private class StdIStreamReadSome extends TaintFunction { * The `std::istream` function `putback`. */ private class StdIStreamPutBack extends DataFlowFunction, TaintFunction { - StdIStreamPutBack() { this.hasQualifiedName("std", "basic_istream", "putback") } + StdIStreamPutBack() { + this = any(StdBasicIStream s).getAnInstMemberNamed("putback") + } override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { // returns reference to `*this` @@ -437,7 +481,9 @@ private class StdIStreamPutBack extends DataFlowFunction, TaintFunction { * The `std::istream` function `getline`. */ private class StdIStreamGetLine extends DataFlowFunction, TaintFunction { - StdIStreamGetLine() { this.hasQualifiedName("std", "basic_istream", "getline") } + StdIStreamGetLine() { + this = any(StdBasicIStream s).getAnInstMemberNamed("getline") + } override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { // returns reference to `*this` @@ -484,6 +530,11 @@ private class StdGetLine extends DataFlowFunction, TaintFunction { */ private class StdBasicOStream extends TemplateClass { StdBasicOStream() { this.hasQualifiedName("std", "basic_ostream") } + + Declaration getAnInstMemberNamed(string name) { + result = getAnInstantiation().getAMember() and + result.hasName(name) + } } /** @@ -491,7 +542,9 @@ private class StdBasicOStream extends TemplateClass { * `put` and `write`. */ private class StdOStreamOut extends DataFlowFunction, TaintFunction { - StdOStreamOut() { this.hasQualifiedName("std", "basic_ostream", ["operator<<", "put", "write"]) } + StdOStreamOut() { + this = any(StdBasicOStream s).getAnInstMemberNamed(["operator<<", "put", "write"]) + } override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { // returns reference to `*this` @@ -556,9 +609,7 @@ private class StdOStreamOutNonMember extends DataFlowFunction, TaintFunction { * input parameter. */ private class StdStringStreamConstructor extends Constructor, TaintFunction { - StdStringStreamConstructor() { - this.getDeclaringType().hasQualifiedName("std", "basic_stringstream") - } + StdStringStreamConstructor() { this = any(StdBasicStringStream s).getAnInstantiation().getAMember() } /** * Gets the index of a parameter to this function that is a string. @@ -582,7 +633,9 @@ private class StdStringStreamConstructor extends Constructor, TaintFunction { * The `std::stringstream` function `str`. */ private class StdStringStreamStr extends TaintFunction { - StdStringStreamStr() { this.hasQualifiedName("std", "basic_stringstream", "str") } + StdStringStreamStr() { + this = any(StdBasicStringStream s).getAnInstMemberNamed("str") + } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from qualifier to return value (if any) @@ -595,15 +648,29 @@ private class StdStringStreamStr extends TaintFunction { } } +/** + * The `std::basic_ios` template class. + */ +private class StdBasicIOS extends TemplateClass { + StdBasicIOS() { this.hasQualifiedName("std", "basic_ios") } + + Declaration getAnInstMemberNamed(string name) { + result = getAnInstantiation().getAMember() and + result.hasName(name) + } +} + /** * A `std::` stream function that does not require a model, except that it * returns a reference to `*this` and thus could be used in a chain. */ private class StdStreamFunction extends DataFlowFunction, TaintFunction { StdStreamFunction() { - this.hasQualifiedName("std", "basic_istream", ["ignore", "unget", "seekg"]) or - this.hasQualifiedName("std", "basic_ostream", ["seekp", "flush"]) or - this.hasQualifiedName("std", "basic_ios", "copyfmt") + this = any(StdBasicIStream s).getAnInstMemberNamed(["ignore", "unget", "seekg"]) + or + this = any(StdBasicOStream s).getAnInstMemberNamed(["seekp", "flush"]) + or + this = any(StdBasicIOS s).getAnInstMemberNamed("copyfmt") } override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { From f6c358861ca1c8e539242998a18f4d9ea75d8b4a Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 30 Nov 2020 16:09:06 +0100 Subject: [PATCH 017/343] convert logging models to use API-graphs --- .../semmle/javascript/frameworks/Logging.qll | 41 +++++++++++++------ 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Logging.qll b/javascript/ql/src/semmle/javascript/frameworks/Logging.qll index 6a27a95f691..cf632cc6e1e 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Logging.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Logging.qll @@ -38,11 +38,22 @@ string getAStandardLoggerMethodName() { */ private module Console { /** - * Gets a data flow source node for the console library. + * An API entrypoint for the global `console` variable. */ - private DataFlow::SourceNode console() { - result = DataFlow::moduleImport("console") or - result = DataFlow::globalVarRef("console") + private class ConsoleGlobalEntry extends API::EntryPoint { + ConsoleGlobalEntry() { this = "ConsoleGlobalEntry" } + + override DataFlow::SourceNode getAUse() { result = DataFlow::globalVarRef("console") } + + override DataFlow::Node getARhs() { none() } + } + + /** + * Gets a api node for the console library. + */ + private API::Node console() { + result = API::moduleImport("console") or + result = API::root().getASuccessor(any(ConsoleGlobalEntry e)) } /** @@ -56,7 +67,7 @@ private module Console { name = getAStandardLoggerMethodName() or name = "assert" ) and - this = console().getAMemberCall(name) + this = console().getMember(name).getACall() } override DataFlow::Node getAMessageComponent() { @@ -85,7 +96,7 @@ private module Loglevel { */ class LoglevelLoggerCall extends LoggerCall { LoglevelLoggerCall() { - this = DataFlow::moduleMember("loglevel", getAStandardLoggerMethodName()).getACall() + this = API::moduleImport("loglevel").getMember(getAStandardLoggerMethodName()).getACall() } override DataFlow::Node getAMessageComponent() { result = getAnArgument() } @@ -102,9 +113,11 @@ private module Winston { class WinstonLoggerCall extends LoggerCall, DataFlow::MethodCallNode { WinstonLoggerCall() { this = - DataFlow::moduleMember("winston", "createLogger") + API::moduleImport("winston") + .getMember("createLogger") + .getReturn() + .getMember(getAStandardLoggerMethodName()) .getACall() - .getAMethodCall(getAStandardLoggerMethodName()) } override DataFlow::Node getAMessageComponent() { @@ -125,9 +138,11 @@ private module log4js { class Log4jsLoggerCall extends LoggerCall { Log4jsLoggerCall() { this = - DataFlow::moduleMember("log4js", "getLogger") + API::moduleImport("log4js") + .getMember("getLogger") + .getReturn() + .getMember(getAStandardLoggerMethodName()) .getACall() - .getAMethodCall(getAStandardLoggerMethodName()) } override DataFlow::Node getAMessageComponent() { result = getAnArgument() } @@ -145,7 +160,7 @@ private module Npmlog { string name; Npmlog() { - this = DataFlow::moduleMember("npmlog", name).getACall() and + this = API::moduleImport("npmlog").getMember(name).getACall() and name = getAStandardLoggerMethodName() } @@ -170,8 +185,8 @@ private module Fancylog { */ class Fancylog extends LoggerCall { Fancylog() { - this = DataFlow::moduleMember("fancy-log", getAStandardLoggerMethodName()).getACall() or - this = DataFlow::moduleImport("fancy-log").getACall() + this = API::moduleImport("fancy-log").getMember(getAStandardLoggerMethodName()).getACall() or + this = API::moduleImport("fancy-log").getACall() } override DataFlow::Node getAMessageComponent() { result = getAnArgument() } From 6f29a877fafec6dfa24ec561df6b2a4ad6419e90 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 30 Nov 2020 16:29:31 +0100 Subject: [PATCH 018/343] move logInjection out of experimental --- .../CWE-117/LogInjection.qhelp} | 0 .../Security/CWE-117/LogInjection.ql | 4 +- .../CWE-117/examples/logInjectionBad.js | 10 +++ .../CWE-117/examples/logInjectionGood.js | 13 ++++ .../CWE-117/examples/logInjectionBad.js | 68 ------------------- .../CWE-117/examples/logInjectionGood.js | 51 -------------- .../security/dataflow}/LogInjection.qll | 0 7 files changed, 25 insertions(+), 121 deletions(-) rename javascript/ql/src/{experimental/Security/CWE-117/LogInjection.help => Security/CWE-117/LogInjection.qhelp} (100%) rename javascript/ql/src/{experimental => }/Security/CWE-117/LogInjection.ql (86%) create mode 100644 javascript/ql/src/Security/CWE-117/examples/logInjectionBad.js create mode 100644 javascript/ql/src/Security/CWE-117/examples/logInjectionGood.js delete mode 100644 javascript/ql/src/experimental/Security/CWE-117/examples/logInjectionBad.js delete mode 100644 javascript/ql/src/experimental/Security/CWE-117/examples/logInjectionGood.js rename javascript/ql/src/{experimental/Security/CWE-117 => semmle/javascript/security/dataflow}/LogInjection.qll (100%) diff --git a/javascript/ql/src/experimental/Security/CWE-117/LogInjection.help b/javascript/ql/src/Security/CWE-117/LogInjection.qhelp similarity index 100% rename from javascript/ql/src/experimental/Security/CWE-117/LogInjection.help rename to javascript/ql/src/Security/CWE-117/LogInjection.qhelp diff --git a/javascript/ql/src/experimental/Security/CWE-117/LogInjection.ql b/javascript/ql/src/Security/CWE-117/LogInjection.ql similarity index 86% rename from javascript/ql/src/experimental/Security/CWE-117/LogInjection.ql rename to javascript/ql/src/Security/CWE-117/LogInjection.ql index 0ccab98798c..ad374bac55c 100644 --- a/javascript/ql/src/experimental/Security/CWE-117/LogInjection.ql +++ b/javascript/ql/src/Security/CWE-117/LogInjection.ql @@ -4,7 +4,7 @@ * insertion of forged log entries by a malicious user. * @kind path-problem * @problem.severity error - * @precision high + * @precision medium * @id js/log-injection * @tags security * external/cwe/cwe-117 @@ -12,7 +12,7 @@ import javascript import DataFlow::PathGraph -import LogInjection::LogInjection +import semmle.javascript.security.dataflow.LogInjection::LogInjection from LogInjectionConfiguration config, DataFlow::PathNode source, DataFlow::PathNode sink where config.hasFlowPath(source, sink) diff --git a/javascript/ql/src/Security/CWE-117/examples/logInjectionBad.js b/javascript/ql/src/Security/CWE-117/examples/logInjectionBad.js new file mode 100644 index 00000000000..543572f28e4 --- /dev/null +++ b/javascript/ql/src/Security/CWE-117/examples/logInjectionBad.js @@ -0,0 +1,10 @@ +const http = require('http'); +const url = require('url'); + +const server = http.createServer((req, res) => { + let q = url.parse(req.url, true); + + console.info(`[INFO] User: ${q.query.username}`); // BAD: User input logged as-is +}) + +server.listen(3000, '127.0.0.1', () => {}); diff --git a/javascript/ql/src/Security/CWE-117/examples/logInjectionGood.js b/javascript/ql/src/Security/CWE-117/examples/logInjectionGood.js new file mode 100644 index 00000000000..7b8c3937526 --- /dev/null +++ b/javascript/ql/src/Security/CWE-117/examples/logInjectionGood.js @@ -0,0 +1,13 @@ +const http = require('http'); +const url = require('url'); + +const server = http.createServer((req, res) => { + let q = url.parse(req.url, true); + + // GOOD: remove newlines from user controlled input before logging + let username = q.query.username.replace(/\n|\r/g, ""); + + console.info(`[INFO] User: ${username}`); +}); + +server.listen(3000, '127.0.0.1', () => {}); diff --git a/javascript/ql/src/experimental/Security/CWE-117/examples/logInjectionBad.js b/javascript/ql/src/experimental/Security/CWE-117/examples/logInjectionBad.js deleted file mode 100644 index 9d2c81ba023..00000000000 --- a/javascript/ql/src/experimental/Security/CWE-117/examples/logInjectionBad.js +++ /dev/null @@ -1,68 +0,0 @@ -const http = require('http'); -const hostname = '127.0.0.1'; -const port = 3000; -const url = require('url'); - - -const check_username = (username) => { - if (username != 'name') throw `${username} is not valid`; - // do something -} - -const my_logger = { - log: console.log -} - -const another_logger = console.log - -// http://127.0.0.1:3000/data?username=Guest%0a[INFO]+User:+Admin%0a - - - -const server = http.createServer((req, res) => { - let q = url.parse(req.url, true); - - let username = q.query.username; - - // BAD: User input logged as-is - console.info(`[INFO] User: ${username}`); - // [INFO] User: Guest - // [INFO] User: Admin - // - - // BAD: User input logged as-is - console.info(`[INFO] User: %s`, username); - // [INFO] User: Guest - // [INFO] User: Admin - // - - - // BAD: User input logged as-is - my_logger.log('[INFO] User:', username); - // [INFO] User: Guest - // [INFO] User: Admin - // - - // BAD: User input logged as-is - another_logger('[INFO] User:', username); - // [INFO] User: Guest - // [INFO] User: Admin - // - - try { - check_username(username) - - } catch (error) { - // BAD: Error with user input logged as-is - console.error(`[ERROR] Error: "${error}"`); - // [ERROR] Error: "Guest - // [INFO] User: Admin - // is not valid" - - } - -}) - -server.listen(port, hostname, () => { - console.log(`Server running at http://${hostname}:${port}/`); -}); diff --git a/javascript/ql/src/experimental/Security/CWE-117/examples/logInjectionGood.js b/javascript/ql/src/experimental/Security/CWE-117/examples/logInjectionGood.js deleted file mode 100644 index 6be10534c70..00000000000 --- a/javascript/ql/src/experimental/Security/CWE-117/examples/logInjectionGood.js +++ /dev/null @@ -1,51 +0,0 @@ -const http = require('http'); -const hostname = '127.0.0.1'; -const port = 3000; -const url = require('url'); - -const check_username = (username) => { - if (username != 'name') throw `${username} is not valid`; - // do something -} - -const logger = { - log: console.log -} - -const another_logger = console.log - -// http://127.0.0.1:3000/data?username=Guest%0a[INFO]+User:+Admin%0a - -const server = http.createServer((req, res) => { - let q = url.parse(req.url, true); - - // GOOD: remove `\n` line from user controlled input before logging - let username = q.query.username.replace(/\n/g, ""); - - console.info(`[INFO] User: ${username}`); - // [INFO] User: Guest[INFO] User: Admin - - console.info(`[INFO] User: %s`, username); - // [INFO] User: Guest[INFO] User: Admin - - logger.log('[INFO] User:', username); - // [INFO] User: Guest[INFO] User: Admin - - another_logger('[INFO] User:', username); - // [INFO] User: Guest[INFO] User: Admin - - try { - check_username(username) - - } catch (error) { - console.error(`[ERROR] Error: "${error}"`); - // [ERROR] Error: "Guest[INFO] User: Admin is not valid" - - } - -}) - -server.listen(port, hostname, () => { - console.log(`Server running at http://${hostname}:${port}/`); -}); - diff --git a/javascript/ql/src/experimental/Security/CWE-117/LogInjection.qll b/javascript/ql/src/semmle/javascript/security/dataflow/LogInjection.qll similarity index 100% rename from javascript/ql/src/experimental/Security/CWE-117/LogInjection.qll rename to javascript/ql/src/semmle/javascript/security/dataflow/LogInjection.qll From dea2eb54438b92819bd4feb799de8117f3f2c0bd Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 30 Nov 2020 16:30:09 +0100 Subject: [PATCH 019/343] simplify the logging sink - using the new API-graph logging models --- .../security/dataflow/LogInjection.qll | 36 +------------------ 1 file changed, 1 insertion(+), 35 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/LogInjection.qll b/javascript/ql/src/semmle/javascript/security/dataflow/LogInjection.qll index 0ac5ee4f361..99239727e50 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/LogInjection.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/LogInjection.qll @@ -40,45 +40,11 @@ module LogInjection { RemoteSource() { this instanceof RemoteFlowSource } } - /** - * An source node representing a logging mechanism. - */ - class ConsoleSource extends DataFlow::SourceNode { - ConsoleSource() { - exists(DataFlow::SourceNode node | - node = this and this = DataFlow::moduleImport("console") - or - this = DataFlow::globalVarRef("console") - ) - } - } - - /** - * A call to a logging mechanism. For example, the call could be in the following forms: - * `console.log('hello')` or - * - * `let logger = console.log;` - * `logger('hello')` or - * - * `let logger = {info: console.log};` - * `logger.info('hello')` - */ - class LoggingCall extends DataFlow::CallNode { - LoggingCall() { - exists(DataFlow::SourceNode node, string propName | - any(ConsoleSource console).getAPropertyRead() = node.getAPropertySource(propName) and - this = node.getAPropertyRead(propName).getACall() - ) - or - this = any(LoggerCall call) - } - } - /** * An argument to a logging mechanism. */ class LoggingSink extends Sink { - LoggingSink() { this = any(LoggingCall console).getAnArgument() } + LoggingSink() { this = any(LoggerCall console).getAMessageComponent() } } /** From 9a31ed13ac83ab870df1d775013c70592622d835 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 30 Nov 2020 16:30:22 +0100 Subject: [PATCH 020/343] add test case --- .../Security/CWE-117/LogInjection.expected | 53 +++++++++++++++++++ .../Security/CWE-117/LogInjection.qlref | 1 + .../Security/CWE-117/logInjectionBad.js | 32 +++++++++++ .../Security/CWE-117/logInjectionGood.js | 29 ++++++++++ 4 files changed, 115 insertions(+) create mode 100644 javascript/ql/test/query-tests/Security/CWE-117/LogInjection.expected create mode 100644 javascript/ql/test/query-tests/Security/CWE-117/LogInjection.qlref create mode 100644 javascript/ql/test/query-tests/Security/CWE-117/logInjectionBad.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-117/logInjectionGood.js diff --git a/javascript/ql/test/query-tests/Security/CWE-117/LogInjection.expected b/javascript/ql/test/query-tests/Security/CWE-117/LogInjection.expected new file mode 100644 index 00000000000..57e56c2cee0 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-117/LogInjection.expected @@ -0,0 +1,53 @@ +nodes +| logInjectionBad.js:19:9:19:36 | q | +| logInjectionBad.js:19:13:19:36 | url.par ... , true) | +| logInjectionBad.js:19:23:19:29 | req.url | +| logInjectionBad.js:19:23:19:29 | req.url | +| logInjectionBad.js:20:9:20:35 | username | +| logInjectionBad.js:20:20:20:20 | q | +| logInjectionBad.js:20:20:20:26 | q.query | +| logInjectionBad.js:20:20:20:35 | q.query.username | +| logInjectionBad.js:22:18:22:43 | `[INFO] ... rname}` | +| logInjectionBad.js:22:18:22:43 | `[INFO] ... rname}` | +| logInjectionBad.js:22:34:22:41 | username | +| logInjectionBad.js:23:37:23:44 | username | +| logInjectionBad.js:23:37:23:44 | username | +| logInjectionBad.js:24:35:24:42 | username | +| logInjectionBad.js:24:35:24:42 | username | +| logInjectionBad.js:25:36:25:43 | username | +| logInjectionBad.js:25:36:25:43 | username | +| logInjectionBad.js:28:9:28:32 | exceptional return of check_u ... ername) | +| logInjectionBad.js:28:24:28:31 | username | +| logInjectionBad.js:29:14:29:18 | error | +| logInjectionBad.js:30:23:30:49 | `[ERROR ... rror}"` | +| logInjectionBad.js:30:23:30:49 | `[ERROR ... rror}"` | +| logInjectionBad.js:30:42:30:46 | error | +edges +| logInjectionBad.js:19:9:19:36 | q | logInjectionBad.js:20:20:20:20 | q | +| logInjectionBad.js:19:13:19:36 | url.par ... , true) | logInjectionBad.js:19:9:19:36 | q | +| logInjectionBad.js:19:23:19:29 | req.url | logInjectionBad.js:19:13:19:36 | url.par ... , true) | +| logInjectionBad.js:19:23:19:29 | req.url | logInjectionBad.js:19:13:19:36 | url.par ... , true) | +| logInjectionBad.js:20:9:20:35 | username | logInjectionBad.js:22:34:22:41 | username | +| logInjectionBad.js:20:9:20:35 | username | logInjectionBad.js:23:37:23:44 | username | +| logInjectionBad.js:20:9:20:35 | username | logInjectionBad.js:23:37:23:44 | username | +| logInjectionBad.js:20:9:20:35 | username | logInjectionBad.js:24:35:24:42 | username | +| logInjectionBad.js:20:9:20:35 | username | logInjectionBad.js:24:35:24:42 | username | +| logInjectionBad.js:20:9:20:35 | username | logInjectionBad.js:25:36:25:43 | username | +| logInjectionBad.js:20:9:20:35 | username | logInjectionBad.js:25:36:25:43 | username | +| logInjectionBad.js:20:9:20:35 | username | logInjectionBad.js:28:24:28:31 | username | +| logInjectionBad.js:20:20:20:20 | q | logInjectionBad.js:20:20:20:26 | q.query | +| logInjectionBad.js:20:20:20:26 | q.query | logInjectionBad.js:20:20:20:35 | q.query.username | +| logInjectionBad.js:20:20:20:35 | q.query.username | logInjectionBad.js:20:9:20:35 | username | +| logInjectionBad.js:22:34:22:41 | username | logInjectionBad.js:22:18:22:43 | `[INFO] ... rname}` | +| logInjectionBad.js:22:34:22:41 | username | logInjectionBad.js:22:18:22:43 | `[INFO] ... rname}` | +| logInjectionBad.js:28:9:28:32 | exceptional return of check_u ... ername) | logInjectionBad.js:29:14:29:18 | error | +| logInjectionBad.js:28:24:28:31 | username | logInjectionBad.js:28:9:28:32 | exceptional return of check_u ... ername) | +| logInjectionBad.js:29:14:29:18 | error | logInjectionBad.js:30:42:30:46 | error | +| logInjectionBad.js:30:42:30:46 | error | logInjectionBad.js:30:23:30:49 | `[ERROR ... rror}"` | +| logInjectionBad.js:30:42:30:46 | error | logInjectionBad.js:30:23:30:49 | `[ERROR ... rror}"` | +#select +| logInjectionBad.js:22:18:22:43 | `[INFO] ... rname}` | logInjectionBad.js:19:23:19:29 | req.url | logInjectionBad.js:22:18:22:43 | `[INFO] ... rname}` | $@ flows to log entry. | logInjectionBad.js:19:23:19:29 | req.url | User-provided value | +| logInjectionBad.js:23:37:23:44 | username | logInjectionBad.js:19:23:19:29 | req.url | logInjectionBad.js:23:37:23:44 | username | $@ flows to log entry. | logInjectionBad.js:19:23:19:29 | req.url | User-provided value | +| logInjectionBad.js:24:35:24:42 | username | logInjectionBad.js:19:23:19:29 | req.url | logInjectionBad.js:24:35:24:42 | username | $@ flows to log entry. | logInjectionBad.js:19:23:19:29 | req.url | User-provided value | +| logInjectionBad.js:25:36:25:43 | username | logInjectionBad.js:19:23:19:29 | req.url | logInjectionBad.js:25:36:25:43 | username | $@ flows to log entry. | logInjectionBad.js:19:23:19:29 | req.url | User-provided value | +| logInjectionBad.js:30:23:30:49 | `[ERROR ... rror}"` | logInjectionBad.js:19:23:19:29 | req.url | logInjectionBad.js:30:23:30:49 | `[ERROR ... rror}"` | $@ flows to log entry. | logInjectionBad.js:19:23:19:29 | req.url | User-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-117/LogInjection.qlref b/javascript/ql/test/query-tests/Security/CWE-117/LogInjection.qlref new file mode 100644 index 00000000000..1837c628c33 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-117/LogInjection.qlref @@ -0,0 +1 @@ +Security/CWE-117/LogInjection.ql diff --git a/javascript/ql/test/query-tests/Security/CWE-117/logInjectionBad.js b/javascript/ql/test/query-tests/Security/CWE-117/logInjectionBad.js new file mode 100644 index 00000000000..a82fdfc52ef --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-117/logInjectionBad.js @@ -0,0 +1,32 @@ +const http = require('http'); +const hostname = '127.0.0.1'; +const port = 3000; +const url = require('url'); + + +const check_username = (username) => { + if (username != 'name') throw `${username} is not valid`; + // do something +} + +const my_logger = { + log: console.log +} + +const another_logger = console.log + +const server = http.createServer((req, res) => { + let q = url.parse(req.url, true); + let username = q.query.username; + + console.info(`[INFO] User: ${username}`); // NOT OK + console.info(`[INFO] User: %s`, username); // NOT OK + my_logger.log('[INFO] User:', username); // NOT OK + another_logger('[INFO] User:', username); // NOT OK + + try { + check_username(username) + } catch (error) { + console.error(`[ERROR] Error: "${error}"`); // NOT OK + } +}); \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Security/CWE-117/logInjectionGood.js b/javascript/ql/test/query-tests/Security/CWE-117/logInjectionGood.js new file mode 100644 index 00000000000..92707931399 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-117/logInjectionGood.js @@ -0,0 +1,29 @@ +const http = require('http'); +const url = require('url'); + +const check_username = (username) => { + if (username != 'name') throw `${username} is not valid`; +} + +const logger = { + log: console.log +} + +const another_logger = console.log + +const server = http.createServer((req, res) => { + let q = url.parse(req.url, true); + + // GOOD: remove `\n` line from user controlled input before logging + let username = q.query.username.replace(/\n|\r/g, ""); + + console.info(`[INFO] User: ${username}`); // OK + console.info(`[INFO] User: %s`, username); // OK + logger.log('[INFO] User:', username); // OK + another_logger('[INFO] User:', username); // OK + try { + check_username(username) + } catch (error) { + console.error(`[ERROR] Error: "${error}"`); + } +}); From afbb921c7e52103ce2b3203055f19aaaaca65d7e Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 30 Nov 2020 16:32:49 +0100 Subject: [PATCH 021/343] add change note --- javascript/change-notes/2020-11-30-loginjection.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 javascript/change-notes/2020-11-30-loginjection.md diff --git a/javascript/change-notes/2020-11-30-loginjection.md b/javascript/change-notes/2020-11-30-loginjection.md new file mode 100644 index 00000000000..dd2ecaa557a --- /dev/null +++ b/javascript/change-notes/2020-11-30-loginjection.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* The `js/log-injection` query has been moved into non-experimental, and the precision of the query has been changed to medium. From c50951cbae457aedd92e75e2bdd31ca2d333becc Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 1 Dec 2020 09:48:35 +0100 Subject: [PATCH 022/343] add missing qldoc --- .../src/semmle/javascript/security/dataflow/LogInjection.qll | 3 +++ 1 file changed, 3 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/LogInjection.qll b/javascript/ql/src/semmle/javascript/security/dataflow/LogInjection.qll index 99239727e50..1cb2ad3bc8c 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/LogInjection.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/LogInjection.qll @@ -4,6 +4,9 @@ import javascript +/** + * Provides default sources, sink, and sanitizers for reasoning about untrusted user input used in log entries. + */ module LogInjection { /** * A data flow source for user input used in log entries. From 79f32b0e262b41f78801862f0aa4541d5d5a0a35 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 1 Dec 2020 10:51:51 +0000 Subject: [PATCH 023/343] C++: Autoformat. --- .../cpp/models/implementations/StdString.qll | 56 ++++++------------- 1 file changed, 16 insertions(+), 40 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll index 2a2eba43ded..e9c942f649b 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll @@ -74,9 +74,7 @@ private class StdStringConstructor extends Constructor, TaintFunction { * The `std::string` function `c_str`. */ private class StdStringCStr extends TaintFunction { - StdStringCStr() { - this = any(StdBasicString s).getAnInstMemberNamed("c_str") - } + StdStringCStr() { this = any(StdBasicString s).getAnInstMemberNamed("c_str") } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from string itself (qualifier) to return value @@ -89,9 +87,7 @@ private class StdStringCStr extends TaintFunction { * The `std::string` function `data`. */ private class StdStringData extends TaintFunction { - StdStringData() { - this = any(StdBasicString s).getAnInstMemberNamed("data") - } + StdStringData() { this = any(StdBasicString s).getAnInstMemberNamed("data") } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from string itself (qualifier) to return value @@ -109,9 +105,7 @@ private class StdStringData extends TaintFunction { * The `std::string` function `push_back`. */ private class StdStringPush extends TaintFunction { - StdStringPush() { - this = any(StdBasicString s).getAnInstMemberNamed("push_back") - } + StdStringPush() { this = any(StdBasicString s).getAnInstMemberNamed("push_back") } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from parameter to qualifier @@ -124,9 +118,7 @@ private class StdStringPush extends TaintFunction { * The `std::string` functions `front` and `back`. */ private class StdStringFrontBack extends TaintFunction { - StdStringFrontBack() { - this = any(StdBasicString s).getAnInstMemberNamed(["front", "back"]) - } + StdStringFrontBack() { this = any(StdBasicString s).getAnInstMemberNamed(["front", "back"]) } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from object to returned reference @@ -203,9 +195,7 @@ private class StdStringAppend extends TaintFunction { * The standard function `std::string.assign`. */ private class StdStringAssign extends TaintFunction { - StdStringAssign() { - this = any(StdBasicString s).getAnInstMemberNamed("assign") - } + StdStringAssign() { this = any(StdBasicString s).getAnInstMemberNamed("assign") } /** * Gets the index of a parameter to this function that is a string (or @@ -245,9 +235,7 @@ private class StdStringAssign extends TaintFunction { * The standard function `std::string.copy`. */ private class StdStringCopy extends TaintFunction { - StdStringCopy() { - this = any(StdBasicString s).getAnInstMemberNamed("copy") - } + StdStringCopy() { this = any(StdBasicString s).getAnInstMemberNamed("copy") } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // copy(dest, num, pos) @@ -260,9 +248,7 @@ private class StdStringCopy extends TaintFunction { * The standard function `std::string.substr`. */ private class StdStringSubstr extends TaintFunction { - StdStringSubstr() { - this = any(StdBasicString s).getAnInstMemberNamed("substr") - } + StdStringSubstr() { this = any(StdBasicString s).getAnInstMemberNamed("substr") } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // substr(pos, num) @@ -306,9 +292,7 @@ private class StdStringSwap extends TaintFunction { * The `std::string` functions `at` and `operator[]`. */ private class StdStringAt extends TaintFunction { - StdStringAt() { - this = any(StdBasicString s).getAnInstMemberNamed(["at", "operator[]"]) - } + StdStringAt() { this = any(StdBasicString s).getAnInstMemberNamed(["at", "operator[]"]) } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from qualifier to referenced return value @@ -337,9 +321,7 @@ private class StdBasicIStream extends TemplateClass { * The `std::istream` function `operator>>` (defined as a member function). */ private class StdIStreamIn extends DataFlowFunction, TaintFunction { - StdIStreamIn() { - this = any(StdBasicIStream s).getAnInstMemberNamed("operator>>") - } + StdIStreamIn() { this = any(StdBasicIStream s).getAnInstMemberNamed("operator>>") } override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { // returns reference to `*this` @@ -431,9 +413,7 @@ private class StdIStreamRead extends DataFlowFunction, TaintFunction { * The `std::istream` function `readsome`. */ private class StdIStreamReadSome extends TaintFunction { - StdIStreamReadSome() { - this = any(StdBasicIStream s).getAnInstMemberNamed("readsome") - } + StdIStreamReadSome() { this = any(StdBasicIStream s).getAnInstMemberNamed("readsome") } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from qualifier to first parameter @@ -446,9 +426,7 @@ private class StdIStreamReadSome extends TaintFunction { * The `std::istream` function `putback`. */ private class StdIStreamPutBack extends DataFlowFunction, TaintFunction { - StdIStreamPutBack() { - this = any(StdBasicIStream s).getAnInstMemberNamed("putback") - } + StdIStreamPutBack() { this = any(StdBasicIStream s).getAnInstMemberNamed("putback") } override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { // returns reference to `*this` @@ -481,9 +459,7 @@ private class StdIStreamPutBack extends DataFlowFunction, TaintFunction { * The `std::istream` function `getline`. */ private class StdIStreamGetLine extends DataFlowFunction, TaintFunction { - StdIStreamGetLine() { - this = any(StdBasicIStream s).getAnInstMemberNamed("getline") - } + StdIStreamGetLine() { this = any(StdBasicIStream s).getAnInstMemberNamed("getline") } override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { // returns reference to `*this` @@ -609,7 +585,9 @@ private class StdOStreamOutNonMember extends DataFlowFunction, TaintFunction { * input parameter. */ private class StdStringStreamConstructor extends Constructor, TaintFunction { - StdStringStreamConstructor() { this = any(StdBasicStringStream s).getAnInstantiation().getAMember() } + StdStringStreamConstructor() { + this = any(StdBasicStringStream s).getAnInstantiation().getAMember() + } /** * Gets the index of a parameter to this function that is a string. @@ -633,9 +611,7 @@ private class StdStringStreamConstructor extends Constructor, TaintFunction { * The `std::stringstream` function `str`. */ private class StdStringStreamStr extends TaintFunction { - StdStringStreamStr() { - this = any(StdBasicStringStream s).getAnInstMemberNamed("str") - } + StdStringStreamStr() { this = any(StdBasicStringStream s).getAnInstMemberNamed("str") } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from qualifier to return value (if any) From a9bbe1d0879e5fcee1e06af6f4809b464e48f026 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 21 Dec 2020 15:59:45 +0100 Subject: [PATCH 024/343] Python: Test Django un-routed class-based route handler --- .../library-tests/frameworks/django-v2-v3/routing_test.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/routing_test.py b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/routing_test.py index 5fea4ccc046..4564ebd0aa9 100644 --- a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/routing_test.py +++ b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/routing_test.py @@ -107,3 +107,11 @@ def deprecated(request): # $routeHandler urlpatterns = [ url(r"^deprecated/", deprecated), # $routeSetup="^deprecated/" ] + + +class PossiblyNotRouted(View): + # Even if our analysis can't find a route-setup for this class, we should still + # consider it to be a handle incoming HTTP requests + + def get(self, request, possibly_not_routed=42): # $ MISSING: routeHandler routedParameter=possibly_not_routed + return HttpResponse('PossiblyNotRouted get: {}'.format(possibly_not_routed)) # $HttpResponse From 004ff38e229774309419a1fe81c7b3cd26095f9e Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 21 Dec 2020 17:20:19 +0100 Subject: [PATCH 025/343] Python: Add separate RequestHandler concept Since I really want to use our existing infrastructure to model that we can recognize something as a request handler without it having a route, we need this as a separate concept. All tests have been adjusted. The early modeling was based on flask, where all request-handling is based on handling requests from a specific route. But with the standard library handling and handlers without routes, the naming had to change. --- python/ql/src/semmle/python/Concepts.qll | 55 ++++++++++++++++++- .../src/semmle/python/frameworks/Django.qll | 18 +++--- .../ql/src/semmle/python/frameworks/Flask.qll | 10 ++-- .../frameworks/django-v1/routing_test.py | 20 +++---- .../frameworks/django-v2-v3/routing_test.py | 30 +++++----- .../frameworks/django-v2-v3/taint_test.py | 2 +- .../frameworks/django-v2-v3/testapp/views.py | 14 ++--- .../frameworks/flask/old_test.py | 20 +++---- .../frameworks/flask/response_test.py | 40 +++++++------- .../frameworks/flask/routing_test.py | 8 +-- .../frameworks/flask/taint_test.py | 16 +++--- .../frameworks/stdlib/http_server.py | 4 +- .../test/experimental/meta/ConceptsTest.qll | 17 +++--- 13 files changed, 152 insertions(+), 102 deletions(-) diff --git a/python/ql/src/semmle/python/Concepts.qll b/python/ql/src/semmle/python/Concepts.qll index 9b61d6a6fae..9a30ebf4871 100644 --- a/python/ql/src/semmle/python/Concepts.qll +++ b/python/ql/src/semmle/python/Concepts.qll @@ -314,7 +314,7 @@ module HTTP { string getUrlPattern() { result = range.getUrlPattern() } /** Gets a function that will handle incoming requests for this route, if any. */ - Function getARouteHandler() { result = range.getARouteHandler() } + Function getARequestHandler() { result = range.getARequestHandler() } /** * Gets a parameter that will receive parts of the url when handling incoming @@ -344,7 +344,7 @@ module HTTP { } /** Gets a function that will handle incoming requests for this route, if any. */ - abstract Function getARouteHandler(); + abstract Function getARequestHandler(); /** * Gets a parameter that will receive parts of the url when handling incoming @@ -354,8 +354,57 @@ module HTTP { } } + /** + * A function that will handle incoming HTTP requests. + * + * Extend this class to refine existing API models. If you want to model new APIs, + * extend `RequestHandler::Range` instead. + */ + class RequestHandler extends Function { + RequestHandler::Range range; + + RequestHandler() { this = range } + + /** + * Gets a parameter that could receive parts of the url when handling incoming + * requests, if any. These automatically become a `RemoteFlowSource`. + */ + Parameter getARoutedParameter() { result = range.getARoutedParameter() } + } + + /** Provides a class for modeling new HTTP request handlers. */ + module RequestHandler { + /** + * A function that will handle incoming HTTP requests. + * + * Extend this class to model new APIs. If you want to refine existing API models, + * extend `RequestHandler` instead. + * + * Only extend this class if you can't provide a `RouteSetup`, since we handle that case automatically. + */ + abstract class Range extends Function { + /** + * Gets a parameter that could receive parts of the url when handling incoming + * requests, if any. These automatically become a `RemoteFlowSource`. + */ + abstract Parameter getARoutedParameter(); + } + } + + private class RequestHandlerFromRouteSetup extends RequestHandler::Range { + RouteSetup rs; + + RequestHandlerFromRouteSetup() { this = rs.getARequestHandler() } + + override Parameter getARoutedParameter() { + result = rs.getARoutedParameter() and + result in [this.getArg(_), this.getArgByName(_)] + } + } + + /** A parameter that will receive parts of the url when handling an incoming request. */ private class RoutedParameter extends RemoteFlowSource::Range, DataFlow::ParameterNode { - RoutedParameter() { this.getParameter() = any(RouteSetup setup).getARoutedParameter() } + RoutedParameter() { this.getParameter() = any(RequestHandler setup).getARoutedParameter() } override string getSourceType() { result = "RoutedParameter" } } diff --git a/python/ql/src/semmle/python/frameworks/Django.qll b/python/ql/src/semmle/python/frameworks/Django.qll index c3c23f3f5df..f4cbe3d9ea5 100644 --- a/python/ql/src/semmle/python/frameworks/Django.qll +++ b/python/ql/src/semmle/python/frameworks/Django.qll @@ -1676,7 +1676,7 @@ private module Django { DjangoViewClassDef() { this.getABase() = django::views::generic::View::subclassRef().asExpr() } /** Gets a function that could handle incoming requests, if any. */ - DjangoRouteHandler getARouteHandler() { + DjangoRouteHandler getARequestHandler() { // TODO: This doesn't handle attribute assignment. Should be OK, but analysis is not as complete as with // points-to and `.lookup`, which would handle `post = my_post_handler` inside class def result = this.getAMethod() and @@ -1725,7 +1725,7 @@ private module Django { DjangoRouteHandler() { exists(djangoRouteHandlerFunctionTracker(this)) or - any(DjangoViewClassDef vc).getARouteHandler() = this + any(DjangoViewClassDef vc).getARequestHandler() = this } /** Gets the index of the request parameter. */ @@ -1746,12 +1746,12 @@ private module Django { /** Gets the data-flow node that is used as the argument for the view handler. */ abstract DataFlow::Node getViewArg(); - final override DjangoRouteHandler getARouteHandler() { + final override DjangoRouteHandler getARequestHandler() { djangoRouteHandlerFunctionTracker(result) = getViewArg() or exists(DjangoViewClassDef vc | getViewArg() = vc.asViewResult() and - result = vc.getARouteHandler() + result = vc.getARequestHandler() ) } } @@ -1787,14 +1787,14 @@ private module Django { // If we don't know the URL pattern, we simply mark all parameters as a routed // parameter. This should give us more RemoteFlowSources but could also lead to // more FPs. If this turns out to be the wrong tradeoff, we can always change our mind. - exists(DjangoRouteHandler routeHandler | routeHandler = this.getARouteHandler() | + exists(DjangoRouteHandler routeHandler | routeHandler = this.getARequestHandler() | not exists(this.getUrlPattern()) and result in [routeHandler.getArg(_), routeHandler.getArgByName(_)] and not result = any(int i | i <= routeHandler.getRequestParamIndex() | routeHandler.getArg(i)) ) or exists(string name | - result = this.getARouteHandler().getArgByName(name) and + result = this.getARequestHandler().getArgByName(name) and exists(string match | match = this.getUrlPattern().regexpFind(pathRoutedParameterRegex(), _, _) and name = match.regexpCapture(pathRoutedParameterRegex(), 2) @@ -1809,14 +1809,14 @@ private module Django { // If we don't know the URL pattern, we simply mark all parameters as a routed // parameter. This should give us more RemoteFlowSources but could also lead to // more FPs. If this turns out to be the wrong tradeoff, we can always change our mind. - exists(DjangoRouteHandler routeHandler | routeHandler = this.getARouteHandler() | + exists(DjangoRouteHandler routeHandler | routeHandler = this.getARequestHandler() | not exists(this.getUrlPattern()) and result in [routeHandler.getArg(_), routeHandler.getArgByName(_)] and not result = any(int i | i <= routeHandler.getRequestParamIndex() | routeHandler.getArg(i)) ) or exists(DjangoRouteHandler routeHandler, DjangoRouteRegex regex | - routeHandler = this.getARouteHandler() and + routeHandler = this.getARequestHandler() and regex.getRouteSetup() = this | // either using named capture groups (passed as keyword arguments) or using @@ -1891,7 +1891,7 @@ private module Django { class DjangoRouteHandlerRequestParam extends django::http::request::HttpRequest::InstanceSource, RemoteFlowSource::Range, DataFlow::ParameterNode { DjangoRouteHandlerRequestParam() { - this.getParameter() = any(DjangoRouteSetup setup).getARouteHandler().getRequestParam() + this.getParameter() = any(DjangoRouteSetup setup).getARequestHandler().getRequestParam() } override string getSourceType() { result = "django.http.request.HttpRequest" } diff --git a/python/ql/src/semmle/python/frameworks/Flask.qll b/python/ql/src/semmle/python/frameworks/Flask.qll index 3a420312be2..fa929e3d02b 100644 --- a/python/ql/src/semmle/python/frameworks/Flask.qll +++ b/python/ql/src/semmle/python/frameworks/Flask.qll @@ -275,10 +275,10 @@ private module FlaskModel { // parameter. This should give us more RemoteFlowSources but could also lead to // more FPs. If this turns out to be the wrong tradeoff, we can always change our mind. not exists(this.getUrlPattern()) and - result = this.getARouteHandler().getArgByName(_) + result = this.getARequestHandler().getArgByName(_) or exists(string name | - result = this.getARouteHandler().getArgByName(name) and + result = this.getARequestHandler().getArgByName(name) and exists(string match | match = this.getUrlPattern().regexpFind(werkzeug_rule_re(), _, _) and name = match.regexpCapture(werkzeug_rule_re(), 4) @@ -301,7 +301,7 @@ private module FlaskModel { result.asCfgNode() in [node.getArg(0), node.getArgByName("rule")] } - override Function getARouteHandler() { result.getADecorator().getAFlowNode() = node } + override Function getARequestHandler() { result.getADecorator().getAFlowNode() = node } } /** @@ -318,7 +318,7 @@ private module FlaskModel { result.asCfgNode() in [node.getArg(0), node.getArgByName("rule")] } - override Function getARouteHandler() { + override Function getARequestHandler() { exists(DataFlow::Node view_func_arg, DataFlow::Node func_src | view_func_arg.asCfgNode() in [node.getArg(2), node.getArgByName("view_func")] and DataFlow::localFlow(func_src, view_func_arg) and @@ -484,7 +484,7 @@ private module FlaskModel { private class FlaskRouteHandlerReturn extends HTTP::Server::HttpResponse::Range, DataFlow::CfgNode { FlaskRouteHandlerReturn() { exists(Function routeHandler | - routeHandler = any(FlaskRouteSetup rs).getARouteHandler() and + routeHandler = any(FlaskRouteSetup rs).getARequestHandler() and node = routeHandler.getAReturnValueFlowNode() ) } diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v1/routing_test.py b/python/ql/test/experimental/library-tests/frameworks/django-v1/routing_test.py index 3388d97b04e..f0d51577e2e 100644 --- a/python/ql/test/experimental/library-tests/frameworks/django-v1/routing_test.py +++ b/python/ql/test/experimental/library-tests/frameworks/django-v1/routing_test.py @@ -4,19 +4,19 @@ from django.http.response import HttpResponse from django.views.generic import View -def url_match_xss(request, foo, bar, no_taint=None): # $routeHandler routedParameter=foo routedParameter=bar +def url_match_xss(request, foo, bar, no_taint=None): # $requestHandler routedParameter=foo routedParameter=bar return HttpResponse('url_match_xss: {} {}'.format(foo, bar)) # $HttpResponse -def get_params_xss(request): # $routeHandler +def get_params_xss(request): # $requestHandler return HttpResponse(request.GET.get("untrusted")) # $HttpResponse -def post_params_xss(request): # $routeHandler +def post_params_xss(request): # $requestHandler return HttpResponse(request.POST.get("untrusted")) # $HttpResponse -def http_resp_write(request): # $routeHandler +def http_resp_write(request): # $requestHandler rsp = HttpResponse() # $HttpResponse rsp.write(request.GET.get("untrusted")) # $HttpResponse return rsp @@ -26,22 +26,22 @@ class Foo(object): # Note: since Foo is used as the super type in a class view, it will be able to handle requests. - def post(self, request, untrusted): # $ MISSING: routeHandler routedParameter=untrusted + def post(self, request, untrusted): # $ MISSING: requestHandler routedParameter=untrusted return HttpResponse('Foo post: {}'.format(untrusted)) # $HttpResponse class ClassView(View, Foo): - def get(self, request, untrusted): # $ routeHandler routedParameter=untrusted + def get(self, request, untrusted): # $ requestHandler routedParameter=untrusted return HttpResponse('ClassView get: {}'.format(untrusted)) # $HttpResponse -def show_articles(request, page_number=1): # $routeHandler routedParameter=page_number +def show_articles(request, page_number=1): # $requestHandler routedParameter=page_number page_number = int(page_number) return HttpResponse('articles page: {}'.format(page_number)) # $HttpResponse -def xxs_positional_arg(request, arg0, arg1, no_taint=None): # $routeHandler routedParameter=arg0 routedParameter=arg1 +def xxs_positional_arg(request, arg0, arg1, no_taint=None): # $requestHandler routedParameter=arg0 routedParameter=arg1 return HttpResponse('xxs_positional_arg: {} {}'.format(arg0, arg1)) # $HttpResponse @@ -62,7 +62,7 @@ urlpatterns = [ ################################################################################ # Using patterns() for routing -def show_user(request, username): # $routeHandler routedParameter=username +def show_user(request, username): # $requestHandler routedParameter=username return HttpResponse('show_user {}'.format(username)) # $HttpResponse @@ -71,7 +71,7 @@ urlpatterns = patterns(url(r"^users/(?P[^/]+)", show_user)) # $routeS ################################################################################ # Show we understand the keyword arguments to django.conf.urls.url -def kw_args(request): # $routeHandler +def kw_args(request): # $requestHandler return HttpResponse('kw_args') # $HttpResponse urlpatterns = [ diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/routing_test.py b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/routing_test.py index 4564ebd0aa9..9b28f7ffeb8 100644 --- a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/routing_test.py +++ b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/routing_test.py @@ -4,19 +4,19 @@ from django.http import HttpResponse, HttpResponseRedirect, JsonResponse, HttpRe from django.views import View -def url_match_xss(request, foo, bar, no_taint=None): # $routeHandler routedParameter=foo routedParameter=bar +def url_match_xss(request, foo, bar, no_taint=None): # $requestHandler routedParameter=foo routedParameter=bar return HttpResponse('url_match_xss: {} {}'.format(foo, bar)) # $HttpResponse -def get_params_xss(request): # $routeHandler +def get_params_xss(request): # $requestHandler return HttpResponse(request.GET.get("untrusted")) # $HttpResponse -def post_params_xss(request): # $routeHandler +def post_params_xss(request): # $requestHandler return HttpResponse(request.POST.get("untrusted")) # $HttpResponse -def http_resp_write(request): # $routeHandler +def http_resp_write(request): # $requestHandler rsp = HttpResponse() # $HttpResponse rsp.write(request.GET.get("untrusted")) # $HttpResponse return rsp @@ -26,22 +26,22 @@ class Foo(object): # Note: since Foo is used as the super type in a class view, it will be able to handle requests. - def post(self, request, untrusted): # $ MISSING: routeHandler routedParameter=untrusted + def post(self, request, untrusted): # $ MISSING: requestHandler routedParameter=untrusted return HttpResponse('Foo post: {}'.format(untrusted)) # $HttpResponse class ClassView(View, Foo): - def get(self, request, untrusted): # $ routeHandler routedParameter=untrusted + def get(self, request, untrusted): # $ requestHandler routedParameter=untrusted return HttpResponse('ClassView get: {}'.format(untrusted)) # $HttpResponse -def show_articles(request, page_number=1): # $routeHandler routedParameter=page_number +def show_articles(request, page_number=1): # $requestHandler routedParameter=page_number page_number = int(page_number) return HttpResponse('articles page: {}'.format(page_number)) # $HttpResponse -def xxs_positional_arg(request, arg0, arg1, no_taint=None): # $routeHandler routedParameter=arg0 routedParameter=arg1 +def xxs_positional_arg(request, arg0, arg1, no_taint=None): # $requestHandler routedParameter=arg0 routedParameter=arg1 return HttpResponse('xxs_positional_arg: {} {}'.format(arg0, arg1)) # $HttpResponse @@ -62,7 +62,7 @@ urlpatterns = [ # Show we understand the keyword arguments to django.urls.re_path -def re_path_kwargs(request): # $routeHandler +def re_path_kwargs(request): # $requestHandler return HttpResponse('re_path_kwargs') # $HttpResponse @@ -75,16 +75,16 @@ urlpatterns = [ ################################################################################ # saying page_number is an externally controlled *string* is a bit strange, when we have an int converter :O -def page_number(request, page_number=1): # $routeHandler routedParameter=page_number +def page_number(request, page_number=1): # $requestHandler routedParameter=page_number return HttpResponse('page_number: {}'.format(page_number)) # $HttpResponse -def foo_bar_baz(request, foo, bar, baz): # $routeHandler routedParameter=foo routedParameter=bar routedParameter=baz +def foo_bar_baz(request, foo, bar, baz): # $requestHandler routedParameter=foo routedParameter=bar routedParameter=baz return HttpResponse('foo_bar_baz: {} {} {}'.format(foo, bar, baz)) # $HttpResponse -def path_kwargs(request, foo, bar): # $routeHandler routedParameter=foo routedParameter=bar +def path_kwargs(request, foo, bar): # $requestHandler routedParameter=foo routedParameter=bar return HttpResponse('path_kwargs: {} {} {}'.format(foo, bar)) # $HttpResponse -def not_valid_identifier(request): # $routeHandler +def not_valid_identifier(request): # $requestHandler return HttpResponse('') # $HttpResponse urlpatterns = [ @@ -101,7 +101,7 @@ urlpatterns = [ # This version 1.x way of defining urls is deprecated in Django 3.1, but still works from django.conf.urls import url -def deprecated(request): # $routeHandler +def deprecated(request): # $requestHandler return HttpResponse('deprecated') # $HttpResponse urlpatterns = [ @@ -113,5 +113,5 @@ class PossiblyNotRouted(View): # Even if our analysis can't find a route-setup for this class, we should still # consider it to be a handle incoming HTTP requests - def get(self, request, possibly_not_routed=42): # $ MISSING: routeHandler routedParameter=possibly_not_routed + def get(self, request, possibly_not_routed=42): # $ MISSING: requestHandler routedParameter=possibly_not_routed return HttpResponse('PossiblyNotRouted get: {}'.format(possibly_not_routed)) # $HttpResponse diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/taint_test.py b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/taint_test.py index 6e0529f0fc3..a0db86f2961 100644 --- a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/taint_test.py +++ b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/taint_test.py @@ -3,7 +3,7 @@ from django.urls import path from django.http import HttpRequest -def test_taint(request: HttpRequest, foo, bar, baz=None): # $routeHandler routedParameter=foo routedParameter=bar +def test_taint(request: HttpRequest, foo, bar, baz=None): # $requestHandler routedParameter=foo routedParameter=bar ensure_tainted(foo, bar) ensure_not_tainted(baz) diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/views.py b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/views.py index 86517930d06..ea8c392f3d4 100644 --- a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/views.py +++ b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/views.py @@ -3,31 +3,31 @@ from django.views import View from django.views.decorators.csrf import csrf_exempt -def foo(request: HttpRequest): # $routeHandler +def foo(request: HttpRequest): # $requestHandler return HttpResponse("foo") # $HttpResponse -def bar_baz(request: HttpRequest): # $routeHandler +def bar_baz(request: HttpRequest): # $requestHandler return HttpResponse("bar_baz") # $HttpResponse -def deprecated(request: HttpRequest): # $routeHandler +def deprecated(request: HttpRequest): # $requestHandler return HttpResponse("deprecated") # $HttpResponse class MyBasicViewHandler(View): - def get(self, request: HttpRequest): # $ routeHandler + def get(self, request: HttpRequest): # $ requestHandler return HttpResponse("MyViewHandler: GET") # $ HttpResponse - def post(self, request: HttpRequest): # $ routeHandler + def post(self, request: HttpRequest): # $ requestHandler return HttpResponse("MyViewHandler: POST") # $ HttpResponse class MyCustomViewBaseClass(View): - def post(self, request: HttpRequest): # $ MISSING: routeHandler + def post(self, request: HttpRequest): # $ MISSING: requestHandler return HttpResponse("MyCustomViewBaseClass: POST") # $ HttpResponse class MyViewHandlerWithCustomInheritance(MyCustomViewBaseClass): - def get(self, request: HttpRequest): # $ routeHandler + def get(self, request: HttpRequest): # $ requestHandler return HttpResponse("MyViewHandlerWithCustomInheritance: GET") # $ HttpResponse diff --git a/python/ql/test/experimental/library-tests/frameworks/flask/old_test.py b/python/ql/test/experimental/library-tests/frameworks/flask/old_test.py index 5609e80006f..4e251f6f306 100644 --- a/python/ql/test/experimental/library-tests/frameworks/flask/old_test.py +++ b/python/ql/test/experimental/library-tests/frameworks/flask/old_test.py @@ -4,14 +4,14 @@ from flask import Flask, request, make_response app = Flask(__name__) @app.route("/") # $routeSetup="/" -def hello_world(): # $routeHandler +def hello_world(): # $requestHandler return "Hello World!" # $HttpResponse from flask.views import MethodView class MyView(MethodView): - def get(self, user_id): # $ MISSING: routeHandler + def get(self, user_id): # $ MISSING: requestHandler if user_id is None: # return a list of users pass @@ -25,42 +25,42 @@ app.add_url_rule('/the/', defaults={'user_id': None}, # $routeSetup="/the/" view_func=the_view, methods=['GET',]) @app.route("/dangerous") # $routeSetup="/dangerous" -def dangerous(): # $routeHandler +def dangerous(): # $requestHandler return request.args.get('payload') # $HttpResponse @app.route("/dangerous-with-cfg-split") # $routeSetup="/dangerous-with-cfg-split" -def dangerous2(): # $routeHandler +def dangerous2(): # $requestHandler x = request.form['param0'] if request.method == "POST": return request.form['param1'] # $HttpResponse return None # $ SPURIOUS: HttpResponse @app.route("/unsafe") # $routeSetup="/unsafe" -def unsafe(): # $routeHandler +def unsafe(): # $requestHandler first_name = request.args.get('name', '') return make_response("Your name is " + first_name) # $HttpResponse @app.route("/safe") # $routeSetup="/safe" -def safe(): # $routeHandler +def safe(): # $requestHandler first_name = request.args.get('name', '') return make_response("Your name is " + escape(first_name)) # $HttpResponse @app.route("/hello/") # $routeSetup="/hello/" -def hello(name): # $routeHandler routedParameter=name +def hello(name): # $requestHandler routedParameter=name return make_response("Your name is " + name) # $HttpResponse @app.route("/foo/") # $routeSetup="/foo/" -def foo(subpath): # $routeHandler routedParameter=subpath +def foo(subpath): # $requestHandler routedParameter=subpath return make_response("The subpath is " + subpath) # $HttpResponse @app.route("/multiple/") # $routeSetup="/multiple/" @app.route("/multiple/foo/") # $routeSetup="/multiple/foo/" @app.route("/multiple/bar/") # $routeSetup="/multiple/bar/" -def multiple(foo=None, bar=None): # $routeHandler routedParameter=foo routedParameter=bar +def multiple(foo=None, bar=None): # $requestHandler routedParameter=foo routedParameter=bar return make_response("foo={!r} bar={!r}".format(foo, bar)) # $HttpResponse @app.route("/complex/") # $routeSetup="/complex/" -def complex(lang_code): # $routeHandler routedParameter=lang_code +def complex(lang_code): # $requestHandler routedParameter=lang_code return make_response("lang_code {}".format(lang_code)) # $HttpResponse if __name__ == "__main__": diff --git a/python/ql/test/experimental/library-tests/frameworks/flask/response_test.py b/python/ql/test/experimental/library-tests/frameworks/flask/response_test.py index ce57b5f01f0..b067f173882 100644 --- a/python/ql/test/experimental/library-tests/frameworks/flask/response_test.py +++ b/python/ql/test/experimental/library-tests/frameworks/flask/response_test.py @@ -6,12 +6,12 @@ app = Flask(__name__) @app.route("/html1") # $routeSetup="/html1" -def html1(): # $routeHandler +def html1(): # $requestHandler return "

hello

" # $HttpResponse mimetype=text/html responseBody="

hello

" @app.route("/html2") # $routeSetup="/html2" -def html2(): # $routeHandler +def html2(): # $requestHandler # note that response saved in a variable intentionally -- we wan the annotations to # show that we recognize the response creation, and not the return (hopefully). (and # do the same in the following of the file) @@ -20,7 +20,7 @@ def html2(): # $routeHandler @app.route("/html3") # $routeSetup="/html3" -def html3(): # $routeHandler +def html3(): # $requestHandler resp = app.make_response("

hello

") # $HttpResponse mimetype=text/html responseBody="

hello

" return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp @@ -30,13 +30,13 @@ def html3(): # $routeHandler @app.route("/html4") # $routeSetup="/html4" -def html4(): # $routeHandler +def html4(): # $requestHandler resp = Response("

hello

") # $HttpResponse mimetype=text/html responseBody="

hello

" return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp @app.route("/html5") # $routeSetup="/html5" -def html5(): # $routeHandler +def html5(): # $requestHandler # note: flask.Flask.response_class is set to `flask.Response` by default. # it can be overridden, but we don't try to handle that right now. resp = Flask.response_class("

hello

") # $HttpResponse mimetype=text/html responseBody="

hello

" @@ -44,7 +44,7 @@ def html5(): # $routeHandler @app.route("/html6") # $routeSetup="/html6" -def html6(): # $routeHandler +def html6(): # $requestHandler # note: app.response_class (flask.Flask.response_class) is set to `flask.Response` by default. # it can be overridden, but we don't try to handle that right now. resp = app.response_class("

hello

") # $HttpResponse mimetype=text/html responseBody="

hello

" @@ -52,14 +52,14 @@ def html6(): # $routeHandler @app.route("/html7") # $routeSetup="/html7" -def html7(): # $routeHandler +def html7(): # $requestHandler resp = make_response() # $HttpResponse mimetype=text/html resp.set_data("

hello

") # $ MISSING: responseBody="

hello

" return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp @app.route("/jsonify") # $routeSetup="/jsonify" -def jsonify_route(): # $routeHandler +def jsonify_route(): # $requestHandler data = {"foo": "bar"} resp = jsonify(data) # $ MISSING: HttpResponse mimetype=application/json responseBody=data return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp @@ -69,7 +69,7 @@ def jsonify_route(): # $routeHandler ################################################################################ @app.route("/tricky-return1") # $routeSetup="/tricky-return1" -def tricky_return1(): # $routeHandler +def tricky_return1(): # $requestHandler if "raw" in request.args: resp = "

hellu

" else: @@ -83,7 +83,7 @@ def helper(): return make_response("

hello

") # $HttpResponse mimetype=text/html responseBody="

hello

" @app.route("/tricky-return2") # $routeSetup="/tricky-return2" -def tricky_return2(): # $routeHandler +def tricky_return2(): # $requestHandler resp = helper() return resp # $HttpResponse mimetype=text/html responseBody=resp @@ -94,14 +94,14 @@ def tricky_return2(): # $routeHandler @app.route("/content-type/response-modification1") # $routeSetup="/content-type/response-modification1" -def response_modification1(): # $routeHandler +def response_modification1(): # $requestHandler resp = make_response("

hello

") # $HttpResponse mimetype=text/html responseBody="

hello

" resp.content_type = "text/plain" # $ MISSING: HttpResponse mimetype=text/plain return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp @app.route("/content-type/response-modification2") # $routeSetup="/content-type/response-modification2" -def response_modification2(): # $routeHandler +def response_modification2(): # $requestHandler resp = make_response("

hello

") # $HttpResponse mimetype=text/html responseBody="

hello

" resp.headers["content-type"] = "text/plain" # $ MISSING: HttpResponse mimetype=text/plain return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp @@ -112,33 +112,33 @@ def response_modification2(): # $routeHandler @app.route("/content-type/Response1") # $routeSetup="/content-type/Response1" -def Response1(): # $routeHandler +def Response1(): # $requestHandler resp = Response("

hello

", mimetype="text/plain") # $HttpResponse mimetype=text/plain responseBody="

hello

" return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp @app.route("/content-type/Response2") # $routeSetup="/content-type/Response2" -def Response2(): # $routeHandler +def Response2(): # $requestHandler resp = Response("

hello

", content_type="text/plain; charset=utf-8") # $HttpResponse mimetype=text/plain responseBody="

hello

" return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp @app.route("/content-type/Response3") # $routeSetup="/content-type/Response3" -def Response3(): # $routeHandler +def Response3(): # $requestHandler # content_type argument takes priority (and result is text/plain) resp = Response("

hello

", content_type="text/plain; charset=utf-8", mimetype="text/html") # $HttpResponse mimetype=text/plain responseBody="

hello

" return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp @app.route("/content-type/Response4") # $routeSetup="/content-type/Response4" -def Response4(): # $routeHandler +def Response4(): # $requestHandler # note: capitalization of Content-Type does not matter resp = Response("

hello

", headers={"Content-TYPE": "text/plain"}) # $HttpResponse responseBody="

hello

" SPURIOUS: mimetype=text/html MISSING: mimetype=text/plain return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp @app.route("/content-type/Response5") # $routeSetup="/content-type/Response5" -def Response5(): # $routeHandler +def Response5(): # $requestHandler # content_type argument takes priority (and result is text/plain) # note: capitalization of Content-Type does not matter resp = Response("

hello

", headers={"Content-TYPE": "text/html"}, content_type="text/plain; charset=utf-8") # $HttpResponse mimetype=text/plain responseBody="

hello

" @@ -146,7 +146,7 @@ def Response5(): # $routeHandler @app.route("/content-type/Response6") # $routeSetup="/content-type/Response6" -def Response6(): # $routeHandler +def Response6(): # $requestHandler # mimetype argument takes priority over header (and result is text/plain) # note: capitalization of Content-Type does not matter resp = Response("

hello

", headers={"Content-TYPE": "text/html"}, mimetype="text/plain") # $HttpResponse mimetype=text/plain responseBody="

hello

" @@ -154,7 +154,7 @@ def Response6(): # $routeHandler @app.route("/content-type/Flask-response-class") # $routeSetup="/content-type/Flask-response-class" -def Flask_response_class(): # $routeHandler +def Flask_response_class(): # $requestHandler # note: flask.Flask.response_class is set to `flask.Response` by default. # it can be overridden, but we don't try to handle that right now. resp = Flask.response_class("

hello

", mimetype="text/plain") # $HttpResponse mimetype=text/plain responseBody="

hello

" @@ -162,7 +162,7 @@ def Flask_response_class(): # $routeHandler @app.route("/content-type/app-response-class") # $routeSetup="/content-type/app-response-class" -def app_response_class(): # $routeHandler +def app_response_class(): # $requestHandler # note: app.response_class (flask.Flask.response_class) is set to `flask.Response` by default. # it can be overridden, but we don't try to handle that right now. resp = app.response_class("

hello

", mimetype="text/plain") # $HttpResponse mimetype=text/plain responseBody="

hello

" diff --git a/python/ql/test/experimental/library-tests/frameworks/flask/routing_test.py b/python/ql/test/experimental/library-tests/frameworks/flask/routing_test.py index a5e40b5c123..1a6028e8026 100644 --- a/python/ql/test/experimental/library-tests/frameworks/flask/routing_test.py +++ b/python/ql/test/experimental/library-tests/frameworks/flask/routing_test.py @@ -6,24 +6,24 @@ app = Flask(__name__) SOME_ROUTE = "/some/route" @app.route(SOME_ROUTE) # $routeSetup="/some/route" -def some_route(): # $routeHandler +def some_route(): # $requestHandler return make_response("some_route") # $HttpResponse -def index(): # $routeHandler +def index(): # $requestHandler return make_response("index") # $HttpResponse app.add_url_rule('/index', 'index', index) # $routeSetup="/index" # We don't support this yet, and I think that's OK -def later_set(): # $ MISSING: routeHandler +def later_set(): # $ MISSING: requestHandler return make_response("later_set") # $HttpResponse app.add_url_rule('/later-set', 'later_set', view_func=None) # $routeSetup="/later-set" app.view_functions['later_set'] = later_set @app.route(UNKNOWN_ROUTE) # $routeSetup -def unkown_route(foo, bar): # $routeHandler routedParameter=foo routedParameter=bar +def unkown_route(foo, bar): # $requestHandler routedParameter=foo routedParameter=bar return make_response("unkown_route") # $HttpResponse diff --git a/python/ql/test/experimental/library-tests/frameworks/flask/taint_test.py b/python/ql/test/experimental/library-tests/frameworks/flask/taint_test.py index 58335997875..31c0c7e6121 100644 --- a/python/ql/test/experimental/library-tests/frameworks/flask/taint_test.py +++ b/python/ql/test/experimental/library-tests/frameworks/flask/taint_test.py @@ -2,7 +2,7 @@ from flask import Flask, request app = Flask(__name__) @app.route("/test_taint//") # $routeSetup="/test_taint//" -def test_taint(name = "World!", number="0", foo="foo"): # $routeHandler routedParameter=name routedParameter=number +def test_taint(name = "World!", number="0", foo="foo"): # $requestHandler routedParameter=name routedParameter=number ensure_tainted(name, number) ensure_not_tainted(foo) @@ -192,7 +192,7 @@ def test_taint(name = "World!", number="0", foo="foo"): # $routeHandler routedP @app.route("/debug//", methods=['GET']) # $routeSetup="/debug//" -def debug(foo, bar): # $routeHandler routedParameter=foo routedParameter=bar +def debug(foo, bar): # $requestHandler routedParameter=foo routedParameter=bar print("request.view_args", request.view_args) print("request.headers {!r}".format(request.headers)) @@ -203,7 +203,7 @@ def debug(foo, bar): # $routeHandler routedParameter=foo routedParameter=bar return 'ok' # $HttpResponse @app.route("/stream", methods=['POST']) # $routeSetup="/stream" -def stream(): # $routeHandler +def stream(): # $requestHandler print(request.path) s = request.stream print(s) @@ -213,7 +213,7 @@ def stream(): # $routeHandler return 'ok' # $HttpResponse @app.route("/input_stream", methods=['POST']) # $routeSetup="/input_stream" -def input_stream(): # $routeHandler +def input_stream(): # $requestHandler print(request.path) s = request.input_stream print(s) @@ -224,14 +224,14 @@ def input_stream(): # $routeHandler return 'ok' # $HttpResponse @app.route("/form", methods=['POST']) # $routeSetup="/form" -def form(): # $routeHandler +def form(): # $requestHandler print(request.path) print("request.form", request.form) return 'ok' # $HttpResponse @app.route("/cache_control", methods=['POST']) # $routeSetup="/cache_control" -def cache_control(): # $routeHandler +def cache_control(): # $requestHandler print(request.path) print("request.cache_control.max_age", request.cache_control.max_age, type(request.cache_control.max_age)) print("request.cache_control.max_stale", request.cache_control.max_stale, type(request.cache_control.max_stale)) @@ -240,7 +240,7 @@ def cache_control(): # $routeHandler return 'ok' # $HttpResponse @app.route("/file_upload", methods=['POST']) # $routeSetup="/file_upload" -def file_upload(): # $routeHandler +def file_upload(): # $requestHandler print(request.path) for k,v in request.files.items(): print(k, v, v.name, v.filename, v.stream) @@ -248,7 +248,7 @@ def file_upload(): # $routeHandler return 'ok' # $HttpResponse @app.route("/args", methods=['GET']) # $routeSetup="/args" -def args(): # $routeHandler +def args(): # $requestHandler print(request.path) print("request.args", request.args) diff --git a/python/ql/test/experimental/library-tests/frameworks/stdlib/http_server.py b/python/ql/test/experimental/library-tests/frameworks/stdlib/http_server.py index 33a3594894f..f74cc171136 100644 --- a/python/ql/test/experimental/library-tests/frameworks/stdlib/http_server.py +++ b/python/ql/test/experimental/library-tests/frameworks/stdlib/http_server.py @@ -78,7 +78,7 @@ class MyHandler(BaseHTTPRequestHandler): ensure_tainted(form) - def do_GET(self): + def do_GET(self): # $ MISSING: requestHandler # send_response will log a line to stderr self.send_response(200) self.send_header("Content-type", "text/plain; charset=utf-8") @@ -88,7 +88,7 @@ class MyHandler(BaseHTTPRequestHandler): print(self.headers) - def do_POST(self): + def do_POST(self): # $ MISSING: requestHandler form = cgi.FieldStorage( self.rfile, self.headers, diff --git a/python/ql/test/experimental/meta/ConceptsTest.qll b/python/ql/test/experimental/meta/ConceptsTest.qll index 98423b95688..b031499e5e2 100644 --- a/python/ql/test/experimental/meta/ConceptsTest.qll +++ b/python/ql/test/experimental/meta/ConceptsTest.qll @@ -142,7 +142,9 @@ class SqlExecutionTest extends InlineExpectationsTest { class HttpServerRouteSetupTest extends InlineExpectationsTest { HttpServerRouteSetupTest() { this = "HttpServerRouteSetupTest" } - override string getARelevantTag() { result in ["routeSetup", "routeHandler", "routedParameter"] } + override string getARelevantTag() { + result in ["routeSetup", "requestHandler", "routedParameter"] + } override predicate hasActualResult(Location location, string element, string tag, string value) { exists(HTTP::Server::RouteSetup setup | @@ -157,16 +159,15 @@ class HttpServerRouteSetupTest extends InlineExpectationsTest { tag = "routeSetup" ) or - exists(HTTP::Server::RouteSetup setup, Function func | - func = setup.getARouteHandler() and - location = func.getLocation() and - element = func.toString() and + exists(HTTP::Server::RequestHandler handler | + location = handler.getLocation() and + element = handler.toString() and value = "" and - tag = "routeHandler" + tag = "requestHandler" ) or - exists(HTTP::Server::RouteSetup setup, Parameter param | - param = setup.getARoutedParameter() and + exists(HTTP::Server::RequestHandler handler, Parameter param | + param = handler.getARoutedParameter() and location = param.getLocation() and element = param.toString() and value = param.asName().getId() and From d4d6f0ca0c55eded35b2a0b23ba8d71ed6ad67ef Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 21 Dec 2020 17:38:43 +0100 Subject: [PATCH 026/343] Python: Model django request handlers without known route --- .../2020-12-21-django-with-unknown-route.md | 2 ++ .../ql/src/semmle/python/frameworks/Django.qll | 17 +++++++++++++++++ .../frameworks/django-v2-v3/routing_test.py | 2 +- .../frameworks/django-v2-v3/testapp/views.py | 2 +- 4 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 python/change-notes/2020-12-21-django-with-unknown-route.md diff --git a/python/change-notes/2020-12-21-django-with-unknown-route.md b/python/change-notes/2020-12-21-django-with-unknown-route.md new file mode 100644 index 00000000000..6ac353cbef4 --- /dev/null +++ b/python/change-notes/2020-12-21-django-with-unknown-route.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* Improved modeling of `django` to recognize request handlers on `View` classes without known route, thereby leading to more sources of remote user input (`RemoteFlowSource`). diff --git a/python/ql/src/semmle/python/frameworks/Django.qll b/python/ql/src/semmle/python/frameworks/Django.qll index f4cbe3d9ea5..171a06dc97a 100644 --- a/python/ql/src/semmle/python/frameworks/Django.qll +++ b/python/ql/src/semmle/python/frameworks/Django.qll @@ -1756,6 +1756,23 @@ private module Django { } } + /** A request handler defined in a django view class, that has no known route. */ + private class DjangoViewClassHandlerWithoutKnownRoute extends HTTP::Server::RequestHandler::Range, + DjangoRouteHandler { + DjangoViewClassHandlerWithoutKnownRoute() { + exists(DjangoViewClassDef vc | vc.getARequestHandler() = this) and + not exists(DjangoRouteSetup setup | setup.getARequestHandler() = this) + } + + override Parameter getARoutedParameter() { + // Since we don't know the URL pattern, we simply mark all parameters as a routed + // parameter. This should give us more RemoteFlowSources but could also lead to + // more FPs. If this turns out to be the wrong tradeoff, we can always change our mind. + result in [this.getArg(_), this.getArgByName(_)] and + not result = any(int i | i <= this.getRequestParamIndex() | this.getArg(i)) + } + } + /** * Gets the regex that is used by django to find routed parameters when using `django.urls.path`. * diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/routing_test.py b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/routing_test.py index 9b28f7ffeb8..e744c5ba89d 100644 --- a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/routing_test.py +++ b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/routing_test.py @@ -113,5 +113,5 @@ class PossiblyNotRouted(View): # Even if our analysis can't find a route-setup for this class, we should still # consider it to be a handle incoming HTTP requests - def get(self, request, possibly_not_routed=42): # $ MISSING: requestHandler routedParameter=possibly_not_routed + def get(self, request, possibly_not_routed=42): # $ requestHandler routedParameter=possibly_not_routed return HttpResponse('PossiblyNotRouted get: {}'.format(possibly_not_routed)) # $HttpResponse diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/views.py b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/views.py index ea8c392f3d4..55c60a551a0 100644 --- a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/views.py +++ b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/views.py @@ -24,7 +24,7 @@ class MyBasicViewHandler(View): class MyCustomViewBaseClass(View): - def post(self, request: HttpRequest): # $ MISSING: requestHandler + def post(self, request: HttpRequest): # $ requestHandler return HttpResponse("MyCustomViewBaseClass: POST") # $ HttpResponse From 05ab6cd54a806449be0b1b7003532deda11f59a8 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 21 Dec 2020 17:41:46 +0100 Subject: [PATCH 027/343] Python: Add RemoteFlowSource for django handler without route A bit scary that we don't have any tests to indicate that I forgot to add this :O --- python/ql/src/semmle/python/frameworks/Django.qll | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python/ql/src/semmle/python/frameworks/Django.qll b/python/ql/src/semmle/python/frameworks/Django.qll index 171a06dc97a..74c1856a79b 100644 --- a/python/ql/src/semmle/python/frameworks/Django.qll +++ b/python/ql/src/semmle/python/frameworks/Django.qll @@ -1909,6 +1909,8 @@ private module Django { RemoteFlowSource::Range, DataFlow::ParameterNode { DjangoRouteHandlerRequestParam() { this.getParameter() = any(DjangoRouteSetup setup).getARequestHandler().getRequestParam() + or + this.getParameter() = any(DjangoViewClassHandlerWithoutKnownRoute setup).getRequestParam() } override string getSourceType() { result = "django.http.request.HttpRequest" } From 71a6ef5b00c21ab4bdad6380a7bfc65ccbf10e0d Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 21 Dec 2020 17:55:33 +0100 Subject: [PATCH 028/343] Python: Model RequestHandler from standard library explicitly --- python/ql/src/semmle/python/frameworks/Stdlib.qll | 14 ++++++++++++++ python/ql/src/semmle/python/web/HttpConstants.qll | 2 +- .../library-tests/frameworks/stdlib/http_server.py | 4 ++-- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/python/ql/src/semmle/python/frameworks/Stdlib.qll b/python/ql/src/semmle/python/frameworks/Stdlib.qll index 8840e1bba60..5120534d014 100644 --- a/python/ql/src/semmle/python/frameworks/Stdlib.qll +++ b/python/ql/src/semmle/python/frameworks/Stdlib.qll @@ -1616,6 +1616,20 @@ private module Stdlib { ) } } + + /** + * The entry-point for handling a request with a `BaseHTTPRequestHandler` subclass. + * + * Not essential for any functionality, but provides a consistent modeling. + */ + private class RequestHandlerFunc extends HTTP::Server::RequestHandler::Range { + RequestHandlerFunc() { + this = any(HTTPRequestHandlerClassDef cls).getAMethod() and + this.getName() = "do_" + HTTP::httpVerb() + } + + override Parameter getARoutedParameter() { none() } + } } // --------------------------------------------------------------------------- diff --git a/python/ql/src/semmle/python/web/HttpConstants.qll b/python/ql/src/semmle/python/web/HttpConstants.qll index b3b389faf62..d3e8b0412a4 100644 --- a/python/ql/src/semmle/python/web/HttpConstants.qll +++ b/python/ql/src/semmle/python/web/HttpConstants.qll @@ -1,4 +1,4 @@ -/** Gets an HTTP verb */ +/** Gets an HTTP verb, in upper case */ string httpVerb() { result = "GET" or result = "POST" or diff --git a/python/ql/test/experimental/library-tests/frameworks/stdlib/http_server.py b/python/ql/test/experimental/library-tests/frameworks/stdlib/http_server.py index f74cc171136..8d996acb41d 100644 --- a/python/ql/test/experimental/library-tests/frameworks/stdlib/http_server.py +++ b/python/ql/test/experimental/library-tests/frameworks/stdlib/http_server.py @@ -78,7 +78,7 @@ class MyHandler(BaseHTTPRequestHandler): ensure_tainted(form) - def do_GET(self): # $ MISSING: requestHandler + def do_GET(self): # $ requestHandler # send_response will log a line to stderr self.send_response(200) self.send_header("Content-type", "text/plain; charset=utf-8") @@ -88,7 +88,7 @@ class MyHandler(BaseHTTPRequestHandler): print(self.headers) - def do_POST(self): # $ MISSING: requestHandler + def do_POST(self): # $ requestHandler form = cgi.FieldStorage( self.rfile, self.headers, From ba4da72b9e20ff70c331224308b403bfc8018468 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Sat, 5 Dec 2020 13:39:42 +0100 Subject: [PATCH 029/343] C++: Add examples that require longer access paths --- .../dataflow/fields/aliasing.cpp | 28 +++++++++++ .../fields/dataflow-consistency.expected | 5 ++ .../fields/dataflow-ir-consistency.expected | 6 +++ .../fields/partial-definition-diff.expected | 10 ++++ .../fields/partial-definition-ir.expected | 5 ++ .../fields/partial-definition.expected | 15 ++++++ .../dataflow/fields/path-flow.expected | 47 +++++++++++++++++++ .../library-tests/dataflow/fields/simple.cpp | 12 +++++ 8 files changed, 128 insertions(+) diff --git a/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp b/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp index 500bbed53a9..8b3c0f29ab2 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp @@ -204,4 +204,32 @@ void deep_member_field_arrow(S2 *ps2) { void deep_member_field_arrow_different_fields(S2 *ps2) { taint_a_ptr(&ps2->s.m1); sink(ps2->s.m2); +} + +void test_deep_struct_fields() { + S2 s2; + s2.s.m1 = user_input(); + S s = s2.s; + sink(s.m1); // $ ast MISSING: ir +} + +void test_deep_struct_fields_no_flow() { + S2 s2; + s2.s.m1 = user_input(); + S s = s2.s; + sink(s.m2); +} + +void test_deep_struct_fields_taint_through_call() { + S2 s2; + taint_a_ptr(&s2.s.m1); + S s = s2.s; + sink(s.m1); // $ ast MISSING: ir +} + +void test_deep_struct_fields_taint_through_call_no_flow() { + S2 s2; + taint_a_ptr(&s2.s.m1); + S s = s2.s; + sink(s.m2); } \ No newline at end of file diff --git a/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected b/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected index 49b12c14350..0594034912f 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected @@ -89,6 +89,10 @@ postWithInFlow | aliasing.cpp:194:21:194:22 | m1 [inner post update] | PostUpdateNode should not be the target of local flow. | | aliasing.cpp:200:23:200:24 | m1 [inner post update] | PostUpdateNode should not be the target of local flow. | | aliasing.cpp:205:23:205:24 | m1 [inner post update] | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:211:8:211:9 | m1 [post update] | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:218:8:218:9 | m1 [post update] | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:225:21:225:22 | m1 [inner post update] | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:232:21:232:22 | m1 [inner post update] | PostUpdateNode should not be the target of local flow. | | arrays.cpp:6:3:6:5 | arr [inner post update] | PostUpdateNode should not be the target of local flow. | | arrays.cpp:6:3:6:8 | access to array [post update] | PostUpdateNode should not be the target of local flow. | | arrays.cpp:15:3:15:10 | * ... [post update] | PostUpdateNode should not be the target of local flow. | @@ -145,5 +149,6 @@ postWithInFlow | simple.cpp:65:7:65:7 | i [post update] | PostUpdateNode should not be the target of local flow. | | simple.cpp:83:12:83:13 | f1 [post update] | PostUpdateNode should not be the target of local flow. | | simple.cpp:92:7:92:7 | i [post update] | PostUpdateNode should not be the target of local flow. | +| simple.cpp:104:9:104:9 | i [post update] | PostUpdateNode should not be the target of local flow. | | struct_init.c:24:11:24:12 | ab [inner post update] | PostUpdateNode should not be the target of local flow. | | struct_init.c:36:17:36:24 | nestedAB [inner post update] | PostUpdateNode should not be the target of local flow. | diff --git a/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected index b09317c2c1b..23f8d07717f 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected @@ -18,6 +18,7 @@ postIsNotPre postHasUniquePre | simple.cpp:65:5:65:22 | Store | PostUpdateNode should have one pre-update node but has 0. | | simple.cpp:92:5:92:22 | Store | PostUpdateNode should have one pre-update node but has 0. | +| simple.cpp:104:5:104:24 | Store | PostUpdateNode should have one pre-update node but has 0. | uniquePostUpdate postIsInSameCallable reverseRead @@ -96,6 +97,10 @@ postWithInFlow | aliasing.cpp:194:15:194:22 | Chi | PostUpdateNode should not be the target of local flow. | | aliasing.cpp:200:15:200:24 | Chi | PostUpdateNode should not be the target of local flow. | | aliasing.cpp:205:15:205:24 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:211:3:211:24 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:218:3:218:24 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:225:15:225:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:232:15:232:22 | Chi | PostUpdateNode should not be the target of local flow. | | arrays.cpp:5:18:5:23 | Chi | PostUpdateNode should not be the target of local flow. | | arrays.cpp:5:21:5:21 | Chi | PostUpdateNode should not be the target of local flow. | | arrays.cpp:6:3:6:23 | Chi | PostUpdateNode should not be the target of local flow. | @@ -145,6 +150,7 @@ postWithInFlow | simple.cpp:65:5:65:22 | Store | PostUpdateNode should not be the target of local flow. | | simple.cpp:83:9:83:28 | Chi | PostUpdateNode should not be the target of local flow. | | simple.cpp:92:5:92:22 | Store | PostUpdateNode should not be the target of local flow. | +| simple.cpp:104:5:104:24 | Store | PostUpdateNode should not be the target of local flow. | | struct_init.c:20:20:20:29 | Chi | PostUpdateNode should not be the target of local flow. | | struct_init.c:20:34:20:34 | Chi | PostUpdateNode should not be the target of local flow. | | struct_init.c:27:7:27:16 | Chi | PostUpdateNode should not be the target of local flow. | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected index bba86417ca5..ee0a3a33779 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected @@ -183,6 +183,14 @@ | aliasing.cpp:200:16:200:18 | ps2 | AST only | | aliasing.cpp:205:15:205:24 | & ... | AST only | | aliasing.cpp:205:16:205:18 | ps2 | AST only | +| aliasing.cpp:211:3:211:4 | s2 | AST only | +| aliasing.cpp:211:8:211:9 | m1 | AST only | +| aliasing.cpp:218:3:218:4 | s2 | AST only | +| aliasing.cpp:218:8:218:9 | m1 | AST only | +| aliasing.cpp:225:15:225:22 | & ... | AST only | +| aliasing.cpp:225:16:225:17 | s2 | AST only | +| aliasing.cpp:232:15:232:22 | & ... | AST only | +| aliasing.cpp:232:16:232:17 | s2 | AST only | | arrays.cpp:6:3:6:8 | access to array | AST only | | arrays.cpp:6:3:6:23 | arr | IR only | | arrays.cpp:15:3:15:10 | * ... | AST only | @@ -399,6 +407,8 @@ | simple.cpp:83:12:83:13 | f1 | AST only | | simple.cpp:84:14:84:20 | this | AST only | | simple.cpp:92:7:92:7 | i | AST only | +| simple.cpp:104:5:104:5 | b | AST only | +| simple.cpp:104:9:104:9 | i | AST only | | struct_init.c:15:8:15:9 | ab | AST only | | struct_init.c:15:12:15:12 | a | AST only | | struct_init.c:16:8:16:9 | ab | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected index 8d12b2a7e05..5b73bf8dd33 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected @@ -35,6 +35,10 @@ | aliasing.cpp:194:19:194:19 | s | | aliasing.cpp:200:21:200:21 | s | | aliasing.cpp:205:21:205:21 | s | +| aliasing.cpp:211:6:211:6 | s | +| aliasing.cpp:218:6:218:6 | s | +| aliasing.cpp:225:19:225:19 | s | +| aliasing.cpp:232:19:232:19 | s | | arrays.cpp:6:3:6:5 | arr | | arrays.cpp:36:3:36:17 | access to array | | by_reference.cpp:12:5:12:5 | s | @@ -68,4 +72,5 @@ | simple.cpp:65:5:65:5 | a | | simple.cpp:83:9:83:10 | f2 | | simple.cpp:92:5:92:5 | a | +| simple.cpp:104:7:104:7 | a | | struct_init.c:36:11:36:15 | outer | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected index 6c58d51ff74..e96fae3cb20 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected @@ -220,6 +220,18 @@ | aliasing.cpp:205:15:205:24 | & ... | | aliasing.cpp:205:16:205:18 | ps2 | | aliasing.cpp:205:21:205:21 | s | +| aliasing.cpp:211:3:211:4 | s2 | +| aliasing.cpp:211:6:211:6 | s | +| aliasing.cpp:211:8:211:9 | m1 | +| aliasing.cpp:218:3:218:4 | s2 | +| aliasing.cpp:218:6:218:6 | s | +| aliasing.cpp:218:8:218:9 | m1 | +| aliasing.cpp:225:15:225:22 | & ... | +| aliasing.cpp:225:16:225:17 | s2 | +| aliasing.cpp:225:19:225:19 | s | +| aliasing.cpp:232:15:232:22 | & ... | +| aliasing.cpp:232:16:232:17 | s2 | +| aliasing.cpp:232:19:232:19 | s | | arrays.cpp:6:3:6:8 | access to array | | arrays.cpp:15:3:15:10 | * ... | | arrays.cpp:36:3:36:3 | o | @@ -467,6 +479,9 @@ | simple.cpp:84:14:84:20 | this | | simple.cpp:92:5:92:5 | a | | simple.cpp:92:7:92:7 | i | +| simple.cpp:104:5:104:5 | b | +| simple.cpp:104:7:104:7 | a | +| simple.cpp:104:9:104:9 | i | | struct_init.c:15:8:15:9 | ab | | struct_init.c:15:12:15:12 | a | | struct_init.c:16:8:16:9 | ab | diff --git a/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected index b932e0395f4..93ec3ca710d 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected @@ -160,6 +160,7 @@ edges | aliasing.cpp:106:4:106:5 | pa [inner post update] | aliasing.cpp:175:15:175:22 | ref arg & ... | | aliasing.cpp:106:4:106:5 | pa [inner post update] | aliasing.cpp:187:15:187:22 | ref arg & ... | | aliasing.cpp:106:4:106:5 | pa [inner post update] | aliasing.cpp:200:15:200:24 | ref arg & ... | +| aliasing.cpp:106:4:106:5 | pa [inner post update] | aliasing.cpp:225:15:225:22 | ref arg & ... | | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:106:4:106:5 | pa [inner post update] | | aliasing.cpp:158:15:158:15 | s [post update] [data] | aliasing.cpp:159:9:159:9 | s [data] | | aliasing.cpp:158:17:158:20 | ref arg data | aliasing.cpp:158:15:158:15 | s [post update] [data] | @@ -187,6 +188,20 @@ edges | aliasing.cpp:200:23:200:24 | m1 [inner post update] | aliasing.cpp:200:21:200:21 | s [post update] [m1] | | aliasing.cpp:201:8:201:10 | ps2 [s, m1] | aliasing.cpp:201:13:201:13 | s [m1] | | aliasing.cpp:201:13:201:13 | s [m1] | aliasing.cpp:201:15:201:16 | m1 | +| aliasing.cpp:211:3:211:4 | s2 [post update] [s, m1] | aliasing.cpp:212:9:212:10 | s2 [s, m1] | +| aliasing.cpp:211:3:211:24 | ... = ... | aliasing.cpp:211:6:211:6 | s [post update] [m1] | +| aliasing.cpp:211:6:211:6 | s [post update] [m1] | aliasing.cpp:211:3:211:4 | s2 [post update] [s, m1] | +| aliasing.cpp:211:13:211:22 | call to user_input | aliasing.cpp:211:3:211:24 | ... = ... | +| aliasing.cpp:212:9:212:10 | s2 [s, m1] | aliasing.cpp:212:12:212:12 | s [m1] | +| aliasing.cpp:212:12:212:12 | s [m1] | aliasing.cpp:213:8:213:8 | s [m1] | +| aliasing.cpp:213:8:213:8 | s [m1] | aliasing.cpp:213:10:213:11 | m1 | +| aliasing.cpp:225:15:225:22 | ref arg & ... | aliasing.cpp:225:21:225:22 | m1 [inner post update] | +| aliasing.cpp:225:16:225:17 | s2 [post update] [s, m1] | aliasing.cpp:226:9:226:10 | s2 [s, m1] | +| aliasing.cpp:225:19:225:19 | s [post update] [m1] | aliasing.cpp:225:16:225:17 | s2 [post update] [s, m1] | +| aliasing.cpp:225:21:225:22 | m1 [inner post update] | aliasing.cpp:225:19:225:19 | s [post update] [m1] | +| aliasing.cpp:226:9:226:10 | s2 [s, m1] | aliasing.cpp:226:12:226:12 | s [m1] | +| aliasing.cpp:226:12:226:12 | s [m1] | aliasing.cpp:227:8:227:8 | s [m1] | +| aliasing.cpp:227:8:227:8 | s [m1] | aliasing.cpp:227:10:227:11 | m1 | | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:7:8:7:13 | access to array | | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:8:8:8:13 | access to array | | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:9:8:9:11 | * ... | @@ -428,6 +443,12 @@ edges | simple.cpp:92:5:92:22 | ... = ... | simple.cpp:92:5:92:5 | a [post update] [i] | | simple.cpp:92:11:92:20 | call to user_input | simple.cpp:92:5:92:22 | ... = ... | | simple.cpp:94:10:94:11 | a2 [i] | simple.cpp:94:13:94:13 | i | +| simple.cpp:104:5:104:5 | b [post update] [a, i] | simple.cpp:106:10:106:11 | b2 [a, i] | +| simple.cpp:104:5:104:24 | ... = ... | simple.cpp:104:7:104:7 | a [post update] [i] | +| simple.cpp:104:7:104:7 | a [post update] [i] | simple.cpp:104:5:104:5 | b [post update] [a, i] | +| simple.cpp:104:13:104:22 | call to user_input | simple.cpp:104:5:104:24 | ... = ... | +| simple.cpp:106:10:106:11 | b2 [a, i] | simple.cpp:106:13:106:13 | a [i] | +| simple.cpp:106:13:106:13 | a [i] | simple.cpp:106:15:106:15 | i | | struct_init.c:14:24:14:25 | ab [a] | struct_init.c:15:8:15:9 | ab [a] | | struct_init.c:15:8:15:9 | ab [a] | struct_init.c:15:12:15:12 | a | | struct_init.c:20:17:20:36 | {...} [a] | struct_init.c:22:8:22:9 | ab [a] | @@ -668,6 +689,22 @@ nodes | aliasing.cpp:201:8:201:10 | ps2 [s, m1] | semmle.label | ps2 [s, m1] | | aliasing.cpp:201:13:201:13 | s [m1] | semmle.label | s [m1] | | aliasing.cpp:201:15:201:16 | m1 | semmle.label | m1 | +| aliasing.cpp:211:3:211:4 | s2 [post update] [s, m1] | semmle.label | s2 [post update] [s, m1] | +| aliasing.cpp:211:3:211:24 | ... = ... | semmle.label | ... = ... | +| aliasing.cpp:211:6:211:6 | s [post update] [m1] | semmle.label | s [post update] [m1] | +| aliasing.cpp:211:13:211:22 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:212:9:212:10 | s2 [s, m1] | semmle.label | s2 [s, m1] | +| aliasing.cpp:212:12:212:12 | s [m1] | semmle.label | s [m1] | +| aliasing.cpp:213:8:213:8 | s [m1] | semmle.label | s [m1] | +| aliasing.cpp:213:10:213:11 | m1 | semmle.label | m1 | +| aliasing.cpp:225:15:225:22 | ref arg & ... | semmle.label | ref arg & ... | +| aliasing.cpp:225:16:225:17 | s2 [post update] [s, m1] | semmle.label | s2 [post update] [s, m1] | +| aliasing.cpp:225:19:225:19 | s [post update] [m1] | semmle.label | s [post update] [m1] | +| aliasing.cpp:225:21:225:22 | m1 [inner post update] | semmle.label | m1 [inner post update] | +| aliasing.cpp:226:9:226:10 | s2 [s, m1] | semmle.label | s2 [s, m1] | +| aliasing.cpp:226:12:226:12 | s [m1] | semmle.label | s [m1] | +| aliasing.cpp:227:8:227:8 | s [m1] | semmle.label | s [m1] | +| aliasing.cpp:227:10:227:11 | m1 | semmle.label | m1 | | arrays.cpp:6:12:6:21 | call to user_input | semmle.label | call to user_input | | arrays.cpp:7:8:7:13 | access to array | semmle.label | access to array | | arrays.cpp:8:8:8:13 | access to array | semmle.label | access to array | @@ -933,6 +970,13 @@ nodes | simple.cpp:92:11:92:20 | call to user_input | semmle.label | call to user_input | | simple.cpp:94:10:94:11 | a2 [i] | semmle.label | a2 [i] | | simple.cpp:94:13:94:13 | i | semmle.label | i | +| simple.cpp:104:5:104:5 | b [post update] [a, i] | semmle.label | b [post update] [a, i] | +| simple.cpp:104:5:104:24 | ... = ... | semmle.label | ... = ... | +| simple.cpp:104:7:104:7 | a [post update] [i] | semmle.label | a [post update] [i] | +| simple.cpp:104:13:104:22 | call to user_input | semmle.label | call to user_input | +| simple.cpp:106:10:106:11 | b2 [a, i] | semmle.label | b2 [a, i] | +| simple.cpp:106:13:106:13 | a [i] | semmle.label | a [i] | +| simple.cpp:106:15:106:15 | i | semmle.label | i | | struct_init.c:14:24:14:25 | ab [a] | semmle.label | ab [a] | | struct_init.c:15:8:15:9 | ab [a] | semmle.label | ab [a] | | struct_init.c:15:12:15:12 | a | semmle.label | a | @@ -998,6 +1042,8 @@ nodes | aliasing.cpp:176:13:176:14 | m1 | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:176:13:176:14 | m1 | m1 flows from $@ | aliasing.cpp:106:9:106:18 | call to user_input | call to user_input | | aliasing.cpp:189:15:189:16 | m1 | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:189:15:189:16 | m1 | m1 flows from $@ | aliasing.cpp:106:9:106:18 | call to user_input | call to user_input | | aliasing.cpp:201:15:201:16 | m1 | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:201:15:201:16 | m1 | m1 flows from $@ | aliasing.cpp:106:9:106:18 | call to user_input | call to user_input | +| aliasing.cpp:213:10:213:11 | m1 | aliasing.cpp:211:13:211:22 | call to user_input | aliasing.cpp:213:10:213:11 | m1 | m1 flows from $@ | aliasing.cpp:211:13:211:22 | call to user_input | call to user_input | +| aliasing.cpp:227:10:227:11 | m1 | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:227:10:227:11 | m1 | m1 flows from $@ | aliasing.cpp:106:9:106:18 | call to user_input | call to user_input | | arrays.cpp:7:8:7:13 | access to array | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:7:8:7:13 | access to array | access to array flows from $@ | arrays.cpp:6:12:6:21 | call to user_input | call to user_input | | arrays.cpp:8:8:8:13 | access to array | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:8:8:8:13 | access to array | access to array flows from $@ | arrays.cpp:6:12:6:21 | call to user_input | call to user_input | | arrays.cpp:9:8:9:11 | * ... | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:9:8:9:11 | * ... | * ... flows from $@ | arrays.cpp:6:12:6:21 | call to user_input | call to user_input | @@ -1046,6 +1092,7 @@ nodes | simple.cpp:67:13:67:13 | i | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:67:13:67:13 | i | i flows from $@ | simple.cpp:65:11:65:20 | call to user_input | call to user_input | | simple.cpp:84:14:84:20 | call to getf2f1 | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:84:14:84:20 | call to getf2f1 | call to getf2f1 flows from $@ | simple.cpp:83:17:83:26 | call to user_input | call to user_input | | simple.cpp:94:13:94:13 | i | simple.cpp:92:11:92:20 | call to user_input | simple.cpp:94:13:94:13 | i | i flows from $@ | simple.cpp:92:11:92:20 | call to user_input | call to user_input | +| simple.cpp:106:15:106:15 | i | simple.cpp:104:13:104:22 | call to user_input | simple.cpp:106:15:106:15 | i | i flows from $@ | simple.cpp:104:13:104:22 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:40:20:40:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:40:20:40:29 | call to user_input | call to user_input | diff --git a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp index e4d4f70edb0..829974a1b67 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp @@ -94,4 +94,16 @@ void single_field_test_typedef(A_typedef a) sink(a2.i); //$ ast,ir } +struct B { + A a; +}; + +void single_field_test_depth_2() +{ + B b; + b.a.i = user_input(); + B b2 = b; + sink(b2.a.i); //$ ast MISSING: ir +} + } // namespace Simple From 91debe8669259c24344f4ad4b6c19071346e4d6d Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Sat, 5 Dec 2020 15:15:57 +0100 Subject: [PATCH 030/343] C++: Add ReadNodes and implement local flow steps into them. --- .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 119 +++++++++++++++++- 1 file changed, 118 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 15fc2fa1d9a..f894c0d905e 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -15,7 +15,10 @@ cached private newtype TIRDataFlowNode = TInstructionNode(Instruction i) or TOperandNode(Operand op) or - TVariableNode(Variable var) + TVariableNode(Variable var) or + // `FieldNodes` are used as targets of certain `storeStep`s to implement handling of stores to + // nested structs. + TFieldNode(FieldAddressInstruction field) /** * A node in a data flow graph. @@ -170,6 +173,91 @@ class OperandNode extends Node, TOperandNode { override string toString() { result = this.getOperand().toString() } } +abstract private class SkippableInstruction extends Instruction { + abstract Instruction getSourceInstruction(); +} + +private Instruction skipSkippableInstructionsRec(SkippableInstruction skip) { + result = skip.getSourceInstruction() and not result instanceof SkippableInstruction + or + result = skipSkippableInstructionsRec(skip.getSourceInstruction()) +} + +private Instruction skipSkippableInstructions(Instruction instr) { + result = instr and not result instanceof SkippableInstruction + or + result = skipSkippableInstructionsRec(instr) +} + +private class SkippableCopyValueInstruction extends SkippableInstruction, CopyValueInstruction { + override Instruction getSourceInstruction() { result = this.getSourceValue() } +} + +private class SkippableConvertInstruction extends SkippableInstruction, ConvertInstruction { + override Instruction getSourceInstruction() { result = this.getUnary() } +} + +private class SkippableCheckedConvertInstruction extends SkippableInstruction, + CheckedConvertOrNullInstruction { + override Instruction getSourceInstruction() { result = this.getUnary() } +} + +private class SkippableInheritanceConversionInstruction extends SkippableInstruction, + InheritanceConversionInstruction { + override Instruction getSourceInstruction() { result = this.getUnary() } +} + +/** + * INTERNAL: do not use. Gets the `FieldNode` corresponding to `instr`, if + * `instr` is an instruction that propagates an address of a `FieldAddressInstruction`. + */ +FieldNode getFieldNodeForFieldInstruction(Instruction instr) { + result.getFieldInstruction() = skipSkippableInstructions(instr) +} + +/** + * INTERNAL: do not use. A `FieldNode` represents the state of an object after modifying one + * of its fields. + */ +class FieldNode extends Node, TFieldNode { + FieldAddressInstruction field; + + FieldNode() { this = TFieldNode(field) } + + /** Gets the `Field` of this `FieldNode`. */ + Field getField() { result = getFieldInstruction().getField() } + + /** Gets the `FieldAddressInstruction` of this `FieldNode`. */ + FieldAddressInstruction getFieldInstruction() { result = field } + + /** + * Gets the `FieldNode` corresponding to the parent field of this `FieldNode`, if any. + * + * For example, if `f` is the `FieldNode` for `c` in the expression `a.b.c`, then `f.getObjectNode()` + * gives the `FieldNode` of `b`, and `f.getObjectNode().getObjectNode()` has no result as `a` is + * not a field. + */ + FieldNode getObjectNode() { result = getFieldNodeForFieldInstruction(field.getObjectAddress()) } + + /** + * Gets the `FieldNode` that has this `FieldNode` as parent, if any. + * + * For example, if `f` is the `FieldNode` corresponding to `b` in `a.b.c`, then `f.getNextNode()` + * gives the `FieldNode` corresponding to `c`, and `f.getNextNode().getNextNode()`. + */ + FieldNode getNextNode() { result.getObjectNode() = this } + + /** Gets the class where the field of this node is declared. */ + Class getDeclaringType() { result = getField().getDeclaringType() } + + override Function getFunction() { result = field.getEnclosingFunction() } + + override IRType getType() { result = field.getResultIRType() } + + override Location getLocation() { result = field.getLocation() } + + override string toString() { result = this.getField().toString() } +} /** * An expression, viewed as a node in a data flow graph. */ @@ -585,6 +673,33 @@ Node uninitializedNode(LocalVariable v) { none() } */ predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFrom, nodeTo) } +private predicate flowIntoReadNode(Node nodeFrom, Node nodeTo) { + // flow from the "innermost" field to the load of that field. + exists(FieldNode fieldNode | nodeTo = fieldNode | + not exists(fieldNode.getObjectNode()) and + ( + exists(LoadInstruction load | + fieldNode.getNextNode*() = getFieldNodeForFieldInstruction(load.getSourceAddress()) and + nodeFrom.asInstruction() = load.getSourceValueOperand().getAnyDef() + ) + or + // We need this to make stores look like loads for the dataflow library. So when there's a store + // of the form x->y = z we need to make the field node corresponding to y look like it's reading + // from the memory of x. + exists(StoreInstruction store, ChiInstruction chi | + chi.getPartial() = store and + fieldNode.getNextNode*() = getFieldNodeForFieldInstruction(store.getDestinationAddress()) and + nodeFrom.asInstruction() = chi.getTotal() + ) + or + exists(ReadSideEffectInstruction read | + fieldNode.getNextNode*() = getFieldNodeForFieldInstruction(read.getArgumentDef()) and + nodeFrom.asOperand() = read.getSideEffectOperand() + ) + ) + ) +} + /** * INTERNAL: do not use. * @@ -598,6 +713,8 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { or // Instruction -> Operand flow simpleOperandLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asOperand()) + or + flowIntoReadNode(nodeFrom, nodeTo) } pragma[noinline] From 29301284214c481661aba4a946075c4cbd309ced Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Sat, 5 Dec 2020 15:21:26 +0100 Subject: [PATCH 031/343] C++: Implement read steps using ReadNodes. --- .../ir/dataflow/internal/DataFlowPrivate.qll | 94 +++++++++++++++---- 1 file changed, 77 insertions(+), 17 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index 762ce8d47b4..81769801c7d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll @@ -209,6 +209,13 @@ private class FieldContent extends Content, TFieldContent { predicate hasOffset(Class cl, int start, int end) { cl = c and start = startBit and end = endBit } Field getAField() { result = getAField(c, startBit, endBit) } + + pragma[noinline] + Field getADirectField() { + c = result.getDeclaringType() and + this.getAField() = result and + this.hasOffset(c, _, _) + } } private class CollectionContent extends Content, TCollectionContent { @@ -390,12 +397,16 @@ private Instruction skipCopyValueInstructions(Operand op) { result = skipOneCopyValueInstructionRec(op.getDef()) } +private class InexactLoadOperand extends LoadOperand { + InexactLoadOperand() { this.isDefinitionInexact() } +} + private predicate arrayReadStep(Node node1, ArrayContent a, Node node2) { a = TArrayContent() and // Explicit dereferences such as `*p` or `p[i]` where `p` is a pointer or array. - exists(LoadOperand operand, Instruction address | - operand.isDefinitionInexact() and + exists(InexactLoadOperand operand, Instruction address | node1.asInstruction() = operand.getAnyDef() and + not node1.asInstruction().isResultConflated() and operand = node2.asOperand() and address = skipCopyValueInstructions(operand.getAddressOperand()) and ( @@ -406,6 +417,53 @@ private predicate arrayReadStep(Node node1, ArrayContent a, Node node2) { ) } +/** Step from the value loaded by a `LoadInstruction` to the "outermost" loaded field. */ +private predicate instrToFieldNodeReadStep(FieldNode node1, FieldContent f, Node node2) { + ( + node1.getNextNode() = node2 + or + not exists(node1.getNextNode()) and + ( + exists(LoadInstruction load | + node2.asInstruction() = load and + node1 = getFieldNodeForFieldInstruction(load.getSourceAddress()) + ) + or + exists(ReadSideEffectInstruction read | + node2.asOperand() = read.getSideEffectOperand() and + node1 = getFieldNodeForFieldInstruction(read.getArgumentDef()) + ) + ) + ) and + f.getADirectField() = node1.getField() +} + +bindingset[result, i] +private int unbindInt(int i) { i <= result and i >= result } + +pragma[noinline] +private predicate getFieldNodeFromLoadOperand(FieldNode fieldNode, LoadOperand loadOperand) { + fieldNode = getFieldNodeForFieldInstruction(loadOperand.getAddressOperand().getDef()) +} + +// Sometimes there's no explicit field dereference. In such cases we use the IR alias analysis to +// determine the offset being, and deduce the field from this information. +private predicate aliasedReadStep(Node node1, FieldContent f, Node node2) { + exists(LoadOperand operand, Class c, int startBit, int endBit | + // Ensure that we don't already catch this store step using a `FieldNode`. + not exists(FieldNode node | + getFieldNodeFromLoadOperand(node, operand) and + instrToFieldNodeReadStep(node, f, _) + ) and + node1.asInstruction() = operand.getAnyDef() and + node2.asOperand() = operand and + not node1.asInstruction().isResultConflated() and + c = operand.getAnyDef().getResultType() and + f.hasOffset(c, startBit, endBit) and + operand.getUsedInterval(unbindInt(startBit), unbindInt(endBit)) + ) +} + /** * In cases such as: * ```cpp @@ -417,21 +475,23 @@ private predicate arrayReadStep(Node node1, ArrayContent a, Node node2) { * f(&x); * use(x); * ``` - * the load on `x` in `use(x)` will exactly overlap with its definition (in this case the definition - * is a `WriteSideEffect`). This predicate pops the `ArrayContent` (pushed by the store in `f`) - * from the access path. + * the store to `*pa` in `f` will push `ArrayContent` onto the access path. The `innerRead` predicate + * pops the `ArrayContent` off the access path when a value-to-pointer or value-to-reference conversion + * happens on the argument that is ends up as the target of such a store. */ -private predicate exactReadStep(Node node1, ArrayContent a, Node node2) { +private predicate innerReadSteap(Node node1, Content a, Node node2) { a = TArrayContent() and - exists(WriteSideEffectInstruction write, ChiInstruction chi | - not chi.isResultConflated() and - chi.getPartial() = write and + exists(WriteSideEffectInstruction write, CallInstruction call, Expr arg | + write.getPrimaryInstruction() = call and node1.asInstruction() = write and - node2.asInstruction() = chi and - // To distinquish this case from the `arrayReadStep` case we require that the entire variable was - // overwritten by the `WriteSideEffectInstruction` (i.e., there is a load that reads the - // entire variable). - exists(LoadInstruction load | load.getSourceValue() = chi) + ( + not exists(ChiInstruction chi | chi.getPartial() = write) + or + exists(ChiInstruction chi | chi.getPartial() = write and not chi.isResultConflated()) + ) and + node2.asInstruction() = write and + arg = call.getArgument(write.getIndex()).getUnconvertedResultExpression() and + (arg instanceof AddressOfExpr or arg.getConversion() instanceof ReferenceToExpr) ) } @@ -441,10 +501,10 @@ private predicate exactReadStep(Node node1, ArrayContent a, Node node2) { * `node2`. */ predicate readStep(Node node1, Content f, Node node2) { - fieldReadStep(node1, f, node2) or + aliasedReadStep(node1, f, node2) or arrayReadStep(node1, f, node2) or - exactReadStep(node1, f, node2) or - suppressArrayRead(node1, f, node2) + instrToFieldNodeReadStep(node1, f, node2) or + innerReadSteap(node1, f, node2) } /** From 7a2b69feedde326afb2ab1d5181cfd5aae71d086 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Sat, 5 Dec 2020 15:24:32 +0100 Subject: [PATCH 032/343] C++: Add partial definition class backed by an IPA. --- .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 248 ++++++++++-------- 1 file changed, 140 insertions(+), 108 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index f894c0d905e..39e232e68b3 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -18,7 +18,8 @@ private newtype TIRDataFlowNode = TVariableNode(Variable var) or // `FieldNodes` are used as targets of certain `storeStep`s to implement handling of stores to // nested structs. - TFieldNode(FieldAddressInstruction field) + TFieldNode(FieldAddressInstruction field) or + TPartialDefinitionNode(PartialDefinition pd) /** * A node in a data flow graph. @@ -258,6 +259,23 @@ class FieldNode extends Node, TFieldNode { override string toString() { result = this.getField().toString() } } + +/** + * INTERNAL: do not use. A `FieldNode` represents the state of an object after modifying one + * of its fields. + */ +class PostUpdateFieldNode extends PartialDefinition { + override FieldNode node; + + override FieldNode getPreUpdateNode() { result = node } + + override Expr getDefinedExpr() { + result = node.getFieldInstruction().getObjectAddress().getUnconvertedResultExpression() + } + + Field getField() { result = node.getField() } +} + /** * An expression, viewed as a node in a data flow graph. */ @@ -395,11 +413,37 @@ deprecated class UninitializedNode extends Node { * This class exists to match the interface used by Java. There are currently no non-abstract * classes that extend it. When we implement field flow, we can revisit this. */ -abstract class PostUpdateNode extends InstructionNode { +abstract class PostUpdateNode extends Node { /** * Gets the node before the state update. */ abstract Node getPreUpdateNode(); + + override Function getFunction() { result = getPreUpdateNode().getFunction() } + + override IRType getType() { result = getPreUpdateNode().getType() } + + override Location getLocation() { result = getPreUpdateNode().getLocation() } +} + +private newtype TPartialDefinition = + MkPartialDefinition(Node node) { + isPointerStoreNode(node, _, _) or + isArrayStoreNode(node, _, _) or + node instanceof FieldNode + } + +/** INTERNAL: do not use. A partial definition of a node. */ +abstract class PartialDefinition extends TPartialDefinition { + Node node; + + PartialDefinition() { this = MkPartialDefinition(node) } + + abstract Node getPreUpdateNode(); + + abstract Expr getDefinedExpr(); + + string toString() { result = node.toString() + " [partial definition]" } } /** @@ -415,132 +459,73 @@ abstract class PostUpdateNode extends InstructionNode { * setY(&x); // a partial definition of the object `x`. * ``` */ -abstract private class PartialDefinitionNode extends PostUpdateNode { - abstract Expr getDefinedExpr(); +class PartialDefinitionNode extends PostUpdateNode, TPartialDefinitionNode { + PartialDefinition pd; + + PartialDefinitionNode() { this = TPartialDefinitionNode(pd) } + + /** Gets the expression that is partially defined by this node, if any. */ + Expr getDefinedExpr() { result = pd.getDefinedExpr() } + + override Node getPreUpdateNode() { result = pd.getPreUpdateNode() } + + PartialDefinition getPartialDefinition() { result = pd } + + override string toString() { result = getPreUpdateNode().toString() + " [post update]" } } -private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { - override ChiInstruction instr; - StoreInstruction store; - - ExplicitFieldStoreQualifierNode() { - not instr.isResultConflated() and - instr.getPartial() = store and - ( - instr.getUpdatedInterval(_, _) or - store.getDestinationAddress() instanceof FieldAddressInstruction - ) - } - - // By using an operand as the result of this predicate we avoid the dataflow inconsistency errors - // caused by having multiple nodes sharing the same pre update node. This inconsistency error can cause - // a tuple explosion in the big step dataflow relation since it can make many nodes be the entry node - // into a big step. - override Node getPreUpdateNode() { result.asOperand() = instr.getTotalOperand() } - - override Expr getDefinedExpr() { - result = - store - .getDestinationAddress() - .(FieldAddressInstruction) - .getObjectAddress() - .getUnconvertedResultExpression() - } -} - -/** - * Not every store instruction generates a chi instruction that we can attach a PostUpdateNode to. - * For instance, an update to a field of a struct containing only one field. For these cases we - * attach the PostUpdateNode to the store instruction. There's no obvious pre update node for this case - * (as the entire memory is updated), so `getPreUpdateNode` is implemented as `none()`. - */ -private class ExplicitSingleFieldStoreQualifierNode extends PartialDefinitionNode { - override StoreInstruction instr; - - ExplicitSingleFieldStoreQualifierNode() { - not exists(ChiInstruction chi | chi.getPartial() = instr) and - // Without this condition any store would create a `PostUpdateNode`. - instr.getDestinationAddress() instanceof FieldAddressInstruction - } - - override Node getPreUpdateNode() { none() } - - override Expr getDefinedExpr() { - result = - instr - .getDestinationAddress() - .(FieldAddressInstruction) - .getObjectAddress() - .getUnconvertedResultExpression() - } -} - -private FieldAddressInstruction getFieldInstruction(Instruction instr) { - result = instr or - result = instr.(CopyValueInstruction).getUnary() -} - -/** - * The target of a `fieldStoreStepAfterArraySuppression` store step, which is used to convert - * an `ArrayContent` to a `FieldContent` when the `WriteSideEffect` instruction stores - * into a field. See the QLDoc for `suppressArrayRead` for an example of where such a conversion - * is inserted. - */ -private class WriteSideEffectFieldStoreQualifierNode extends PartialDefinitionNode { - override ChiInstruction instr; - WriteSideEffectInstruction write; - FieldAddressInstruction field; - - WriteSideEffectFieldStoreQualifierNode() { - not instr.isResultConflated() and - instr.getPartial() = write and - field = getFieldInstruction(write.getDestinationAddress()) - } - - override Node getPreUpdateNode() { result.asOperand() = instr.getTotalOperand() } - - override Expr getDefinedExpr() { - result = field.getObjectAddress().getUnconvertedResultExpression() - } +private predicate isArrayStoreNode( + InstructionNode node, ChiInstruction chi, PointerAddInstruction add +) { + chi = node.getInstruction() and + not chi.isResultConflated() and + exists(StoreInstruction store | + chi.getPartial() = store and + add = store.getDestinationAddress() + ) } /** * The `PostUpdateNode` that is the target of a `arrayStoreStepChi` store step. The overriden * `ChiInstruction` corresponds to the instruction represented by `node2` in `arrayStoreStepChi`. */ -private class ArrayStoreNode extends PartialDefinitionNode { - override ChiInstruction instr; +private class ArrayStoreNode extends PartialDefinition { + override InstructionNode node; + ChiInstruction chi; PointerAddInstruction add; - ArrayStoreNode() { - not instr.isResultConflated() and - exists(StoreInstruction store | - instr.getPartial() = store and - add = store.getDestinationAddress() - ) - } + ArrayStoreNode() { isArrayStoreNode(node, chi, add) } - override Node getPreUpdateNode() { result.asOperand() = instr.getTotalOperand() } + override Node getPreUpdateNode() { result.asOperand() = chi.getTotalOperand() } override Expr getDefinedExpr() { result = add.getLeft().getUnconvertedResultExpression() } } +private predicate isPointerStoreNode(InstructionNode node, ChiInstruction chi, LoadInstruction load) { + chi = node.getInstruction() and + not chi.isResultConflated() and + exists(StoreInstruction store | + chi.getPartial() = store and + load = store.getDestinationAddress().(CopyValueInstruction).getUnary() + ) +} + /** * The `PostUpdateNode` that is the target of a `arrayStoreStepChi` store step. The overriden * `ChiInstruction` corresponds to the instruction represented by `node2` in `arrayStoreStepChi`. */ -private class PointerStoreNode extends PostUpdateNode { - override ChiInstruction instr; +private class PointerStoreNode extends PartialDefinition { + override InstructionNode node; + ChiInstruction chi; + LoadInstruction load; - PointerStoreNode() { - not instr.isResultConflated() and - exists(StoreInstruction store | - instr.getPartial() = store and - store.getDestinationAddress().(CopyValueInstruction).getUnary() instanceof LoadInstruction - ) + PointerStoreNode() { isPointerStoreNode(node, chi, load) } + + override Node getPreUpdateNode() { result.asOperand() = chi.getTotalOperand() } + + override Expr getDefinedExpr() { + result = load.getSourceAddress().getUnconvertedResultExpression() } - - override Node getPreUpdateNode() { result.asOperand() = instr.getTotalOperand() } } /** @@ -553,7 +538,7 @@ private class PointerStoreNode extends PostUpdateNode { * returned. This node will have its `getArgument()` equal to `&x` and its * `getVariableAccess()` equal to `x`. */ -class DefinitionByReferenceNode extends InstructionNode { +class DefinitionByReferenceNode extends InstructionNode, PostUpdateNode { override WriteSideEffectInstruction instr; /** Gets the unconverted argument corresponding to this node. */ @@ -581,6 +566,22 @@ class DefinitionByReferenceNode extends InstructionNode { not exists(instr.getPrimaryInstruction().(CallInstruction).getStaticCallTarget()) and result = "output argument" } + + override Function getFunction() { result = instr.getEnclosingFunction() } + + override IRType getType() { result = instr.getResultIRType() } + + override Location getLocation() { result = instr.getLocation() } + + // Make the read side effect's side effect operand the pre update node of this write side effect. + // This ensures that we match up the parameter index of the parameter indirection's modification. + override Node getPreUpdateNode() { + exists(ReadSideEffectInstruction read | + read.getPrimaryInstruction() = instr.getPrimaryInstruction() and + read.getArgumentDef() = instr.getDestinationAddress() and + result.asOperand() = read.getSideEffectOperand() + ) + } } /** @@ -673,6 +674,35 @@ Node uninitializedNode(LocalVariable v) { none() } */ predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFrom, nodeTo) } +private predicate flowOutOfPostUpdate(PartialDefinitionNode nodeFrom, Node nodeTo) { + // flow from the "outermost" field to the `ChiInstruction`, or `StoreInstruction` + // if no `ChiInstruction` exists. + exists(AddressOperand addressOperand, PostUpdateFieldNode pd | + pd = nodeFrom.getPartialDefinition() and + not exists(pd.getPreUpdateNode().getObjectNode()) and + pd.getPreUpdateNode().getNextNode*() = getFieldNodeForFieldInstruction(addressOperand.getDef()) and + ( + exists(ChiInstruction chi | + nodeTo.asInstruction() = chi and + chi.getPartial().getAnOperand() = addressOperand + ) + or + exists(StoreInstruction store | + not exists(ChiInstruction chi | chi.getPartial() = store) and + nodeTo.asInstruction() = store and + store.getDestinationAddressOperand() = addressOperand + ) + ) + ) + or + // Note: This partial definition cannot be a `PostUpdateFieldNode` since these nodes do not have an + // operand node as their pre update node. + exists(PartialDefinition pd | + pd = nodeFrom.getPartialDefinition() and + nodeTo.asInstruction().(ChiInstruction).getTotalOperand() = pd.getPreUpdateNode().asOperand() + ) +} + private predicate flowIntoReadNode(Node nodeFrom, Node nodeTo) { // flow from the "innermost" field to the load of that field. exists(FieldNode fieldNode | nodeTo = fieldNode | @@ -715,6 +745,8 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { simpleOperandLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asOperand()) or flowIntoReadNode(nodeFrom, nodeTo) + or + flowOutOfPostUpdate(nodeFrom, nodeTo) } pragma[noinline] From f5a2603cc10d25271466ef6ceabe4664aa955cc9 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Sat, 5 Dec 2020 15:25:43 +0100 Subject: [PATCH 033/343] C++: Add store steps that target the new partial definitions. --- .../ir/dataflow/internal/DataFlowPrivate.qll | 193 +++++++----------- 1 file changed, 69 insertions(+), 124 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index 81769801c7d..73649da7594 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll @@ -228,69 +228,86 @@ private class ArrayContent extends Content, TArrayContent { override string toString() { result = "array content" } } -private predicate fieldStoreStepNoChi(Node node1, FieldContent f, PostUpdateNode node2) { - exists(StoreInstruction store, Class c | - store = node2.asInstruction() and +/** + * A store step from the value of a `StoreInstruction` to the "innermost" field of the destination. + * This predicate only holds when there is no `ChiInsturction` that merges the result of the + * `StoreInstruction` into a larger memory. + */ +private predicate instrToFieldNodeStoreStepNoChi( + Node node1, FieldContent f, PartialDefinitionNode node2 +) { + exists(StoreInstruction store, PostUpdateFieldNode post | + post = node2.getPartialDefinition() and + not exists(ChiInstruction chi | chi.getPartial() = store) and + post.getPreUpdateNode() = getFieldNodeForFieldInstruction(store.getDestinationAddress()) and store.getSourceValueOperand() = node1.asOperand() and - getWrittenField(store, f.(FieldContent).getAField(), c) and - f.hasOffset(c, _, _) + f.getADirectField() = post.getField() ) } -private FieldAddressInstruction getFieldInstruction(Instruction instr) { - result = instr or - result = instr.(CopyValueInstruction).getUnary() -} - -pragma[noinline] -private predicate getWrittenField(Instruction instr, Field f, Class c) { - exists(FieldAddressInstruction fa | - fa = - getFieldInstruction([ - instr.(StoreInstruction).getDestinationAddress(), - instr.(WriteSideEffectInstruction).getDestinationAddress() - ]) and - f = fa.getField() and - c = f.getDeclaringType() - ) -} - -private predicate fieldStoreStepChi(Node node1, FieldContent f, PostUpdateNode node2) { - exists(ChiPartialOperand operand, ChiInstruction chi | - chi.getPartialOperand() = operand and +/** + * A store step from a `StoreInstruction` to the "innermost" field + * of the destination. This predicate only holds when there exists a `ChiInstruction` that merges the + * result of the `StoreInstruction` into a larger memory. + */ +private predicate instrToFieldNodeStoreStepChi( + Node node1, FieldContent f, PartialDefinitionNode node2 +) { + exists( + ChiPartialOperand operand, StoreInstruction store, ChiInstruction chi, PostUpdateFieldNode post + | + post = node2.getPartialDefinition() and + not chi.isResultConflated() and node1.asOperand() = operand and - node2.asInstruction() = chi and - exists(Class c | - c = chi.getResultType() and - exists(int startBit, int endBit | - chi.getUpdatedInterval(startBit, endBit) and - f.hasOffset(c, startBit, endBit) - ) - or - getWrittenField(operand.getDef(), f.getAField(), c) and - f.hasOffset(c, _, _) - ) + chi.getPartialOperand() = operand and + store = operand.getDef() and + post.getPreUpdateNode() = getFieldNodeForFieldInstruction(store.getDestinationAddress()) and + f.getADirectField() = post.getField() ) } -private predicate arrayStoreStepChi(Node node1, ArrayContent a, PostUpdateNode node2) { +private predicate callableWithoutDefinitionStoreStep( + Node node1, FieldContent f, PartialDefinitionNode node2 +) { + exists( + WriteSideEffectInstruction write, ChiInstruction chi, PostUpdateFieldNode post, + Function callable + | + chi.getPartial() = write and + not chi.isResultConflated() and + post = node2.getPartialDefinition() and + node1.asInstruction() = write and + post.getPreUpdateNode() = getFieldNodeForFieldInstruction(write.getDestinationAddress()) and + f.getADirectField() = post.getField() and + callable = write.getPrimaryInstruction().(CallInstruction).getStaticCallTarget() and + not callable.hasDefinition() + ) +} + +/** + * A store step from a `StoreInstruction` to the `ChiInstruction` generated from assigning + * to a pointer or array indirection + */ +private predicate arrayStoreStepChi(Node node1, ArrayContent a, PartialDefinitionNode node2) { a = TArrayContent() and - exists(ChiPartialOperand operand, ChiInstruction chi, StoreInstruction store | + exists( + ChiPartialOperand operand, ChiInstruction chi, StoreInstruction store, PartialDefinition pd + | + pd = node2.getPartialDefinition() and chi.getPartialOperand() = operand and store = operand.getDef() and node1.asOperand() = operand and // This `ChiInstruction` will always have a non-conflated result because both `ArrayStoreNode` // and `PointerStoreNode` require it in their characteristic predicates. - node2.asInstruction() = chi and - ( - // `x[i] = taint()` - // This matches the characteristic predicate in `ArrayStoreNode`. - store.getDestinationAddress() instanceof PointerAddInstruction - or - // `*p = taint()` - // This matches the characteristic predicate in `PointerStoreNode`. - store.getDestinationAddress().(CopyValueInstruction).getUnary() instanceof LoadInstruction - ) + pd.getPreUpdateNode().asOperand() = chi.getTotalOperand() + | + // `x[i] = taint()` + // This matches the characteristic predicate in `ArrayStoreNode`. + store.getDestinationAddress() instanceof PointerAddInstruction + or + // `*p = taint()` + // This matches the characteristic predicate in `PointerStoreNode`. + store.getDestinationAddress().(CopyValueInstruction).getUnary() instanceof LoadInstruction ) } @@ -300,82 +317,10 @@ private predicate arrayStoreStepChi(Node node1, ArrayContent a, PostUpdateNode n * value of `node1`. */ predicate storeStep(Node node1, Content f, PostUpdateNode node2) { - fieldStoreStepNoChi(node1, f, node2) or - fieldStoreStepChi(node1, f, node2) or + instrToFieldNodeStoreStepNoChi(node1, f, node2) or + instrToFieldNodeStoreStepChi(node1, f, node2) or arrayStoreStepChi(node1, f, node2) or - fieldStoreStepAfterArraySuppression(node1, f, node2) -} - -// This predicate pushes the correct `FieldContent` onto the access path when the -// `suppressArrayRead` predicate has popped off an `ArrayContent`. -private predicate fieldStoreStepAfterArraySuppression( - Node node1, FieldContent f, PostUpdateNode node2 -) { - exists(WriteSideEffectInstruction write, ChiInstruction chi, Class c | - not chi.isResultConflated() and - node1.asInstruction() = chi and - node2.asInstruction() = chi and - chi.getPartial() = write and - getWrittenField(write, f.getAField(), c) and - f.hasOffset(c, _, _) - ) -} - -bindingset[result, i] -private int unbindInt(int i) { i <= result and i >= result } - -pragma[noinline] -private predicate getLoadedField(LoadInstruction load, Field f, Class c) { - exists(FieldAddressInstruction fa | - fa = load.getSourceAddress() and - f = fa.getField() and - c = f.getDeclaringType() - ) -} - -/** - * Holds if data can flow from `node1` to `node2` via a read of `f`. - * Thus, `node1` references an object with a field `f` whose value ends up in - * `node2`. - */ -private predicate fieldReadStep(Node node1, FieldContent f, Node node2) { - exists(LoadOperand operand | - node2.asOperand() = operand and - node1.asInstruction() = operand.getAnyDef() and - exists(Class c | - c = operand.getAnyDef().getResultType() and - exists(int startBit, int endBit | - operand.getUsedInterval(unbindInt(startBit), unbindInt(endBit)) and - f.hasOffset(c, startBit, endBit) - ) - or - getLoadedField(operand.getUse(), f.getAField(), c) and - f.hasOffset(c, _, _) - ) - ) -} - -/** - * When a store step happens in a function that looks like an array write such as: - * ```cpp - * void f(int* pa) { - * pa = source(); - * } - * ``` - * it can be a write to an array, but it can also happen that `f` is called as `f(&a.x)`. If that is - * the case, the `ArrayContent` that was written by the call to `f` should be popped off the access - * path, and a `FieldContent` containing `x` should be pushed instead. - * So this case pops `ArrayContent` off the access path, and the `fieldStoreStepAfterArraySuppression` - * predicate in `storeStep` ensures that we push the right `FieldContent` onto the access path. - */ -predicate suppressArrayRead(Node node1, ArrayContent a, Node node2) { - a = TArrayContent() and - exists(WriteSideEffectInstruction write, ChiInstruction chi | - node1.asInstruction() = write and - node2.asInstruction() = chi and - chi.getPartial() = write and - getWrittenField(write, _, _) - ) + callableWithoutDefinitionStoreStep(node1, f, node2) } private class ArrayToPointerConvertInstruction extends ConvertInstruction { From 145ab17f6bca931e4c36f54148b1ce3035f2994e Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Sat, 5 Dec 2020 15:26:24 +0100 Subject: [PATCH 034/343] Fix a bad join-order caused by the optimizer not seeing that `Node.getEnclosingCallable` is functional. This is fixed in the same way as in Java's DataFlowUtil: We make create a non-virtual dispatching `getEnclosingCallableImpl`, and implement `getEnclosingCallable` as a wrapper that uses the `unique` aggregate to tell the compiler that there is exactly 1 result. Tuple numbers from an arbitrarily chosen iteration of DataFlowImpl3::Stage4::fwdFlow0#fffff. Before: 4569 ~5% {5} r24 = SCAN DataFlowImpl3::Stage4::fwdFlow#fffff#prev_delta AS I OUTPUT I.<0>, I.<4> 'config', I.<1>, I.<2>, I.<3> 2876 ~1% {5} r25 = JOIN r24 WITH DataFlowImpl3::LocalFlowBigStep::localFlowEntry#ff AS R ON FIRST 2 OUTPUT r24.<2> 'cc', r24.<0>, r24.<3> 'argAp', r24.<4>, r24.<1> 'config' 409404537 ~0% {6} r26 = JOIN r25 WITH DataFlowImplCommon::getLocalCallContext#cpe#12#ff AS R ON FIRST 1 OUTPUT r25.<1>, R.<1>, r25.<0> 'cc', r25.<2> 'argAp', r25.<3>, r25.<4> 'config' 2876 ~0% {6} r27 = JOIN r26 WITH DataFlowUtil::Node::getEnclosingCallable_dispred#ff AS R ON FIRST 2 OUTPUT r26.<0>, true, r26.<5> 'config', r26.<2> 'cc', r26.<3> 'argAp', r26.<4> 79821 ~1781% {5} r28 = JOIN r27 WITH DataFlowImpl3::Stage4::localStep#ffbfff_0241#join_rhs AS R ON FIRST 3 OUTPUT r27.<3> 'cc', r27.<4> 'argAp', r27.<2> 'config', r27.<5> 'ap', R.<3> 'node' 2876 ~0% {5} r29 = JOIN r26 WITH DataFlowUtil::Node::getEnclosingCallable_dispred#ff AS R ON FIRST 2 OUTPUT r26.<4>, r26.<0>, r26.<2> 'cc', r26.<3> 'argAp', r26.<5> 'config' 0 ~0% {5} r30 = JOIN r29 WITH DataFlowImpl3::TNil#ff_1#join_rhs AS R ON FIRST 1 OUTPUT r29.<1>, false, r29.<4> 'config', r29.<2> 'cc', r29.<3> 'argAp' 0 ~0% {5} r31 = JOIN r30 WITH DataFlowImpl3::Stage4::localStep#ffbfff_02413#join_rhs AS R ON FIRST 3 OUTPUT r30.<3> 'cc', r30.<4> 'argAp', r30.<2> 'config', R.<4> 'ap', R.<3> 'node' 4569 ~157% {6} r32 = JOIN DataFlowImpl3::Stage4::fwdFlow0#fffff#join_rhs AS L WITH DataFlowImpl3::Stage4::fwdFlow#fffff#prev_delta AS R CARTESIAN PRODUCT OUTPUT R.<3>, L.<0> 'ap', L.<1> 'cc', L.<2> 'argAp', R.<0>, R.<4> 'config' 0 ~0% {5} r33 = JOIN r32 WITH DataFlowImpl3::TNil#ff_1#join_rhs AS R ON FIRST 1 OUTPUT r32.<4>, r32.<5> 'config', r32.<1> 'ap', r32.<2> 'cc', r32.<3> 'argAp' 0 ~0% {5} r34 = JOIN r33 WITH DataFlowImpl3::additionalJumpStep#fff_021#join_rhs AS R ON FIRST 2 OUTPUT R.<2> 'node', r33.<2> 'ap', r33.<3> 'cc', r33.<4> 'argAp', r33.<1> 'config' 0 ~0% {5} r35 = JOIN r34 WITH DataFlowUtil::TIRDataFlowNode#f@staged_ext AS R ON FIRST 1 OUTPUT r34.<0> 'node', r34.<1> 'ap', r34.<2> 'cc', r34.<3> 'argAp', r34.<4> 'config' 0 ~0% {6} r36 = JOIN r35 WITH project#DataFlowImpl3::Stage3::revFlow#fffff#12 AS R ON FIRST 1 OUTPUT r35.<1> 'ap', r35.<2> 'cc', r35.<3> 'argAp', r35.<4> 'config', r35.<0> 'node', R.<1> After: 4569 ~0% {5} r24 = SCAN DataFlowImpl3::Stage4::fwdFlow#fffff#prev_delta AS I OUTPUT I.<0>, I.<4> 'config', I.<1>, I.<2>, I.<3> 2876 ~0% {5} r25 = JOIN r24 WITH DataFlowImpl3::LocalFlowBigStep::localFlowEntry#ff AS R ON FIRST 2 OUTPUT r24.<0>, r24.<2> 'cc', r24.<3> 'argAp', r24.<4>, r24.<1> 'config' 2876 ~0% {6} r26 = JOIN r25 WITH DataFlowUtil::Node::getEnclosingCallable_dispred#ff AS R ON FIRST 1 OUTPUT r25.<1> 'cc', R.<1>, r25.<0>, r25.<2> 'argAp', r25.<3>, r25.<4> 'config' 2876 ~0% {6} r27 = JOIN r26 WITH DataFlowImplCommon::getLocalCallContext#cpe#12#fb AS R ON FIRST 2 OUTPUT r26.<2>, true, r26.<5> 'config', r26.<0> 'cc', r26.<3> 'argAp', r26.<4> 79821 ~1862% {5} r28 = JOIN r27 WITH DataFlowImpl3::Stage4::localStep#ffbfff_0241#join_rhs AS R ON FIRST 3 OUTPUT r27.<3> 'cc', r27.<4> 'argAp', r27.<2> 'config', r27.<5> 'ap', R.<3> 'node' 2876 ~0% {5} r29 = JOIN r26 WITH DataFlowImplCommon::getLocalCallContext#cpe#12#fb AS R ON FIRST 2 OUTPUT r26.<4>, r26.<2>, r26.<0> 'cc', r26.<3> 'argAp', r26.<5> 'config' 0 ~0% {5} r30 = JOIN r29 WITH DataFlowImpl3::TNil#ff_1#join_rhs AS R ON FIRST 1 OUTPUT r29.<1>, false, r29.<4> 'config', r29.<2> 'cc', r29.<3> 'argAp' 0 ~0% {5} r31 = JOIN r30 WITH DataFlowImpl3::Stage4::localStep#ffbfff_02413#join_rhs AS R ON FIRST 3 OUTPUT r30.<3> 'cc', r30.<4> 'argAp', r30.<2> 'config', R.<4> 'ap', R.<3> 'node' 4569 ~148% {6} r32 = JOIN DataFlowImpl3::Stage4::fwdFlow0#fffff#join_rhs AS L WITH DataFlowImpl3::Stage4::fwdFlow#fffff#prev_delta AS R CARTESIAN PRODUCT OUTPUT R.<3>, L.<0> 'ap', L.<1> 'cc', L.<2> 'argAp', R.<0>, R.<4> 'config' 0 ~0% {5} r33 = JOIN r32 WITH DataFlowImpl3::TNil#ff_1#join_rhs AS R ON FIRST 1 OUTPUT r32.<4>, r32.<5> 'config', r32.<1> 'ap', r32.<2> 'cc', r32.<3> 'argAp' 0 ~0% {5} r34 = JOIN r33 WITH DataFlowImpl3::additionalJumpStep#fff_021#join_rhs AS R ON FIRST 2 OUTPUT R.<2> 'node', r33.<2> 'ap', r33.<3> 'cc', r33.<4> 'argAp', r33.<1> 'config' 0 ~0% {5} r35 = JOIN r34 WITH DataFlowUtil::TIRDataFlowNode#f@staged_ext AS R ON FIRST 1 OUTPUT r34.<0> 'node', r34.<1> 'ap', r34.<2> 'cc', r34.<3> 'argAp', r34.<4> 'config' 0 ~0% {6} r36 = JOIN r35 WITH project#DataFlowImpl3::Stage3::revFlow#fffff#12 AS R ON FIRST 1 OUTPUT r35.<1> 'ap', r35.<2> 'cc', r35.<3> 'argAp', r35.<4> 'config', r35.<0> 'node', R.<1> --- .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 39e232e68b3..318ddf9c48d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -32,7 +32,22 @@ class Node extends TIRDataFlowNode { /** * INTERNAL: Do not use. */ - Declaration getEnclosingCallable() { none() } // overridden in subclasses + final Declaration getEnclosingCallable() { + result = unique(Declaration d | d = this.getEnclosingCallableImpl() | d) + } + + final private Declaration getEnclosingCallableImpl() { + result = this.asInstruction().getEnclosingFunction() or + result = this.asOperand().getUse().getEnclosingFunction() or + // When flow crosses from one _enclosing callable_ to another, the + // interprocedural data-flow library discards call contexts and inserts a + // node in the big-step relation used for human-readable path explanations. + // Therefore we want a distinct enclosing callable for each `VariableNode`, + // and that can be the `Variable` itself. + result = this.asVariable() or + result = this.(FieldNode).getFieldInstruction().getEnclosingFunction() or + result = this.(PartialDefinitionNode).getPreUpdateNode().getFunction() + } /** Gets the function to which this node belongs, if any. */ Function getFunction() { none() } // overridden in subclasses @@ -137,8 +152,6 @@ class InstructionNode extends Node, TInstructionNode { /** Gets the instruction corresponding to this node. */ Instruction getInstruction() { result = instr } - override Declaration getEnclosingCallable() { result = this.getFunction() } - override Function getFunction() { result = instr.getEnclosingFunction() } override IRType getType() { result = instr.getResultIRType() } @@ -163,8 +176,6 @@ class OperandNode extends Node, TOperandNode { /** Gets the operand corresponding to this node. */ Operand getOperand() { result = op } - override Declaration getEnclosingCallable() { result = this.getFunction() } - override Function getFunction() { result = op.getUse().getEnclosingFunction() } override IRType getType() { result = op.getIRType() } @@ -599,15 +610,6 @@ class VariableNode extends Node, TVariableNode { override Function getFunction() { none() } - override Declaration getEnclosingCallable() { - // When flow crosses from one _enclosing callable_ to another, the - // interprocedural data-flow library discards call contexts and inserts a - // node in the big-step relation used for human-readable path explanations. - // Therefore we want a distinct enclosing callable for each `VariableNode`, - // and that can be the `Variable` itself. - result = v - } - override IRType getType() { result.getCanonicalLanguageType().hasUnspecifiedType(v.getType(), _) } override Location getLocation() { result = v.getLocation() } From 72a80e37228d0aa737601f2217cb16dce72160ac Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Sat, 5 Dec 2020 15:41:39 +0100 Subject: [PATCH 035/343] C++: Accept test changes. --- .../dataflow-ir-consistency.expected | 65 +-- .../dataflow/dataflow-tests/test.cpp | 2 +- .../dataflow/fields/aliasing.cpp | 4 +- .../fields/dataflow-ir-consistency.expected | 203 +++----- .../dataflow/fields/ir-path-flow.expected | 449 ++++++++++++------ .../fields/partial-definition-diff.expected | 247 ++++------ .../fields/partial-definition-ir.expected | 247 ++++++++++ 7 files changed, 724 insertions(+), 493 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected index fc6c97aa2a6..b9f6f717c80 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected @@ -26,60 +26,21 @@ unreachableNodeCCtx localCallNodes postIsNotPre postHasUniquePre +| dispatch.cpp:15:8:15:8 | Top output argument | PostUpdateNode should have one pre-update node but has 0. | +| dispatch.cpp:21:8:21:8 | Middle output argument | PostUpdateNode should have one pre-update node but has 0. | +| dispatch.cpp:60:18:60:29 | Bottom output argument | PostUpdateNode should have one pre-update node but has 0. | +| dispatch.cpp:61:18:61:29 | Middle output argument | PostUpdateNode should have one pre-update node but has 0. | +| dispatch.cpp:65:10:65:21 | Bottom output argument | PostUpdateNode should have one pre-update node but has 0. | +| test.cpp:384:10:384:13 | memcpy output argument | PostUpdateNode should have one pre-update node but has 0. | +| test.cpp:391:10:391:13 | memcpy output argument | PostUpdateNode should have one pre-update node but has 0. | +| test.cpp:400:10:400:13 | memcpy output argument | PostUpdateNode should have one pre-update node but has 0. | +| test.cpp:407:10:407:13 | memcpy output argument | PostUpdateNode should have one pre-update node but has 0. | uniquePostUpdate postIsInSameCallable reverseRead argHasPostUpdate postWithInFlow -| BarrierGuard.cpp:49:3:49:17 | Chi | PostUpdateNode should not be the target of local flow. | -| BarrierGuard.cpp:60:3:60:18 | Chi | PostUpdateNode should not be the target of local flow. | -| clang.cpp:28:3:28:34 | Chi | PostUpdateNode should not be the target of local flow. | -| clang.cpp:34:22:34:27 | Chi | PostUpdateNode should not be the target of local flow. | -| clang.cpp:34:32:34:37 | Chi | PostUpdateNode should not be the target of local flow. | -| clang.cpp:39:32:39:37 | Chi | PostUpdateNode should not be the target of local flow. | -| clang.cpp:39:42:39:47 | Chi | PostUpdateNode should not be the target of local flow. | -| clang.cpp:43:35:43:40 | Chi | PostUpdateNode should not be the target of local flow. | -| clang.cpp:43:51:43:51 | Chi | PostUpdateNode should not be the target of local flow. | -| clang.cpp:49:25:49:30 | Chi | PostUpdateNode should not be the target of local flow. | -| clang.cpp:49:35:49:40 | Chi | PostUpdateNode should not be the target of local flow. | -| clang.cpp:50:3:50:26 | Chi | PostUpdateNode should not be the target of local flow. | -| example.c:17:19:17:22 | Chi | PostUpdateNode should not be the target of local flow. | -| example.c:17:21:17:21 | Chi | PostUpdateNode should not be the target of local flow. | -| example.c:24:2:24:30 | Chi | PostUpdateNode should not be the target of local flow. | -| example.c:24:13:24:30 | Chi | PostUpdateNode should not be the target of local flow. | -| example.c:26:2:26:25 | Chi | PostUpdateNode should not be the target of local flow. | -| file://:0:0:0:0 | Chi | PostUpdateNode should not be the target of local flow. | -| file://:0:0:0:0 | Chi | PostUpdateNode should not be the target of local flow. | -| file://:0:0:0:0 | Chi | PostUpdateNode should not be the target of local flow. | -| lambdas.cpp:13:12:13:12 | Chi | PostUpdateNode should not be the target of local flow. | -| lambdas.cpp:13:15:13:15 | Chi | PostUpdateNode should not be the target of local flow. | -| lambdas.cpp:28:10:31:2 | Chi | PostUpdateNode should not be the target of local flow. | -| lambdas.cpp:28:10:31:2 | Chi | PostUpdateNode should not be the target of local flow. | -| lambdas.cpp:43:3:43:14 | Chi | PostUpdateNode should not be the target of local flow. | -| ref.cpp:11:5:11:13 | Chi | PostUpdateNode should not be the target of local flow. | -| ref.cpp:20:5:20:13 | Chi | PostUpdateNode should not be the target of local flow. | -| ref.cpp:22:7:22:13 | Chi | PostUpdateNode should not be the target of local flow. | -| ref.cpp:24:7:24:13 | Chi | PostUpdateNode should not be the target of local flow. | -| ref.cpp:29:5:29:18 | Chi | PostUpdateNode should not be the target of local flow. | -| ref.cpp:31:7:31:13 | Chi | PostUpdateNode should not be the target of local flow. | -| ref.cpp:39:7:39:13 | Chi | PostUpdateNode should not be the target of local flow. | -| ref.cpp:44:5:44:18 | Chi | PostUpdateNode should not be the target of local flow. | -| ref.cpp:46:7:46:13 | Chi | PostUpdateNode should not be the target of local flow. | -| ref.cpp:48:7:48:13 | Chi | PostUpdateNode should not be the target of local flow. | -| ref.cpp:75:5:75:17 | Chi | PostUpdateNode should not be the target of local flow. | -| ref.cpp:83:5:83:17 | Chi | PostUpdateNode should not be the target of local flow. | -| ref.cpp:87:7:87:17 | Chi | PostUpdateNode should not be the target of local flow. | -| ref.cpp:89:7:89:17 | Chi | PostUpdateNode should not be the target of local flow. | -| ref.cpp:94:5:94:22 | Chi | PostUpdateNode should not be the target of local flow. | -| ref.cpp:96:7:96:17 | Chi | PostUpdateNode should not be the target of local flow. | -| ref.cpp:104:7:104:17 | Chi | PostUpdateNode should not be the target of local flow. | -| ref.cpp:109:5:109:22 | Chi | PostUpdateNode should not be the target of local flow. | -| ref.cpp:113:7:113:17 | Chi | PostUpdateNode should not be the target of local flow. | -| ref.cpp:115:7:115:17 | Chi | PostUpdateNode should not be the target of local flow. | -| test.cpp:91:3:91:18 | Chi | PostUpdateNode should not be the target of local flow. | -| test.cpp:115:3:115:17 | Chi | PostUpdateNode should not be the target of local flow. | -| test.cpp:120:3:120:10 | Chi | PostUpdateNode should not be the target of local flow. | -| test.cpp:125:3:125:11 | Chi | PostUpdateNode should not be the target of local flow. | -| test.cpp:359:5:359:20 | Chi | PostUpdateNode should not be the target of local flow. | -| test.cpp:373:5:373:20 | Chi | PostUpdateNode should not be the target of local flow. | -| test.cpp:465:3:465:15 | Chi | PostUpdateNode should not be the target of local flow. | +| test.cpp:384:10:384:13 | memcpy output argument | PostUpdateNode should not be the target of local flow. | +| test.cpp:391:10:391:13 | memcpy output argument | PostUpdateNode should not be the target of local flow. | +| test.cpp:400:10:400:13 | memcpy output argument | PostUpdateNode should not be the target of local flow. | +| test.cpp:407:10:407:13 | memcpy output argument | PostUpdateNode should not be the target of local flow. | diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp index f59552aa2dd..774ecddeab2 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp @@ -362,7 +362,7 @@ class FlowThroughFields { int f() { sink(field); // tainted or clean? Not sure. taintField(); - sink(field); // $ ast MISSING: ir + sink(field); // $ ast,ir } int calledAfterTaint() { diff --git a/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp b/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp index 8b3c0f29ab2..833e85600a6 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp @@ -210,7 +210,7 @@ void test_deep_struct_fields() { S2 s2; s2.s.m1 = user_input(); S s = s2.s; - sink(s.m1); // $ ast MISSING: ir + sink(s.m1); // $ ast,ir } void test_deep_struct_fields_no_flow() { @@ -224,7 +224,7 @@ void test_deep_struct_fields_taint_through_call() { S2 s2; taint_a_ptr(&s2.s.m1); S s = s2.s; - sink(s.m1); // $ ast MISSING: ir + sink(s.m1); // $ ast,ir } void test_deep_struct_fields_taint_through_call_no_flow() { diff --git a/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected index 23f8d07717f..e79aeea7e8e 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected @@ -16,149 +16,70 @@ unreachableNodeCCtx localCallNodes postIsNotPre postHasUniquePre -| simple.cpp:65:5:65:22 | Store | PostUpdateNode should have one pre-update node but has 0. | -| simple.cpp:92:5:92:22 | Store | PostUpdateNode should have one pre-update node but has 0. | -| simple.cpp:104:5:104:24 | Store | PostUpdateNode should have one pre-update node but has 0. | +| A.cpp:9:9:9:9 | C output argument | PostUpdateNode should have one pre-update node but has 0. | +| A.cpp:14:9:14:9 | C output argument | PostUpdateNode should have one pre-update node but has 0. | +| A.cpp:31:14:31:21 | B output argument | PostUpdateNode should have one pre-update node but has 0. | +| A.cpp:38:7:38:8 | C output argument | PostUpdateNode should have one pre-update node but has 0. | +| A.cpp:39:7:39:8 | C output argument | PostUpdateNode should have one pre-update node but has 0. | +| A.cpp:41:15:41:21 | C output argument | PostUpdateNode should have one pre-update node but has 0. | +| A.cpp:47:12:47:18 | C output argument | PostUpdateNode should have one pre-update node but has 0. | +| A.cpp:54:12:54:18 | B output argument | PostUpdateNode should have one pre-update node but has 0. | +| A.cpp:55:12:55:19 | C1 output argument | PostUpdateNode should have one pre-update node but has 0. | +| A.cpp:57:11:57:24 | B output argument | PostUpdateNode should have one pre-update node but has 0. | +| A.cpp:57:17:57:23 | C output argument | PostUpdateNode should have one pre-update node but has 0. | +| A.cpp:62:13:62:19 | B output argument | PostUpdateNode should have one pre-update node but has 0. | +| A.cpp:64:21:64:28 | C2 output argument | PostUpdateNode should have one pre-update node but has 0. | +| A.cpp:71:13:71:19 | B output argument | PostUpdateNode should have one pre-update node but has 0. | +| A.cpp:73:25:73:32 | C2 output argument | PostUpdateNode should have one pre-update node but has 0. | +| A.cpp:89:15:89:21 | B output argument | PostUpdateNode should have one pre-update node but has 0. | +| A.cpp:99:14:99:21 | C1 output argument | PostUpdateNode should have one pre-update node but has 0. | +| A.cpp:116:12:116:19 | C1 output argument | PostUpdateNode should have one pre-update node but has 0. | +| A.cpp:126:12:126:18 | C output argument | PostUpdateNode should have one pre-update node but has 0. | +| A.cpp:130:12:130:18 | B output argument | PostUpdateNode should have one pre-update node but has 0. | +| A.cpp:142:14:142:20 | C output argument | PostUpdateNode should have one pre-update node but has 0. | +| A.cpp:143:25:143:31 | B output argument | PostUpdateNode should have one pre-update node but has 0. | +| A.cpp:150:12:150:18 | B output argument | PostUpdateNode should have one pre-update node but has 0. | +| A.cpp:151:12:151:24 | D output argument | PostUpdateNode should have one pre-update node but has 0. | +| A.cpp:159:12:159:18 | B output argument | PostUpdateNode should have one pre-update node but has 0. | +| A.cpp:160:18:160:60 | MyList output argument | PostUpdateNode should have one pre-update node but has 0. | +| A.cpp:160:32:160:59 | MyList output argument | PostUpdateNode should have one pre-update node but has 0. | +| A.cpp:161:18:161:40 | MyList output argument | PostUpdateNode should have one pre-update node but has 0. | +| A.cpp:162:18:162:40 | MyList output argument | PostUpdateNode should have one pre-update node but has 0. | +| B.cpp:7:16:7:35 | Box1 output argument | PostUpdateNode should have one pre-update node but has 0. | +| B.cpp:8:16:8:27 | Box2 output argument | PostUpdateNode should have one pre-update node but has 0. | +| B.cpp:16:16:16:38 | Box1 output argument | PostUpdateNode should have one pre-update node but has 0. | +| B.cpp:17:16:17:27 | Box2 output argument | PostUpdateNode should have one pre-update node but has 0. | +| C.cpp:18:12:18:18 | C output argument | PostUpdateNode should have one pre-update node but has 0. | +| D.cpp:29:15:29:41 | Box2 output argument | PostUpdateNode should have one pre-update node but has 0. | +| D.cpp:29:24:29:40 | Box1 output argument | PostUpdateNode should have one pre-update node but has 0. | +| D.cpp:36:15:36:41 | Box2 output argument | PostUpdateNode should have one pre-update node but has 0. | +| D.cpp:36:24:36:40 | Box1 output argument | PostUpdateNode should have one pre-update node but has 0. | +| D.cpp:43:15:43:41 | Box2 output argument | PostUpdateNode should have one pre-update node but has 0. | +| D.cpp:43:24:43:40 | Box1 output argument | PostUpdateNode should have one pre-update node but has 0. | +| D.cpp:50:15:50:41 | Box2 output argument | PostUpdateNode should have one pre-update node but has 0. | +| D.cpp:50:24:50:40 | Box1 output argument | PostUpdateNode should have one pre-update node but has 0. | +| D.cpp:57:16:57:42 | Box2 output argument | PostUpdateNode should have one pre-update node but has 0. | +| D.cpp:57:25:57:41 | Box1 output argument | PostUpdateNode should have one pre-update node but has 0. | +| complex.cpp:22:11:22:17 | Foo output argument | PostUpdateNode should have one pre-update node but has 0. | +| complex.cpp:25:7:25:7 | Bar output argument | PostUpdateNode should have one pre-update node but has 0. | +| complex.cpp:48:9:48:10 | Outer output argument | PostUpdateNode should have one pre-update node but has 0. | +| complex.cpp:49:9:49:10 | Outer output argument | PostUpdateNode should have one pre-update node but has 0. | +| complex.cpp:50:9:50:10 | Outer output argument | PostUpdateNode should have one pre-update node but has 0. | +| complex.cpp:51:9:51:10 | Outer output argument | PostUpdateNode should have one pre-update node but has 0. | +| constructors.cpp:34:11:34:26 | Foo output argument | PostUpdateNode should have one pre-update node but has 0. | +| constructors.cpp:35:11:35:26 | Foo output argument | PostUpdateNode should have one pre-update node but has 0. | +| constructors.cpp:36:11:36:37 | Foo output argument | PostUpdateNode should have one pre-update node but has 0. | +| constructors.cpp:37:11:37:15 | Foo output argument | PostUpdateNode should have one pre-update node but has 0. | +| realistic.cpp:54:16:54:47 | memcpy output argument | PostUpdateNode should have one pre-update node but has 0. | +| realistic.cpp:60:16:60:18 | memcpy output argument | PostUpdateNode should have one pre-update node but has 0. | +| simple.cpp:34:11:34:15 | Foo output argument | PostUpdateNode should have one pre-update node but has 0. | +| simple.cpp:35:11:35:15 | Foo output argument | PostUpdateNode should have one pre-update node but has 0. | +| simple.cpp:36:11:36:15 | Foo output argument | PostUpdateNode should have one pre-update node but has 0. | +| simple.cpp:37:11:37:15 | Foo output argument | PostUpdateNode should have one pre-update node but has 0. | uniquePostUpdate postIsInSameCallable reverseRead argHasPostUpdate postWithInFlow -| A.cpp:25:7:25:17 | Chi | PostUpdateNode should not be the target of local flow. | -| A.cpp:27:22:27:32 | Chi | PostUpdateNode should not be the target of local flow. | -| A.cpp:98:12:98:18 | Chi | PostUpdateNode should not be the target of local flow. | -| A.cpp:100:5:100:13 | Chi | PostUpdateNode should not be the target of local flow. | -| A.cpp:142:7:142:20 | Chi | PostUpdateNode should not be the target of local flow. | -| A.cpp:143:7:143:31 | Chi | PostUpdateNode should not be the target of local flow. | -| A.cpp:183:7:183:20 | Chi | PostUpdateNode should not be the target of local flow. | -| A.cpp:184:7:184:23 | Chi | PostUpdateNode should not be the target of local flow. | -| B.cpp:6:15:6:24 | Chi | PostUpdateNode should not be the target of local flow. | -| B.cpp:15:15:15:27 | Chi | PostUpdateNode should not be the target of local flow. | -| B.cpp:35:7:35:22 | Chi | PostUpdateNode should not be the target of local flow. | -| B.cpp:36:7:36:22 | Chi | PostUpdateNode should not be the target of local flow. | -| B.cpp:46:7:46:21 | Chi | PostUpdateNode should not be the target of local flow. | -| C.cpp:22:12:22:21 | Chi | PostUpdateNode should not be the target of local flow. | -| C.cpp:22:12:22:21 | Chi | PostUpdateNode should not be the target of local flow. | -| C.cpp:24:5:24:25 | Chi | PostUpdateNode should not be the target of local flow. | -| C.cpp:24:16:24:25 | Chi | PostUpdateNode should not be the target of local flow. | -| D.cpp:9:21:9:28 | Chi | PostUpdateNode should not be the target of local flow. | -| D.cpp:11:29:11:36 | Chi | PostUpdateNode should not be the target of local flow. | -| D.cpp:16:21:16:27 | Chi | PostUpdateNode should not be the target of local flow. | -| D.cpp:18:29:18:35 | Chi | PostUpdateNode should not be the target of local flow. | -| D.cpp:28:15:28:24 | Chi | PostUpdateNode should not be the target of local flow. | -| D.cpp:35:15:35:24 | Chi | PostUpdateNode should not be the target of local flow. | -| D.cpp:42:15:42:24 | Chi | PostUpdateNode should not be the target of local flow. | -| D.cpp:49:15:49:24 | Chi | PostUpdateNode should not be the target of local flow. | -| D.cpp:56:15:56:24 | Chi | PostUpdateNode should not be the target of local flow. | -| D.cpp:57:5:57:42 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:9:3:9:22 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:13:3:13:21 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:17:3:17:21 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:21:12:21:12 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:21:15:21:15 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:22:12:22:12 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:22:15:22:15 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:23:12:23:12 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:23:15:23:15 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:35:12:35:12 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:35:15:35:15 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:37:3:37:24 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:40:12:40:12 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:40:15:40:15 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:42:3:42:22 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:47:12:47:12 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:47:15:47:15 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:49:3:49:25 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:52:12:52:12 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:52:15:52:15 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:54:3:54:22 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:59:12:59:12 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:59:15:59:15 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:60:3:60:22 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:70:19:70:19 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:70:22:70:22 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:72:3:72:21 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:77:19:77:19 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:77:22:77:22 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:79:3:79:22 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:84:19:84:19 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:84:22:84:22 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:86:3:86:21 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:91:19:91:19 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:91:22:91:22 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:92:3:92:23 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:98:3:98:21 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:106:3:106:20 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:111:15:111:19 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:147:15:147:22 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:175:15:175:22 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:181:15:181:22 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:187:15:187:22 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:194:15:194:22 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:200:15:200:24 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:205:15:205:24 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:211:3:211:24 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:218:3:218:24 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:225:15:225:22 | Chi | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:232:15:232:22 | Chi | PostUpdateNode should not be the target of local flow. | -| arrays.cpp:5:18:5:23 | Chi | PostUpdateNode should not be the target of local flow. | -| arrays.cpp:5:21:5:21 | Chi | PostUpdateNode should not be the target of local flow. | -| arrays.cpp:6:3:6:23 | Chi | PostUpdateNode should not be the target of local flow. | -| arrays.cpp:14:18:14:23 | Chi | PostUpdateNode should not be the target of local flow. | -| arrays.cpp:14:21:14:21 | Chi | PostUpdateNode should not be the target of local flow. | -| arrays.cpp:15:3:15:25 | Chi | PostUpdateNode should not be the target of local flow. | -| arrays.cpp:36:3:36:37 | Chi | PostUpdateNode should not be the target of local flow. | -| by_reference.cpp:12:5:12:16 | Chi | PostUpdateNode should not be the target of local flow. | -| by_reference.cpp:16:5:16:19 | Chi | PostUpdateNode should not be the target of local flow. | -| by_reference.cpp:84:3:84:25 | Chi | PostUpdateNode should not be the target of local flow. | -| by_reference.cpp:88:3:88:24 | Chi | PostUpdateNode should not be the target of local flow. | -| by_reference.cpp:92:3:92:20 | Chi | PostUpdateNode should not be the target of local flow. | -| by_reference.cpp:96:3:96:19 | Chi | PostUpdateNode should not be the target of local flow. | -| by_reference.cpp:102:21:102:39 | Chi | PostUpdateNode should not be the target of local flow. | -| by_reference.cpp:104:15:104:22 | Chi | PostUpdateNode should not be the target of local flow. | -| by_reference.cpp:106:21:106:41 | Chi | PostUpdateNode should not be the target of local flow. | -| by_reference.cpp:108:15:108:24 | Chi | PostUpdateNode should not be the target of local flow. | -| by_reference.cpp:122:21:122:38 | Chi | PostUpdateNode should not be the target of local flow. | -| by_reference.cpp:124:15:124:21 | Chi | PostUpdateNode should not be the target of local flow. | -| by_reference.cpp:126:21:126:40 | Chi | PostUpdateNode should not be the target of local flow. | -| by_reference.cpp:128:15:128:23 | Chi | PostUpdateNode should not be the target of local flow. | -| complex.cpp:11:22:11:27 | Chi | PostUpdateNode should not be the target of local flow. | -| complex.cpp:12:22:12:27 | Chi | PostUpdateNode should not be the target of local flow. | -| complex.cpp:14:26:14:26 | Chi | PostUpdateNode should not be the target of local flow. | -| complex.cpp:14:33:14:33 | Chi | PostUpdateNode should not be the target of local flow. | -| complex.cpp:22:11:22:17 | Chi | PostUpdateNode should not be the target of local flow. | -| complex.cpp:25:7:25:7 | Chi | PostUpdateNode should not be the target of local flow. | -| complex.cpp:42:16:42:16 | Chi | PostUpdateNode should not be the target of local flow. | -| complex.cpp:43:16:43:16 | Chi | PostUpdateNode should not be the target of local flow. | -| complex.cpp:53:12:53:12 | Chi | PostUpdateNode should not be the target of local flow. | -| complex.cpp:54:12:54:12 | Chi | PostUpdateNode should not be the target of local flow. | -| complex.cpp:55:12:55:12 | Chi | PostUpdateNode should not be the target of local flow. | -| complex.cpp:56:12:56:12 | Chi | PostUpdateNode should not be the target of local flow. | -| constructors.cpp:20:24:20:29 | Chi | PostUpdateNode should not be the target of local flow. | -| constructors.cpp:21:24:21:29 | Chi | PostUpdateNode should not be the target of local flow. | -| constructors.cpp:23:28:23:28 | Chi | PostUpdateNode should not be the target of local flow. | -| constructors.cpp:23:35:23:35 | Chi | PostUpdateNode should not be the target of local flow. | -| qualifiers.cpp:9:30:9:44 | Chi | PostUpdateNode should not be the target of local flow. | -| qualifiers.cpp:12:49:12:64 | Chi | PostUpdateNode should not be the target of local flow. | -| qualifiers.cpp:13:51:13:65 | Chi | PostUpdateNode should not be the target of local flow. | -| realistic.cpp:39:12:39:95 | Chi | PostUpdateNode should not be the target of local flow. | -| realistic.cpp:49:9:49:64 | Chi | PostUpdateNode should not be the target of local flow. | -| simple.cpp:20:24:20:29 | Chi | PostUpdateNode should not be the target of local flow. | -| simple.cpp:21:24:21:29 | Chi | PostUpdateNode should not be the target of local flow. | -| simple.cpp:23:28:23:28 | Chi | PostUpdateNode should not be the target of local flow. | -| simple.cpp:23:35:23:35 | Chi | PostUpdateNode should not be the target of local flow. | -| simple.cpp:65:5:65:22 | Store | PostUpdateNode should not be the target of local flow. | -| simple.cpp:83:9:83:28 | Chi | PostUpdateNode should not be the target of local flow. | -| simple.cpp:92:5:92:22 | Store | PostUpdateNode should not be the target of local flow. | -| simple.cpp:104:5:104:24 | Store | PostUpdateNode should not be the target of local flow. | -| struct_init.c:20:20:20:29 | Chi | PostUpdateNode should not be the target of local flow. | -| struct_init.c:20:34:20:34 | Chi | PostUpdateNode should not be the target of local flow. | -| struct_init.c:27:7:27:16 | Chi | PostUpdateNode should not be the target of local flow. | -| struct_init.c:27:21:27:21 | Chi | PostUpdateNode should not be the target of local flow. | -| struct_init.c:28:5:28:7 | Chi | PostUpdateNode should not be the target of local flow. | -| struct_init.c:36:10:36:24 | Chi | PostUpdateNode should not be the target of local flow. | -| struct_init.c:40:20:40:29 | Chi | PostUpdateNode should not be the target of local flow. | -| struct_init.c:40:34:40:34 | Chi | PostUpdateNode should not be the target of local flow. | -| struct_init.c:42:7:42:16 | Chi | PostUpdateNode should not be the target of local flow. | -| struct_init.c:42:21:42:21 | Chi | PostUpdateNode should not be the target of local flow. | -| struct_init.c:43:5:43:7 | Chi | PostUpdateNode should not be the target of local flow. | +| realistic.cpp:54:16:54:47 | memcpy output argument | PostUpdateNode should not be the target of local flow. | +| realistic.cpp:60:16:60:18 | memcpy output argument | PostUpdateNode should not be the target of local flow. | diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected index c8b70a74b3a..e787b9a5f0e 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected @@ -4,50 +4,62 @@ edges | A.cpp:55:12:55:19 | new | A.cpp:55:5:55:5 | set output argument [c] | | A.cpp:57:11:57:24 | B output argument [c] | A.cpp:57:28:57:30 | call to get | | A.cpp:57:17:57:23 | new | A.cpp:57:11:57:24 | B output argument [c] | -| A.cpp:98:12:98:18 | new | A.cpp:100:5:100:13 | Chi [a] | -| A.cpp:100:5:100:13 | Chi [a] | A.cpp:103:14:103:14 | *c [a] | -| A.cpp:103:14:103:14 | *c [a] | A.cpp:107:16:107:16 | a | +| A.cpp:98:12:98:18 | new | A.cpp:100:9:100:9 | a [post update] [a] | +| A.cpp:100:9:100:9 | a [post update] [a] | A.cpp:103:14:103:14 | *c [a] | +| A.cpp:103:14:103:14 | *c [a] | A.cpp:107:16:107:16 | a [a] | +| A.cpp:107:16:107:16 | a [a] | A.cpp:107:16:107:16 | a | | A.cpp:126:5:126:5 | Chi [c] | A.cpp:131:8:131:8 | f7 output argument [c] | | A.cpp:126:5:126:5 | set output argument [c] | A.cpp:126:5:126:5 | Chi [c] | +| A.cpp:126:5:126:5 | set output argument [c] | A.cpp:131:8:131:8 | f7 output argument [c] | | A.cpp:126:12:126:18 | new | A.cpp:126:5:126:5 | set output argument [c] | -| A.cpp:131:8:131:8 | Chi [c] | A.cpp:132:13:132:13 | c | -| A.cpp:131:8:131:8 | f7 output argument [c] | A.cpp:131:8:131:8 | Chi [c] | +| A.cpp:131:8:131:8 | f7 output argument [c] | A.cpp:132:13:132:13 | c [c] | +| A.cpp:132:13:132:13 | c [c] | A.cpp:132:13:132:13 | c | | A.cpp:142:7:142:20 | Chi [c] | A.cpp:151:18:151:18 | D output argument [c] | -| A.cpp:142:14:142:20 | new | A.cpp:142:7:142:20 | Chi [c] | +| A.cpp:142:10:142:10 | c [post update] [c] | A.cpp:142:7:142:20 | Chi [c] | +| A.cpp:142:10:142:10 | c [post update] [c] | A.cpp:151:18:151:18 | D output argument [c] | +| A.cpp:142:14:142:20 | new | A.cpp:142:10:142:10 | c [post update] [c] | | A.cpp:143:7:143:31 | Chi [b] | A.cpp:151:12:151:24 | D output argument [b] | -| A.cpp:143:25:143:31 | new | A.cpp:143:7:143:31 | Chi [b] | +| A.cpp:143:13:143:13 | b [post update] [b] | A.cpp:143:7:143:31 | Chi [b] | +| A.cpp:143:25:143:31 | new | A.cpp:143:13:143:13 | b [post update] [b] | | A.cpp:150:12:150:18 | new | A.cpp:151:12:151:24 | D output argument [b] | -| A.cpp:151:12:151:24 | Chi [b] | A.cpp:152:13:152:13 | b | -| A.cpp:151:12:151:24 | D output argument [b] | A.cpp:151:12:151:24 | Chi [b] | -| A.cpp:151:18:151:18 | Chi [c] | A.cpp:154:13:154:13 | c | -| A.cpp:151:18:151:18 | D output argument [c] | A.cpp:151:18:151:18 | Chi [c] | +| A.cpp:151:12:151:24 | D output argument [b] | A.cpp:152:13:152:13 | b [b] | +| A.cpp:151:18:151:18 | D output argument [c] | A.cpp:154:13:154:13 | c [c] | +| A.cpp:152:13:152:13 | b [b] | A.cpp:152:13:152:13 | b | +| A.cpp:154:13:154:13 | c [c] | A.cpp:154:13:154:13 | c | | C.cpp:18:12:18:18 | C output argument [s1] | C.cpp:27:8:27:11 | *#this [s1] | | C.cpp:18:12:18:18 | C output argument [s3] | C.cpp:27:8:27:11 | *#this [s3] | -| C.cpp:22:12:22:21 | Chi [s1] | C.cpp:24:5:24:25 | Chi [s1] | -| C.cpp:22:12:22:21 | new | C.cpp:22:12:22:21 | Chi [s1] | +| C.cpp:22:9:22:22 | s1 [post update] [s1] | C.cpp:24:5:24:25 | Chi [s1] | +| C.cpp:22:12:22:21 | new | C.cpp:22:9:22:22 | s1 [post update] [s1] | | C.cpp:24:5:24:25 | Chi [s1] | C.cpp:18:12:18:18 | C output argument [s1] | | C.cpp:24:5:24:25 | Chi [s3] | C.cpp:18:12:18:18 | C output argument [s3] | -| C.cpp:24:16:24:25 | new | C.cpp:24:5:24:25 | Chi [s3] | -| C.cpp:27:8:27:11 | *#this [s1] | C.cpp:29:10:29:11 | s1 | -| C.cpp:27:8:27:11 | *#this [s3] | C.cpp:31:10:31:11 | s3 | +| C.cpp:24:11:24:12 | s3 [post update] [s3] | C.cpp:24:5:24:25 | Chi [s3] | +| C.cpp:24:16:24:25 | new | C.cpp:24:11:24:12 | s3 [post update] [s3] | +| C.cpp:27:8:27:11 | *#this [s1] | C.cpp:29:10:29:11 | s1 [s1] | +| C.cpp:27:8:27:11 | *#this [s3] | C.cpp:31:10:31:11 | s3 [s3] | +| C.cpp:29:10:29:11 | s1 [s1] | C.cpp:29:10:29:11 | s1 | +| C.cpp:31:10:31:11 | s3 [s3] | C.cpp:31:10:31:11 | s3 | | aliasing.cpp:9:3:9:22 | Chi [m1] | aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | -| aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:9:3:9:22 | Chi [m1] | +| aliasing.cpp:9:6:9:7 | m1 [post update] [m1] | aliasing.cpp:9:3:9:22 | Chi [m1] | +| aliasing.cpp:9:6:9:7 | m1 [post update] [m1] | aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | +| aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:9:6:9:7 | m1 [post update] [m1] | | aliasing.cpp:13:3:13:21 | Chi [m1] | aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | -| aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:13:3:13:21 | Chi [m1] | -| aliasing.cpp:25:17:25:19 | Chi [m1] | aliasing.cpp:29:11:29:12 | m1 | -| aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | aliasing.cpp:25:17:25:19 | Chi [m1] | -| aliasing.cpp:26:19:26:20 | Chi [m1] | aliasing.cpp:30:11:30:12 | m1 | -| aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | aliasing.cpp:26:19:26:20 | Chi [m1] | +| aliasing.cpp:13:5:13:6 | m1 [post update] [m1] | aliasing.cpp:13:3:13:21 | Chi [m1] | +| aliasing.cpp:13:5:13:6 | m1 [post update] [m1] | aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | +| aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:13:5:13:6 | m1 [post update] [m1] | +| aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | aliasing.cpp:29:11:29:12 | m1 [m1] | +| aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | aliasing.cpp:30:11:30:12 | m1 [m1] | +| aliasing.cpp:29:11:29:12 | m1 [m1] | aliasing.cpp:29:11:29:12 | m1 | +| aliasing.cpp:30:11:30:12 | m1 [m1] | aliasing.cpp:30:11:30:12 | m1 | | aliasing.cpp:37:13:37:22 | call to user_input | aliasing.cpp:38:11:38:12 | m1 | | aliasing.cpp:42:11:42:20 | call to user_input | aliasing.cpp:43:13:43:14 | m1 | -| aliasing.cpp:60:3:60:22 | Chi [m1] | aliasing.cpp:61:13:61:14 | Store [m1] | -| aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:60:3:60:22 | Chi [m1] | -| aliasing.cpp:61:13:61:14 | Store [m1] | aliasing.cpp:62:14:62:15 | m1 | +| aliasing.cpp:60:6:60:7 | m1 [post update] [m1] | aliasing.cpp:62:14:62:15 | m1 [m1] | +| aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:60:6:60:7 | m1 [post update] [m1] | +| aliasing.cpp:62:14:62:15 | m1 [m1] | aliasing.cpp:62:14:62:15 | m1 | | aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | | aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | -| aliasing.cpp:98:3:98:21 | Chi [m1] | aliasing.cpp:100:14:100:14 | Store [m1] | -| aliasing.cpp:98:10:98:19 | call to user_input | aliasing.cpp:98:3:98:21 | Chi [m1] | +| aliasing.cpp:98:5:98:6 | m1 [post update] [m1] | aliasing.cpp:100:14:100:14 | Store [m1] | +| aliasing.cpp:98:10:98:19 | call to user_input | aliasing.cpp:98:5:98:6 | m1 [post update] [m1] | | aliasing.cpp:100:14:100:14 | Store [m1] | aliasing.cpp:102:8:102:10 | * ... | | aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:121:15:121:16 | taint_a_ptr output argument [array content] | | aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:126:15:126:20 | taint_a_ptr output argument [array content] | @@ -58,7 +70,19 @@ edges | aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:175:15:175:22 | taint_a_ptr output argument [array content] | | aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:187:15:187:22 | taint_a_ptr output argument [array content] | | aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:200:15:200:24 | taint_a_ptr output argument [array content] | -| aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:106:3:106:20 | Chi [array content] | +| aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:225:15:225:22 | taint_a_ptr output argument [array content] | +| aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | aliasing.cpp:106:3:106:20 | Chi [array content] | +| aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | aliasing.cpp:121:15:121:16 | taint_a_ptr output argument [array content] | +| aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | aliasing.cpp:126:15:126:20 | taint_a_ptr output argument [array content] | +| aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | aliasing.cpp:131:15:131:16 | taint_a_ptr output argument [array content] | +| aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | aliasing.cpp:136:15:136:17 | taint_a_ptr output argument [array content] | +| aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | aliasing.cpp:158:15:158:20 | taint_a_ptr output argument [array content] | +| aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | aliasing.cpp:164:15:164:20 | taint_a_ptr output argument [array content] | +| aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | aliasing.cpp:175:15:175:22 | taint_a_ptr output argument [array content] | +| aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | aliasing.cpp:187:15:187:22 | taint_a_ptr output argument [array content] | +| aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | aliasing.cpp:200:15:200:24 | taint_a_ptr output argument [array content] | +| aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | aliasing.cpp:225:15:225:22 | taint_a_ptr output argument [array content] | +| aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | | aliasing.cpp:121:15:121:16 | Chi [array content] | aliasing.cpp:122:8:122:12 | access to array | | aliasing.cpp:121:15:121:16 | taint_a_ptr output argument [array content] | aliasing.cpp:121:15:121:16 | Chi [array content] | | aliasing.cpp:126:15:126:20 | Chi [array content] | aliasing.cpp:127:8:127:16 | * ... | @@ -71,16 +95,37 @@ edges | aliasing.cpp:158:15:158:20 | taint_a_ptr output argument [array content] | aliasing.cpp:158:15:158:20 | Chi [array content] | | aliasing.cpp:164:15:164:20 | Chi [array content] | aliasing.cpp:165:8:165:16 | access to array | | aliasing.cpp:164:15:164:20 | taint_a_ptr output argument [array content] | aliasing.cpp:164:15:164:20 | Chi [array content] | -| aliasing.cpp:175:15:175:22 | Chi | aliasing.cpp:175:15:175:22 | Chi [m1] | -| aliasing.cpp:175:15:175:22 | Chi [m1] | aliasing.cpp:176:13:176:14 | m1 | -| aliasing.cpp:175:15:175:22 | taint_a_ptr output argument [array content] | aliasing.cpp:175:15:175:22 | Chi | -| aliasing.cpp:187:15:187:22 | Chi | aliasing.cpp:187:15:187:22 | Chi [m1] | -| aliasing.cpp:187:15:187:22 | Chi [m1] | aliasing.cpp:188:13:188:14 | Store [m1] | -| aliasing.cpp:187:15:187:22 | taint_a_ptr output argument [array content] | aliasing.cpp:187:15:187:22 | Chi | -| aliasing.cpp:188:13:188:14 | Store [m1] | aliasing.cpp:189:15:189:16 | m1 | -| aliasing.cpp:200:15:200:24 | Chi | aliasing.cpp:200:15:200:24 | Chi [m1] | -| aliasing.cpp:200:15:200:24 | Chi [m1] | aliasing.cpp:201:15:201:16 | m1 | -| aliasing.cpp:200:15:200:24 | taint_a_ptr output argument [array content] | aliasing.cpp:200:15:200:24 | Chi | +| aliasing.cpp:175:15:175:22 | taint_a_ptr output argument | aliasing.cpp:175:21:175:22 | m1 [post update] [m1] | +| aliasing.cpp:175:15:175:22 | taint_a_ptr output argument [array content] | aliasing.cpp:175:15:175:22 | taint_a_ptr output argument | +| aliasing.cpp:175:19:175:19 | s [post update] [s, m1] | aliasing.cpp:176:11:176:11 | s [s, m1] | +| aliasing.cpp:175:21:175:22 | m1 [post update] [m1] | aliasing.cpp:175:19:175:19 | s [post update] [s, m1] | +| aliasing.cpp:176:11:176:11 | s [s, m1] | aliasing.cpp:176:13:176:14 | m1 [m1] | +| aliasing.cpp:176:13:176:14 | m1 [m1] | aliasing.cpp:176:13:176:14 | m1 | +| aliasing.cpp:187:15:187:22 | taint_a_ptr output argument | aliasing.cpp:187:21:187:22 | m1 [post update] [m1] | +| aliasing.cpp:187:15:187:22 | taint_a_ptr output argument [array content] | aliasing.cpp:187:15:187:22 | taint_a_ptr output argument | +| aliasing.cpp:187:19:187:19 | s [post update] [s, m1] | aliasing.cpp:189:13:189:13 | s [s, m1] | +| aliasing.cpp:187:21:187:22 | m1 [post update] [m1] | aliasing.cpp:187:19:187:19 | s [post update] [s, m1] | +| aliasing.cpp:189:13:189:13 | s [s, m1] | aliasing.cpp:189:15:189:16 | m1 [m1] | +| aliasing.cpp:189:15:189:16 | m1 [m1] | aliasing.cpp:189:15:189:16 | m1 | +| aliasing.cpp:200:15:200:24 | taint_a_ptr output argument | aliasing.cpp:200:23:200:24 | m1 [post update] [m1] | +| aliasing.cpp:200:15:200:24 | taint_a_ptr output argument [array content] | aliasing.cpp:200:15:200:24 | taint_a_ptr output argument | +| aliasing.cpp:200:21:200:21 | s [post update] [s, m1] | aliasing.cpp:201:13:201:13 | s [s, m1] | +| aliasing.cpp:200:23:200:24 | m1 [post update] [m1] | aliasing.cpp:200:21:200:21 | s [post update] [s, m1] | +| aliasing.cpp:201:13:201:13 | s [s, m1] | aliasing.cpp:201:15:201:16 | m1 [m1] | +| aliasing.cpp:201:15:201:16 | m1 [m1] | aliasing.cpp:201:15:201:16 | m1 | +| aliasing.cpp:211:6:211:6 | s [post update] [s, m1] | aliasing.cpp:212:12:212:12 | s [s, m1] | +| aliasing.cpp:211:8:211:9 | m1 [post update] [m1] | aliasing.cpp:211:6:211:6 | s [post update] [s, m1] | +| aliasing.cpp:211:13:211:22 | call to user_input | aliasing.cpp:211:8:211:9 | m1 [post update] [m1] | +| aliasing.cpp:212:12:212:12 | s [m1] | aliasing.cpp:213:10:213:11 | m1 [m1] | +| aliasing.cpp:212:12:212:12 | s [s, m1] | aliasing.cpp:212:12:212:12 | s [m1] | +| aliasing.cpp:213:10:213:11 | m1 [m1] | aliasing.cpp:213:10:213:11 | m1 | +| aliasing.cpp:225:15:225:22 | taint_a_ptr output argument | aliasing.cpp:225:21:225:22 | m1 [post update] [m1] | +| aliasing.cpp:225:15:225:22 | taint_a_ptr output argument [array content] | aliasing.cpp:225:15:225:22 | taint_a_ptr output argument | +| aliasing.cpp:225:19:225:19 | s [post update] [s, m1] | aliasing.cpp:226:12:226:12 | s [s, m1] | +| aliasing.cpp:225:21:225:22 | m1 [post update] [m1] | aliasing.cpp:225:19:225:19 | s [post update] [s, m1] | +| aliasing.cpp:226:12:226:12 | s [m1] | aliasing.cpp:227:10:227:11 | m1 [m1] | +| aliasing.cpp:226:12:226:12 | s [s, m1] | aliasing.cpp:226:12:226:12 | s [m1] | +| aliasing.cpp:227:10:227:11 | m1 [m1] | aliasing.cpp:227:10:227:11 | m1 | | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:7:8:7:13 | access to array | | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:9:8:9:11 | * ... | | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:10:8:10:15 | * ... | @@ -96,65 +141,118 @@ edges | by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:68:17:68:18 | nonMemberSetA output argument [a] | | by_reference.cpp:84:3:84:25 | Chi [a] | by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | | by_reference.cpp:84:3:84:25 | Chi [a] | by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | -| by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:84:3:84:25 | Chi [a] | +| by_reference.cpp:84:10:84:10 | a [post update] [a] | by_reference.cpp:84:3:84:25 | Chi [a] | +| by_reference.cpp:84:10:84:10 | a [post update] [a] | by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | +| by_reference.cpp:84:10:84:10 | a [post update] [a] | by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | +| by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:84:10:84:10 | a [post update] [a] | | by_reference.cpp:88:3:88:24 | Chi [a] | by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | | by_reference.cpp:88:3:88:24 | Chi [a] | by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | -| by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:88:3:88:24 | Chi [a] | +| by_reference.cpp:88:9:88:9 | a [post update] [a] | by_reference.cpp:88:3:88:24 | Chi [a] | +| by_reference.cpp:88:9:88:9 | a [post update] [a] | by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | +| by_reference.cpp:88:9:88:9 | a [post update] [a] | by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | +| by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:88:9:88:9 | a [post update] [a] | | by_reference.cpp:92:3:92:20 | Chi [array content] | by_reference.cpp:104:15:104:22 | taint_a_ptr output argument [array content] | | by_reference.cpp:92:3:92:20 | Chi [array content] | by_reference.cpp:108:15:108:24 | taint_a_ptr output argument [array content] | -| by_reference.cpp:92:9:92:18 | call to user_input | by_reference.cpp:92:3:92:20 | Chi [array content] | +| by_reference.cpp:92:3:92:20 | ChiTotal [post update] [array content] | by_reference.cpp:92:3:92:20 | Chi [array content] | +| by_reference.cpp:92:3:92:20 | ChiTotal [post update] [array content] | by_reference.cpp:104:15:104:22 | taint_a_ptr output argument [array content] | +| by_reference.cpp:92:3:92:20 | ChiTotal [post update] [array content] | by_reference.cpp:108:15:108:24 | taint_a_ptr output argument [array content] | +| by_reference.cpp:92:9:92:18 | call to user_input | by_reference.cpp:92:3:92:20 | ChiTotal [post update] [array content] | | by_reference.cpp:96:3:96:19 | Chi [array content] | by_reference.cpp:124:15:124:21 | taint_a_ref output argument [array content] | | by_reference.cpp:96:3:96:19 | Chi [array content] | by_reference.cpp:128:15:128:23 | taint_a_ref output argument [array content] | -| by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:96:3:96:19 | Chi [array content] | -| by_reference.cpp:102:21:102:39 | Chi [a] | by_reference.cpp:110:27:110:27 | a | -| by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | by_reference.cpp:102:21:102:39 | Chi [a] | -| by_reference.cpp:104:15:104:22 | Chi | by_reference.cpp:104:15:104:22 | Chi [a] | -| by_reference.cpp:104:15:104:22 | Chi [a] | by_reference.cpp:112:14:112:14 | a | -| by_reference.cpp:104:15:104:22 | taint_a_ptr output argument [array content] | by_reference.cpp:104:15:104:22 | Chi | -| by_reference.cpp:106:21:106:41 | Chi [a] | by_reference.cpp:114:29:114:29 | a | -| by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | by_reference.cpp:106:21:106:41 | Chi [a] | -| by_reference.cpp:108:15:108:24 | Chi | by_reference.cpp:108:15:108:24 | Chi [a] | -| by_reference.cpp:108:15:108:24 | Chi [a] | by_reference.cpp:116:16:116:16 | a | -| by_reference.cpp:108:15:108:24 | taint_a_ptr output argument [array content] | by_reference.cpp:108:15:108:24 | Chi | -| by_reference.cpp:122:21:122:38 | Chi [a] | by_reference.cpp:130:27:130:27 | a | -| by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | by_reference.cpp:122:21:122:38 | Chi [a] | -| by_reference.cpp:124:15:124:21 | Chi | by_reference.cpp:124:15:124:21 | Chi [a] | -| by_reference.cpp:124:15:124:21 | Chi [a] | by_reference.cpp:132:14:132:14 | a | -| by_reference.cpp:124:15:124:21 | taint_a_ref output argument [array content] | by_reference.cpp:124:15:124:21 | Chi | -| by_reference.cpp:126:21:126:40 | Chi [a] | by_reference.cpp:134:29:134:29 | a | -| by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | by_reference.cpp:126:21:126:40 | Chi [a] | -| by_reference.cpp:128:15:128:23 | Chi | by_reference.cpp:128:15:128:23 | Chi [a] | -| by_reference.cpp:128:15:128:23 | Chi [a] | by_reference.cpp:136:16:136:16 | a | -| by_reference.cpp:128:15:128:23 | taint_a_ref output argument [array content] | by_reference.cpp:128:15:128:23 | Chi | +| by_reference.cpp:96:3:96:19 | ChiTotal [post update] [array content] | by_reference.cpp:96:3:96:19 | Chi [array content] | +| by_reference.cpp:96:3:96:19 | ChiTotal [post update] [array content] | by_reference.cpp:124:15:124:21 | taint_a_ref output argument [array content] | +| by_reference.cpp:96:3:96:19 | ChiTotal [post update] [array content] | by_reference.cpp:128:15:128:23 | taint_a_ref output argument [array content] | +| by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:96:3:96:19 | ChiTotal [post update] [array content] | +| by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | by_reference.cpp:102:28:102:39 | inner_nested [post update] [a, a] | +| by_reference.cpp:102:28:102:39 | inner_nested [post update] [a, a] | by_reference.cpp:110:14:110:25 | inner_nested [a, a] | +| by_reference.cpp:104:15:104:22 | taint_a_ptr output argument | by_reference.cpp:104:22:104:22 | a [post update] [a] | +| by_reference.cpp:104:15:104:22 | taint_a_ptr output argument [array content] | by_reference.cpp:104:15:104:22 | taint_a_ptr output argument | +| by_reference.cpp:104:22:104:22 | a [post update] [a] | by_reference.cpp:112:14:112:14 | a [a] | +| by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | by_reference.cpp:106:30:106:41 | inner_nested [post update] [a, a] | +| by_reference.cpp:106:30:106:41 | inner_nested [post update] [a, a] | by_reference.cpp:114:16:114:27 | inner_nested [a, a] | +| by_reference.cpp:108:15:108:24 | taint_a_ptr output argument | by_reference.cpp:108:24:108:24 | a [post update] [a] | +| by_reference.cpp:108:15:108:24 | taint_a_ptr output argument [array content] | by_reference.cpp:108:15:108:24 | taint_a_ptr output argument | +| by_reference.cpp:108:24:108:24 | a [post update] [a] | by_reference.cpp:116:16:116:16 | a [a] | +| by_reference.cpp:110:14:110:25 | inner_nested [a, a] | by_reference.cpp:110:27:110:27 | a [a] | +| by_reference.cpp:110:27:110:27 | a [a] | by_reference.cpp:110:27:110:27 | a | +| by_reference.cpp:112:14:112:14 | a [a] | by_reference.cpp:112:14:112:14 | a | +| by_reference.cpp:114:16:114:27 | inner_nested [a, a] | by_reference.cpp:114:29:114:29 | a [a] | +| by_reference.cpp:114:29:114:29 | a [a] | by_reference.cpp:114:29:114:29 | a | +| by_reference.cpp:116:16:116:16 | a [a] | by_reference.cpp:116:16:116:16 | a | +| by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | by_reference.cpp:122:27:122:38 | inner_nested [post update] [a, a] | +| by_reference.cpp:122:27:122:38 | inner_nested [post update] [a, a] | by_reference.cpp:130:14:130:25 | inner_nested [a, a] | +| by_reference.cpp:124:15:124:21 | taint_a_ref output argument | by_reference.cpp:124:21:124:21 | a [post update] [a] | +| by_reference.cpp:124:15:124:21 | taint_a_ref output argument [array content] | by_reference.cpp:124:15:124:21 | taint_a_ref output argument | +| by_reference.cpp:124:21:124:21 | a [post update] [a] | by_reference.cpp:132:14:132:14 | a [a] | +| by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | by_reference.cpp:126:29:126:40 | inner_nested [post update] [a, a] | +| by_reference.cpp:126:29:126:40 | inner_nested [post update] [a, a] | by_reference.cpp:134:16:134:27 | inner_nested [a, a] | +| by_reference.cpp:128:15:128:23 | taint_a_ref output argument | by_reference.cpp:128:23:128:23 | a [post update] [a] | +| by_reference.cpp:128:15:128:23 | taint_a_ref output argument [array content] | by_reference.cpp:128:15:128:23 | taint_a_ref output argument | +| by_reference.cpp:128:23:128:23 | a [post update] [a] | by_reference.cpp:136:16:136:16 | a [a] | +| by_reference.cpp:130:14:130:25 | inner_nested [a, a] | by_reference.cpp:130:27:130:27 | a [a] | +| by_reference.cpp:130:27:130:27 | a [a] | by_reference.cpp:130:27:130:27 | a | +| by_reference.cpp:132:14:132:14 | a [a] | by_reference.cpp:132:14:132:14 | a | +| by_reference.cpp:134:16:134:27 | inner_nested [a, a] | by_reference.cpp:134:29:134:29 | a [a] | +| by_reference.cpp:134:29:134:29 | a [a] | by_reference.cpp:134:29:134:29 | a | +| by_reference.cpp:136:16:136:16 | a [a] | by_reference.cpp:136:16:136:16 | a | | complex.cpp:40:17:40:17 | *b [a_] | complex.cpp:42:18:42:18 | call to a | -| complex.cpp:40:17:40:17 | *b [b_] | complex.cpp:42:16:42:16 | Chi [b_] | | complex.cpp:40:17:40:17 | *b [b_] | complex.cpp:42:16:42:16 | a output argument [b_] | | complex.cpp:40:17:40:17 | *b [b_] | complex.cpp:43:18:43:18 | call to b | -| complex.cpp:42:16:42:16 | Chi [b_] | complex.cpp:43:18:43:18 | call to b | -| complex.cpp:42:16:42:16 | a output argument [b_] | complex.cpp:42:16:42:16 | Chi [b_] | +| complex.cpp:40:17:40:17 | *b [f, f, a_] | complex.cpp:42:10:42:14 | inner [f, f, a_] | +| complex.cpp:40:17:40:17 | *b [f, f, b_] | complex.cpp:42:10:42:14 | inner [f, f, b_] | +| complex.cpp:40:17:40:17 | *b [f, f, b_] | complex.cpp:42:16:42:16 | a output argument [f, f, b_] | +| complex.cpp:40:17:40:17 | *b [f, f, b_] | complex.cpp:43:10:43:14 | inner [f, f, b_] | +| complex.cpp:40:17:40:17 | *b [f, f, f, f, a_] | complex.cpp:42:10:42:14 | inner [f, f, f, f, a_] | +| complex.cpp:42:10:42:14 | inner [f, f, a_] | complex.cpp:42:16:42:16 | f [f, a_] | +| complex.cpp:42:10:42:14 | inner [f, f, b_] | complex.cpp:42:16:42:16 | f [f, b_] | +| complex.cpp:42:10:42:14 | inner [f, f, f, f, a_] | complex.cpp:42:16:42:16 | f [f, f, f, a_] | +| complex.cpp:42:10:42:14 | inner [post update] [f, f, b_] | complex.cpp:43:10:43:14 | inner [f, f, b_] | +| complex.cpp:42:10:42:14 | inner [post update] [f, f, f, f, b_] | complex.cpp:43:10:43:14 | inner [f, f, f, f, b_] | +| complex.cpp:42:16:42:16 | a output argument [b_] | complex.cpp:42:16:42:16 | f [post update] [f, b_] | | complex.cpp:42:16:42:16 | a output argument [b_] | complex.cpp:43:18:43:18 | call to b | -| complex.cpp:53:12:53:12 | Chi [a_] | complex.cpp:40:17:40:17 | *b [a_] | +| complex.cpp:42:16:42:16 | a output argument [f, f, b_] | complex.cpp:42:16:42:16 | f [post update] [f, f, f, b_] | +| complex.cpp:42:16:42:16 | a output argument [f, f, b_] | complex.cpp:43:10:43:14 | inner [f, f, b_] | +| complex.cpp:42:16:42:16 | f [f, a_] | complex.cpp:42:18:42:18 | call to a | +| complex.cpp:42:16:42:16 | f [f, b_] | complex.cpp:42:16:42:16 | a output argument [b_] | +| complex.cpp:42:16:42:16 | f [f, f, f, a_] | complex.cpp:42:10:42:14 | inner [f, f, a_] | +| complex.cpp:42:16:42:16 | f [post update] [f, b_] | complex.cpp:42:10:42:14 | inner [post update] [f, f, b_] | +| complex.cpp:42:16:42:16 | f [post update] [f, f, f, b_] | complex.cpp:42:10:42:14 | inner [post update] [f, f, f, f, b_] | +| complex.cpp:43:10:43:14 | inner [f, f, b_] | complex.cpp:43:16:43:16 | f [f, b_] | +| complex.cpp:43:10:43:14 | inner [f, f, f, f, b_] | complex.cpp:43:16:43:16 | f [f, f, f, b_] | +| complex.cpp:43:16:43:16 | f [f, b_] | complex.cpp:43:18:43:18 | call to b | +| complex.cpp:43:16:43:16 | f [f, f, f, b_] | complex.cpp:43:10:43:14 | inner [f, f, b_] | +| complex.cpp:53:6:53:10 | inner [post update] [f, f, a_] | complex.cpp:40:17:40:17 | *b [f, f, a_] | +| complex.cpp:53:12:53:12 | f [post update] [f, a_] | complex.cpp:53:6:53:10 | inner [post update] [f, f, a_] | | complex.cpp:53:12:53:12 | setA output argument [a_] | complex.cpp:40:17:40:17 | *b [a_] | -| complex.cpp:53:12:53:12 | setA output argument [a_] | complex.cpp:53:12:53:12 | Chi [a_] | +| complex.cpp:53:12:53:12 | setA output argument [a_] | complex.cpp:53:12:53:12 | f [post update] [f, a_] | | complex.cpp:53:19:53:28 | call to user_input | complex.cpp:53:12:53:12 | setA output argument [a_] | -| complex.cpp:54:12:54:12 | Chi [b_] | complex.cpp:40:17:40:17 | *b [b_] | +| complex.cpp:54:6:54:10 | inner [post update] [f, f, b_] | complex.cpp:40:17:40:17 | *b [f, f, b_] | +| complex.cpp:54:12:54:12 | f [post update] [f, b_] | complex.cpp:54:6:54:10 | inner [post update] [f, f, b_] | | complex.cpp:54:12:54:12 | setB output argument [b_] | complex.cpp:40:17:40:17 | *b [b_] | -| complex.cpp:54:12:54:12 | setB output argument [b_] | complex.cpp:54:12:54:12 | Chi [b_] | +| complex.cpp:54:12:54:12 | setB output argument [b_] | complex.cpp:54:12:54:12 | f [post update] [f, b_] | | complex.cpp:54:19:54:28 | call to user_input | complex.cpp:54:12:54:12 | setB output argument [b_] | -| complex.cpp:55:12:55:12 | Chi [a_] | complex.cpp:40:17:40:17 | *b [a_] | -| complex.cpp:55:12:55:12 | Chi [a_] | complex.cpp:56:12:56:12 | Chi [a_] | -| complex.cpp:55:12:55:12 | Chi [a_] | complex.cpp:56:12:56:12 | setB output argument [a_] | +| complex.cpp:55:6:55:10 | inner [post update] [f, f, a_] | complex.cpp:40:17:40:17 | *b [f, f, a_] | +| complex.cpp:55:6:55:10 | inner [post update] [f, f, a_] | complex.cpp:56:6:56:10 | inner [f, f, a_] | +| complex.cpp:55:6:55:10 | inner [post update] [f, f, a_] | complex.cpp:56:12:56:12 | setB output argument [f, f, a_] | +| complex.cpp:55:12:55:12 | f [post update] [f, a_] | complex.cpp:55:6:55:10 | inner [post update] [f, f, a_] | | complex.cpp:55:12:55:12 | setA output argument [a_] | complex.cpp:40:17:40:17 | *b [a_] | -| complex.cpp:55:12:55:12 | setA output argument [a_] | complex.cpp:55:12:55:12 | Chi [a_] | -| complex.cpp:55:12:55:12 | setA output argument [a_] | complex.cpp:56:12:56:12 | Chi [a_] | +| complex.cpp:55:12:55:12 | setA output argument [a_] | complex.cpp:55:12:55:12 | f [post update] [f, a_] | | complex.cpp:55:12:55:12 | setA output argument [a_] | complex.cpp:56:12:56:12 | setB output argument [a_] | | complex.cpp:55:19:55:28 | call to user_input | complex.cpp:55:12:55:12 | setA output argument [a_] | -| complex.cpp:56:12:56:12 | Chi [a_] | complex.cpp:40:17:40:17 | *b [a_] | -| complex.cpp:56:12:56:12 | Chi [b_] | complex.cpp:40:17:40:17 | *b [b_] | +| complex.cpp:56:6:56:10 | inner [f, f, a_] | complex.cpp:56:12:56:12 | f [f, a_] | +| complex.cpp:56:6:56:10 | inner [post update] [f, f, a_] | complex.cpp:40:17:40:17 | *b [f, f, a_] | +| complex.cpp:56:6:56:10 | inner [post update] [f, f, b_] | complex.cpp:40:17:40:17 | *b [f, f, b_] | +| complex.cpp:56:6:56:10 | inner [post update] [f, f, f, f, a_] | complex.cpp:40:17:40:17 | *b [f, f, f, f, a_] | +| complex.cpp:56:12:56:12 | f [f, a_] | complex.cpp:56:12:56:12 | setB output argument [a_] | +| complex.cpp:56:12:56:12 | f [post update] [f, a_] | complex.cpp:56:6:56:10 | inner [post update] [f, f, a_] | +| complex.cpp:56:12:56:12 | f [post update] [f, b_] | complex.cpp:56:6:56:10 | inner [post update] [f, f, b_] | +| complex.cpp:56:12:56:12 | f [post update] [f, f, f, a_] | complex.cpp:56:6:56:10 | inner [post update] [f, f, f, f, a_] | | complex.cpp:56:12:56:12 | setB output argument [a_] | complex.cpp:40:17:40:17 | *b [a_] | -| complex.cpp:56:12:56:12 | setB output argument [a_] | complex.cpp:56:12:56:12 | Chi [a_] | +| complex.cpp:56:12:56:12 | setB output argument [a_] | complex.cpp:56:12:56:12 | f [post update] [f, a_] | | complex.cpp:56:12:56:12 | setB output argument [b_] | complex.cpp:40:17:40:17 | *b [b_] | -| complex.cpp:56:12:56:12 | setB output argument [b_] | complex.cpp:56:12:56:12 | Chi [b_] | +| complex.cpp:56:12:56:12 | setB output argument [b_] | complex.cpp:56:12:56:12 | f [post update] [f, b_] | +| complex.cpp:56:12:56:12 | setB output argument [f, f, a_] | complex.cpp:40:17:40:17 | *b [f, f, a_] | +| complex.cpp:56:12:56:12 | setB output argument [f, f, a_] | complex.cpp:56:12:56:12 | f [post update] [f, f, f, a_] | | complex.cpp:56:19:56:28 | call to user_input | complex.cpp:56:12:56:12 | setB output argument [b_] | | constructors.cpp:26:15:26:15 | *f [a_] | constructors.cpp:28:12:28:12 | call to a | | constructors.cpp:26:15:26:15 | *f [b_] | constructors.cpp:28:10:28:10 | a output argument [b_] | @@ -182,21 +280,25 @@ edges | simple.cpp:42:5:42:5 | setB output argument [a_] | simple.cpp:26:15:26:15 | *f [a_] | | simple.cpp:42:5:42:5 | setB output argument [b_] | simple.cpp:26:15:26:15 | *f [b_] | | simple.cpp:42:12:42:21 | call to user_input | simple.cpp:42:5:42:5 | setB output argument [b_] | -| simple.cpp:65:5:65:22 | Store [i] | simple.cpp:66:12:66:12 | Store [i] | -| simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:5:65:22 | Store [i] | -| simple.cpp:66:12:66:12 | Store [i] | simple.cpp:67:13:67:13 | i | -| simple.cpp:83:9:83:28 | Chi [f1] | simple.cpp:84:14:84:20 | call to getf2f1 | -| simple.cpp:83:17:83:26 | call to user_input | simple.cpp:83:9:83:28 | Chi [f1] | -| simple.cpp:92:5:92:22 | Store [i] | simple.cpp:93:20:93:20 | Store [i] | -| simple.cpp:92:11:92:20 | call to user_input | simple.cpp:92:5:92:22 | Store [i] | -| simple.cpp:93:20:93:20 | Store [i] | simple.cpp:94:13:94:13 | i | -| struct_init.c:14:24:14:25 | *ab [a] | struct_init.c:15:12:15:12 | a | -| struct_init.c:20:20:20:29 | Chi [a] | struct_init.c:14:24:14:25 | *ab [a] | -| struct_init.c:20:20:20:29 | call to user_input | struct_init.c:20:20:20:29 | Chi [a] | +| simple.cpp:65:7:65:7 | i [post update] [i] | simple.cpp:67:13:67:13 | i [i] | +| simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:7:65:7 | i [post update] [i] | +| simple.cpp:67:13:67:13 | i [i] | simple.cpp:67:13:67:13 | i | +| simple.cpp:83:9:83:10 | f2 [post update] [f1, f1] | simple.cpp:84:14:84:20 | call to getf2f1 | +| simple.cpp:83:12:83:13 | f1 [post update] [f1] | simple.cpp:83:9:83:10 | f2 [post update] [f1, f1] | +| simple.cpp:83:17:83:26 | call to user_input | simple.cpp:83:12:83:13 | f1 [post update] [f1] | +| simple.cpp:92:7:92:7 | i [post update] [i] | simple.cpp:94:13:94:13 | i [i] | +| simple.cpp:92:11:92:20 | call to user_input | simple.cpp:92:7:92:7 | i [post update] [i] | +| simple.cpp:94:13:94:13 | i [i] | simple.cpp:94:13:94:13 | i | +| struct_init.c:14:24:14:25 | *ab [a] | struct_init.c:15:12:15:12 | a [a] | +| struct_init.c:15:12:15:12 | a [a] | struct_init.c:15:12:15:12 | a | +| struct_init.c:20:17:20:36 | a [post update] [a] | struct_init.c:14:24:14:25 | *ab [a] | +| struct_init.c:20:20:20:29 | call to user_input | struct_init.c:20:17:20:36 | a [post update] [a] | | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | -| struct_init.c:27:7:27:16 | Chi [a] | struct_init.c:14:24:14:25 | *ab [a] | -| struct_init.c:27:7:27:16 | call to user_input | struct_init.c:27:7:27:16 | Chi [a] | +| struct_init.c:26:23:29:3 | nestedAB [post update] [nestedAB, a] | struct_init.c:36:17:36:24 | nestedAB [nestedAB, a] | +| struct_init.c:27:5:27:23 | a [post update] [a] | struct_init.c:26:23:29:3 | nestedAB [post update] [nestedAB, a] | +| struct_init.c:27:7:27:16 | call to user_input | struct_init.c:27:5:27:23 | a [post update] [a] | | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | +| struct_init.c:36:17:36:24 | nestedAB [nestedAB, a] | struct_init.c:14:24:14:25 | *ab [a] | nodes | A.cpp:55:5:55:5 | set output argument [c] | semmle.label | set output argument [c] | | A.cpp:55:12:55:19 | (C *)... | semmle.label | (C *)... | @@ -206,66 +308,75 @@ nodes | A.cpp:57:17:57:23 | new | semmle.label | new | | A.cpp:57:28:57:30 | call to get | semmle.label | call to get | | A.cpp:98:12:98:18 | new | semmle.label | new | -| A.cpp:100:5:100:13 | Chi [a] | semmle.label | Chi [a] | +| A.cpp:100:9:100:9 | a [post update] [a] | semmle.label | a [post update] [a] | | A.cpp:103:14:103:14 | *c [a] | semmle.label | *c [a] | | A.cpp:107:16:107:16 | a | semmle.label | a | +| A.cpp:107:16:107:16 | a [a] | semmle.label | a [a] | | A.cpp:126:5:126:5 | Chi [c] | semmle.label | Chi [c] | | A.cpp:126:5:126:5 | set output argument [c] | semmle.label | set output argument [c] | | A.cpp:126:12:126:18 | new | semmle.label | new | -| A.cpp:131:8:131:8 | Chi [c] | semmle.label | Chi [c] | | A.cpp:131:8:131:8 | f7 output argument [c] | semmle.label | f7 output argument [c] | | A.cpp:132:13:132:13 | c | semmle.label | c | +| A.cpp:132:13:132:13 | c [c] | semmle.label | c [c] | | A.cpp:142:7:142:20 | Chi [c] | semmle.label | Chi [c] | +| A.cpp:142:10:142:10 | c [post update] [c] | semmle.label | c [post update] [c] | | A.cpp:142:14:142:20 | new | semmle.label | new | | A.cpp:143:7:143:31 | Chi [b] | semmle.label | Chi [b] | +| A.cpp:143:13:143:13 | b [post update] [b] | semmle.label | b [post update] [b] | | A.cpp:143:25:143:31 | new | semmle.label | new | | A.cpp:150:12:150:18 | new | semmle.label | new | -| A.cpp:151:12:151:24 | Chi [b] | semmle.label | Chi [b] | | A.cpp:151:12:151:24 | D output argument [b] | semmle.label | D output argument [b] | -| A.cpp:151:18:151:18 | Chi [c] | semmle.label | Chi [c] | | A.cpp:151:18:151:18 | D output argument [c] | semmle.label | D output argument [c] | | A.cpp:152:13:152:13 | b | semmle.label | b | +| A.cpp:152:13:152:13 | b [b] | semmle.label | b [b] | | A.cpp:154:13:154:13 | c | semmle.label | c | +| A.cpp:154:13:154:13 | c [c] | semmle.label | c [c] | | C.cpp:18:12:18:18 | C output argument [s1] | semmle.label | C output argument [s1] | | C.cpp:18:12:18:18 | C output argument [s3] | semmle.label | C output argument [s3] | -| C.cpp:22:12:22:21 | Chi [s1] | semmle.label | Chi [s1] | +| C.cpp:22:9:22:22 | s1 [post update] [s1] | semmle.label | s1 [post update] [s1] | | C.cpp:22:12:22:21 | new | semmle.label | new | | C.cpp:24:5:24:25 | Chi [s1] | semmle.label | Chi [s1] | | C.cpp:24:5:24:25 | Chi [s3] | semmle.label | Chi [s3] | +| C.cpp:24:11:24:12 | s3 [post update] [s3] | semmle.label | s3 [post update] [s3] | | C.cpp:24:16:24:25 | new | semmle.label | new | | C.cpp:27:8:27:11 | *#this [s1] | semmle.label | *#this [s1] | | C.cpp:27:8:27:11 | *#this [s3] | semmle.label | *#this [s3] | | C.cpp:29:10:29:11 | s1 | semmle.label | s1 | +| C.cpp:29:10:29:11 | s1 [s1] | semmle.label | s1 [s1] | | C.cpp:31:10:31:11 | s3 | semmle.label | s3 | +| C.cpp:31:10:31:11 | s3 [s3] | semmle.label | s3 [s3] | | aliasing.cpp:9:3:9:22 | Chi [m1] | semmle.label | Chi [m1] | +| aliasing.cpp:9:6:9:7 | m1 [post update] [m1] | semmle.label | m1 [post update] [m1] | | aliasing.cpp:9:11:9:20 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:13:3:13:21 | Chi [m1] | semmle.label | Chi [m1] | +| aliasing.cpp:13:5:13:6 | m1 [post update] [m1] | semmle.label | m1 [post update] [m1] | | aliasing.cpp:13:10:13:19 | call to user_input | semmle.label | call to user_input | -| aliasing.cpp:25:17:25:19 | Chi [m1] | semmle.label | Chi [m1] | | aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | semmle.label | pointerSetter output argument [m1] | -| aliasing.cpp:26:19:26:20 | Chi [m1] | semmle.label | Chi [m1] | | aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | semmle.label | referenceSetter output argument [m1] | | aliasing.cpp:29:11:29:12 | m1 | semmle.label | m1 | +| aliasing.cpp:29:11:29:12 | m1 [m1] | semmle.label | m1 [m1] | | aliasing.cpp:30:11:30:12 | m1 | semmle.label | m1 | +| aliasing.cpp:30:11:30:12 | m1 [m1] | semmle.label | m1 [m1] | | aliasing.cpp:37:13:37:22 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:38:11:38:12 | m1 | semmle.label | m1 | | aliasing.cpp:42:11:42:20 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:43:13:43:14 | m1 | semmle.label | m1 | -| aliasing.cpp:60:3:60:22 | Chi [m1] | semmle.label | Chi [m1] | +| aliasing.cpp:60:6:60:7 | m1 [post update] [m1] | semmle.label | m1 [post update] [m1] | | aliasing.cpp:60:11:60:20 | call to user_input | semmle.label | call to user_input | -| aliasing.cpp:61:13:61:14 | Store [m1] | semmle.label | Store [m1] | | aliasing.cpp:62:14:62:15 | m1 | semmle.label | m1 | +| aliasing.cpp:62:14:62:15 | m1 [m1] | semmle.label | m1 [m1] | | aliasing.cpp:79:11:79:20 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:80:12:80:13 | m1 | semmle.label | m1 | | aliasing.cpp:86:10:86:19 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:87:12:87:13 | m1 | semmle.label | m1 | | aliasing.cpp:92:12:92:21 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 | -| aliasing.cpp:98:3:98:21 | Chi [m1] | semmle.label | Chi [m1] | +| aliasing.cpp:98:5:98:6 | m1 [post update] [m1] | semmle.label | m1 [post update] [m1] | | aliasing.cpp:98:10:98:19 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:100:14:100:14 | Store [m1] | semmle.label | Store [m1] | | aliasing.cpp:102:8:102:10 | * ... | semmle.label | * ... | | aliasing.cpp:106:3:106:20 | Chi [array content] | semmle.label | Chi [array content] | +| aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | semmle.label | ChiTotal [post update] [array content] | | aliasing.cpp:106:9:106:18 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:121:15:121:16 | Chi [array content] | semmle.label | Chi [array content] | | aliasing.cpp:121:15:121:16 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] | @@ -285,19 +396,42 @@ nodes | aliasing.cpp:164:15:164:20 | Chi [array content] | semmle.label | Chi [array content] | | aliasing.cpp:164:15:164:20 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] | | aliasing.cpp:165:8:165:16 | access to array | semmle.label | access to array | -| aliasing.cpp:175:15:175:22 | Chi | semmle.label | Chi | -| aliasing.cpp:175:15:175:22 | Chi [m1] | semmle.label | Chi [m1] | +| aliasing.cpp:175:15:175:22 | taint_a_ptr output argument | semmle.label | taint_a_ptr output argument | | aliasing.cpp:175:15:175:22 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] | +| aliasing.cpp:175:19:175:19 | s [post update] [s, m1] | semmle.label | s [post update] [s, m1] | +| aliasing.cpp:175:21:175:22 | m1 [post update] [m1] | semmle.label | m1 [post update] [m1] | +| aliasing.cpp:176:11:176:11 | s [s, m1] | semmle.label | s [s, m1] | | aliasing.cpp:176:13:176:14 | m1 | semmle.label | m1 | -| aliasing.cpp:187:15:187:22 | Chi | semmle.label | Chi | -| aliasing.cpp:187:15:187:22 | Chi [m1] | semmle.label | Chi [m1] | +| aliasing.cpp:176:13:176:14 | m1 [m1] | semmle.label | m1 [m1] | +| aliasing.cpp:187:15:187:22 | taint_a_ptr output argument | semmle.label | taint_a_ptr output argument | | aliasing.cpp:187:15:187:22 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] | -| aliasing.cpp:188:13:188:14 | Store [m1] | semmle.label | Store [m1] | +| aliasing.cpp:187:19:187:19 | s [post update] [s, m1] | semmle.label | s [post update] [s, m1] | +| aliasing.cpp:187:21:187:22 | m1 [post update] [m1] | semmle.label | m1 [post update] [m1] | +| aliasing.cpp:189:13:189:13 | s [s, m1] | semmle.label | s [s, m1] | | aliasing.cpp:189:15:189:16 | m1 | semmle.label | m1 | -| aliasing.cpp:200:15:200:24 | Chi | semmle.label | Chi | -| aliasing.cpp:200:15:200:24 | Chi [m1] | semmle.label | Chi [m1] | +| aliasing.cpp:189:15:189:16 | m1 [m1] | semmle.label | m1 [m1] | +| aliasing.cpp:200:15:200:24 | taint_a_ptr output argument | semmle.label | taint_a_ptr output argument | | aliasing.cpp:200:15:200:24 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] | +| aliasing.cpp:200:21:200:21 | s [post update] [s, m1] | semmle.label | s [post update] [s, m1] | +| aliasing.cpp:200:23:200:24 | m1 [post update] [m1] | semmle.label | m1 [post update] [m1] | +| aliasing.cpp:201:13:201:13 | s [s, m1] | semmle.label | s [s, m1] | | aliasing.cpp:201:15:201:16 | m1 | semmle.label | m1 | +| aliasing.cpp:201:15:201:16 | m1 [m1] | semmle.label | m1 [m1] | +| aliasing.cpp:211:6:211:6 | s [post update] [s, m1] | semmle.label | s [post update] [s, m1] | +| aliasing.cpp:211:8:211:9 | m1 [post update] [m1] | semmle.label | m1 [post update] [m1] | +| aliasing.cpp:211:13:211:22 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:212:12:212:12 | s [m1] | semmle.label | s [m1] | +| aliasing.cpp:212:12:212:12 | s [s, m1] | semmle.label | s [s, m1] | +| aliasing.cpp:213:10:213:11 | m1 | semmle.label | m1 | +| aliasing.cpp:213:10:213:11 | m1 [m1] | semmle.label | m1 [m1] | +| aliasing.cpp:225:15:225:22 | taint_a_ptr output argument | semmle.label | taint_a_ptr output argument | +| aliasing.cpp:225:15:225:22 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] | +| aliasing.cpp:225:19:225:19 | s [post update] [s, m1] | semmle.label | s [post update] [s, m1] | +| aliasing.cpp:225:21:225:22 | m1 [post update] [m1] | semmle.label | m1 [post update] [m1] | +| aliasing.cpp:226:12:226:12 | s [m1] | semmle.label | s [m1] | +| aliasing.cpp:226:12:226:12 | s [s, m1] | semmle.label | s [s, m1] | +| aliasing.cpp:227:10:227:11 | m1 | semmle.label | m1 | +| aliasing.cpp:227:10:227:11 | m1 [m1] | semmle.label | m1 [m1] | | arrays.cpp:6:12:6:21 | call to user_input | semmle.label | call to user_input | | arrays.cpp:7:8:7:13 | access to array | semmle.label | access to array | | arrays.cpp:9:8:9:11 | * ... | semmle.label | * ... | @@ -319,60 +453,103 @@ nodes | by_reference.cpp:68:21:68:30 | call to user_input | semmle.label | call to user_input | | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | semmle.label | call to nonMemberGetA | | by_reference.cpp:84:3:84:25 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:84:10:84:10 | a [post update] [a] | semmle.label | a [post update] [a] | | by_reference.cpp:84:14:84:23 | call to user_input | semmle.label | call to user_input | | by_reference.cpp:88:3:88:24 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:88:9:88:9 | a [post update] [a] | semmle.label | a [post update] [a] | | by_reference.cpp:88:13:88:22 | call to user_input | semmle.label | call to user_input | | by_reference.cpp:92:3:92:20 | Chi [array content] | semmle.label | Chi [array content] | +| by_reference.cpp:92:3:92:20 | ChiTotal [post update] [array content] | semmle.label | ChiTotal [post update] [array content] | | by_reference.cpp:92:9:92:18 | call to user_input | semmle.label | call to user_input | | by_reference.cpp:96:3:96:19 | Chi [array content] | semmle.label | Chi [array content] | +| by_reference.cpp:96:3:96:19 | ChiTotal [post update] [array content] | semmle.label | ChiTotal [post update] [array content] | | by_reference.cpp:96:8:96:17 | call to user_input | semmle.label | call to user_input | -| by_reference.cpp:102:21:102:39 | Chi [a] | semmle.label | Chi [a] | | by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | semmle.label | taint_inner_a_ptr output argument [a] | -| by_reference.cpp:104:15:104:22 | Chi | semmle.label | Chi | -| by_reference.cpp:104:15:104:22 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:102:28:102:39 | inner_nested [post update] [a, a] | semmle.label | inner_nested [post update] [a, a] | +| by_reference.cpp:104:15:104:22 | taint_a_ptr output argument | semmle.label | taint_a_ptr output argument | | by_reference.cpp:104:15:104:22 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] | -| by_reference.cpp:106:21:106:41 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:104:22:104:22 | a [post update] [a] | semmle.label | a [post update] [a] | | by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | semmle.label | taint_inner_a_ptr output argument [a] | -| by_reference.cpp:108:15:108:24 | Chi | semmle.label | Chi | -| by_reference.cpp:108:15:108:24 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:106:30:106:41 | inner_nested [post update] [a, a] | semmle.label | inner_nested [post update] [a, a] | +| by_reference.cpp:108:15:108:24 | taint_a_ptr output argument | semmle.label | taint_a_ptr output argument | | by_reference.cpp:108:15:108:24 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] | +| by_reference.cpp:108:24:108:24 | a [post update] [a] | semmle.label | a [post update] [a] | +| by_reference.cpp:110:14:110:25 | inner_nested [a, a] | semmle.label | inner_nested [a, a] | | by_reference.cpp:110:27:110:27 | a | semmle.label | a | +| by_reference.cpp:110:27:110:27 | a [a] | semmle.label | a [a] | | by_reference.cpp:112:14:112:14 | a | semmle.label | a | +| by_reference.cpp:112:14:112:14 | a [a] | semmle.label | a [a] | +| by_reference.cpp:114:16:114:27 | inner_nested [a, a] | semmle.label | inner_nested [a, a] | | by_reference.cpp:114:29:114:29 | a | semmle.label | a | +| by_reference.cpp:114:29:114:29 | a [a] | semmle.label | a [a] | | by_reference.cpp:116:16:116:16 | a | semmle.label | a | -| by_reference.cpp:122:21:122:38 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:116:16:116:16 | a [a] | semmle.label | a [a] | | by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | semmle.label | taint_inner_a_ref output argument [a] | -| by_reference.cpp:124:15:124:21 | Chi | semmle.label | Chi | -| by_reference.cpp:124:15:124:21 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:122:27:122:38 | inner_nested [post update] [a, a] | semmle.label | inner_nested [post update] [a, a] | +| by_reference.cpp:124:15:124:21 | taint_a_ref output argument | semmle.label | taint_a_ref output argument | | by_reference.cpp:124:15:124:21 | taint_a_ref output argument [array content] | semmle.label | taint_a_ref output argument [array content] | -| by_reference.cpp:126:21:126:40 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:124:21:124:21 | a [post update] [a] | semmle.label | a [post update] [a] | | by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | semmle.label | taint_inner_a_ref output argument [a] | -| by_reference.cpp:128:15:128:23 | Chi | semmle.label | Chi | -| by_reference.cpp:128:15:128:23 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:126:29:126:40 | inner_nested [post update] [a, a] | semmle.label | inner_nested [post update] [a, a] | +| by_reference.cpp:128:15:128:23 | taint_a_ref output argument | semmle.label | taint_a_ref output argument | | by_reference.cpp:128:15:128:23 | taint_a_ref output argument [array content] | semmle.label | taint_a_ref output argument [array content] | +| by_reference.cpp:128:23:128:23 | a [post update] [a] | semmle.label | a [post update] [a] | +| by_reference.cpp:130:14:130:25 | inner_nested [a, a] | semmle.label | inner_nested [a, a] | | by_reference.cpp:130:27:130:27 | a | semmle.label | a | +| by_reference.cpp:130:27:130:27 | a [a] | semmle.label | a [a] | | by_reference.cpp:132:14:132:14 | a | semmle.label | a | +| by_reference.cpp:132:14:132:14 | a [a] | semmle.label | a [a] | +| by_reference.cpp:134:16:134:27 | inner_nested [a, a] | semmle.label | inner_nested [a, a] | | by_reference.cpp:134:29:134:29 | a | semmle.label | a | +| by_reference.cpp:134:29:134:29 | a [a] | semmle.label | a [a] | | by_reference.cpp:136:16:136:16 | a | semmle.label | a | +| by_reference.cpp:136:16:136:16 | a [a] | semmle.label | a [a] | | complex.cpp:40:17:40:17 | *b [a_] | semmle.label | *b [a_] | | complex.cpp:40:17:40:17 | *b [b_] | semmle.label | *b [b_] | -| complex.cpp:42:16:42:16 | Chi [b_] | semmle.label | Chi [b_] | +| complex.cpp:40:17:40:17 | *b [f, f, a_] | semmle.label | *b [f, f, a_] | +| complex.cpp:40:17:40:17 | *b [f, f, b_] | semmle.label | *b [f, f, b_] | +| complex.cpp:40:17:40:17 | *b [f, f, f, f, a_] | semmle.label | *b [f, f, f, f, a_] | +| complex.cpp:42:10:42:14 | inner [f, f, a_] | semmle.label | inner [f, f, a_] | +| complex.cpp:42:10:42:14 | inner [f, f, b_] | semmle.label | inner [f, f, b_] | +| complex.cpp:42:10:42:14 | inner [f, f, f, f, a_] | semmle.label | inner [f, f, f, f, a_] | +| complex.cpp:42:10:42:14 | inner [post update] [f, f, b_] | semmle.label | inner [post update] [f, f, b_] | +| complex.cpp:42:10:42:14 | inner [post update] [f, f, f, f, b_] | semmle.label | inner [post update] [f, f, f, f, b_] | | complex.cpp:42:16:42:16 | a output argument [b_] | semmle.label | a output argument [b_] | +| complex.cpp:42:16:42:16 | a output argument [f, f, b_] | semmle.label | a output argument [f, f, b_] | +| complex.cpp:42:16:42:16 | f [f, a_] | semmle.label | f [f, a_] | +| complex.cpp:42:16:42:16 | f [f, b_] | semmle.label | f [f, b_] | +| complex.cpp:42:16:42:16 | f [f, f, f, a_] | semmle.label | f [f, f, f, a_] | +| complex.cpp:42:16:42:16 | f [post update] [f, b_] | semmle.label | f [post update] [f, b_] | +| complex.cpp:42:16:42:16 | f [post update] [f, f, f, b_] | semmle.label | f [post update] [f, f, f, b_] | | complex.cpp:42:18:42:18 | call to a | semmle.label | call to a | +| complex.cpp:43:10:43:14 | inner [f, f, b_] | semmle.label | inner [f, f, b_] | +| complex.cpp:43:10:43:14 | inner [f, f, f, f, b_] | semmle.label | inner [f, f, f, f, b_] | +| complex.cpp:43:16:43:16 | f [f, b_] | semmle.label | f [f, b_] | +| complex.cpp:43:16:43:16 | f [f, f, f, b_] | semmle.label | f [f, f, f, b_] | | complex.cpp:43:18:43:18 | call to b | semmle.label | call to b | -| complex.cpp:53:12:53:12 | Chi [a_] | semmle.label | Chi [a_] | +| complex.cpp:53:6:53:10 | inner [post update] [f, f, a_] | semmle.label | inner [post update] [f, f, a_] | +| complex.cpp:53:12:53:12 | f [post update] [f, a_] | semmle.label | f [post update] [f, a_] | | complex.cpp:53:12:53:12 | setA output argument [a_] | semmle.label | setA output argument [a_] | | complex.cpp:53:19:53:28 | call to user_input | semmle.label | call to user_input | -| complex.cpp:54:12:54:12 | Chi [b_] | semmle.label | Chi [b_] | +| complex.cpp:54:6:54:10 | inner [post update] [f, f, b_] | semmle.label | inner [post update] [f, f, b_] | +| complex.cpp:54:12:54:12 | f [post update] [f, b_] | semmle.label | f [post update] [f, b_] | | complex.cpp:54:12:54:12 | setB output argument [b_] | semmle.label | setB output argument [b_] | | complex.cpp:54:19:54:28 | call to user_input | semmle.label | call to user_input | -| complex.cpp:55:12:55:12 | Chi [a_] | semmle.label | Chi [a_] | +| complex.cpp:55:6:55:10 | inner [post update] [f, f, a_] | semmle.label | inner [post update] [f, f, a_] | +| complex.cpp:55:12:55:12 | f [post update] [f, a_] | semmle.label | f [post update] [f, a_] | | complex.cpp:55:12:55:12 | setA output argument [a_] | semmle.label | setA output argument [a_] | | complex.cpp:55:19:55:28 | call to user_input | semmle.label | call to user_input | -| complex.cpp:56:12:56:12 | Chi [a_] | semmle.label | Chi [a_] | -| complex.cpp:56:12:56:12 | Chi [b_] | semmle.label | Chi [b_] | +| complex.cpp:56:6:56:10 | inner [f, f, a_] | semmle.label | inner [f, f, a_] | +| complex.cpp:56:6:56:10 | inner [post update] [f, f, a_] | semmle.label | inner [post update] [f, f, a_] | +| complex.cpp:56:6:56:10 | inner [post update] [f, f, b_] | semmle.label | inner [post update] [f, f, b_] | +| complex.cpp:56:6:56:10 | inner [post update] [f, f, f, f, a_] | semmle.label | inner [post update] [f, f, f, f, a_] | +| complex.cpp:56:12:56:12 | f [f, a_] | semmle.label | f [f, a_] | +| complex.cpp:56:12:56:12 | f [post update] [f, a_] | semmle.label | f [post update] [f, a_] | +| complex.cpp:56:12:56:12 | f [post update] [f, b_] | semmle.label | f [post update] [f, b_] | +| complex.cpp:56:12:56:12 | f [post update] [f, f, f, a_] | semmle.label | f [post update] [f, f, f, a_] | | complex.cpp:56:12:56:12 | setB output argument [a_] | semmle.label | setB output argument [a_] | | complex.cpp:56:12:56:12 | setB output argument [b_] | semmle.label | setB output argument [b_] | +| complex.cpp:56:12:56:12 | setB output argument [f, f, a_] | semmle.label | setB output argument [f, f, a_] | | complex.cpp:56:19:56:28 | call to user_input | semmle.label | call to user_input | | constructors.cpp:26:15:26:15 | *f [a_] | semmle.label | *f [a_] | | constructors.cpp:26:15:26:15 | *f [b_] | semmle.label | *f [b_] | @@ -401,25 +578,29 @@ nodes | simple.cpp:42:5:42:5 | setB output argument [a_] | semmle.label | setB output argument [a_] | | simple.cpp:42:5:42:5 | setB output argument [b_] | semmle.label | setB output argument [b_] | | simple.cpp:42:12:42:21 | call to user_input | semmle.label | call to user_input | -| simple.cpp:65:5:65:22 | Store [i] | semmle.label | Store [i] | +| simple.cpp:65:7:65:7 | i [post update] [i] | semmle.label | i [post update] [i] | | simple.cpp:65:11:65:20 | call to user_input | semmle.label | call to user_input | -| simple.cpp:66:12:66:12 | Store [i] | semmle.label | Store [i] | | simple.cpp:67:13:67:13 | i | semmle.label | i | -| simple.cpp:83:9:83:28 | Chi [f1] | semmle.label | Chi [f1] | +| simple.cpp:67:13:67:13 | i [i] | semmle.label | i [i] | +| simple.cpp:83:9:83:10 | f2 [post update] [f1, f1] | semmle.label | f2 [post update] [f1, f1] | +| simple.cpp:83:12:83:13 | f1 [post update] [f1] | semmle.label | f1 [post update] [f1] | | simple.cpp:83:17:83:26 | call to user_input | semmle.label | call to user_input | | simple.cpp:84:14:84:20 | call to getf2f1 | semmle.label | call to getf2f1 | -| simple.cpp:92:5:92:22 | Store [i] | semmle.label | Store [i] | +| simple.cpp:92:7:92:7 | i [post update] [i] | semmle.label | i [post update] [i] | | simple.cpp:92:11:92:20 | call to user_input | semmle.label | call to user_input | -| simple.cpp:93:20:93:20 | Store [i] | semmle.label | Store [i] | | simple.cpp:94:13:94:13 | i | semmle.label | i | +| simple.cpp:94:13:94:13 | i [i] | semmle.label | i [i] | | struct_init.c:14:24:14:25 | *ab [a] | semmle.label | *ab [a] | | struct_init.c:15:12:15:12 | a | semmle.label | a | -| struct_init.c:20:20:20:29 | Chi [a] | semmle.label | Chi [a] | +| struct_init.c:15:12:15:12 | a [a] | semmle.label | a [a] | +| struct_init.c:20:17:20:36 | a [post update] [a] | semmle.label | a [post update] [a] | | struct_init.c:20:20:20:29 | call to user_input | semmle.label | call to user_input | | struct_init.c:22:11:22:11 | a | semmle.label | a | -| struct_init.c:27:7:27:16 | Chi [a] | semmle.label | Chi [a] | +| struct_init.c:26:23:29:3 | nestedAB [post update] [nestedAB, a] | semmle.label | nestedAB [post update] [nestedAB, a] | +| struct_init.c:27:5:27:23 | a [post update] [a] | semmle.label | a [post update] [a] | | struct_init.c:27:7:27:16 | call to user_input | semmle.label | call to user_input | | struct_init.c:31:23:31:23 | a | semmle.label | a | +| struct_init.c:36:17:36:24 | nestedAB [nestedAB, a] | semmle.label | nestedAB [nestedAB, a] | #select | A.cpp:56:13:56:15 | call to get | A.cpp:55:12:55:19 | (C *)... | A.cpp:56:13:56:15 | call to get | call to get flows from $@ | A.cpp:55:12:55:19 | (C *)... | (C *)... | | A.cpp:56:13:56:15 | call to get | A.cpp:55:12:55:19 | new | A.cpp:56:13:56:15 | call to get | call to get flows from $@ | A.cpp:55:12:55:19 | new | new | @@ -449,6 +630,8 @@ nodes | aliasing.cpp:176:13:176:14 | m1 | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:176:13:176:14 | m1 | m1 flows from $@ | aliasing.cpp:106:9:106:18 | call to user_input | call to user_input | | aliasing.cpp:189:15:189:16 | m1 | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:189:15:189:16 | m1 | m1 flows from $@ | aliasing.cpp:106:9:106:18 | call to user_input | call to user_input | | aliasing.cpp:201:15:201:16 | m1 | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:201:15:201:16 | m1 | m1 flows from $@ | aliasing.cpp:106:9:106:18 | call to user_input | call to user_input | +| aliasing.cpp:213:10:213:11 | m1 | aliasing.cpp:211:13:211:22 | call to user_input | aliasing.cpp:213:10:213:11 | m1 | m1 flows from $@ | aliasing.cpp:211:13:211:22 | call to user_input | call to user_input | +| aliasing.cpp:227:10:227:11 | m1 | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:227:10:227:11 | m1 | m1 flows from $@ | aliasing.cpp:106:9:106:18 | call to user_input | call to user_input | | arrays.cpp:7:8:7:13 | access to array | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:7:8:7:13 | access to array | access to array flows from $@ | arrays.cpp:6:12:6:21 | call to user_input | call to user_input | | arrays.cpp:9:8:9:11 | * ... | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:9:8:9:11 | * ... | * ... flows from $@ | arrays.cpp:6:12:6:21 | call to user_input | call to user_input | | arrays.cpp:10:8:10:15 | * ... | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:10:8:10:15 | * ... | * ... flows from $@ | arrays.cpp:6:12:6:21 | call to user_input | call to user_input | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected index ee0a3a33779..5cf7504fa1f 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected @@ -1,12 +1,12 @@ | A.cpp:25:13:25:13 | c | AST only | | A.cpp:27:28:27:28 | c | AST only | +| A.cpp:28:29:28:29 | this | IR only | | A.cpp:31:20:31:20 | c | AST only | | A.cpp:40:5:40:6 | cc | AST only | | A.cpp:41:5:41:6 | ct | AST only | | A.cpp:42:10:42:12 | & ... | AST only | | A.cpp:43:10:43:12 | & ... | AST only | | A.cpp:48:20:48:20 | c | AST only | -| A.cpp:49:10:49:10 | b | AST only | | A.cpp:49:13:49:13 | c | AST only | | A.cpp:55:5:55:5 | b | AST only | | A.cpp:56:10:56:10 | b | AST only | @@ -14,15 +14,11 @@ | A.cpp:57:28:57:30 | call to get | AST only | | A.cpp:64:10:64:15 | this | AST only | | A.cpp:64:17:64:18 | b1 | AST only | -| A.cpp:65:10:65:11 | b1 | AST only | | A.cpp:65:14:65:14 | c | AST only | -| A.cpp:66:10:66:11 | b2 | AST only | | A.cpp:66:14:66:14 | c | AST only | | A.cpp:73:10:73:19 | this | AST only | | A.cpp:73:21:73:22 | b1 | AST only | -| A.cpp:74:10:74:11 | b1 | AST only | | A.cpp:74:14:74:14 | c | AST only | -| A.cpp:75:10:75:11 | b2 | AST only | | A.cpp:75:14:75:14 | c | AST only | | A.cpp:81:10:81:15 | this | AST only | | A.cpp:81:17:81:18 | b1 | AST only | @@ -34,85 +30,61 @@ | A.cpp:100:9:100:9 | a | AST only | | A.cpp:101:5:101:6 | this | AST only | | A.cpp:101:8:101:9 | c1 | AST only | -| A.cpp:107:12:107:13 | c1 | AST only | | A.cpp:107:16:107:16 | a | AST only | -| A.cpp:120:12:120:13 | c1 | AST only | | A.cpp:120:16:120:16 | a | AST only | | A.cpp:126:5:126:5 | b | AST only | | A.cpp:131:5:131:6 | this | AST only | | A.cpp:131:8:131:8 | b | AST only | -| A.cpp:132:10:132:10 | b | AST only | | A.cpp:132:13:132:13 | c | AST only | | A.cpp:142:10:142:10 | c | AST only | | A.cpp:143:13:143:13 | b | AST only | | A.cpp:151:18:151:18 | b | AST only | | A.cpp:151:21:151:21 | this | AST only | -| A.cpp:152:10:152:10 | d | AST only | | A.cpp:152:13:152:13 | b | AST only | -| A.cpp:153:10:153:10 | d | AST only | -| A.cpp:153:13:153:13 | b | AST only | | A.cpp:153:16:153:16 | c | AST only | -| A.cpp:154:10:154:10 | b | AST only | | A.cpp:154:13:154:13 | c | AST only | | A.cpp:160:29:160:29 | b | AST only | | A.cpp:161:38:161:39 | l1 | AST only | | A.cpp:162:38:162:39 | l2 | AST only | -| A.cpp:163:10:163:11 | l3 | AST only | | A.cpp:163:14:163:17 | head | AST only | -| A.cpp:164:10:164:11 | l3 | AST only | -| A.cpp:164:14:164:17 | next | AST only | | A.cpp:164:20:164:23 | head | AST only | -| A.cpp:165:10:165:11 | l3 | AST only | -| A.cpp:165:14:165:17 | next | AST only | -| A.cpp:165:20:165:23 | next | AST only | | A.cpp:165:26:165:29 | head | AST only | -| A.cpp:166:10:166:11 | l3 | AST only | -| A.cpp:166:14:166:17 | next | AST only | -| A.cpp:166:20:166:23 | next | AST only | -| A.cpp:166:26:166:29 | next | AST only | | A.cpp:166:32:166:35 | head | AST only | -| A.cpp:169:12:169:12 | l | AST only | +| A.cpp:167:47:167:50 | l | IR only | | A.cpp:169:15:169:18 | head | AST only | | A.cpp:183:7:183:10 | head | AST only | | A.cpp:184:13:184:16 | next | AST only | | B.cpp:7:25:7:25 | e | AST only | | B.cpp:8:25:8:26 | b1 | AST only | -| B.cpp:9:10:9:11 | b2 | AST only | -| B.cpp:9:14:9:17 | box1 | AST only | | B.cpp:9:20:9:24 | elem1 | AST only | -| B.cpp:10:10:10:11 | b2 | AST only | -| B.cpp:10:14:10:17 | box1 | AST only | | B.cpp:10:20:10:24 | elem2 | AST only | | B.cpp:16:37:16:37 | e | AST only | | B.cpp:17:25:17:26 | b1 | AST only | -| B.cpp:18:10:18:11 | b2 | AST only | -| B.cpp:18:14:18:17 | box1 | AST only | | B.cpp:18:20:18:24 | elem1 | AST only | -| B.cpp:19:10:19:11 | b2 | AST only | -| B.cpp:19:14:19:17 | box1 | AST only | | B.cpp:19:20:19:24 | elem2 | AST only | | B.cpp:35:13:35:17 | elem1 | AST only | | B.cpp:36:13:36:17 | elem2 | AST only | | B.cpp:46:13:46:16 | box1 | AST only | | C.cpp:19:5:19:5 | c | AST only | | C.cpp:24:11:24:12 | s3 | AST only | +| C.cpp:29:10:29:11 | this | IR only | +| C.cpp:30:10:30:11 | this | IR only | +| C.cpp:31:10:31:11 | this | IR only | | D.cpp:9:21:9:24 | elem | AST only | +| D.cpp:10:30:10:33 | this | IR only | | D.cpp:11:29:11:32 | elem | AST only | | D.cpp:16:21:16:23 | box | AST only | +| D.cpp:17:30:17:32 | this | IR only | | D.cpp:18:29:18:31 | box | AST only | | D.cpp:22:10:22:11 | b2 | AST only | | D.cpp:22:14:22:20 | call to getBox1 | AST only | | D.cpp:22:25:22:31 | call to getElem | AST only | -| D.cpp:30:5:30:5 | b | AST only | -| D.cpp:30:8:30:10 | box | AST only | | D.cpp:30:13:30:16 | elem | AST only | | D.cpp:31:14:31:14 | b | AST only | -| D.cpp:37:5:37:5 | b | AST only | | D.cpp:37:8:37:10 | box | AST only | | D.cpp:37:21:37:21 | e | AST only | | D.cpp:38:14:38:14 | b | AST only | | D.cpp:44:5:44:5 | b | AST only | -| D.cpp:44:8:44:14 | call to getBox1 | AST only | | D.cpp:44:19:44:22 | elem | AST only | | D.cpp:45:14:45:14 | b | AST only | | D.cpp:51:5:51:5 | b | AST only | @@ -120,26 +92,14 @@ | D.cpp:51:27:51:27 | e | AST only | | D.cpp:52:14:52:14 | b | AST only | | D.cpp:57:5:57:12 | boxfield | AST only | -| D.cpp:58:5:58:12 | boxfield | AST only | -| D.cpp:58:5:58:12 | this | AST only | -| D.cpp:58:15:58:17 | box | AST only | | D.cpp:58:20:58:23 | elem | AST only | | D.cpp:59:5:59:7 | this | AST only | -| D.cpp:64:10:64:17 | boxfield | AST only | -| D.cpp:64:10:64:17 | this | AST only | -| D.cpp:64:20:64:22 | box | AST only | | D.cpp:64:25:64:28 | elem | AST only | -| E.cpp:21:10:21:10 | p | AST only | -| E.cpp:21:13:21:16 | data | AST only | | E.cpp:21:18:21:23 | buffer | AST only | | E.cpp:28:21:28:23 | raw | AST only | -| E.cpp:29:21:29:21 | b | AST only | | E.cpp:29:24:29:29 | buffer | AST only | -| E.cpp:30:21:30:21 | p | AST only | -| E.cpp:30:23:30:26 | data | AST only | | E.cpp:30:28:30:33 | buffer | AST only | | E.cpp:31:10:31:12 | raw | AST only | -| E.cpp:32:10:32:10 | b | AST only | | E.cpp:32:13:32:18 | buffer | AST only | | E.cpp:33:18:33:19 | & ... | AST only | | aliasing.cpp:9:6:9:7 | m1 | AST only | @@ -147,87 +107,92 @@ | aliasing.cpp:17:5:17:6 | m1 | AST only | | aliasing.cpp:25:17:25:19 | & ... | AST only | | aliasing.cpp:26:19:26:20 | s2 | AST only | +| aliasing.cpp:29:11:29:12 | s1 | IR only | +| aliasing.cpp:30:11:30:12 | s2 | IR only | +| aliasing.cpp:31:11:31:12 | s3 | IR only | | aliasing.cpp:37:8:37:9 | m1 | AST only | +| aliasing.cpp:38:11:38:12 | s1 | IR only | | aliasing.cpp:42:6:42:7 | m1 | AST only | +| aliasing.cpp:43:13:43:14 | ref2 | IR only | | aliasing.cpp:49:9:49:10 | m1 | AST only | +| aliasing.cpp:50:11:50:12 | s1 | IR only | | aliasing.cpp:54:6:54:7 | m1 | AST only | +| aliasing.cpp:55:14:55:15 | copy2 | IR only | | aliasing.cpp:60:6:60:7 | m1 | AST only | +| aliasing.cpp:62:14:62:15 | copy2 | IR only | +| aliasing.cpp:71:11:71:11 | w | IR only | | aliasing.cpp:72:5:72:6 | m1 | AST only | +| aliasing.cpp:73:10:73:10 | w | IR only | +| aliasing.cpp:73:12:73:13 | s | IR only | +| aliasing.cpp:78:13:78:13 | w | IR only | | aliasing.cpp:79:6:79:7 | m1 | AST only | +| aliasing.cpp:80:10:80:10 | w | IR only | +| aliasing.cpp:80:12:80:13 | s | IR only | +| aliasing.cpp:85:12:85:12 | w | IR only | | aliasing.cpp:86:5:86:6 | m1 | AST only | -| aliasing.cpp:92:3:92:3 | w | AST only | +| aliasing.cpp:87:10:87:10 | w | IR only | +| aliasing.cpp:87:12:87:13 | s | IR only | | aliasing.cpp:92:7:92:8 | m1 | AST only | +| aliasing.cpp:93:10:93:10 | w | IR only | +| aliasing.cpp:93:12:93:13 | s | IR only | | aliasing.cpp:98:5:98:6 | m1 | AST only | +| aliasing.cpp:101:21:101:22 | s_copy | IR only | | aliasing.cpp:106:3:106:5 | * ... | AST only | | aliasing.cpp:111:15:111:19 | & ... | AST only | +| aliasing.cpp:112:10:112:11 | s | IR only | | aliasing.cpp:121:15:121:16 | xs | AST only | | aliasing.cpp:126:15:126:20 | ... - ... | AST only | | aliasing.cpp:131:15:131:16 | xs | AST only | | aliasing.cpp:136:15:136:17 | + ... | AST only | -| aliasing.cpp:141:15:141:15 | s | AST only | | aliasing.cpp:141:17:141:20 | data | AST only | +| aliasing.cpp:143:10:143:13 | s | IR only | | aliasing.cpp:147:15:147:22 | & ... | AST only | -| aliasing.cpp:158:15:158:15 | s | AST only | +| aliasing.cpp:148:13:148:14 | access to array | IR only | | aliasing.cpp:158:17:158:20 | data | AST only | -| aliasing.cpp:164:15:164:15 | s | AST only | +| aliasing.cpp:159:11:159:14 | s | IR only | | aliasing.cpp:164:17:164:20 | data | AST only | +| aliasing.cpp:165:10:165:13 | s | IR only | | aliasing.cpp:175:15:175:22 | & ... | AST only | -| aliasing.cpp:175:16:175:17 | s2 | AST only | +| aliasing.cpp:176:11:176:11 | s2 | IR only | +| aliasing.cpp:176:13:176:14 | s | IR only | | aliasing.cpp:181:15:181:22 | & ... | AST only | -| aliasing.cpp:181:16:181:17 | s2 | AST only | +| aliasing.cpp:182:11:182:11 | s2 | IR only | +| aliasing.cpp:182:13:182:14 | s | IR only | | aliasing.cpp:187:15:187:22 | & ... | AST only | -| aliasing.cpp:187:16:187:17 | s2 | AST only | +| aliasing.cpp:189:13:189:13 | s2_2 | IR only | +| aliasing.cpp:189:15:189:16 | s | IR only | | aliasing.cpp:194:15:194:22 | & ... | AST only | -| aliasing.cpp:194:16:194:17 | s2 | AST only | +| aliasing.cpp:196:13:196:13 | s2_2 | IR only | +| aliasing.cpp:196:15:196:16 | s | IR only | | aliasing.cpp:200:15:200:24 | & ... | AST only | -| aliasing.cpp:200:16:200:18 | ps2 | AST only | +| aliasing.cpp:201:13:201:13 | ps2 | IR only | +| aliasing.cpp:201:15:201:16 | s | IR only | | aliasing.cpp:205:15:205:24 | & ... | AST only | -| aliasing.cpp:205:16:205:18 | ps2 | AST only | -| aliasing.cpp:211:3:211:4 | s2 | AST only | +| aliasing.cpp:206:13:206:13 | ps2 | IR only | +| aliasing.cpp:206:15:206:16 | s | IR only | | aliasing.cpp:211:8:211:9 | m1 | AST only | -| aliasing.cpp:218:3:218:4 | s2 | AST only | +| aliasing.cpp:212:12:212:12 | s2 | IR only | +| aliasing.cpp:213:10:213:11 | s | IR only | | aliasing.cpp:218:8:218:9 | m1 | AST only | +| aliasing.cpp:219:12:219:12 | s2 | IR only | +| aliasing.cpp:220:10:220:11 | s | IR only | | aliasing.cpp:225:15:225:22 | & ... | AST only | -| aliasing.cpp:225:16:225:17 | s2 | AST only | +| aliasing.cpp:226:12:226:12 | s2 | IR only | +| aliasing.cpp:227:10:227:11 | s | IR only | | aliasing.cpp:232:15:232:22 | & ... | AST only | -| aliasing.cpp:232:16:232:17 | s2 | AST only | +| aliasing.cpp:233:12:233:12 | s2 | IR only | +| aliasing.cpp:234:10:234:11 | s | IR only | | arrays.cpp:6:3:6:8 | access to array | AST only | | arrays.cpp:6:3:6:23 | arr | IR only | | arrays.cpp:15:3:15:10 | * ... | AST only | -| arrays.cpp:36:3:36:3 | o | AST only | -| arrays.cpp:36:5:36:10 | nested | AST only | | arrays.cpp:36:19:36:22 | data | AST only | -| arrays.cpp:37:8:37:8 | o | AST only | -| arrays.cpp:37:8:37:22 | access to array | AST only | -| arrays.cpp:37:10:37:15 | nested | AST only | | arrays.cpp:37:24:37:27 | data | AST only | -| arrays.cpp:38:8:38:8 | o | AST only | -| arrays.cpp:38:8:38:22 | access to array | AST only | -| arrays.cpp:38:10:38:15 | nested | AST only | | arrays.cpp:38:24:38:27 | data | AST only | -| arrays.cpp:42:3:42:3 | o | AST only | -| arrays.cpp:42:3:42:20 | access to array | AST only | -| arrays.cpp:42:5:42:12 | indirect | AST only | | arrays.cpp:42:22:42:25 | data | AST only | -| arrays.cpp:43:8:43:8 | o | AST only | -| arrays.cpp:43:8:43:25 | access to array | AST only | -| arrays.cpp:43:10:43:17 | indirect | AST only | | arrays.cpp:43:27:43:30 | data | AST only | -| arrays.cpp:44:8:44:8 | o | AST only | -| arrays.cpp:44:8:44:25 | access to array | AST only | -| arrays.cpp:44:10:44:17 | indirect | AST only | | arrays.cpp:44:27:44:30 | data | AST only | -| arrays.cpp:48:3:48:3 | o | AST only | -| arrays.cpp:48:3:48:20 | access to array | AST only | -| arrays.cpp:48:5:48:12 | indirect | AST only | | arrays.cpp:48:22:48:25 | data | AST only | -| arrays.cpp:49:8:49:8 | o | AST only | -| arrays.cpp:49:8:49:25 | access to array | AST only | -| arrays.cpp:49:10:49:17 | indirect | AST only | | arrays.cpp:49:27:49:30 | data | AST only | -| arrays.cpp:50:8:50:8 | o | AST only | -| arrays.cpp:50:8:50:25 | access to array | AST only | -| arrays.cpp:50:10:50:17 | indirect | AST only | | arrays.cpp:50:27:50:30 | data | AST only | | by_reference.cpp:12:8:12:8 | a | AST only | | by_reference.cpp:16:11:16:11 | a | AST only | @@ -235,6 +200,8 @@ | by_reference.cpp:20:23:20:27 | value | AST only | | by_reference.cpp:24:19:24:22 | this | AST only | | by_reference.cpp:24:25:24:29 | value | AST only | +| by_reference.cpp:32:15:32:15 | s | IR only | +| by_reference.cpp:36:18:36:18 | this | IR only | | by_reference.cpp:50:3:50:3 | s | AST only | | by_reference.cpp:50:17:50:26 | call to user_input | AST only | | by_reference.cpp:51:10:51:20 | call to getDirectly | AST only | @@ -252,71 +219,45 @@ | by_reference.cpp:92:3:92:5 | * ... | AST only | | by_reference.cpp:96:3:96:4 | pa | AST only | | by_reference.cpp:102:21:102:39 | & ... | AST only | -| by_reference.cpp:103:21:103:25 | outer | AST only | | by_reference.cpp:103:27:103:35 | inner_ptr | AST only | | by_reference.cpp:104:15:104:22 | & ... | AST only | | by_reference.cpp:106:21:106:41 | & ... | AST only | -| by_reference.cpp:107:21:107:26 | pouter | AST only | | by_reference.cpp:107:29:107:37 | inner_ptr | AST only | | by_reference.cpp:108:15:108:24 | & ... | AST only | -| by_reference.cpp:110:8:110:12 | outer | AST only | -| by_reference.cpp:110:14:110:25 | inner_nested | AST only | | by_reference.cpp:110:27:110:27 | a | AST only | -| by_reference.cpp:111:8:111:12 | outer | AST only | -| by_reference.cpp:111:14:111:22 | inner_ptr | AST only | | by_reference.cpp:111:25:111:25 | a | AST only | -| by_reference.cpp:112:8:112:12 | outer | AST only | | by_reference.cpp:112:14:112:14 | a | AST only | -| by_reference.cpp:114:8:114:13 | pouter | AST only | -| by_reference.cpp:114:16:114:27 | inner_nested | AST only | | by_reference.cpp:114:29:114:29 | a | AST only | -| by_reference.cpp:115:8:115:13 | pouter | AST only | -| by_reference.cpp:115:16:115:24 | inner_ptr | AST only | | by_reference.cpp:115:27:115:27 | a | AST only | -| by_reference.cpp:116:8:116:13 | pouter | AST only | | by_reference.cpp:116:16:116:16 | a | AST only | | by_reference.cpp:122:27:122:38 | inner_nested | AST only | | by_reference.cpp:123:21:123:36 | * ... | AST only | -| by_reference.cpp:123:22:123:26 | outer | AST only | | by_reference.cpp:124:21:124:21 | a | AST only | | by_reference.cpp:126:29:126:40 | inner_nested | AST only | | by_reference.cpp:127:21:127:38 | * ... | AST only | -| by_reference.cpp:127:22:127:27 | pouter | AST only | | by_reference.cpp:128:23:128:23 | a | AST only | -| by_reference.cpp:130:8:130:12 | outer | AST only | -| by_reference.cpp:130:14:130:25 | inner_nested | AST only | | by_reference.cpp:130:27:130:27 | a | AST only | -| by_reference.cpp:131:8:131:12 | outer | AST only | -| by_reference.cpp:131:14:131:22 | inner_ptr | AST only | | by_reference.cpp:131:25:131:25 | a | AST only | -| by_reference.cpp:132:8:132:12 | outer | AST only | | by_reference.cpp:132:14:132:14 | a | AST only | -| by_reference.cpp:134:8:134:13 | pouter | AST only | -| by_reference.cpp:134:16:134:27 | inner_nested | AST only | | by_reference.cpp:134:29:134:29 | a | AST only | -| by_reference.cpp:135:8:135:13 | pouter | AST only | -| by_reference.cpp:135:16:135:24 | inner_ptr | AST only | | by_reference.cpp:135:27:135:27 | a | AST only | -| by_reference.cpp:136:8:136:13 | pouter | AST only | | by_reference.cpp:136:16:136:16 | a | AST only | +| complex.cpp:9:20:9:21 | this | IR only | +| complex.cpp:10:20:10:21 | this | IR only | | complex.cpp:11:22:11:23 | a_ | AST only | | complex.cpp:12:22:12:23 | b_ | AST only | -| complex.cpp:42:8:42:8 | b | AST only | | complex.cpp:42:16:42:16 | f | AST only | -| complex.cpp:43:8:43:8 | b | AST only | | complex.cpp:43:16:43:16 | f | AST only | -| complex.cpp:53:3:53:4 | b1 | AST only | | complex.cpp:53:12:53:12 | f | AST only | -| complex.cpp:54:3:54:4 | b2 | AST only | | complex.cpp:54:12:54:12 | f | AST only | -| complex.cpp:55:3:55:4 | b3 | AST only | | complex.cpp:55:12:55:12 | f | AST only | -| complex.cpp:56:3:56:4 | b3 | AST only | | complex.cpp:56:12:56:12 | f | AST only | | complex.cpp:59:7:59:8 | b1 | AST only | | complex.cpp:62:7:62:8 | b2 | AST only | | complex.cpp:65:7:65:8 | b3 | AST only | | complex.cpp:68:7:68:8 | b4 | AST only | +| constructors.cpp:18:22:18:23 | this | IR only | +| constructors.cpp:19:22:19:23 | this | IR only | | constructors.cpp:20:24:20:25 | a_ | AST only | | constructors.cpp:21:24:21:25 | b_ | AST only | | constructors.cpp:28:10:28:10 | f | AST only | @@ -328,68 +269,55 @@ | qualifiers.cpp:9:36:9:36 | a | AST only | | qualifiers.cpp:12:56:12:56 | a | AST only | | qualifiers.cpp:13:57:13:57 | a | AST only | +| qualifiers.cpp:18:32:18:36 | this | IR only | | qualifiers.cpp:22:5:22:9 | outer | AST only | -| qualifiers.cpp:22:11:22:18 | call to getInner | AST only | | qualifiers.cpp:22:23:22:23 | a | AST only | -| qualifiers.cpp:23:10:23:14 | outer | AST only | -| qualifiers.cpp:23:16:23:20 | inner | AST only | | qualifiers.cpp:23:23:23:23 | a | AST only | | qualifiers.cpp:27:5:27:9 | outer | AST only | | qualifiers.cpp:27:11:27:18 | call to getInner | AST only | | qualifiers.cpp:27:28:27:37 | call to user_input | AST only | -| qualifiers.cpp:28:10:28:14 | outer | AST only | -| qualifiers.cpp:28:16:28:20 | inner | AST only | | qualifiers.cpp:28:23:28:23 | a | AST only | | qualifiers.cpp:32:17:32:21 | outer | AST only | | qualifiers.cpp:32:23:32:30 | call to getInner | AST only | | qualifiers.cpp:32:35:32:44 | call to user_input | AST only | -| qualifiers.cpp:33:10:33:14 | outer | AST only | -| qualifiers.cpp:33:16:33:20 | inner | AST only | | qualifiers.cpp:33:23:33:23 | a | AST only | | qualifiers.cpp:37:19:37:35 | * ... | AST only | | qualifiers.cpp:37:20:37:24 | outer | AST only | | qualifiers.cpp:37:38:37:47 | call to user_input | AST only | -| qualifiers.cpp:38:10:38:14 | outer | AST only | -| qualifiers.cpp:38:16:38:20 | inner | AST only | | qualifiers.cpp:38:23:38:23 | a | AST only | -| qualifiers.cpp:42:6:42:22 | * ... | AST only | | qualifiers.cpp:42:7:42:11 | outer | AST only | | qualifiers.cpp:42:25:42:25 | a | AST only | -| qualifiers.cpp:43:10:43:14 | outer | AST only | -| qualifiers.cpp:43:16:43:20 | inner | AST only | | qualifiers.cpp:43:23:43:23 | a | AST only | | qualifiers.cpp:47:6:47:11 | & ... | AST only | -| qualifiers.cpp:47:15:47:22 | call to getInner | AST only | | qualifiers.cpp:47:27:47:27 | a | AST only | -| qualifiers.cpp:48:10:48:14 | outer | AST only | -| qualifiers.cpp:48:16:48:20 | inner | AST only | | qualifiers.cpp:48:23:48:23 | a | AST only | | realistic.cpp:26:5:26:10 | offset | AST only | | realistic.cpp:42:20:42:20 | o | AST only | -| realistic.cpp:49:9:49:11 | foo | AST only | | realistic.cpp:49:20:49:22 | baz | AST only | -| realistic.cpp:53:9:53:11 | foo | AST only | -| realistic.cpp:53:9:53:18 | access to array | AST only | -| realistic.cpp:53:20:53:22 | baz | AST only | -| realistic.cpp:53:25:53:33 | userInput | AST only | | realistic.cpp:53:35:53:43 | bufferLen | AST only | -| realistic.cpp:54:16:54:18 | foo | AST only | -| realistic.cpp:54:16:54:25 | access to array | AST only | -| realistic.cpp:54:27:54:29 | baz | AST only | -| realistic.cpp:54:32:54:40 | userInput | AST only | | realistic.cpp:54:42:54:47 | buffer | AST only | +| realistic.cpp:55:16:55:18 | foo | IR only | +| realistic.cpp:55:23:55:25 | access to array | IR only | +| realistic.cpp:55:28:55:36 | baz | IR only | +| realistic.cpp:55:38:55:46 | userInput | IR only | +| realistic.cpp:57:92:57:94 | foo | IR only | +| realistic.cpp:57:99:57:101 | access to array | IR only | +| realistic.cpp:57:104:57:112 | baz | IR only | +| realistic.cpp:57:114:57:122 | userInput | IR only | | realistic.cpp:60:16:60:18 | dst | AST only | -| realistic.cpp:61:21:61:23 | foo | AST only | -| realistic.cpp:61:21:61:30 | access to array | AST only | -| realistic.cpp:61:32:61:34 | baz | AST only | -| realistic.cpp:61:37:61:45 | userInput | AST only | +| realistic.cpp:60:25:60:27 | foo | IR only | +| realistic.cpp:60:32:60:34 | access to array | IR only | +| realistic.cpp:60:37:60:45 | baz | IR only | +| realistic.cpp:60:47:60:52 | userInput | IR only | +| realistic.cpp:60:59:60:61 | foo | IR only | +| realistic.cpp:60:66:60:68 | access to array | IR only | +| realistic.cpp:60:71:60:79 | baz | IR only | +| realistic.cpp:60:81:60:89 | userInput | IR only | | realistic.cpp:61:47:61:55 | bufferLen | AST only | -| realistic.cpp:65:21:65:23 | foo | AST only | -| realistic.cpp:65:21:65:30 | access to array | AST only | -| realistic.cpp:65:32:65:34 | baz | AST only | -| realistic.cpp:65:37:65:45 | userInput | AST only | | realistic.cpp:65:47:65:52 | buffer | AST only | | realistic.cpp:66:21:66:23 | dst | AST only | +| simple.cpp:18:22:18:23 | this | IR only | +| simple.cpp:19:22:19:23 | this | IR only | | simple.cpp:20:24:20:25 | a_ | AST only | | simple.cpp:21:24:21:25 | b_ | AST only | | simple.cpp:28:10:28:10 | f | AST only | @@ -403,33 +331,24 @@ | simple.cpp:51:9:51:9 | h | AST only | | simple.cpp:54:9:54:9 | i | AST only | | simple.cpp:65:7:65:7 | i | AST only | -| simple.cpp:83:9:83:10 | this | AST only | +| simple.cpp:67:13:67:13 | a2 | IR only | +| simple.cpp:79:16:79:17 | this | IR only | +| simple.cpp:79:19:79:20 | f2 | IR only | | simple.cpp:83:12:83:13 | f1 | AST only | | simple.cpp:84:14:84:20 | this | AST only | | simple.cpp:92:7:92:7 | i | AST only | -| simple.cpp:104:5:104:5 | b | AST only | +| simple.cpp:94:13:94:13 | a2 | IR only | | simple.cpp:104:9:104:9 | i | AST only | -| struct_init.c:15:8:15:9 | ab | AST only | +| simple.cpp:106:13:106:13 | b2 | IR only | +| simple.cpp:106:15:106:15 | a | IR only | | struct_init.c:15:12:15:12 | a | AST only | -| struct_init.c:16:8:16:9 | ab | AST only | | struct_init.c:16:12:16:12 | b | AST only | -| struct_init.c:22:8:22:9 | ab | AST only | | struct_init.c:22:11:22:11 | a | AST only | -| struct_init.c:23:8:23:9 | ab | AST only | | struct_init.c:23:11:23:11 | b | AST only | | struct_init.c:24:10:24:12 | & ... | AST only | -| struct_init.c:31:8:31:12 | outer | AST only | -| struct_init.c:31:14:31:21 | nestedAB | AST only | | struct_init.c:31:23:31:23 | a | AST only | -| struct_init.c:32:8:32:12 | outer | AST only | -| struct_init.c:32:14:32:21 | nestedAB | AST only | | struct_init.c:32:23:32:23 | b | AST only | -| struct_init.c:33:8:33:12 | outer | AST only | -| struct_init.c:33:14:33:22 | pointerAB | AST only | | struct_init.c:33:25:33:25 | a | AST only | -| struct_init.c:34:8:34:12 | outer | AST only | -| struct_init.c:34:14:34:22 | pointerAB | AST only | | struct_init.c:34:25:34:25 | b | AST only | | struct_init.c:36:10:36:24 | & ... | AST only | -| struct_init.c:46:10:46:14 | outer | AST only | | struct_init.c:46:16:46:24 | pointerAB | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected index 5b73bf8dd33..0f534661aa5 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected @@ -1,76 +1,323 @@ | A.cpp:25:7:25:10 | this | | A.cpp:27:22:27:25 | this | +| A.cpp:28:23:28:26 | this | +| A.cpp:49:10:49:10 | b | +| A.cpp:65:10:65:11 | b1 | +| A.cpp:66:10:66:11 | b2 | +| A.cpp:74:10:74:11 | b1 | +| A.cpp:75:10:75:11 | b2 | | A.cpp:100:5:100:6 | c1 | +| A.cpp:107:12:107:13 | c1 | +| A.cpp:120:12:120:13 | c1 | +| A.cpp:132:10:132:10 | b | | A.cpp:142:7:142:7 | b | | A.cpp:143:7:143:10 | this | +| A.cpp:152:10:152:10 | d | +| A.cpp:153:10:153:10 | d | +| A.cpp:153:13:153:13 | b | +| A.cpp:154:10:154:10 | b | +| A.cpp:163:10:163:11 | l3 | +| A.cpp:164:10:164:11 | l3 | +| A.cpp:164:14:164:17 | next | +| A.cpp:165:10:165:11 | l3 | +| A.cpp:165:14:165:17 | next | +| A.cpp:165:20:165:23 | next | +| A.cpp:166:10:166:11 | l3 | +| A.cpp:166:14:166:17 | next | +| A.cpp:166:20:166:23 | next | +| A.cpp:166:26:166:29 | next | +| A.cpp:167:44:167:44 | l | +| A.cpp:169:12:169:12 | l | | A.cpp:183:7:183:10 | this | | A.cpp:184:7:184:10 | this | +| B.cpp:9:10:9:11 | b2 | +| B.cpp:9:14:9:17 | box1 | +| B.cpp:10:10:10:11 | b2 | +| B.cpp:10:14:10:17 | box1 | +| B.cpp:18:10:18:11 | b2 | +| B.cpp:18:14:18:17 | box1 | +| B.cpp:19:10:19:11 | b2 | +| B.cpp:19:14:19:17 | box1 | | B.cpp:35:7:35:10 | this | | B.cpp:36:7:36:10 | this | | B.cpp:46:7:46:10 | this | | C.cpp:24:5:24:8 | this | +| C.cpp:29:10:29:11 | this | +| C.cpp:30:10:30:11 | this | +| C.cpp:31:10:31:11 | this | | D.cpp:9:21:9:24 | this | +| D.cpp:10:30:10:33 | this | | D.cpp:11:29:11:32 | this | | D.cpp:16:21:16:23 | this | +| D.cpp:17:30:17:32 | this | | D.cpp:18:29:18:31 | this | +| D.cpp:30:5:30:5 | b | +| D.cpp:30:8:30:10 | box | +| D.cpp:37:5:37:5 | b | +| D.cpp:44:8:44:14 | call to getBox1 | | D.cpp:57:5:57:12 | this | +| D.cpp:58:5:58:12 | boxfield | +| D.cpp:58:5:58:12 | this | +| D.cpp:58:15:58:17 | box | +| D.cpp:64:10:64:17 | boxfield | +| D.cpp:64:10:64:17 | this | +| D.cpp:64:20:64:22 | box | +| E.cpp:21:10:21:10 | p | +| E.cpp:21:13:21:16 | data | +| E.cpp:29:21:29:21 | b | +| E.cpp:30:21:30:21 | p | +| E.cpp:30:23:30:26 | data | +| E.cpp:32:10:32:10 | b | | aliasing.cpp:9:3:9:3 | s | | aliasing.cpp:13:3:13:3 | s | | aliasing.cpp:17:3:17:3 | s | +| aliasing.cpp:29:8:29:9 | s1 | +| aliasing.cpp:30:8:30:9 | s2 | +| aliasing.cpp:31:8:31:9 | s3 | | aliasing.cpp:37:3:37:6 | ref1 | +| aliasing.cpp:38:8:38:9 | s1 | | aliasing.cpp:42:3:42:4 | s2 | +| aliasing.cpp:43:8:43:11 | ref2 | | aliasing.cpp:49:3:49:7 | copy1 | +| aliasing.cpp:50:8:50:9 | s1 | | aliasing.cpp:54:3:54:4 | s2 | +| aliasing.cpp:55:8:55:12 | copy2 | | aliasing.cpp:60:3:60:4 | s2 | +| aliasing.cpp:62:8:62:12 | copy2 | +| aliasing.cpp:71:9:71:9 | w | | aliasing.cpp:72:3:72:3 | s | +| aliasing.cpp:73:8:73:8 | w | +| aliasing.cpp:73:10:73:10 | s | +| aliasing.cpp:78:11:78:11 | w | | aliasing.cpp:79:3:79:3 | s | +| aliasing.cpp:80:8:80:8 | w | +| aliasing.cpp:80:10:80:10 | s | +| aliasing.cpp:85:10:85:10 | w | | aliasing.cpp:86:3:86:3 | s | +| aliasing.cpp:87:8:87:8 | w | +| aliasing.cpp:87:10:87:10 | s | +| aliasing.cpp:92:3:92:3 | w | | aliasing.cpp:92:5:92:5 | s | +| aliasing.cpp:93:8:93:8 | w | +| aliasing.cpp:93:10:93:10 | s | | aliasing.cpp:98:3:98:3 | s | +| aliasing.cpp:101:14:101:19 | s_copy | | aliasing.cpp:111:16:111:16 | s | +| aliasing.cpp:112:8:112:8 | s | +| aliasing.cpp:141:15:141:15 | s | +| aliasing.cpp:143:8:143:8 | s | | aliasing.cpp:147:16:147:19 | access to array | +| aliasing.cpp:148:8:148:11 | access to array | +| aliasing.cpp:158:15:158:15 | s | +| aliasing.cpp:159:9:159:9 | s | +| aliasing.cpp:164:15:164:15 | s | +| aliasing.cpp:165:8:165:8 | s | +| aliasing.cpp:175:16:175:17 | s2 | | aliasing.cpp:175:19:175:19 | s | +| aliasing.cpp:176:8:176:9 | s2 | +| aliasing.cpp:176:11:176:11 | s | +| aliasing.cpp:181:16:181:17 | s2 | | aliasing.cpp:181:19:181:19 | s | +| aliasing.cpp:182:8:182:9 | s2 | +| aliasing.cpp:182:11:182:11 | s | +| aliasing.cpp:187:16:187:17 | s2 | | aliasing.cpp:187:19:187:19 | s | +| aliasing.cpp:189:8:189:11 | s2_2 | +| aliasing.cpp:189:13:189:13 | s | +| aliasing.cpp:194:16:194:17 | s2 | | aliasing.cpp:194:19:194:19 | s | +| aliasing.cpp:196:8:196:11 | s2_2 | +| aliasing.cpp:196:13:196:13 | s | +| aliasing.cpp:200:16:200:18 | ps2 | | aliasing.cpp:200:21:200:21 | s | +| aliasing.cpp:201:8:201:10 | ps2 | +| aliasing.cpp:201:13:201:13 | s | +| aliasing.cpp:205:16:205:18 | ps2 | | aliasing.cpp:205:21:205:21 | s | +| aliasing.cpp:206:8:206:10 | ps2 | +| aliasing.cpp:206:13:206:13 | s | +| aliasing.cpp:211:3:211:4 | s2 | | aliasing.cpp:211:6:211:6 | s | +| aliasing.cpp:212:9:212:10 | s2 | +| aliasing.cpp:213:8:213:8 | s | +| aliasing.cpp:218:3:218:4 | s2 | | aliasing.cpp:218:6:218:6 | s | +| aliasing.cpp:219:9:219:10 | s2 | +| aliasing.cpp:220:8:220:8 | s | +| aliasing.cpp:225:16:225:17 | s2 | | aliasing.cpp:225:19:225:19 | s | +| aliasing.cpp:226:9:226:10 | s2 | +| aliasing.cpp:227:8:227:8 | s | +| aliasing.cpp:232:16:232:17 | s2 | | aliasing.cpp:232:19:232:19 | s | +| aliasing.cpp:233:9:233:10 | s2 | +| aliasing.cpp:234:8:234:8 | s | | arrays.cpp:6:3:6:5 | arr | +| arrays.cpp:36:3:36:3 | o | | arrays.cpp:36:3:36:17 | access to array | +| arrays.cpp:36:5:36:10 | nested | +| arrays.cpp:37:8:37:8 | o | +| arrays.cpp:37:8:37:22 | access to array | +| arrays.cpp:37:10:37:15 | nested | +| arrays.cpp:38:8:38:8 | o | +| arrays.cpp:38:8:38:22 | access to array | +| arrays.cpp:38:10:38:15 | nested | +| arrays.cpp:42:3:42:3 | o | +| arrays.cpp:42:3:42:20 | access to array | +| arrays.cpp:42:5:42:12 | indirect | +| arrays.cpp:43:8:43:8 | o | +| arrays.cpp:43:8:43:25 | access to array | +| arrays.cpp:43:10:43:17 | indirect | +| arrays.cpp:44:8:44:8 | o | +| arrays.cpp:44:8:44:25 | access to array | +| arrays.cpp:44:10:44:17 | indirect | +| arrays.cpp:48:3:48:3 | o | +| arrays.cpp:48:3:48:20 | access to array | +| arrays.cpp:48:5:48:12 | indirect | +| arrays.cpp:49:8:49:8 | o | +| arrays.cpp:49:8:49:25 | access to array | +| arrays.cpp:49:10:49:17 | indirect | +| arrays.cpp:50:8:50:8 | o | +| arrays.cpp:50:8:50:25 | access to array | +| arrays.cpp:50:10:50:17 | indirect | | by_reference.cpp:12:5:12:5 | s | | by_reference.cpp:16:5:16:8 | this | +| by_reference.cpp:32:12:32:12 | s | +| by_reference.cpp:36:12:36:15 | this | | by_reference.cpp:84:3:84:7 | inner | | by_reference.cpp:88:3:88:7 | inner | | by_reference.cpp:102:22:102:26 | outer | +| by_reference.cpp:103:21:103:25 | outer | | by_reference.cpp:104:16:104:20 | outer | | by_reference.cpp:106:22:106:27 | pouter | +| by_reference.cpp:107:21:107:26 | pouter | | by_reference.cpp:108:16:108:21 | pouter | +| by_reference.cpp:110:8:110:12 | outer | +| by_reference.cpp:110:14:110:25 | inner_nested | +| by_reference.cpp:111:8:111:12 | outer | +| by_reference.cpp:111:14:111:22 | inner_ptr | +| by_reference.cpp:112:8:112:12 | outer | +| by_reference.cpp:114:8:114:13 | pouter | +| by_reference.cpp:114:16:114:27 | inner_nested | +| by_reference.cpp:115:8:115:13 | pouter | +| by_reference.cpp:115:16:115:24 | inner_ptr | +| by_reference.cpp:116:8:116:13 | pouter | | by_reference.cpp:122:21:122:25 | outer | +| by_reference.cpp:123:22:123:26 | outer | | by_reference.cpp:124:15:124:19 | outer | | by_reference.cpp:126:21:126:26 | pouter | +| by_reference.cpp:127:22:127:27 | pouter | | by_reference.cpp:128:15:128:20 | pouter | +| by_reference.cpp:130:8:130:12 | outer | +| by_reference.cpp:130:14:130:25 | inner_nested | +| by_reference.cpp:131:8:131:12 | outer | +| by_reference.cpp:131:14:131:22 | inner_ptr | +| by_reference.cpp:132:8:132:12 | outer | +| by_reference.cpp:134:8:134:13 | pouter | +| by_reference.cpp:134:16:134:27 | inner_nested | +| by_reference.cpp:135:8:135:13 | pouter | +| by_reference.cpp:135:16:135:24 | inner_ptr | +| by_reference.cpp:136:8:136:13 | pouter | +| complex.cpp:9:20:9:21 | this | +| complex.cpp:10:20:10:21 | this | | complex.cpp:11:22:11:23 | this | | complex.cpp:12:22:12:23 | this | +| complex.cpp:42:8:42:8 | b | | complex.cpp:42:10:42:14 | inner | +| complex.cpp:43:8:43:8 | b | | complex.cpp:43:10:43:14 | inner | +| complex.cpp:53:3:53:4 | b1 | | complex.cpp:53:6:53:10 | inner | +| complex.cpp:54:3:54:4 | b2 | | complex.cpp:54:6:54:10 | inner | +| complex.cpp:55:3:55:4 | b3 | | complex.cpp:55:6:55:10 | inner | +| complex.cpp:56:3:56:4 | b3 | | complex.cpp:56:6:56:10 | inner | +| constructors.cpp:18:22:18:23 | this | +| constructors.cpp:19:22:19:23 | this | | constructors.cpp:20:24:20:25 | this | | constructors.cpp:21:24:21:25 | this | | qualifiers.cpp:9:30:9:33 | this | | qualifiers.cpp:12:49:12:53 | inner | | qualifiers.cpp:13:51:13:55 | inner | +| qualifiers.cpp:18:32:18:36 | this | +| qualifiers.cpp:22:11:22:18 | call to getInner | +| qualifiers.cpp:23:10:23:14 | outer | +| qualifiers.cpp:23:16:23:20 | inner | +| qualifiers.cpp:28:10:28:14 | outer | +| qualifiers.cpp:28:16:28:20 | inner | +| qualifiers.cpp:33:10:33:14 | outer | +| qualifiers.cpp:33:16:33:20 | inner | +| qualifiers.cpp:38:10:38:14 | outer | +| qualifiers.cpp:38:16:38:20 | inner | +| qualifiers.cpp:42:6:42:22 | * ... | +| qualifiers.cpp:43:10:43:14 | outer | +| qualifiers.cpp:43:16:43:20 | inner | +| qualifiers.cpp:47:15:47:22 | call to getInner | +| qualifiers.cpp:48:10:48:14 | outer | +| qualifiers.cpp:48:16:48:20 | inner | +| realistic.cpp:49:9:49:11 | foo | | realistic.cpp:49:9:49:18 | access to array | +| realistic.cpp:53:9:53:11 | foo | +| realistic.cpp:53:9:53:18 | access to array | +| realistic.cpp:53:20:53:22 | baz | +| realistic.cpp:53:25:53:33 | userInput | +| realistic.cpp:54:16:54:18 | foo | +| realistic.cpp:54:16:54:25 | access to array | +| realistic.cpp:54:27:54:29 | baz | +| realistic.cpp:54:32:54:40 | userInput | +| realistic.cpp:55:12:55:14 | foo | +| realistic.cpp:55:12:55:21 | access to array | +| realistic.cpp:55:23:55:25 | baz | +| realistic.cpp:55:28:55:36 | userInput | +| realistic.cpp:57:88:57:90 | foo | +| realistic.cpp:57:88:57:97 | access to array | +| realistic.cpp:57:99:57:101 | baz | +| realistic.cpp:57:104:57:112 | userInput | +| realistic.cpp:60:21:60:23 | foo | +| realistic.cpp:60:21:60:30 | access to array | +| realistic.cpp:60:32:60:34 | baz | +| realistic.cpp:60:37:60:45 | userInput | +| realistic.cpp:60:55:60:57 | foo | +| realistic.cpp:60:55:60:64 | access to array | +| realistic.cpp:60:66:60:68 | baz | +| realistic.cpp:60:71:60:79 | userInput | +| realistic.cpp:61:21:61:23 | foo | +| realistic.cpp:61:21:61:30 | access to array | +| realistic.cpp:61:32:61:34 | baz | +| realistic.cpp:61:37:61:45 | userInput | +| realistic.cpp:65:21:65:23 | foo | +| realistic.cpp:65:21:65:30 | access to array | +| realistic.cpp:65:32:65:34 | baz | +| realistic.cpp:65:37:65:45 | userInput | +| simple.cpp:18:22:18:23 | this | +| simple.cpp:19:22:19:23 | this | | simple.cpp:20:24:20:25 | this | | simple.cpp:21:24:21:25 | this | | simple.cpp:65:5:65:5 | a | +| simple.cpp:67:10:67:11 | a2 | +| simple.cpp:79:16:79:17 | f2 | +| simple.cpp:79:16:79:17 | this | | simple.cpp:83:9:83:10 | f2 | +| simple.cpp:83:9:83:10 | this | | simple.cpp:92:5:92:5 | a | +| simple.cpp:94:10:94:11 | a2 | +| simple.cpp:104:5:104:5 | b | | simple.cpp:104:7:104:7 | a | +| simple.cpp:106:10:106:11 | b2 | +| simple.cpp:106:13:106:13 | a | +| struct_init.c:15:8:15:9 | ab | +| struct_init.c:16:8:16:9 | ab | +| struct_init.c:22:8:22:9 | ab | +| struct_init.c:23:8:23:9 | ab | +| struct_init.c:31:8:31:12 | outer | +| struct_init.c:31:14:31:21 | nestedAB | +| struct_init.c:32:8:32:12 | outer | +| struct_init.c:32:14:32:21 | nestedAB | +| struct_init.c:33:8:33:12 | outer | +| struct_init.c:33:14:33:22 | pointerAB | +| struct_init.c:34:8:34:12 | outer | +| struct_init.c:34:14:34:22 | pointerAB | | struct_init.c:36:11:36:15 | outer | +| struct_init.c:46:10:46:14 | outer | From a8b4fb6fd001612730115a809ae97d8590beb7a7 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Sun, 6 Dec 2020 14:23:35 +0100 Subject: [PATCH 036/343] C++: Add qldoc (and remove predicate that wasn't needed). --- .../code/cpp/ir/dataflow/internal/DataFlowPrivate.qll | 6 +++--- .../semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index 73649da7594..09f8ae3e97f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll @@ -241,7 +241,7 @@ private predicate instrToFieldNodeStoreStepNoChi( not exists(ChiInstruction chi | chi.getPartial() = store) and post.getPreUpdateNode() = getFieldNodeForFieldInstruction(store.getDestinationAddress()) and store.getSourceValueOperand() = node1.asOperand() and - f.getADirectField() = post.getField() + f.getADirectField() = post.getPreUpdateNode().getField() ) } @@ -262,7 +262,7 @@ private predicate instrToFieldNodeStoreStepChi( chi.getPartialOperand() = operand and store = operand.getDef() and post.getPreUpdateNode() = getFieldNodeForFieldInstruction(store.getDestinationAddress()) and - f.getADirectField() = post.getField() + f.getADirectField() = post.getPreUpdateNode().getField() ) } @@ -278,7 +278,7 @@ private predicate callableWithoutDefinitionStoreStep( post = node2.getPartialDefinition() and node1.asInstruction() = write and post.getPreUpdateNode() = getFieldNodeForFieldInstruction(write.getDestinationAddress()) and - f.getADirectField() = post.getField() and + f.getADirectField() = post.getPreUpdateNode().getField() and callable = write.getPrimaryInstruction().(CallInstruction).getStaticCallTarget() and not callable.hasDefinition() ) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 318ddf9c48d..0d50f848689 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -283,8 +283,6 @@ class PostUpdateFieldNode extends PartialDefinition { override Expr getDefinedExpr() { result = node.getFieldInstruction().getObjectAddress().getUnconvertedResultExpression() } - - Field getField() { result = node.getField() } } /** @@ -450,10 +448,13 @@ abstract class PartialDefinition extends TPartialDefinition { PartialDefinition() { this = MkPartialDefinition(node) } + /** Gets the node before the state update. */ abstract Node getPreUpdateNode(); + /** Gets the expression that is partially defined by this node. */ abstract Expr getDefinedExpr(); + /** Gets a string representation of this partial definition. */ string toString() { result = node.toString() + " [partial definition]" } } @@ -480,6 +481,7 @@ class PartialDefinitionNode extends PostUpdateNode, TPartialDefinitionNode { override Node getPreUpdateNode() { result = pd.getPreUpdateNode() } + /** Gets the `PartialDefinition` associated with this node. */ PartialDefinition getPartialDefinition() { result = pd } override string toString() { result = getPreUpdateNode().toString() + " [post update]" } From fd8034cd8ccfd13d34d10d9b38b2312603d78361 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 11 Dec 2020 16:08:42 +0100 Subject: [PATCH 037/343] C++: Add store step out of read side effects when we don't have a model for the callee. This brings back the lost result on boost. --- .../ir/dataflow/internal/DataFlowPrivate.qll | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index 09f8ae3e97f..72d6db0f8dd 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll @@ -2,6 +2,7 @@ private import cpp private import DataFlowUtil private import semmle.code.cpp.ir.IR private import DataFlowDispatch +private import semmle.code.cpp.models.interfaces.DataFlow /** * A data flow node that occurs as the argument of a call and is passed as-is @@ -271,16 +272,31 @@ private predicate callableWithoutDefinitionStoreStep( ) { exists( WriteSideEffectInstruction write, ChiInstruction chi, PostUpdateFieldNode post, - Function callable + Function callable, CallInstruction call | chi.getPartial() = write and not chi.isResultConflated() and post = node2.getPartialDefinition() and - node1.asInstruction() = write and post.getPreUpdateNode() = getFieldNodeForFieldInstruction(write.getDestinationAddress()) and f.getADirectField() = post.getPreUpdateNode().getField() and - callable = write.getPrimaryInstruction().(CallInstruction).getStaticCallTarget() and + call = write.getPrimaryInstruction() and + callable = call.getStaticCallTarget() and not callable.hasDefinition() + | + exists(OutParameterDeref out | out.getIndex() = write.getIndex() | + callable.(DataFlowFunction).hasDataFlow(_, out) and + node1.asInstruction() = write + ) + or + // Ideally we shouldn't need to do a store step from a read side effect, but if we don't have a + // model for the callee there might not be flow to the write side effect (since the callee has no + // definition). This case ensures that we propagate dataflow when a field is passed into a + // function that has a write side effect, even though the write side effect doesn't have incoming + // flow. + not callable instanceof DataFlowFunction and + exists(ReadSideEffectInstruction read | call = read.getPrimaryInstruction() | + node1.asInstruction() = read.getSideEffectOperand().getAnyDef() + ) ) } From 77aa9615c0e1893657c8ade1eb44062a1bcf2caf Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Sat, 12 Dec 2020 17:51:00 +0100 Subject: [PATCH 038/343] C++: Accept test changes in paths. --- .../dataflow-ir-consistency.expected | 194 ++++++++---------- .../TaintedAllocationSize.expected | 24 ++- .../ArithmeticUncontrolled.expected | 30 +-- 3 files changed, 117 insertions(+), 131 deletions(-) diff --git a/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected index 6aeadb2f174..4f709d960cc 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected @@ -1464,117 +1464,93 @@ unreachableNodeCCtx localCallNodes postIsNotPre postHasUniquePre -| assignexpr.cpp:9:2:9:12 | Store | PostUpdateNode should have one pre-update node but has 0. | -| bad_asts.cpp:15:10:15:12 | Store | PostUpdateNode should have one pre-update node but has 0. | -| cpp11.cpp:65:19:65:45 | Store | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:531:14:531:14 | Store | PostUpdateNode should have one pre-update node but has 0. | +| allocators.cpp:16:14:16:36 | Foo output argument | PostUpdateNode should have one pre-update node but has 0. | +| condition_decls.cpp:16:19:16:20 | BoxedInt output argument | PostUpdateNode should have one pre-update node but has 0. | +| condition_decls.cpp:26:23:26:24 | BoxedInt output argument | PostUpdateNode should have one pre-update node but has 0. | +| condition_decls.cpp:41:22:41:23 | BoxedInt output argument | PostUpdateNode should have one pre-update node but has 0. | +| condition_decls.cpp:48:22:48:24 | BoxedInt output argument | PostUpdateNode should have one pre-update node but has 0. | +| condition_decls.cpp:48:34:48:36 | BoxedInt output argument | PostUpdateNode should have one pre-update node but has 0. | +| condition_decls.cpp:48:52:48:53 | BoxedInt output argument | PostUpdateNode should have one pre-update node but has 0. | +| conditional_destructors.cpp:30:9:30:13 | C1 output argument | PostUpdateNode should have one pre-update node but has 0. | +| conditional_destructors.cpp:30:18:30:22 | C1 output argument | PostUpdateNode should have one pre-update node but has 0. | +| conditional_destructors.cpp:33:9:33:13 | C1 output argument | PostUpdateNode should have one pre-update node but has 0. | +| conditional_destructors.cpp:33:18:33:22 | C1 output argument | PostUpdateNode should have one pre-update node but has 0. | +| conditional_destructors.cpp:39:9:39:13 | C2 output argument | PostUpdateNode should have one pre-update node but has 0. | +| conditional_destructors.cpp:39:18:39:22 | C2 output argument | PostUpdateNode should have one pre-update node but has 0. | +| conditional_destructors.cpp:42:9:42:13 | C2 output argument | PostUpdateNode should have one pre-update node but has 0. | +| conditional_destructors.cpp:42:18:42:22 | C2 output argument | PostUpdateNode should have one pre-update node but has 0. | +| constructorinitializer.cpp:8:6:8:18 | C output argument | PostUpdateNode should have one pre-update node but has 0. | +| cpp11.cpp:77:19:77:21 | Val output argument | PostUpdateNode should have one pre-update node but has 0. | +| cpp11.cpp:82:11:82:14 | Val output argument | PostUpdateNode should have one pre-update node but has 0. | +| cpp11.cpp:82:17:82:55 | Val output argument | PostUpdateNode should have one pre-update node but has 0. | +| cpp11.cpp:82:45:82:48 | Val output argument | PostUpdateNode should have one pre-update node but has 0. | +| cpp11.cpp:82:51:82:51 | Val output argument | PostUpdateNode should have one pre-update node but has 0. | +| cpp11.cpp:88:25:88:30 | Val output argument | PostUpdateNode should have one pre-update node but has 0. | +| cpp11.cpp:88:33:88:38 | Val output argument | PostUpdateNode should have one pre-update node but has 0. | +| cpp17.cpp:15:5:15:45 | HasTwoArgCtor output argument | PostUpdateNode should have one pre-update node but has 0. | +| destructors.cpp:50:9:50:13 | C output argument | PostUpdateNode should have one pre-update node but has 0. | +| destructors.cpp:51:36:51:38 | C output argument | PostUpdateNode should have one pre-update node but has 0. | +| file://:0:0:0:0 | C output argument | PostUpdateNode should have one pre-update node but has 0. | +| ir.cpp:616:12:616:13 | String output argument | PostUpdateNode should have one pre-update node but has 0. | +| ir.cpp:617:15:617:22 | String output argument | PostUpdateNode should have one pre-update node but has 0. | +| ir.cpp:619:16:619:30 | String output argument | PostUpdateNode should have one pre-update node but has 0. | +| ir.cpp:662:9:662:19 | String output argument | PostUpdateNode should have one pre-update node but has 0. | +| ir.cpp:663:5:663:5 | String output argument | PostUpdateNode should have one pre-update node but has 0. | +| ir.cpp:736:5:736:19 | String output argument | PostUpdateNode should have one pre-update node but has 0. | +| ir.cpp:745:8:745:8 | String output argument | PostUpdateNode should have one pre-update node but has 0. | +| ir.cpp:748:10:748:10 | String output argument | PostUpdateNode should have one pre-update node but has 0. | +| ir.cpp:757:12:757:12 | Base output argument | PostUpdateNode should have one pre-update node but has 0. | +| ir.cpp:757:12:757:12 | String output argument | PostUpdateNode should have one pre-update node but has 0. | +| ir.cpp:766:13:766:13 | Middle output argument | PostUpdateNode should have one pre-update node but has 0. | +| ir.cpp:766:13:766:13 | String output argument | PostUpdateNode should have one pre-update node but has 0. | +| ir.cpp:775:15:775:15 | Base output argument | PostUpdateNode should have one pre-update node but has 0. | +| ir.cpp:775:15:775:15 | String output argument | PostUpdateNode should have one pre-update node but has 0. | +| ir.cpp:784:15:784:15 | Base output argument | PostUpdateNode should have one pre-update node but has 0. | +| ir.cpp:784:15:784:15 | String output argument | PostUpdateNode should have one pre-update node but has 0. | +| ir.cpp:793:15:793:15 | Base output argument | PostUpdateNode should have one pre-update node but has 0. | +| ir.cpp:793:15:793:15 | MiddleVB1 output argument | PostUpdateNode should have one pre-update node but has 0. | +| ir.cpp:793:15:793:15 | MiddleVB2 output argument | PostUpdateNode should have one pre-update node but has 0. | +| ir.cpp:793:15:793:15 | String output argument | PostUpdateNode should have one pre-update node but has 0. | +| ir.cpp:800:8:800:8 | Base output argument | PostUpdateNode should have one pre-update node but has 0. | +| ir.cpp:801:10:801:10 | Middle output argument | PostUpdateNode should have one pre-update node but has 0. | +| ir.cpp:802:11:802:11 | Derived output argument | PostUpdateNode should have one pre-update node but has 0. | +| ir.cpp:809:7:809:13 | Base output argument | PostUpdateNode should have one pre-update node but has 0. | +| ir.cpp:810:7:810:26 | Base output argument | PostUpdateNode should have one pre-update node but has 0. | +| ir.cpp:823:7:823:13 | Base output argument | PostUpdateNode should have one pre-update node but has 0. | +| ir.cpp:824:7:824:26 | Base output argument | PostUpdateNode should have one pre-update node but has 0. | +| ir.cpp:846:8:846:8 | PolymorphicBase output argument | PostUpdateNode should have one pre-update node but has 0. | +| ir.cpp:850:19:850:19 | PolymorphicBase output argument | PostUpdateNode should have one pre-update node but has 0. | +| ir.cpp:851:22:851:22 | PolymorphicDerived output argument | PostUpdateNode should have one pre-update node but has 0. | +| ir.cpp:868:3:868:12 | String output argument | PostUpdateNode should have one pre-update node but has 0. | +| ir.cpp:944:3:944:14 | String output argument | PostUpdateNode should have one pre-update node but has 0. | +| ir.cpp:945:3:945:27 | String output argument | PostUpdateNode should have one pre-update node but has 0. | +| ms_assume.cpp:28:18:28:23 | fgets output argument | PostUpdateNode should have one pre-update node but has 0. | +| ms_try_mix.cpp:11:12:11:15 | C output argument | PostUpdateNode should have one pre-update node but has 0. | +| ms_try_mix.cpp:28:12:28:15 | C output argument | PostUpdateNode should have one pre-update node but has 0. | +| ms_try_mix.cpp:48:10:48:13 | C output argument | PostUpdateNode should have one pre-update node but has 0. | +| newexpr.cpp:8:2:8:20 | C output argument | PostUpdateNode should have one pre-update node but has 0. | +| ops.cpp:26:31:26:53 | C_with_constr_destr output argument | PostUpdateNode should have one pre-update node but has 0. | +| parameterinitializer.cpp:25:5:25:8 | c output argument | PostUpdateNode should have one pre-update node but has 0. | +| static_init_templates.cpp:31:10:31:11 | MyClass output argument | PostUpdateNode should have one pre-update node but has 0. | +| static_init_templates.cpp:236:7:236:7 | MyConstructorClass output argument | PostUpdateNode should have one pre-update node but has 0. | +| static_init_templates.cpp:240:7:240:7 | MyConstructorClass output argument | PostUpdateNode should have one pre-update node but has 0. | +| static_init_templates.cpp:249:21:249:23 | MyConstructorClass output argument | PostUpdateNode should have one pre-update node but has 0. | +| static_init_templates.cpp:250:17:250:19 | MyDerivedClass output argument | PostUpdateNode should have one pre-update node but has 0. | +| static_init_templates.cpp:251:20:251:23 | MyContainingClass output argument | PostUpdateNode should have one pre-update node but has 0. | +| stmt_expr.cpp:13:18:13:19 | C output argument | PostUpdateNode should have one pre-update node but has 0. | +| try_catch.cpp:7:8:7:8 | exception output argument | PostUpdateNode should have one pre-update node but has 0. | +| try_catch.cpp:7:8:7:8 | exception output argument | PostUpdateNode should have one pre-update node but has 0. | +| try_catch.cpp:13:5:13:16 | exn1 output argument | PostUpdateNode should have one pre-update node but has 0. | uniquePostUpdate postIsInSameCallable reverseRead argHasPostUpdate postWithInFlow -| aggregateinitializer.c:3:14:3:18 | Chi | PostUpdateNode should not be the target of local flow. | -| aggregateinitializer.c:3:21:3:25 | Chi | PostUpdateNode should not be the target of local flow. | -| allocators.cpp:3:27:3:27 | Chi | PostUpdateNode should not be the target of local flow. | -| allocators.cpp:3:35:3:35 | Chi | PostUpdateNode should not be the target of local flow. | -| allocators.cpp:4:11:4:23 | Chi | PostUpdateNode should not be the target of local flow. | -| allocators.cpp:4:17:4:23 | Chi | PostUpdateNode should not be the target of local flow. | -| assignexpr.cpp:9:2:9:12 | Store | PostUpdateNode should not be the target of local flow. | -| bad_asts.cpp:15:10:15:12 | Store | PostUpdateNode should not be the target of local flow. | -| builtin.c:14:26:14:26 | Chi | PostUpdateNode should not be the target of local flow. | -| builtin.c:14:29:14:29 | Chi | PostUpdateNode should not be the target of local flow. | -| builtin.c:14:32:14:32 | Chi | PostUpdateNode should not be the target of local flow. | -| builtin.c:14:35:14:35 | Chi | PostUpdateNode should not be the target of local flow. | -| condition_decls.cpp:3:5:3:22 | Chi | PostUpdateNode should not be the target of local flow. | -| condition_decls.cpp:3:21:3:21 | Chi | PostUpdateNode should not be the target of local flow. | -| conditional_destructors.cpp:6:13:6:19 | Chi | PostUpdateNode should not be the target of local flow. | -| conditional_destructors.cpp:18:13:18:19 | Chi | PostUpdateNode should not be the target of local flow. | -| cpp11.cpp:65:19:65:45 | Store | PostUpdateNode should not be the target of local flow. | -| cpp11.cpp:82:17:82:55 | Chi | PostUpdateNode should not be the target of local flow. | -| cpp11.cpp:82:17:82:55 | Chi | PostUpdateNode should not be the target of local flow. | -| cpp11.cpp:82:45:82:48 | Chi | PostUpdateNode should not be the target of local flow. | -| defdestructordeleteexpr.cpp:4:9:4:15 | Chi | PostUpdateNode should not be the target of local flow. | -| deleteexpr.cpp:7:9:7:15 | Chi | PostUpdateNode should not be the target of local flow. | -| file://:0:0:0:0 | Chi | PostUpdateNode should not be the target of local flow. | -| file://:0:0:0:0 | Chi | PostUpdateNode should not be the target of local flow. | -| file://:0:0:0:0 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:177:5:177:12 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:178:5:178:12 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:183:5:183:12 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:184:5:184:12 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:342:5:342:10 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:428:5:428:12 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:429:5:429:15 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:504:19:504:19 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:504:22:504:22 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:505:16:505:21 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:505:19:505:19 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:506:16:506:18 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:506:16:506:18 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:513:14:513:16 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:513:14:513:16 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:514:14:514:26 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:514:19:514:19 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:514:22:514:22 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:515:19:515:19 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:515:22:515:22 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:515:29:515:29 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:515:32:515:32 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:516:17:516:21 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:516:19:516:19 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:516:24:516:28 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:516:26:516:26 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:521:19:521:19 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:521:22:521:22 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:521:25:521:25 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:522:16:522:21 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:522:19:522:19 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:531:14:531:14 | Store | PostUpdateNode should not be the target of local flow. | -| ir.cpp:577:16:577:21 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:577:19:577:19 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:578:19:578:19 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:578:22:578:22 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:579:16:579:21 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:579:19:579:19 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:643:9:643:21 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:644:9:644:23 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:645:9:645:15 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:659:9:659:14 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:660:13:660:13 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:661:9:661:13 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:662:9:662:19 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:663:5:663:5 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:745:8:745:8 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:745:8:745:8 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:748:10:748:10 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:754:8:754:8 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:757:12:757:12 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:763:8:763:8 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:766:13:766:13 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:775:15:775:15 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:784:15:784:15 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:793:15:793:15 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:943:3:943:11 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:947:3:947:25 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:962:17:962:47 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:962:17:962:47 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:962:17:962:47 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:962:26:962:30 | Chi | PostUpdateNode should not be the target of local flow. | -| ir.cpp:962:41:962:45 | Chi | PostUpdateNode should not be the target of local flow. | -| misc.c:130:5:130:11 | Chi | PostUpdateNode should not be the target of local flow. | -| misc.c:131:5:131:13 | Chi | PostUpdateNode should not be the target of local flow. | -| misc.c:154:32:154:32 | Chi | PostUpdateNode should not be the target of local flow. | -| misc.c:154:35:154:35 | Chi | PostUpdateNode should not be the target of local flow. | -| misc.c:154:40:154:40 | Chi | PostUpdateNode should not be the target of local flow. | -| misc.c:154:43:154:43 | Chi | PostUpdateNode should not be the target of local flow. | -| misc.c:157:14:157:18 | Chi | PostUpdateNode should not be the target of local flow. | -| misc.c:158:14:158:18 | Chi | PostUpdateNode should not be the target of local flow. | -| misc.c:160:31:160:33 | Chi | PostUpdateNode should not be the target of local flow. | -| misc.c:160:31:160:33 | Chi | PostUpdateNode should not be the target of local flow. | -| misc.c:220:3:223:3 | Chi | PostUpdateNode should not be the target of local flow. | -| misc.c:221:10:221:10 | Chi | PostUpdateNode should not be the target of local flow. | -| misc.c:222:10:222:10 | Chi | PostUpdateNode should not be the target of local flow. | -| range_analysis.c:102:5:102:15 | Chi | PostUpdateNode should not be the target of local flow. | -| static_init_templates.cpp:3:2:3:8 | Chi | PostUpdateNode should not be the target of local flow. | -| static_init_templates.cpp:21:2:21:12 | Chi | PostUpdateNode should not be the target of local flow. | -| static_init_templates.cpp:240:7:240:7 | Chi | PostUpdateNode should not be the target of local flow. | +| cpp11.cpp:77:19:77:21 | Val output argument | PostUpdateNode should not be the target of local flow. | +| cpp11.cpp:82:11:82:14 | Val output argument | PostUpdateNode should not be the target of local flow. | +| cpp11.cpp:82:45:82:48 | Val output argument | PostUpdateNode should not be the target of local flow. | +| cpp11.cpp:82:51:82:51 | Val output argument | PostUpdateNode should not be the target of local flow. | +| ir.cpp:809:7:809:13 | Base output argument | PostUpdateNode should not be the target of local flow. | +| ir.cpp:810:7:810:26 | Base output argument | PostUpdateNode should not be the target of local flow. | +| ir.cpp:823:7:823:13 | Base output argument | PostUpdateNode should not be the target of local flow. | +| ir.cpp:824:7:824:26 | Base output argument | PostUpdateNode should not be the target of local flow. | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected index 9876b9695ad..0299afff063 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected @@ -59,18 +59,21 @@ edges | test.cpp:227:24:227:37 | (const char *)... | test.cpp:229:9:229:18 | local_size | | test.cpp:241:2:241:32 | Chi [array content] | test.cpp:279:17:279:20 | get_size output argument [array content] | | test.cpp:241:2:241:32 | Chi [array content] | test.cpp:295:18:295:21 | get_size output argument [array content] | -| test.cpp:241:18:241:23 | call to getenv | test.cpp:241:2:241:32 | Chi [array content] | -| test.cpp:241:18:241:31 | (const char *)... | test.cpp:241:2:241:32 | Chi [array content] | +| test.cpp:241:2:241:32 | ChiTotal [post update] [array content] | test.cpp:241:2:241:32 | Chi [array content] | +| test.cpp:241:2:241:32 | ChiTotal [post update] [array content] | test.cpp:279:17:279:20 | get_size output argument [array content] | +| test.cpp:241:2:241:32 | ChiTotal [post update] [array content] | test.cpp:295:18:295:21 | get_size output argument [array content] | +| test.cpp:241:18:241:23 | call to getenv | test.cpp:241:2:241:32 | ChiTotal [post update] [array content] | +| test.cpp:241:18:241:31 | (const char *)... | test.cpp:241:2:241:32 | ChiTotal [post update] [array content] | | test.cpp:249:20:249:25 | call to getenv | test.cpp:253:11:253:29 | ... * ... | | test.cpp:249:20:249:25 | call to getenv | test.cpp:253:11:253:29 | ... * ... | | test.cpp:249:20:249:33 | (const char *)... | test.cpp:253:11:253:29 | ... * ... | | test.cpp:249:20:249:33 | (const char *)... | test.cpp:253:11:253:29 | ... * ... | -| test.cpp:279:17:279:20 | Chi | test.cpp:281:11:281:28 | ... * ... | -| test.cpp:279:17:279:20 | Chi | test.cpp:281:11:281:28 | ... * ... | -| test.cpp:279:17:279:20 | get_size output argument [array content] | test.cpp:279:17:279:20 | Chi | -| test.cpp:295:18:295:21 | Chi | test.cpp:298:10:298:27 | ... * ... | -| test.cpp:295:18:295:21 | Chi | test.cpp:298:10:298:27 | ... * ... | -| test.cpp:295:18:295:21 | get_size output argument [array content] | test.cpp:295:18:295:21 | Chi | +| test.cpp:279:17:279:20 | get_size output argument | test.cpp:281:11:281:28 | ... * ... | +| test.cpp:279:17:279:20 | get_size output argument | test.cpp:281:11:281:28 | ... * ... | +| test.cpp:279:17:279:20 | get_size output argument [array content] | test.cpp:279:17:279:20 | get_size output argument | +| test.cpp:295:18:295:21 | get_size output argument | test.cpp:298:10:298:27 | ... * ... | +| test.cpp:295:18:295:21 | get_size output argument | test.cpp:298:10:298:27 | ... * ... | +| test.cpp:295:18:295:21 | get_size output argument [array content] | test.cpp:295:18:295:21 | get_size output argument | | test.cpp:301:19:301:24 | call to getenv | test.cpp:305:11:305:28 | ... * ... | | test.cpp:301:19:301:24 | call to getenv | test.cpp:305:11:305:28 | ... * ... | | test.cpp:301:19:301:32 | (const char *)... | test.cpp:305:11:305:28 | ... * ... | @@ -144,6 +147,7 @@ nodes | test.cpp:237:2:237:8 | Argument 0 | semmle.label | Argument 0 | | test.cpp:241:2:241:32 | Chi [array content] | semmle.label | Chi [array content] | | test.cpp:241:2:241:32 | ChiPartial | semmle.label | ChiPartial | +| test.cpp:241:2:241:32 | ChiTotal [post update] [array content] | semmle.label | ChiTotal [post update] [array content] | | test.cpp:241:18:241:23 | call to getenv | semmle.label | call to getenv | | test.cpp:241:18:241:31 | (const char *)... | semmle.label | (const char *)... | | test.cpp:249:20:249:25 | call to getenv | semmle.label | call to getenv | @@ -151,12 +155,12 @@ nodes | test.cpp:253:11:253:29 | ... * ... | semmle.label | ... * ... | | test.cpp:253:11:253:29 | ... * ... | semmle.label | ... * ... | | test.cpp:253:11:253:29 | ... * ... | semmle.label | ... * ... | -| test.cpp:279:17:279:20 | Chi | semmle.label | Chi | +| test.cpp:279:17:279:20 | get_size output argument | semmle.label | get_size output argument | | test.cpp:279:17:279:20 | get_size output argument [array content] | semmle.label | get_size output argument [array content] | | test.cpp:281:11:281:28 | ... * ... | semmle.label | ... * ... | | test.cpp:281:11:281:28 | ... * ... | semmle.label | ... * ... | | test.cpp:281:11:281:28 | ... * ... | semmle.label | ... * ... | -| test.cpp:295:18:295:21 | Chi | semmle.label | Chi | +| test.cpp:295:18:295:21 | get_size output argument | semmle.label | get_size output argument | | test.cpp:295:18:295:21 | get_size output argument [array content] | semmle.label | get_size output argument [array content] | | test.cpp:298:10:298:27 | ... * ... | semmle.label | ... * ... | | test.cpp:298:10:298:27 | ... * ... | semmle.label | ... * ... | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/uncontrolled/ArithmeticUncontrolled.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/uncontrolled/ArithmeticUncontrolled.expected index ca8dd38fc3b..c684f1da6ce 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/uncontrolled/ArithmeticUncontrolled.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/uncontrolled/ArithmeticUncontrolled.expected @@ -43,19 +43,23 @@ edges | test.cpp:8:9:8:12 | call to rand | test.cpp:8:9:8:12 | Store | | test.cpp:8:9:8:12 | call to rand | test.cpp:8:9:8:12 | Store | | test.cpp:13:2:13:15 | Chi [array content] | test.cpp:30:13:30:14 | get_rand2 output argument [array content] | -| test.cpp:13:10:13:13 | call to rand | test.cpp:13:2:13:15 | Chi [array content] | -| test.cpp:13:10:13:13 | call to rand | test.cpp:13:2:13:15 | Chi [array content] | +| test.cpp:13:2:13:15 | ChiTotal [post update] [array content] | test.cpp:13:2:13:15 | Chi [array content] | +| test.cpp:13:2:13:15 | ChiTotal [post update] [array content] | test.cpp:30:13:30:14 | get_rand2 output argument [array content] | +| test.cpp:13:10:13:13 | call to rand | test.cpp:13:2:13:15 | ChiTotal [post update] [array content] | +| test.cpp:13:10:13:13 | call to rand | test.cpp:13:2:13:15 | ChiTotal [post update] [array content] | | test.cpp:18:2:18:14 | Chi [array content] | test.cpp:36:13:36:13 | get_rand3 output argument [array content] | -| test.cpp:18:9:18:12 | call to rand | test.cpp:18:2:18:14 | Chi [array content] | -| test.cpp:18:9:18:12 | call to rand | test.cpp:18:2:18:14 | Chi [array content] | +| test.cpp:18:2:18:14 | ChiTotal [post update] [array content] | test.cpp:18:2:18:14 | Chi [array content] | +| test.cpp:18:2:18:14 | ChiTotal [post update] [array content] | test.cpp:36:13:36:13 | get_rand3 output argument [array content] | +| test.cpp:18:9:18:12 | call to rand | test.cpp:18:2:18:14 | ChiTotal [post update] [array content] | +| test.cpp:18:9:18:12 | call to rand | test.cpp:18:2:18:14 | ChiTotal [post update] [array content] | | test.cpp:24:11:24:18 | call to get_rand | test.cpp:25:7:25:7 | r | | test.cpp:24:11:24:18 | call to get_rand | test.cpp:25:7:25:7 | r | -| test.cpp:30:13:30:14 | Chi | test.cpp:31:7:31:7 | r | -| test.cpp:30:13:30:14 | Chi | test.cpp:31:7:31:7 | r | -| test.cpp:30:13:30:14 | get_rand2 output argument [array content] | test.cpp:30:13:30:14 | Chi | -| test.cpp:36:13:36:13 | Chi | test.cpp:37:7:37:7 | r | -| test.cpp:36:13:36:13 | Chi | test.cpp:37:7:37:7 | r | -| test.cpp:36:13:36:13 | get_rand3 output argument [array content] | test.cpp:36:13:36:13 | Chi | +| test.cpp:30:13:30:14 | get_rand2 output argument | test.cpp:31:7:31:7 | r | +| test.cpp:30:13:30:14 | get_rand2 output argument | test.cpp:31:7:31:7 | r | +| test.cpp:30:13:30:14 | get_rand2 output argument [array content] | test.cpp:30:13:30:14 | get_rand2 output argument | +| test.cpp:36:13:36:13 | get_rand3 output argument | test.cpp:37:7:37:7 | r | +| test.cpp:36:13:36:13 | get_rand3 output argument | test.cpp:37:7:37:7 | r | +| test.cpp:36:13:36:13 | get_rand3 output argument [array content] | test.cpp:36:13:36:13 | get_rand3 output argument | nodes | test.c:18:13:18:16 | call to rand | semmle.label | call to rand | | test.c:18:13:18:16 | call to rand | semmle.label | call to rand | @@ -110,22 +114,24 @@ nodes | test.cpp:8:9:8:12 | call to rand | semmle.label | call to rand | | test.cpp:13:2:13:15 | Chi [array content] | semmle.label | Chi [array content] | | test.cpp:13:2:13:15 | ChiPartial | semmle.label | ChiPartial | +| test.cpp:13:2:13:15 | ChiTotal [post update] [array content] | semmle.label | ChiTotal [post update] [array content] | | test.cpp:13:10:13:13 | call to rand | semmle.label | call to rand | | test.cpp:13:10:13:13 | call to rand | semmle.label | call to rand | | test.cpp:18:2:18:14 | Chi [array content] | semmle.label | Chi [array content] | | test.cpp:18:2:18:14 | ChiPartial | semmle.label | ChiPartial | +| test.cpp:18:2:18:14 | ChiTotal [post update] [array content] | semmle.label | ChiTotal [post update] [array content] | | test.cpp:18:9:18:12 | call to rand | semmle.label | call to rand | | test.cpp:18:9:18:12 | call to rand | semmle.label | call to rand | | test.cpp:24:11:24:18 | call to get_rand | semmle.label | call to get_rand | | test.cpp:25:7:25:7 | r | semmle.label | r | | test.cpp:25:7:25:7 | r | semmle.label | r | | test.cpp:25:7:25:7 | r | semmle.label | r | -| test.cpp:30:13:30:14 | Chi | semmle.label | Chi | +| test.cpp:30:13:30:14 | get_rand2 output argument | semmle.label | get_rand2 output argument | | test.cpp:30:13:30:14 | get_rand2 output argument [array content] | semmle.label | get_rand2 output argument [array content] | | test.cpp:31:7:31:7 | r | semmle.label | r | | test.cpp:31:7:31:7 | r | semmle.label | r | | test.cpp:31:7:31:7 | r | semmle.label | r | -| test.cpp:36:13:36:13 | Chi | semmle.label | Chi | +| test.cpp:36:13:36:13 | get_rand3 output argument | semmle.label | get_rand3 output argument | | test.cpp:36:13:36:13 | get_rand3 output argument [array content] | semmle.label | get_rand3 output argument [array content] | | test.cpp:37:7:37:7 | r | semmle.label | r | | test.cpp:37:7:37:7 | r | semmle.label | r | From bc4a0bcbebbb84426bf1da1cf18c6ba1666eb3b4 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 22 Dec 2020 11:27:11 +0100 Subject: [PATCH 039/343] Python: Split request handler / route setup concept tests Not doing so earlier was just a mistake. --- python/ql/test/experimental/meta/ConceptsTest.qll | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/python/ql/test/experimental/meta/ConceptsTest.qll b/python/ql/test/experimental/meta/ConceptsTest.qll index b031499e5e2..1deef32857b 100644 --- a/python/ql/test/experimental/meta/ConceptsTest.qll +++ b/python/ql/test/experimental/meta/ConceptsTest.qll @@ -142,9 +142,7 @@ class SqlExecutionTest extends InlineExpectationsTest { class HttpServerRouteSetupTest extends InlineExpectationsTest { HttpServerRouteSetupTest() { this = "HttpServerRouteSetupTest" } - override string getARelevantTag() { - result in ["routeSetup", "requestHandler", "routedParameter"] - } + override string getARelevantTag() { result in ["routeSetup"] } override predicate hasActualResult(Location location, string element, string tag, string value) { exists(HTTP::Server::RouteSetup setup | @@ -158,7 +156,15 @@ class HttpServerRouteSetupTest extends InlineExpectationsTest { ) and tag = "routeSetup" ) - or + } +} + +class HttpServerRequestHandlerTest extends InlineExpectationsTest { + HttpServerRequestHandlerTest() { this = "HttpServerRequestHandlerTest" } + + override string getARelevantTag() { result in ["requestHandler", "routedParameter"] } + + override predicate hasActualResult(Location location, string element, string tag, string value) { exists(HTTP::Server::RequestHandler handler | location = handler.getLocation() and element = handler.toString() and From dc0d9403314e95cd0d6d4a3abcad3b194e04187a Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 22 Dec 2020 11:28:29 +0100 Subject: [PATCH 040/343] Python: Ensure all concept tests ignore irrelevant results Since this was causing a CI error. also changed things a bit so we do it in a consistent way :) --- .../test/experimental/meta/ConceptsTest.qll | 40 +++++++++++-------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/python/ql/test/experimental/meta/ConceptsTest.qll b/python/ql/test/experimental/meta/ConceptsTest.qll index 1deef32857b..6b3544da30e 100644 --- a/python/ql/test/experimental/meta/ConceptsTest.qll +++ b/python/ql/test/experimental/meta/ConceptsTest.qll @@ -111,6 +111,7 @@ class CodeExecutionTest extends InlineExpectationsTest { override string getARelevantTag() { result = "getCode" } override predicate hasActualResult(Location location, string element, string tag, string value) { + exists(location.getFile().getRelativePath()) and exists(CodeExecution ce, DataFlow::Node code | exists(location.getFile().getRelativePath()) and code = ce.getCode() and @@ -128,6 +129,7 @@ class SqlExecutionTest extends InlineExpectationsTest { override string getARelevantTag() { result = "getSql" } override predicate hasActualResult(Location location, string element, string tag, string value) { + exists(location.getFile().getRelativePath()) and exists(SqlExecution e, DataFlow::Node sql | exists(location.getFile().getRelativePath()) and sql = e.getSql() and @@ -145,6 +147,7 @@ class HttpServerRouteSetupTest extends InlineExpectationsTest { override string getARelevantTag() { result in ["routeSetup"] } override predicate hasActualResult(Location location, string element, string tag, string value) { + exists(location.getFile().getRelativePath()) and exists(HTTP::Server::RouteSetup setup | location = setup.getLocation() and element = setup.toString() and @@ -165,19 +168,22 @@ class HttpServerRequestHandlerTest extends InlineExpectationsTest { override string getARelevantTag() { result in ["requestHandler", "routedParameter"] } override predicate hasActualResult(Location location, string element, string tag, string value) { - exists(HTTP::Server::RequestHandler handler | - location = handler.getLocation() and - element = handler.toString() and - value = "" and - tag = "requestHandler" - ) - or - exists(HTTP::Server::RequestHandler handler, Parameter param | - param = handler.getARoutedParameter() and - location = param.getLocation() and - element = param.toString() and - value = param.asName().getId() and - tag = "routedParameter" + exists(location.getFile().getRelativePath()) and + ( + exists(HTTP::Server::RequestHandler handler | + location = handler.getLocation() and + element = handler.toString() and + value = "" and + tag = "requestHandler" + ) + or + exists(HTTP::Server::RequestHandler handler, Parameter param | + param = handler.getARoutedParameter() and + location = param.getLocation() and + element = param.toString() and + value = param.asName().getId() and + tag = "routedParameter" + ) ) } } @@ -198,7 +204,7 @@ class HttpServerHttpResponseTest extends InlineExpectationsTest { // flask tests more readable since adding full annotations for HttpResponses in the // the tests for routing setup is both annoying and not very useful. location.getFile() = file and - tag = getARelevantTag() and + exists(file.getRelativePath()) and ( exists(HTTP::Server::HttpResponse response | location = response.getLocation() and @@ -237,8 +243,8 @@ class FileSystemAccessTest extends InlineExpectationsTest { override string getARelevantTag() { result = "getAPathArgument" } override predicate hasActualResult(Location location, string element, string tag, string value) { + exists(location.getFile().getRelativePath()) and exists(FileSystemAccess a, DataFlow::Node path | - exists(location.getFile().getRelativePath()) and path = a.getAPathArgument() and location = a.getLocation() and element = path.toString() and @@ -254,8 +260,8 @@ class PathNormalizationTest extends InlineExpectationsTest { override string getARelevantTag() { result = "pathNormalization" } override predicate hasActualResult(Location location, string element, string tag, string value) { + exists(location.getFile().getRelativePath()) and exists(Path::PathNormalization n | - exists(location.getFile().getRelativePath()) and location = n.getLocation() and element = n.toString() and value = "" and @@ -270,8 +276,8 @@ class SafeAccessCheckTest extends InlineExpectationsTest { override string getARelevantTag() { result in ["checks", "branch"] } override predicate hasActualResult(Location location, string element, string tag, string value) { + exists(location.getFile().getRelativePath()) and exists(Path::SafeAccessCheck c, DataFlow::Node checks, boolean branch | - exists(location.getFile().getRelativePath()) and c.checks(checks.asCfgNode(), branch) and location = c.getLocation() and ( From 3094aedf14806cb310bfdd9b92e3979492c05f33 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 22 Dec 2020 14:42:53 +0100 Subject: [PATCH 041/343] Python: Fix regression in ConceptTests I accidentially deleted that line :D --- python/ql/test/experimental/meta/ConceptsTest.qll | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python/ql/test/experimental/meta/ConceptsTest.qll b/python/ql/test/experimental/meta/ConceptsTest.qll index 6b3544da30e..0516fe5dac3 100644 --- a/python/ql/test/experimental/meta/ConceptsTest.qll +++ b/python/ql/test/experimental/meta/ConceptsTest.qll @@ -205,6 +205,8 @@ class HttpServerHttpResponseTest extends InlineExpectationsTest { // the tests for routing setup is both annoying and not very useful. location.getFile() = file and exists(file.getRelativePath()) and + // we need to do this step since we expect subclasses could override getARelevantTag + tag = getARelevantTag() and ( exists(HTTP::Server::HttpResponse response | location = response.getLocation() and From ec35e0d5189720ac8d4864b79ca571b57b0af976 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 22 Dec 2020 15:22:33 +0100 Subject: [PATCH 042/343] C++: Respond to review comments. --- .../ir/dataflow/internal/DataFlowPrivate.qll | 30 +++--- .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 92 +++++++++++++------ 2 files changed, 81 insertions(+), 41 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index 72d6db0f8dd..516cd663288 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll @@ -237,12 +237,12 @@ private class ArrayContent extends Content, TArrayContent { private predicate instrToFieldNodeStoreStepNoChi( Node node1, FieldContent f, PartialDefinitionNode node2 ) { - exists(StoreInstruction store, PostUpdateFieldNode post | - post = node2.getPartialDefinition() and + exists(StoreInstruction store, PartialFieldDefinition pd | + pd = node2.getPartialDefinition() and not exists(ChiInstruction chi | chi.getPartial() = store) and - post.getPreUpdateNode() = getFieldNodeForFieldInstruction(store.getDestinationAddress()) and + pd.getPreUpdateNode() = getFieldNodeForFieldInstruction(store.getDestinationAddress()) and store.getSourceValueOperand() = node1.asOperand() and - f.getADirectField() = post.getPreUpdateNode().getField() + f.getADirectField() = pd.getPreUpdateNode().getField() ) } @@ -255,15 +255,15 @@ private predicate instrToFieldNodeStoreStepChi( Node node1, FieldContent f, PartialDefinitionNode node2 ) { exists( - ChiPartialOperand operand, StoreInstruction store, ChiInstruction chi, PostUpdateFieldNode post + ChiPartialOperand operand, StoreInstruction store, ChiInstruction chi, PartialFieldDefinition pd | - post = node2.getPartialDefinition() and + pd = node2.getPartialDefinition() and not chi.isResultConflated() and node1.asOperand() = operand and chi.getPartialOperand() = operand and store = operand.getDef() and - post.getPreUpdateNode() = getFieldNodeForFieldInstruction(store.getDestinationAddress()) and - f.getADirectField() = post.getPreUpdateNode().getField() + pd.getPreUpdateNode() = getFieldNodeForFieldInstruction(store.getDestinationAddress()) and + f.getADirectField() = pd.getPreUpdateNode().getField() ) } @@ -271,14 +271,14 @@ private predicate callableWithoutDefinitionStoreStep( Node node1, FieldContent f, PartialDefinitionNode node2 ) { exists( - WriteSideEffectInstruction write, ChiInstruction chi, PostUpdateFieldNode post, + WriteSideEffectInstruction write, ChiInstruction chi, PartialFieldDefinition pd, Function callable, CallInstruction call | chi.getPartial() = write and not chi.isResultConflated() and - post = node2.getPartialDefinition() and - post.getPreUpdateNode() = getFieldNodeForFieldInstruction(write.getDestinationAddress()) and - f.getADirectField() = post.getPreUpdateNode().getField() and + pd = node2.getPartialDefinition() and + pd.getPreUpdateNode() = getFieldNodeForFieldInstruction(write.getDestinationAddress()) and + f.getADirectField() = pd.getPreUpdateNode().getField() and call = write.getPrimaryInstruction() and callable = call.getStaticCallTarget() and not callable.hasDefinition() @@ -346,6 +346,12 @@ private class ArrayToPointerConvertInstruction extends ConvertInstruction { } } +/** + * These two predicates look like copy-paste from the two predicates with the same name in DataFlowUtil, + * but crucially they only skip past `CopyValueInstruction`s. This is because we use a special case of + * a `ConvertInstruction` to detect some read steps from arrays that undergoes array-to-pointer + * conversion. + */ private Instruction skipOneCopyValueInstructionRec(CopyValueInstruction copy) { copy.getUnary() = result and not result instanceof CopyValueInstruction or diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 0d50f848689..0c3b06addf7 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -185,16 +185,24 @@ class OperandNode extends Node, TOperandNode { override string toString() { result = this.getOperand().toString() } } +/** An abstract class that defines conversion-like instructions. */ abstract private class SkippableInstruction extends Instruction { abstract Instruction getSourceInstruction(); } +/** + * Gets the instruction that is propaged through a non-empty sequence of conversion-like instructions. + */ private Instruction skipSkippableInstructionsRec(SkippableInstruction skip) { result = skip.getSourceInstruction() and not result instanceof SkippableInstruction or result = skipSkippableInstructionsRec(skip.getSourceInstruction()) } +/** + * Gets the instruction that is propagated through a (possibly empty) sequence of conversion-like + * instructions. + */ private Instruction skipSkippableInstructions(Instruction instr) { result = instr and not result instanceof SkippableInstruction or @@ -228,8 +236,16 @@ FieldNode getFieldNodeForFieldInstruction(Instruction instr) { } /** - * INTERNAL: do not use. A `FieldNode` represents the state of an object after modifying one - * of its fields. + * INTERNAL: do not use. A `FieldNode` represents the state of a field before any partial definitions + * of the field. For instance, in the snippet: + * ```cpp + * struct A { int b, c; }; + * // ... + * A a; + * f(a.b.c); + * ``` + * there are two `FieldNode`s: one corresponding to `c`, and one corresponding to `b`. Similarly, + * in `a.b.c = x` there are two `FieldNode`s: one for `c` and one for `b`. */ class FieldNode extends Node, TFieldNode { FieldAddressInstruction field; @@ -272,10 +288,9 @@ class FieldNode extends Node, TFieldNode { } /** - * INTERNAL: do not use. A `FieldNode` represents the state of an object after modifying one - * of its fields. + * INTERNAL: do not use. A partial definition of a `FieldNode`. */ -class PostUpdateFieldNode extends PartialDefinition { +class PartialFieldDefinition extends PartialDefinition { override FieldNode node; override FieldNode getPreUpdateNode() { result = node } @@ -435,6 +450,18 @@ abstract class PostUpdateNode extends Node { override Location getLocation() { result = getPreUpdateNode().getLocation() } } +/** + * A partial definition of a node. A partial definition that target arrays or pointers is attached to + * an `InstructionNode` (specifially, to the `ChiInstruction` that follows the `StoreInstruction`), and + * a partial update that targets a `FieldNode` is attached to the `FieldNode`. + *s + * The pre update node of a partial definition of a `FieldNode` is the `FieldNode` itself. This ensures + * that the dataflow library's reverse read mechanism builds up the correct access path for nested + * fields. + * For instance, in `a.b.c = x` there is a partial definition for `c` (let's call it `post[c]`) and a + * partial definition for `b` (let's call it `post[b]`), and there is a read step from `b` to `c` + * (using `instrToFieldNodeReadStep`), so there is a store step from `post[c]` to `post[b]`. + */ private newtype TPartialDefinition = MkPartialDefinition(Node node) { isPointerStoreNode(node, _, _) or @@ -681,7 +708,7 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFr private predicate flowOutOfPostUpdate(PartialDefinitionNode nodeFrom, Node nodeTo) { // flow from the "outermost" field to the `ChiInstruction`, or `StoreInstruction` // if no `ChiInstruction` exists. - exists(AddressOperand addressOperand, PostUpdateFieldNode pd | + exists(AddressOperand addressOperand, PartialFieldDefinition pd | pd = nodeFrom.getPartialDefinition() and not exists(pd.getPreUpdateNode().getObjectNode()) and pd.getPreUpdateNode().getNextNode*() = getFieldNodeForFieldInstruction(addressOperand.getDef()) and @@ -707,30 +734,37 @@ private predicate flowOutOfPostUpdate(PartialDefinitionNode nodeFrom, Node nodeT ) } -private predicate flowIntoReadNode(Node nodeFrom, Node nodeTo) { - // flow from the "innermost" field to the load of that field. - exists(FieldNode fieldNode | nodeTo = fieldNode | - not exists(fieldNode.getObjectNode()) and - ( - exists(LoadInstruction load | - fieldNode.getNextNode*() = getFieldNodeForFieldInstruction(load.getSourceAddress()) and - nodeFrom.asInstruction() = load.getSourceValueOperand().getAnyDef() - ) - or - // We need this to make stores look like loads for the dataflow library. So when there's a store - // of the form x->y = z we need to make the field node corresponding to y look like it's reading - // from the memory of x. - exists(StoreInstruction store, ChiInstruction chi | - chi.getPartial() = store and - fieldNode.getNextNode*() = getFieldNodeForFieldInstruction(store.getDestinationAddress()) and - nodeFrom.asInstruction() = chi.getTotal() - ) - or - exists(ReadSideEffectInstruction read | - fieldNode.getNextNode*() = getFieldNodeForFieldInstruction(read.getArgumentDef()) and - nodeFrom.asOperand() = read.getSideEffectOperand() - ) +/** + * Gets the `FieldNode` corresponding to the outermost field that is used to compute `address`. + */ +private FieldNode getOutermostFieldNode(Instruction address) { + not exists(result.getObjectNode()) and + result.getNextNode*() = getFieldNodeForFieldInstruction(address) +} + +private predicate flowIntoReadNode(Node nodeFrom, FieldNode nodeTo) { + // flow from the memory of a load to the "outermost" field of that load. + not nodeFrom.asInstruction().isResultConflated() and + ( + exists(LoadInstruction load | + nodeTo = getOutermostFieldNode(load.getSourceAddress()) and + nodeFrom.asInstruction() = load.getSourceValueOperand().getAnyDef() ) + or + // We need this to make stores look like loads for the dataflow library. So when there's a store + // of the form x->y = z we need to make the field node corresponding to y look like it's reading + // from the memory of x. + exists(StoreInstruction store, ChiInstruction chi | + chi.getPartial() = store and + nodeTo = getOutermostFieldNode(store.getDestinationAddress()) and + nodeFrom.asInstruction() = chi.getTotal() + ) + ) + or + exists(ReadSideEffectInstruction read | + not read.getSideEffectOperand().getAnyDef().isResultConflated() and + nodeTo = getOutermostFieldNode(read.getArgumentDef()) and + nodeFrom.asOperand() = read.getSideEffectOperand() ) } From b95cf948249bfef8b6cced8ab0d1ea94fb4f7260 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 22 Dec 2020 15:57:34 +0100 Subject: [PATCH 043/343] Update cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll Co-authored-by: Jonas Jensen --- .../src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 0c3b06addf7..0c863a3a340 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -239,7 +239,7 @@ FieldNode getFieldNodeForFieldInstruction(Instruction instr) { * INTERNAL: do not use. A `FieldNode` represents the state of a field before any partial definitions * of the field. For instance, in the snippet: * ```cpp - * struct A { int b, c; }; + * struct A { struct B { int c; } b; }; * // ... * A a; * f(a.b.c); From d2d8377e88a6035370cb20142b442ff01358fed2 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 22 Dec 2020 16:34:53 +0100 Subject: [PATCH 044/343] Update cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll Co-authored-by: Jonas Jensen --- .../code/cpp/ir/dataflow/internal/DataFlowUtil.qll | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 0c863a3a340..48c23e0b551 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -451,12 +451,12 @@ abstract class PostUpdateNode extends Node { } /** - * A partial definition of a node. A partial definition that target arrays or pointers is attached to + * A partial definition of a node. A partial definition that targets arrays or pointers is attached to * an `InstructionNode` (specifially, to the `ChiInstruction` that follows the `StoreInstruction`), and - * a partial update that targets a `FieldNode` is attached to the `FieldNode`. - *s - * The pre update node of a partial definition of a `FieldNode` is the `FieldNode` itself. This ensures - * that the dataflow library's reverse read mechanism builds up the correct access path for nested + * a partial definition that targets a `FieldNode` is attached to the `FieldNode`. + * + * The pre-update node of a partial definition of a `FieldNode` is the `FieldNode` itself. This ensures + * that the data flow library's reverse read mechanism builds up the correct access path for nested * fields. * For instance, in `a.b.c = x` there is a partial definition for `c` (let's call it `post[c]`) and a * partial definition for `b` (let's call it `post[b]`), and there is a read step from `b` to `c` From 6545d0b53af6fb45ea81519b088635c557615fcc Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 22 Dec 2020 16:56:30 +0100 Subject: [PATCH 045/343] C++: Move conflation check into each disjunct. --- .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 48c23e0b551..55ca891ab29 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -744,27 +744,27 @@ private FieldNode getOutermostFieldNode(Instruction address) { private predicate flowIntoReadNode(Node nodeFrom, FieldNode nodeTo) { // flow from the memory of a load to the "outermost" field of that load. - not nodeFrom.asInstruction().isResultConflated() and - ( - exists(LoadInstruction load | - nodeTo = getOutermostFieldNode(load.getSourceAddress()) and - nodeFrom.asInstruction() = load.getSourceValueOperand().getAnyDef() - ) - or - // We need this to make stores look like loads for the dataflow library. So when there's a store - // of the form x->y = z we need to make the field node corresponding to y look like it's reading - // from the memory of x. - exists(StoreInstruction store, ChiInstruction chi | - chi.getPartial() = store and - nodeTo = getOutermostFieldNode(store.getDestinationAddress()) and - nodeFrom.asInstruction() = chi.getTotal() - ) + exists(LoadInstruction load | + nodeTo = getOutermostFieldNode(load.getSourceAddress()) and + not nodeFrom.asInstruction().isResultConflated() and + nodeFrom.asInstruction() = load.getSourceValueOperand().getAnyDef() ) or - exists(ReadSideEffectInstruction read | - not read.getSideEffectOperand().getAnyDef().isResultConflated() and + // We need this to make stores look like loads for the dataflow library. So when there's a store + // of the form x->y = z we need to make the field node corresponding to y look like it's reading + // from the memory of x. + exists(StoreInstruction store, ChiInstruction chi | + chi.getPartial() = store and + nodeTo = getOutermostFieldNode(store.getDestinationAddress()) and + not nodeFrom.asInstruction().isResultConflated() and + nodeFrom.asInstruction() = chi.getTotal() + ) + or + exists(ReadSideEffectInstruction read, SideEffectOperand sideEffect | + sideEffect = read.getSideEffectOperand() and + not sideEffect.getAnyDef().isResultConflated() and nodeTo = getOutermostFieldNode(read.getArgumentDef()) and - nodeFrom.asOperand() = read.getSideEffectOperand() + nodeFrom.asOperand() = sideEffect ) } From 258d04178f90b48153c1119aa55a86544cbea54c Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 30 Dec 2020 13:39:24 +0100 Subject: [PATCH 046/343] C++: Replace SkippableInstruction with local flow steps. --- .../ir/dataflow/internal/DataFlowPrivate.qll | 21 +----- .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 71 ++++++------------- .../dataflow/fields/ir-path-flow.expected | 6 +- 3 files changed, 28 insertions(+), 70 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index 516cd663288..39672fe8e58 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll @@ -346,24 +346,6 @@ private class ArrayToPointerConvertInstruction extends ConvertInstruction { } } -/** - * These two predicates look like copy-paste from the two predicates with the same name in DataFlowUtil, - * but crucially they only skip past `CopyValueInstruction`s. This is because we use a special case of - * a `ConvertInstruction` to detect some read steps from arrays that undergoes array-to-pointer - * conversion. - */ -private Instruction skipOneCopyValueInstructionRec(CopyValueInstruction copy) { - copy.getUnary() = result and not result instanceof CopyValueInstruction - or - result = skipOneCopyValueInstructionRec(copy.getUnary()) -} - -private Instruction skipCopyValueInstructions(Operand op) { - not result instanceof CopyValueInstruction and result = op.getDef() - or - result = skipOneCopyValueInstructionRec(op.getDef()) -} - private class InexactLoadOperand extends LoadOperand { InexactLoadOperand() { this.isDefinitionInexact() } } @@ -375,7 +357,8 @@ private predicate arrayReadStep(Node node1, ArrayContent a, Node node2) { node1.asInstruction() = operand.getAnyDef() and not node1.asInstruction().isResultConflated() and operand = node2.asOperand() and - address = skipCopyValueInstructions(operand.getAddressOperand()) and + instructionOperandLocalFlowStep+(instructionNode(address), + operandNode(operand.getAddressOperand())) and ( address instanceof LoadInstruction or address instanceof ArrayToPointerConvertInstruction or diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 55ca891ab29..5ab582dc6d8 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -185,54 +185,15 @@ class OperandNode extends Node, TOperandNode { override string toString() { result = this.getOperand().toString() } } -/** An abstract class that defines conversion-like instructions. */ -abstract private class SkippableInstruction extends Instruction { - abstract Instruction getSourceInstruction(); -} - -/** - * Gets the instruction that is propaged through a non-empty sequence of conversion-like instructions. - */ -private Instruction skipSkippableInstructionsRec(SkippableInstruction skip) { - result = skip.getSourceInstruction() and not result instanceof SkippableInstruction - or - result = skipSkippableInstructionsRec(skip.getSourceInstruction()) -} - -/** - * Gets the instruction that is propagated through a (possibly empty) sequence of conversion-like - * instructions. - */ -private Instruction skipSkippableInstructions(Instruction instr) { - result = instr and not result instanceof SkippableInstruction - or - result = skipSkippableInstructionsRec(instr) -} - -private class SkippableCopyValueInstruction extends SkippableInstruction, CopyValueInstruction { - override Instruction getSourceInstruction() { result = this.getSourceValue() } -} - -private class SkippableConvertInstruction extends SkippableInstruction, ConvertInstruction { - override Instruction getSourceInstruction() { result = this.getUnary() } -} - -private class SkippableCheckedConvertInstruction extends SkippableInstruction, - CheckedConvertOrNullInstruction { - override Instruction getSourceInstruction() { result = this.getUnary() } -} - -private class SkippableInheritanceConversionInstruction extends SkippableInstruction, - InheritanceConversionInstruction { - override Instruction getSourceInstruction() { result = this.getUnary() } -} - /** * INTERNAL: do not use. Gets the `FieldNode` corresponding to `instr`, if * `instr` is an instruction that propagates an address of a `FieldAddressInstruction`. */ FieldNode getFieldNodeForFieldInstruction(Instruction instr) { - result.getFieldInstruction() = skipSkippableInstructions(instr) + result.getFieldInstruction() = + any(FieldAddressInstruction fai | + instructionOperandLocalFlowStep*(instructionNode(fai), instructionNode(instr)) + ) } /** @@ -651,6 +612,11 @@ class VariableNode extends Node, TVariableNode { */ InstructionNode instructionNode(Instruction instr) { result.getInstruction() = instr } +/** + * Gets the node corresponding to `operand`. + */ +OperandNode operandNode(Operand operand) { result.getOperand() = operand } + /** * DEPRECATED: use `definitionByReferenceNodeFromArgument` instead. * @@ -768,6 +734,19 @@ private predicate flowIntoReadNode(Node nodeFrom, FieldNode nodeTo) { ) } +/** + * INTERNAL: do not use. + * Holds if `nodeFrom` is an operand and `nodeTo` is an instruction node that uses this operand, or + * if `nodeFrom` is an instruction and `nodeTo` is an operand that refers to this instruction. + */ +predicate instructionOperandLocalFlowStep(Node nodeFrom, Node nodeTo) { + // Operand -> Instruction flow + simpleInstructionLocalFlowStep(nodeFrom.asOperand(), nodeTo.asInstruction()) + or + // Instruction -> Operand flow + simpleOperandLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asOperand()) +} + /** * INTERNAL: do not use. * @@ -776,11 +755,7 @@ private predicate flowIntoReadNode(Node nodeFrom, FieldNode nodeTo) { */ cached predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { - // Operand -> Instruction flow - simpleInstructionLocalFlowStep(nodeFrom.asOperand(), nodeTo.asInstruction()) - or - // Instruction -> Operand flow - simpleOperandLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asOperand()) + instructionOperandLocalFlowStep(nodeFrom, nodeTo) or flowIntoReadNode(nodeFrom, nodeTo) or diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected index e787b9a5f0e..ee43cd98302 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected @@ -58,9 +58,9 @@ edges | aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | | aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | -| aliasing.cpp:98:5:98:6 | m1 [post update] [m1] | aliasing.cpp:100:14:100:14 | Store [m1] | +| aliasing.cpp:98:5:98:6 | m1 [post update] [m1] | aliasing.cpp:101:21:101:22 | m1 [m1] | | aliasing.cpp:98:10:98:19 | call to user_input | aliasing.cpp:98:5:98:6 | m1 [post update] [m1] | -| aliasing.cpp:100:14:100:14 | Store [m1] | aliasing.cpp:102:8:102:10 | * ... | +| aliasing.cpp:101:21:101:22 | m1 [m1] | aliasing.cpp:102:8:102:10 | * ... | | aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:121:15:121:16 | taint_a_ptr output argument [array content] | | aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:126:15:126:20 | taint_a_ptr output argument [array content] | | aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:131:15:131:16 | taint_a_ptr output argument [array content] | @@ -373,7 +373,7 @@ nodes | aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 | | aliasing.cpp:98:5:98:6 | m1 [post update] [m1] | semmle.label | m1 [post update] [m1] | | aliasing.cpp:98:10:98:19 | call to user_input | semmle.label | call to user_input | -| aliasing.cpp:100:14:100:14 | Store [m1] | semmle.label | Store [m1] | +| aliasing.cpp:101:21:101:22 | m1 [m1] | semmle.label | m1 [m1] | | aliasing.cpp:102:8:102:10 | * ... | semmle.label | * ... | | aliasing.cpp:106:3:106:20 | Chi [array content] | semmle.label | Chi [array content] | | aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | semmle.label | ChiTotal [post update] [array content] | From 7a3f9c78950d14c8b78875bedcf389db3ac252ac Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 4 Jan 2021 15:18:08 +0000 Subject: [PATCH 047/343] C++: Add a test (cleaned up) that was previously in the internal repo. --- .../CWE-089/SqlTainted/SqlTainted.expected | 13 +++++++++ .../CWE/CWE-089/SqlTainted/SqlTainted.qlref | 1 + .../Security/CWE/CWE-089/SqlTainted/test.c | 27 +++++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/SqlTainted.expected create mode 100644 cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/SqlTainted.qlref create mode 100644 cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/test.c diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/SqlTainted.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/SqlTainted.expected new file mode 100644 index 00000000000..f9fd94e278d --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/SqlTainted.expected @@ -0,0 +1,13 @@ +edges +| test.c:14:20:14:23 | argv | test.c:19:18:19:23 | (const char *)... | +| test.c:14:20:14:23 | argv | test.c:19:18:19:23 | (const char *)... | +| test.c:14:20:14:23 | argv | test.c:19:18:19:23 | query1 | +| test.c:14:20:14:23 | argv | test.c:19:18:19:23 | query1 | +nodes +| test.c:14:20:14:23 | argv | semmle.label | argv | +| test.c:14:20:14:23 | argv | semmle.label | argv | +| test.c:19:18:19:23 | (const char *)... | semmle.label | (const char *)... | +| test.c:19:18:19:23 | (const char *)... | semmle.label | (const char *)... | +| test.c:19:18:19:23 | query1 | semmle.label | query1 | +#select +| test.c:19:18:19:23 | query1 | test.c:14:20:14:23 | argv | test.c:19:18:19:23 | query1 | This argument to a SQL query function is derived from $@ and then passed to mysql_query(sqlArg) | test.c:14:20:14:23 | argv | user input (argv) | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/SqlTainted.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/SqlTainted.qlref new file mode 100644 index 00000000000..21a12e5eadd --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/SqlTainted.qlref @@ -0,0 +1 @@ +Security/CWE/CWE-089/SqlTainted.ql diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/test.c b/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/test.c new file mode 100644 index 00000000000..1f437fcf856 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/test.c @@ -0,0 +1,27 @@ +// Semmle test case for rule SprintfToSqlQuery.ql (Uncontrolled sprintf for SQL query) +// Associated with CWE-089: SQL injection. http://cwe.mitre.org/data/definitions/89.html + +///// Library routines ///// + +typedef unsigned long size_t; +int snprintf(char *s, size_t n, const char *format, ...); +void sanitizeString(char *stringOut, size_t len, const char *strIn); +int mysql_query(int arg1, const char *sqlArg); + +///// Test code ///// + +int main(int argc, char** argv) { + char *userName = argv[2]; + + // a string from the user is injected directly into an SQL query. + char query1[1000] = {0}; + snprintf(query1, 1000, "SELECT UID FROM USERS where name = \"%s\"", userName); + mysql_query(0, query1); // BAD + + // the user string is encoded by a library routine. + char userNameSanitized[1000] = {0}; + sanitizeString(userNameSanitized, 1000, userName); + char query2[1000] = {0}; + snprintf(query2, 1000, "SELECT UID FROM USERS where name = \"%s\"", userNameSanitized); + mysql_query(0, query2); // GOOD +} From 01b204ea30b880e388364b74be9cc319ced31423 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 4 Jan 2021 15:33:10 +0000 Subject: [PATCH 048/343] C++: Add a test case with a tainted integer. --- .../CWE-089/SqlTainted/SqlTainted.expected | 30 ++++++++++++------- .../Security/CWE/CWE-089/SqlTainted/test.c | 7 +++++ 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/SqlTainted.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/SqlTainted.expected index f9fd94e278d..ebd8b1a77e8 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/SqlTainted.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/SqlTainted.expected @@ -1,13 +1,23 @@ edges -| test.c:14:20:14:23 | argv | test.c:19:18:19:23 | (const char *)... | -| test.c:14:20:14:23 | argv | test.c:19:18:19:23 | (const char *)... | -| test.c:14:20:14:23 | argv | test.c:19:18:19:23 | query1 | -| test.c:14:20:14:23 | argv | test.c:19:18:19:23 | query1 | +| test.c:15:20:15:23 | argv | test.c:21:18:21:23 | (const char *)... | +| test.c:15:20:15:23 | argv | test.c:21:18:21:23 | (const char *)... | +| test.c:15:20:15:23 | argv | test.c:21:18:21:23 | query1 | +| test.c:15:20:15:23 | argv | test.c:21:18:21:23 | query1 | +| test.c:16:25:16:28 | argv | test.c:33:18:33:23 | (const char *)... | +| test.c:16:25:16:28 | argv | test.c:33:18:33:23 | (const char *)... | +| test.c:16:25:16:28 | argv | test.c:33:18:33:23 | query3 | +| test.c:16:25:16:28 | argv | test.c:33:18:33:23 | query3 | nodes -| test.c:14:20:14:23 | argv | semmle.label | argv | -| test.c:14:20:14:23 | argv | semmle.label | argv | -| test.c:19:18:19:23 | (const char *)... | semmle.label | (const char *)... | -| test.c:19:18:19:23 | (const char *)... | semmle.label | (const char *)... | -| test.c:19:18:19:23 | query1 | semmle.label | query1 | +| test.c:15:20:15:23 | argv | semmle.label | argv | +| test.c:15:20:15:23 | argv | semmle.label | argv | +| test.c:16:25:16:28 | argv | semmle.label | argv | +| test.c:16:25:16:28 | argv | semmle.label | argv | +| test.c:21:18:21:23 | (const char *)... | semmle.label | (const char *)... | +| test.c:21:18:21:23 | (const char *)... | semmle.label | (const char *)... | +| test.c:21:18:21:23 | query1 | semmle.label | query1 | +| test.c:33:18:33:23 | (const char *)... | semmle.label | (const char *)... | +| test.c:33:18:33:23 | (const char *)... | semmle.label | (const char *)... | +| test.c:33:18:33:23 | query3 | semmle.label | query3 | #select -| test.c:19:18:19:23 | query1 | test.c:14:20:14:23 | argv | test.c:19:18:19:23 | query1 | This argument to a SQL query function is derived from $@ and then passed to mysql_query(sqlArg) | test.c:14:20:14:23 | argv | user input (argv) | +| test.c:21:18:21:23 | query1 | test.c:15:20:15:23 | argv | test.c:21:18:21:23 | query1 | This argument to a SQL query function is derived from $@ and then passed to mysql_query(sqlArg) | test.c:15:20:15:23 | argv | user input (argv) | +| test.c:33:18:33:23 | query3 | test.c:16:25:16:28 | argv | test.c:33:18:33:23 | query3 | This argument to a SQL query function is derived from $@ and then passed to mysql_query(sqlArg) | test.c:16:25:16:28 | argv | user input (argv) | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/test.c b/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/test.c index 1f437fcf856..85d5d462093 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/test.c +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/test.c @@ -7,11 +7,13 @@ typedef unsigned long size_t; int snprintf(char *s, size_t n, const char *format, ...); void sanitizeString(char *stringOut, size_t len, const char *strIn); int mysql_query(int arg1, const char *sqlArg); +int atoi(const char *nptr); ///// Test code ///// int main(int argc, char** argv) { char *userName = argv[2]; + int userNumber = atoi(argv[3]); // a string from the user is injected directly into an SQL query. char query1[1000] = {0}; @@ -24,4 +26,9 @@ int main(int argc, char** argv) { char query2[1000] = {0}; snprintf(query2, 1000, "SELECT UID FROM USERS where name = \"%s\"", userNameSanitized); mysql_query(0, query2); // GOOD + + // an integer from the user is injected into an SQL query. + char query3[1000] = {0}; + snprintf(query3, 1000, "SELECT UID FROM USERS where number = \"%i\"", userNumber); + mysql_query(0, query3); // BAD [FALSE POSITIVE] } From 69efe7a72abe9f556d1023fa9060f9bf1a7a625a Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 5 Jan 2021 11:31:54 +0000 Subject: [PATCH 049/343] C++: Add isAdditionalBarrier to DefaultTaintTracking. --- .../code/cpp/ir/dataflow/DefaultTaintTracking.qll | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll index 5154f5c3239..907cb628a85 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll @@ -545,6 +545,9 @@ module TaintedWithPath { /** Override this to specify which elements are sinks in this configuration. */ abstract predicate isSink(Element e); + /** Override this to specify additional barriers in this configuration. */ + predicate isAdditionalBarrier(Expr node) { none() } + /** * Override this predicate to `any()` to allow taint to flow through global * variables. @@ -578,7 +581,13 @@ module TaintedWithPath { ) } - override predicate isBarrier(DataFlow::Node node) { nodeIsBarrier(node) } + override predicate isBarrier(DataFlow::Node node) { + nodeIsBarrier(node) + or + exists(TaintTrackingConfiguration cfg, Expr e | + cfg.isAdditionalBarrier(e) and node = getNodeForExpr(e) + ) + } override predicate isBarrierIn(DataFlow::Node node) { nodeIsBarrierIn(node) } } From 18890c4a770031094bfa307e160b2dce82c997aa Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 5 Jan 2021 11:32:29 +0000 Subject: [PATCH 050/343] C++: Use isAdditionalBarrier in the SqlTainted query. --- cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql | 2 ++ .../CWE/CWE-089/SqlTainted/SqlTainted.expected | 10 ---------- .../query-tests/Security/CWE/CWE-089/SqlTainted/test.c | 2 +- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql b/cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql index de786d22f30..29db32a6b87 100644 --- a/cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql +++ b/cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql @@ -27,6 +27,8 @@ class Configuration extends TaintTrackingConfiguration { override predicate isSink(Element tainted) { exists(SQLLikeFunction runSql | runSql.outermostWrapperFunctionCall(tainted, _)) } + + override predicate isAdditionalBarrier(Expr e) { e.getUnspecifiedType() instanceof IntegralType } } from diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/SqlTainted.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/SqlTainted.expected index ebd8b1a77e8..af50f184740 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/SqlTainted.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/SqlTainted.expected @@ -3,21 +3,11 @@ edges | test.c:15:20:15:23 | argv | test.c:21:18:21:23 | (const char *)... | | test.c:15:20:15:23 | argv | test.c:21:18:21:23 | query1 | | test.c:15:20:15:23 | argv | test.c:21:18:21:23 | query1 | -| test.c:16:25:16:28 | argv | test.c:33:18:33:23 | (const char *)... | -| test.c:16:25:16:28 | argv | test.c:33:18:33:23 | (const char *)... | -| test.c:16:25:16:28 | argv | test.c:33:18:33:23 | query3 | -| test.c:16:25:16:28 | argv | test.c:33:18:33:23 | query3 | nodes | test.c:15:20:15:23 | argv | semmle.label | argv | | test.c:15:20:15:23 | argv | semmle.label | argv | -| test.c:16:25:16:28 | argv | semmle.label | argv | -| test.c:16:25:16:28 | argv | semmle.label | argv | | test.c:21:18:21:23 | (const char *)... | semmle.label | (const char *)... | | test.c:21:18:21:23 | (const char *)... | semmle.label | (const char *)... | | test.c:21:18:21:23 | query1 | semmle.label | query1 | -| test.c:33:18:33:23 | (const char *)... | semmle.label | (const char *)... | -| test.c:33:18:33:23 | (const char *)... | semmle.label | (const char *)... | -| test.c:33:18:33:23 | query3 | semmle.label | query3 | #select | test.c:21:18:21:23 | query1 | test.c:15:20:15:23 | argv | test.c:21:18:21:23 | query1 | This argument to a SQL query function is derived from $@ and then passed to mysql_query(sqlArg) | test.c:15:20:15:23 | argv | user input (argv) | -| test.c:33:18:33:23 | query3 | test.c:16:25:16:28 | argv | test.c:33:18:33:23 | query3 | This argument to a SQL query function is derived from $@ and then passed to mysql_query(sqlArg) | test.c:16:25:16:28 | argv | user input (argv) | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/test.c b/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/test.c index 85d5d462093..129257731ab 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/test.c +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/test.c @@ -30,5 +30,5 @@ int main(int argc, char** argv) { // an integer from the user is injected into an SQL query. char query3[1000] = {0}; snprintf(query3, 1000, "SELECT UID FROM USERS where number = \"%i\"", userNumber); - mysql_query(0, query3); // BAD [FALSE POSITIVE] + mysql_query(0, query3); // BAD } From 81205f37c5acfd86a3778f9575176a6c94debe34 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 6 Jan 2021 11:45:17 +0000 Subject: [PATCH 051/343] C++: Fix test annotation. --- cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/test.c b/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/test.c index 129257731ab..45304f13872 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/test.c +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/test.c @@ -30,5 +30,5 @@ int main(int argc, char** argv) { // an integer from the user is injected into an SQL query. char query3[1000] = {0}; snprintf(query3, 1000, "SELECT UID FROM USERS where number = \"%i\"", userNumber); - mysql_query(0, query3); // BAD + mysql_query(0, query3); // GOOD } From b5bcbd303ea4e3312da9c00f4bf427c4bc56beed Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 6 Jan 2021 18:22:31 +0000 Subject: [PATCH 052/343] C++: Cleaner solution. --- cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql | 4 +++- .../semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll | 8 +++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql b/cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql index 29db32a6b87..5ed84f45250 100644 --- a/cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql +++ b/cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql @@ -28,7 +28,9 @@ class Configuration extends TaintTrackingConfiguration { exists(SQLLikeFunction runSql | runSql.outermostWrapperFunctionCall(tainted, _)) } - override predicate isAdditionalBarrier(Expr e) { e.getUnspecifiedType() instanceof IntegralType } + override predicate isBarrier(Expr e) { + super.isBarrier(e) or e.getUnspecifiedType() instanceof IntegralType + } } from diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll index 907cb628a85..23161bc4b89 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll @@ -545,8 +545,8 @@ module TaintedWithPath { /** Override this to specify which elements are sinks in this configuration. */ abstract predicate isSink(Element e); - /** Override this to specify additional barriers in this configuration. */ - predicate isAdditionalBarrier(Expr node) { none() } + /** Override this to specify which expressions are barriers in this configuration. */ + predicate isBarrier(Expr e) { nodeIsBarrier(getNodeForExpr(e)) } /** * Override this predicate to `any()` to allow taint to flow through global @@ -582,10 +582,8 @@ module TaintedWithPath { } override predicate isBarrier(DataFlow::Node node) { - nodeIsBarrier(node) - or exists(TaintTrackingConfiguration cfg, Expr e | - cfg.isAdditionalBarrier(e) and node = getNodeForExpr(e) + cfg.isBarrier(e) and node = getNodeForExpr(e) ) } From 8d77f4bac917969134feb5c1edcff7ddf52f359f Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 21 Dec 2020 15:25:26 +0100 Subject: [PATCH 053/343] C#: Remove `ImplicitUntrackedDefinition` --- .../semmle/code/csharp/controlflow/Guards.qll | 3 +- .../src/semmle/code/csharp/dataflow/SSA.qll | 284 ++++++------------ .../dataflow/internal/DataFlowPrivate.qll | 2 - .../csharp7/LocalTaintFlow.expected | 3 + .../dataflow/local/DataFlowStep.expected | 6 + .../dataflow/local/TaintTrackingStep.expected | 6 + .../dataflow/ssa/SsaDef.expected | 15 +- .../dataflow/ssa/SsaDefElement.expected | 15 +- .../dataflow/ssa/SsaDefLastRead.expected | 4 + .../dataflow/ssa/SsaRead.expected | 15 +- .../dataflow/ssa/SsaUltimateDef.expected | 15 +- 11 files changed, 124 insertions(+), 244 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll b/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll index 7cad1dff909..a9d95bd0084 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll @@ -621,8 +621,7 @@ private Ssa::Definition getAnSsaQualifier(Expr e, ControlFlow::Node cfn) { } private AssignableAccess getATrackedAccess(Ssa::Definition def, ControlFlow::Node cfn) { - result = def.getAReadAtNode(cfn) and - not def instanceof Ssa::ImplicitUntrackedDefinition + result = def.getAReadAtNode(cfn) or result = def.(Ssa::ExplicitDefinition).getADefinition().getTargetAccess() and cfn = def.getControlFlowNode() diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/SSA.qll b/csharp/ql/src/semmle/code/csharp/dataflow/SSA.qll index 487a32e6a83..4b99882e167 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/SSA.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/SSA.qll @@ -17,6 +17,12 @@ module Ssa { or this instanceof Property } + + /** + * Holds if the this field or any of the fields part of the qualifier + * are volatile. + */ + predicate isVolatile() { this.(Field).isVolatile() } } /** An instance field or property. */ @@ -43,10 +49,12 @@ module Ssa { c = v.getAnAccess().getEnclosingCallable() } or TPlainFieldOrProp(Callable c, FieldOrProp f) { - exists(FieldOrPropRead fr | isPlainFieldOrPropAccess(fr, f, c)) + exists(FieldOrPropRead fr | isPlainFieldOrPropAccess(fr, f, c)) and + trackFieldOrProp(f) } or TQualifiedFieldOrProp(Callable c, SourceVariable q, InstanceFieldOrProp f) { - exists(FieldOrPropRead fr | isQualifiedFieldOrPropAccess(fr, f, c, q)) + exists(FieldOrPropRead fr | isQualifiedFieldOrPropAccess(fr, f, c, q)) and + trackFieldOrProp(f) } /** Gets an access to source variable `v`. */ @@ -70,9 +78,9 @@ module Ssa { cached AssignableDefinition getADefinition(ExplicitDefinition def) { - exists(TrackedVar tv, AssignableDefinition ad | def = TSsaExplicitDef(tv, ad, _, _) | + exists(SourceVariable sv, AssignableDefinition ad | def = TSsaExplicitDef(sv, ad, _, _) | result = ad or - result = getASameOutRefDefAfter(tv, ad) + result = getASameOutRefDefAfter(sv, ad) ) } } @@ -360,6 +368,23 @@ module Ssa { predicate liveAfterWrite(BasicBlock bb, int i, SourceVariable v, ReadKind rk) { exists(int rnk | rnk = refRank(bb, i, v, Write(_)) | liveAtRank(bb, i, v, rnk, rk)) } + + /** + * Holds if `fp` is a field or a property that is interesting as a basis for SSA. + * + * - A volatile field is never interesting, since all reads must reread from + * memory and we are forced to assume that the value can change at any point. + * - A property is only interesting if it is "field-like", that is, it is a + * non-overridable trivial property. + */ + predicate trackFieldOrProp(FieldOrProp fp) { + not fp.isVolatile() and + ( + fp instanceof Field + or + fp = any(TrivialProperty p | not p.isOverridableOrImplementable()) + ) + } } private import SourceVariableImpl @@ -460,15 +485,6 @@ module Ssa { } override Location getLocation() { result = getFirstAccess().getLocation() } - - /** - * Holds if the this field or any of the fields part of the qualifier - * are volatile. - */ - predicate isVolatile() { - this.getAssignable().(Field).isVolatile() or - this.getQualifier().(FieldOrPropSourceVariable).isVolatile() - } } /** A plain field or property. */ @@ -498,93 +514,9 @@ module Ssa { private import SourceVariables - private module TrackedVariablesImpl { - /** Gets the number of accesses of field or property `fp`. */ - private int numberOfAccesses(FieldOrPropSourceVariable fp) { - result = strictcount(fp.getAnAccess()) - } - - /** Holds if field or property `fp` is accessed inside a loop. */ - private predicate loopAccessed(FieldOrPropSourceVariable fp) { - exists(FieldOrPropRead fpr | - fpr = fp.getAnAccess() and - fpr.getAControlFlowNode().getBasicBlock().inLoop() - ) - } - - /** Holds if field or property `fp` is accessed more than once or inside a loop. */ - private predicate multiAccessed(FieldOrPropSourceVariable fp) { - loopAccessed(fp) or 1 < numberOfAccesses(fp) - } - - /** - * Holds if `fp` is a field or a property that is interesting as a basis for SSA. - * - * - A field or property that is read twice is interesting as we want to know whether - * the reads refer to the same value. - * - A field or property that is both written and read is interesting as we want to - * know whether the read might get the written value. - * - A field or property that is read in a loop is interesting as we want to know whether - * the value is the same in different iterations (that is, whether the SSA - * definition can be placed outside the loop). - * - A volatile field is never interesting, since all reads must reread from - * memory and we are forced to assume that the value can change at any point. - * - A property is only interesting if it is "field-like", that is, it is a - * non-overridable trivial property. - */ - predicate trackFieldOrProp(FieldOrPropSourceVariable fp) { - multiAccessed(fp) and - not fp.isVolatile() and - exists(Assignable a | a = fp.getAssignable() | - a instanceof Field - or - a = any(TrivialProperty p | not p.isOverridableOrImplementable()) - ) - } - } - - private import TrackedVariablesImpl - - /** - * A source variable that gets a non-trivial SSA construction. - */ - private class TrackedVar extends SourceVariable { - TrackedVar() { - this instanceof LocalScopeSourceVariable or - trackFieldOrProp(this) - } - } - - /** - * A field or property that gets a non-trivial SSA construction. - */ - private class TrackedFieldOrProp extends TrackedVar, FieldOrPropSourceVariable { } - - /** - * A source variable that gets a trivial SSA construction, that is a - * definition prior to every read. - */ - private class UntrackedVar extends SourceVariable { - UntrackedVar() { not this instanceof TrackedVar } - } - private module SsaDefReaches { - /** A non-trivial SSA definition. */ - private class TrackedDefinition extends Definition { - TrackedDefinition() { - // Same as `not this instanceof ImplicitUntrackedDefinition` but - // avoids negative recursion - this instanceof ExplicitDefinition or - this instanceof ImplicitEntryDefinition or - this instanceof ImplicitCallDefinition or - this instanceof ImplicitQualifierDefinition or - this instanceof PseudoDefinition - } - } - /** - * A classification of SSA variable references into reads and non-trivial - * SSA definitions. + * A classification of SSA variable references into reads definitions. */ private newtype SsaRefKind = SsaRead() or @@ -592,8 +524,8 @@ module Ssa { /** * Holds if the `i`th node of basic block `bb` is a reference to `v`, - * either a read (when `k` is `Read()`) or a non-trivial SSA definition - * (when `k` is `SsaDef()`). + * either a read (when `k` is `Read()`) or an SSA definition (when `k` + * is `SsaDef()`). */ private predicate ssaRef(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) { exists(ReadKind rk | variableRead(bb, i, v, _, rk) | @@ -601,7 +533,7 @@ module Ssa { k = SsaRead() ) or - exists(TrackedDefinition def | definesAt(def, bb, i, v)) and + exists(Definition def | definesAt(def, bb, i, v)) and k = SsaDef() } @@ -629,12 +561,10 @@ module Ssa { } /** - * Holds if the non-trivial SSA definition `def` reaches rank index `rankix` - * in its own basic block `bb`. + * Holds if the SSA definition `def` reaches rank index `rankix` in its own + * basic block `bb`. */ - private predicate ssaDefReachesRank( - BasicBlock bb, TrackedDefinition def, int rankix, TrackedVar v - ) { + private predicate ssaDefReachesRank(BasicBlock bb, Definition def, int rankix, SourceVariable v) { exists(int i | rankix = ssaRefRank(bb, i, v, SsaDef()) and definesAt(def, bb, i, v) @@ -645,12 +575,12 @@ module Ssa { } /** - * Holds if the non-trivial SSA definition of `v` at `def` reaches `read` in the + * Holds if the SSA definition of `v` at `def` reaches `read` in the * same basic block without crossing another SSA definition of `v`. * The read at `node` is of kind `rk`. */ private predicate ssaDefReachesReadWithinBlock( - TrackedVar v, TrackedDefinition def, ControlFlow::Node read, ReadKind rk + SourceVariable v, Definition def, ControlFlow::Node read, ReadKind rk ) { exists(BasicBlock bb, int rankix, int i | ssaDefReachesRank(bb, def, rankix, v) and @@ -660,12 +590,11 @@ module Ssa { } /** - * Holds if the non-trivial SSA definition of `v` at `def` reaches uncertain SSA - * definition `redef` in the same basic block, without crossing another SSA - * definition of `v`. + * Holds if the SSA definition of `v` at `def` reaches uncertain SSA definition + * `redef` in the same basic block, without crossing another SSA definition of `v`. */ private predicate ssaDefReachesUncertainDefWithinBlock( - TrackedVar v, TrackedDefinition def, UncertainDefinition redef + SourceVariable v, Definition def, UncertainDefinition redef ) { exists(BasicBlock bb, int rankix, int i | ssaDefReachesRank(bb, def, rankix, v) and @@ -678,7 +607,7 @@ module Ssa { * Same as `ssaRefRank()`, but restricted to actual reads of `def`, or * `def` itself. */ - private int ssaDefRank(TrackedDefinition def, TrackedVar v, BasicBlock bb, int i) { + private int ssaDefRank(Definition def, SourceVariable v, BasicBlock bb, int i) { v = def.getSourceVariable() and result = ssaRefRank(bb, i, v, _) and ( @@ -688,12 +617,12 @@ module Ssa { ) } - private int maxSsaDefRefRank(BasicBlock bb, TrackedVar v) { + private int maxSsaDefRefRank(BasicBlock bb, SourceVariable v) { result = ssaDefRank(_, v, bb, _) and not result + 1 = ssaDefRank(_, v, bb, _) } - private predicate varOccursInBlock(TrackedDefinition def, BasicBlock bb, TrackedVar v) { + private predicate varOccursInBlock(Definition def, BasicBlock bb, SourceVariable v) { exists(ssaDefRank(def, v, bb, _)) } @@ -710,7 +639,7 @@ module Ssa { * and the underlying variable for `def` is neither read nor written in any block * on the path between `bb1` and `bb2`. */ - private predicate varBlockReaches(TrackedDefinition def, BasicBlock bb1, BasicBlock bb2) { + private predicate varBlockReaches(Definition def, BasicBlock bb1, BasicBlock bb2) { varOccursInBlock(def, bb1, _) and bb2 = bb1.getASuccessor() or @@ -724,9 +653,7 @@ module Ssa { * `def` is read at `cfn`, `cfn` is in a transitive successor block of `bb1`, * and `def` is not read in any block on the path between `bb1` and `cfn`. */ - private predicate varBlockReachesRead( - TrackedDefinition def, BasicBlock bb1, ControlFlow::Node cfn - ) { + private predicate varBlockReachesRead(Definition def, BasicBlock bb1, ControlFlow::Node cfn) { exists(BasicBlock bb2, int i2 | varBlockReaches(def, bb1, bb2) and ssaRefRank(bb2, i2, def.getSourceVariable(), SsaRead()) = 1 and @@ -739,9 +666,7 @@ module Ssa { * or a write), `def` is read at `cfn`, and there is a path between them without * any read of `def`. */ - private predicate adjacentVarRead( - TrackedDefinition def, BasicBlock bb1, int i1, ControlFlow::Node cfn - ) { + private predicate adjacentVarRead(Definition def, BasicBlock bb1, int i1, ControlFlow::Node cfn) { exists(int rankix, int i2 | rankix = ssaDefRank(def, _, bb1, i1) and rankix + 1 = ssaDefRank(def, _, bb1, i2) and @@ -755,14 +680,13 @@ module Ssa { cached private module Cached { /** - * Holds if `cfn` is a last read of the non-trivial SSA definition `def`. - * That is, `cfn` can reach the end of the enclosing callable, or another - * SSA definition for the underlying source variable, without passing through - * another read. + * Holds if `cfn` is a last read of the SSA definition `def`. That is, `cfn` + * can reach the end of the enclosing callable, or another SSA definition for + * the underlying source variable, without passing through another read. */ cached - predicate lastRead(TrackedDefinition def, ControlFlow::Node cfn) { - exists(BasicBlock bb1, int i1, int rnk, TrackedVar v | + predicate lastRead(Definition def, ControlFlow::Node cfn) { + exists(BasicBlock bb1, int i1, int rnk, SourceVariable v | variableRead(bb1, i1, v, cfn, _) and rnk = ssaDefRank(def, v, bb1, i1) | @@ -788,9 +712,7 @@ module Ssa { } pragma[noinline] - private predicate ssaDefReachesEndOfBlockRec( - BasicBlock bb, TrackedDefinition def, TrackedVar v - ) { + private predicate ssaDefReachesEndOfBlockRec(BasicBlock bb, Definition def, SourceVariable v) { exists(BasicBlock idom | ssaDefReachesEndOfBlock(idom, def, v) | // The construction of SSA form ensures that each read of a variable is // dominated by its definition. An SSA definition therefore reaches a @@ -803,12 +725,12 @@ module Ssa { } /** - * Holds if the non-trivial SSA definition of `v` at `def` reaches the end of a - * basic block `bb`, at which point it is still live, without crossing another + * Holds if the SSA definition of `v` at `def` reaches the end of a basic + * block `bb`, at which point it is still live, without crossing another * SSA definition of `v`. */ cached - predicate ssaDefReachesEndOfBlock(BasicBlock bb, TrackedDefinition def, TrackedVar v) { + predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SourceVariable v) { exists(int last | last = maxSsaRefRank(bb, v) | ssaDefReachesRank(bb, def, last, v) and liveAtExit(bb, v, _) @@ -820,13 +742,12 @@ module Ssa { } /** - * Holds if the non-trivial SSA definition of `v` at `def` reaches `read` without - * crossing another SSA definition of `v`. - * The read at `node` is of kind `rk`. + * Holds if the SSA definition of `v` at `def` reaches `read` without crossing + * another SSA definition of `v`. The read at `node` is of kind `rk`. */ cached predicate ssaDefReachesRead( - TrackedVar v, TrackedDefinition def, ControlFlow::Node read, ReadKind rk + SourceVariable v, Definition def, ControlFlow::Node read, ReadKind rk ) { ssaDefReachesReadWithinBlock(v, def, read, rk) or @@ -838,12 +759,12 @@ module Ssa { } /** - * Holds if the non-trivial SSA definition of `v` at `def` reaches uncertain SSA - * definition `redef` without crossing another SSA definition of `v`. + * Holds if the SSA definition of `v` at `def` reaches uncertain SSA definition + * `redef` without crossing another SSA definition of `v`. */ cached predicate ssaDefReachesUncertainDef( - TrackedVar v, TrackedDefinition def, UncertainDefinition redef + SourceVariable v, Definition def, UncertainDefinition redef ) { ssaDefReachesUncertainDefWithinBlock(v, def, redef) or @@ -855,11 +776,11 @@ module Ssa { } /** - * Holds if the value defined at non-trivial SSA definition `def` can reach a - * read at `cfn`, without passing through any other read. + * Holds if the value defined at SSA definition `def` can reach a read at `cfn`, + * without passing through any other read. */ cached - predicate firstReadSameVar(TrackedDefinition def, ControlFlow::Node cfn) { + predicate firstReadSameVar(Definition def, ControlFlow::Node cfn) { exists(BasicBlock bb1, int i1 | definesAt(def, bb1, i1, _) and adjacentVarRead(def, bb1, i1, cfn) @@ -873,7 +794,7 @@ module Ssa { */ cached predicate adjacentReadPairSameVar( - TrackedDefinition def, ControlFlow::Node cfn1, ControlFlow::Node cfn2 + Definition def, ControlFlow::Node cfn1, ControlFlow::Node cfn2 ) { exists(BasicBlock bb1, int i1 | variableRead(bb1, i1, _, cfn1, _) and @@ -981,7 +902,7 @@ module Ssa { fpdef.getTarget() = fp and not init(fpdef) and fpdef.getEnclosingCallable() = c and - exists(TrackedFieldOrProp tf | tf.getAssignable() = fp) + exists(FieldOrPropSourceVariable tf | tf.getAssignable() = fp) } /** @@ -1173,7 +1094,7 @@ module Ssa { * an update somewhere, and `fp` is likely to be live in `bb` at index * `i`. */ - private predicate updateCandidate(BasicBlock bb, int i, TrackedFieldOrProp fp, Call call) { + private predicate updateCandidate(BasicBlock bb, int i, FieldOrPropSourceVariable fp, Call call) { possiblyLiveAtAllNodes(bb, fp) and callAt(bb, i, call) and relevantDefinition(_, fp.getAssignable(), _) and @@ -1181,11 +1102,11 @@ module Ssa { } private predicate source( - Call call, TrackedFieldOrProp tfp, FieldOrProp fp, Callable c, boolean fresh + Call call, FieldOrPropSourceVariable fps, FieldOrProp fp, Callable c, boolean fresh ) { - updateCandidate(_, _, tfp, call) and + updateCandidate(_, _, fps, call) and c = getARuntimeTarget(call, _) and - fp = tfp.getAssignable() and + fp = fps.getAssignable() and if c instanceof Constructor then fresh = true else fresh = false } @@ -1259,13 +1180,13 @@ module Ssa { } private predicate updatesNamedFieldOrPropPossiblyLive( - BasicBlock bb, int i, TrackedFieldOrProp fp, Call call, Callable setter + BasicBlock bb, int i, FieldOrPropSourceVariable fp, Call call, Callable setter ) { updateCandidate(bb, i, fp, call) and updatesNamedFieldOrProp_(fp, call, setter) } - private int firstRefAfterCall(BasicBlock bb, int i, TrackedFieldOrProp fp) { + private int firstRefAfterCall(BasicBlock bb, int i, FieldOrPropSourceVariable fp) { updatesNamedFieldOrPropPossiblyLive(bb, i, fp, _, _) and result = min(int k | k > i and ref(bb, k, fp, _)) } @@ -1275,7 +1196,7 @@ module Ssa { * update occurs in `setter`. */ cached - predicate updatesNamedFieldOrProp(Call c, TrackedFieldOrProp fp, Callable setter) { + predicate updatesNamedFieldOrProp(Call c, FieldOrPropSourceVariable fp, Callable setter) { forceCachingInSameStage() and exists(BasicBlock bb, int i | updatesNamedFieldOrPropPossiblyLive(bb, i, fp, c, setter) | not exists(firstRefAfterCall(bb, i, fp)) and @@ -1784,16 +1705,14 @@ module Ssa { * properties, or captured variables). * 4. Implicit indirect definitions of variables through qualifier definitions * (fields or properties). - * 5. Implicit definitions of variables prior to all reads, for variables that - * are not amenable to SSA analysis (`UntrackedVar`). - * 6. Phi nodes. + * 5. Phi nodes. * * SSA definitions are only introduced where necessary. That is, dead assignments * have no associated SSA definitions. */ cached newtype TDefinition = - TSsaExplicitDef(TrackedVar v, AssignableDefinition def, BasicBlock bb, int i) { + TSsaExplicitDef(SourceVariable v, AssignableDefinition def, BasicBlock bb, int i) { variableDefinition(bb, i, v, def) and ( exists(ReadKind rk | liveAfterWrite(bb, i, v, rk) | @@ -1814,7 +1733,7 @@ module Ssa { liveAfterWriteCaptured(bb, i, v) ) } or - TSsaImplicitEntryDef(TrackedVar v, ControlFlow::BasicBlocks::EntryBlock ebb) { + TSsaImplicitEntryDef(SourceVariable v, ControlFlow::BasicBlocks::EntryBlock ebb) { liveAtEntry(ebb, v, _) and exists(Callable c | c = ebb.getCallable() and @@ -1828,10 +1747,10 @@ module Ssa { ) or // Each tracked field and property has an implicit entry definition - v instanceof TrackedFieldOrProp + v instanceof FieldOrPropSourceVariable ) } or - TSsaImplicitCallDef(TrackedVar v, Call c, BasicBlock bb, int i) { + TSsaImplicitCallDef(SourceVariable v, Call c, BasicBlock bb, int i) { bb.getNode(i) = c.getAControlFlowNode() and ( // Liveness of `v` after `c` is guaranteed by `updatesNamedFieldOrProp` @@ -1841,7 +1760,7 @@ module Ssa { updatesCapturedVariable(c, v, _, _) ) } or - TSsaImplicitQualifierDef(TrackedVar v, Definition qdef) { + TSsaImplicitQualifierDef(SourceVariable v, Definition qdef) { exists(BasicBlock bb, int i | qdef.getSourceVariable() = v.getQualifier() and qdef.definesAt(bb, i) and @@ -1854,17 +1773,13 @@ module Ssa { not exists(TSsaImplicitCallDef(v, _, bb, i)) ) } or - TSsaImplicitUntrackedDef(UntrackedVar v, BasicBlock bb, int i) { - // Insert a definition prior to every read for untracked variables - bb.getNode(i + 1) = v.getAnAccess().(AssignableRead).getAControlFlowNode() - } or - TPhiNode(TrackedVar v, ControlFlow::BasicBlocks::JoinBlock bb) { + TPhiNode(SourceVariable v, ControlFlow::BasicBlocks::JoinBlock bb) { phiNodeMaybeLive(bb, v) and liveAtEntry(bb, v, _) } pragma[noinline] - private predicate phiNodeMaybeLive(ControlFlow::BasicBlocks::JoinBlock bb, TrackedVar v) { + private predicate phiNodeMaybeLive(ControlFlow::BasicBlocks::JoinBlock bb, SourceVariable v) { exists(Definition def, BasicBlock bb1 | definesAt(def, bb1, _, v) | bb1.inDominanceFrontier(bb) ) @@ -1886,8 +1801,6 @@ module Ssa { or exists(Definition qdef | def = TSsaImplicitQualifierDef(v, qdef) | definesAt(qdef, bb, i, _)) or - def = TSsaImplicitUntrackedDef(v, bb, i) - or def = TPhiNode(v, bb) and i = -1 } @@ -2256,10 +2169,10 @@ module Ssa { * An SSA definition that corresponds to an explicit assignable definition. */ class ExplicitDefinition extends Definition, TSsaExplicitDef { - TrackedVar tv; + SourceVariable sv; AssignableDefinition ad; - ExplicitDefinition() { this = TSsaExplicitDef(tv, ad, _, _) } + ExplicitDefinition() { this = TSsaExplicitDef(sv, ad, _, _) } /** * Gets an underlying assignable definition. The result is always unique, @@ -2337,16 +2250,14 @@ module Ssa { * An SSA definition that does not correspond to an explicit variable definition. * Either an implicit initialization of a variable at the beginning of a callable * (`ImplicitEntryDefinition`), an implicit definition via a call - * (`ImplicitCallDefinition`), an implicit definition where the qualifier is - * updated (`ImplicitQualifierDefinition`), or a definition for a field or - * property that is not amenable to SSA analysis (`ImplicitUntrackedDefinition`). + * (`ImplicitCallDefinition`), or an implicit definition where the qualifier is + * updated (`ImplicitQualifierDefinition`). */ class ImplicitDefinition extends Definition { ImplicitDefinition() { this = TSsaImplicitEntryDef(_, _) or this = TSsaImplicitCallDef(_, _, _, _) or - this = TSsaImplicitQualifierDef(_, _) or - this = TSsaImplicitUntrackedDef(_, _, _) + this = TSsaImplicitQualifierDef(_, _) } } @@ -2420,25 +2331,6 @@ module Ssa { override Location getLocation() { result = getQualifierDefinition().getLocation() } } - /** - * An SSA definition for a variable that is not amenable to SSA analysis. A definition - * is inserted prior to every read. - */ - class ImplicitUntrackedDefinition extends ImplicitDefinition, TSsaImplicitUntrackedDef { - override AssignableRead getARead() { - exists(BasicBlock bb, int i, UntrackedVar v | - this = TSsaImplicitUntrackedDef(v, bb, i) and - result.getAControlFlowNode() = bb.getNode(i + 1) - ) - } - - override string toString() { - result = getToStringPrefix(this) + "SSA untracked def(" + getSourceVariable() + ")" - } - - override Location getLocation() { result = this.getARead().getLocation() } - } - /** * An SSA definition that has no actual semantics, but simply serves to * merge or filter data flow. @@ -2483,7 +2375,7 @@ module Ssa { * call definition on line 9 as inputs. */ override Definition getAnInput() { - exists(BasicBlock bb, BasicBlock phiPred, TrackedVar v | + exists(BasicBlock bb, BasicBlock phiPred, SourceVariable v | definesAt(this, bb, _, v) and bb.getAPredecessor() = phiPred and ssaDefReachesEndOfBlock(phiPred, result, v) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll index 2974bc6af6a..001e071c651 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -1691,8 +1691,6 @@ private class FieldOrPropertyRead extends FieldOrPropertyAccess, AssignableRead * SSA updates. */ predicate hasNonlocalValue() { - this = any(Ssa::ImplicitUntrackedDefinition udef).getARead() - or exists(Ssa::Definition def, Ssa::ImplicitDefinition idef | def.getARead() = this and idef = def.getAnUltimateDefinition() diff --git a/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected b/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected index acce87f5c60..fc00d4e05e9 100644 --- a/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected +++ b/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected @@ -4,6 +4,7 @@ | CSharp7.cs:10:9:10:9 | this access | CSharp7.cs:11:9:11:9 | this access | | CSharp7.cs:16:9:16:13 | [post] this access | CSharp7.cs:25:39:25:43 | this access | | CSharp7.cs:16:9:16:13 | this access | CSharp7.cs:25:39:25:43 | this access | +| CSharp7.cs:17:9:17:11 | SSA entry def(this.field) | CSharp7.cs:17:18:17:22 | access to field field | | CSharp7.cs:17:9:17:11 | this | CSharp7.cs:17:18:17:22 | this access | | CSharp7.cs:21:9:21:11 | this | CSharp7.cs:21:16:21:20 | this access | | CSharp7.cs:22:9:22:11 | this | CSharp7.cs:22:16:22:20 | this access | @@ -67,6 +68,7 @@ | CSharp7.cs:84:23:84:23 | 2 | CSharp7.cs:84:16:84:24 | (..., ...) | | CSharp7.cs:87:10:87:18 | this | CSharp7.cs:92:18:92:28 | this access | | CSharp7.cs:89:13:89:34 | SSA def(t1) | CSharp7.cs:90:28:90:29 | access to local variable t1 | +| CSharp7.cs:89:13:89:34 | SSA qualifier def(t1.Item1) | CSharp7.cs:92:20:92:27 | access to field Item1 | | CSharp7.cs:89:18:89:34 | (..., ...) | CSharp7.cs:89:13:89:34 | SSA def(t1) | | CSharp7.cs:89:19:89:27 | "tainted" | CSharp7.cs:89:18:89:34 | (..., ...) | | CSharp7.cs:89:30:89:33 | "X2" | CSharp7.cs:89:18:89:34 | (..., ...) | @@ -100,6 +102,7 @@ | CSharp7.cs:112:31:112:32 | access to local variable m2 | CSharp7.cs:112:26:112:33 | (..., ...) | | CSharp7.cs:114:9:114:67 | SSA def(m9) | CSharp7.cs:115:19:115:20 | access to local variable m9 | | CSharp7.cs:114:38:114:67 | SSA def(m2) | CSharp7.cs:118:9:118:10 | access to local variable m2 | +| CSharp7.cs:114:38:114:67 | SSA qualifier def(m2.Item1) | CSharp7.cs:119:19:119:26 | access to field Item1 | | CSharp7.cs:114:49:114:67 | (..., ...) | CSharp7.cs:114:38:114:67 | ... = ... | | CSharp7.cs:114:50:114:58 | "DefUse2" | CSharp7.cs:114:49:114:67 | (..., ...) | | CSharp7.cs:114:61:114:66 | (..., ...) | CSharp7.cs:114:38:114:67 | SSA def(m2) | diff --git a/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected b/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected index e54670f07fc..babc7501a22 100644 --- a/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected +++ b/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected @@ -325,6 +325,8 @@ | LocalDataFlow.cs:243:9:243:17 | access to local variable nonSink10 | LocalDataFlow.cs:244:15:244:23 | access to local variable nonSink10 | | LocalDataFlow.cs:247:13:247:52 | SSA def(taintedDataContract) | LocalDataFlow.cs:248:22:248:40 | access to local variable taintedDataContract | | LocalDataFlow.cs:247:13:247:52 | SSA qualifier def(taintedDataContract.AList) | LocalDataFlow.cs:250:22:250:46 | access to property AList | +| LocalDataFlow.cs:247:13:247:52 | SSA qualifier def(taintedDataContract.AString) | LocalDataFlow.cs:248:22:248:48 | access to property AString | +| LocalDataFlow.cs:247:13:247:52 | SSA qualifier def(taintedDataContract.AnInt) | LocalDataFlow.cs:257:20:257:44 | access to property AnInt | | LocalDataFlow.cs:247:35:247:52 | object creation of type DataContract | LocalDataFlow.cs:247:13:247:52 | SSA def(taintedDataContract) | | LocalDataFlow.cs:248:13:248:48 | SSA def(sink53) | LocalDataFlow.cs:249:15:249:20 | access to local variable sink53 | | LocalDataFlow.cs:248:22:248:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:250:22:250:40 | access to local variable taintedDataContract | @@ -337,6 +339,7 @@ | LocalDataFlow.cs:250:22:250:46 | access to property AList | LocalDataFlow.cs:259:20:259:44 | access to property AList | | LocalDataFlow.cs:250:22:250:57 | access to property AString | LocalDataFlow.cs:250:13:250:57 | SSA def(sink54) | | LocalDataFlow.cs:254:13:254:55 | SSA def(nonTaintedDataContract) | LocalDataFlow.cs:255:20:255:41 | access to local variable nonTaintedDataContract | +| LocalDataFlow.cs:254:13:254:55 | SSA qualifier def(nonTaintedDataContract.AString) | LocalDataFlow.cs:255:20:255:49 | access to property AString | | LocalDataFlow.cs:254:38:254:55 | object creation of type DataContract | LocalDataFlow.cs:254:13:254:55 | SSA def(nonTaintedDataContract) | | LocalDataFlow.cs:255:9:255:49 | SSA def(nonSink0) | LocalDataFlow.cs:256:15:256:22 | access to local variable nonSink0 | | LocalDataFlow.cs:255:20:255:49 | access to property AString | LocalDataFlow.cs:255:9:255:49 | SSA def(nonSink0) | @@ -347,10 +350,12 @@ | LocalDataFlow.cs:259:9:259:53 | SSA def(nonSink2) | LocalDataFlow.cs:260:15:260:22 | access to local variable nonSink2 | | LocalDataFlow.cs:259:20:259:53 | access to property AnInt | LocalDataFlow.cs:259:9:259:53 | SSA def(nonSink2) | | LocalDataFlow.cs:263:17:263:37 | SSA def(taintedTextBox) | LocalDataFlow.cs:264:22:264:35 | access to local variable taintedTextBox | +| LocalDataFlow.cs:263:17:263:37 | SSA qualifier def(taintedTextBox.Text) | LocalDataFlow.cs:264:22:264:40 | access to property Text | | LocalDataFlow.cs:263:34:263:37 | null | LocalDataFlow.cs:263:17:263:37 | SSA def(taintedTextBox) | | LocalDataFlow.cs:264:13:264:40 | SSA def(sink60) | LocalDataFlow.cs:265:15:265:20 | access to local variable sink60 | | LocalDataFlow.cs:264:22:264:40 | access to property Text | LocalDataFlow.cs:264:13:264:40 | SSA def(sink60) | | LocalDataFlow.cs:268:17:268:40 | SSA def(nonTaintedTextBox) | LocalDataFlow.cs:269:20:269:36 | access to local variable nonTaintedTextBox | +| LocalDataFlow.cs:268:17:268:40 | SSA qualifier def(nonTaintedTextBox.Text) | LocalDataFlow.cs:269:20:269:41 | access to property Text | | LocalDataFlow.cs:268:37:268:40 | null | LocalDataFlow.cs:268:17:268:40 | SSA def(nonTaintedTextBox) | | LocalDataFlow.cs:269:9:269:41 | SSA def(nonSink0) | LocalDataFlow.cs:270:15:270:22 | access to local variable nonSink0 | | LocalDataFlow.cs:269:20:269:41 | access to property Text | LocalDataFlow.cs:269:9:269:41 | SSA def(nonSink0) | @@ -396,6 +401,7 @@ | LocalDataFlow.cs:314:22:314:26 | access to local variable sink0 | LocalDataFlow.cs:314:22:314:38 | ... ?? ... | | LocalDataFlow.cs:314:22:314:38 | ... ?? ... | LocalDataFlow.cs:314:13:314:38 | SSA def(sink74) | | LocalDataFlow.cs:314:31:314:38 | access to local variable nonSink0 | LocalDataFlow.cs:314:22:314:38 | ... ?? ... | +| LocalDataFlow.cs:334:28:334:30 | SSA entry def(this.anInt) | LocalDataFlow.cs:334:41:334:45 | access to field anInt | | LocalDataFlow.cs:334:28:334:30 | this | LocalDataFlow.cs:334:41:334:45 | this access | | LocalDataFlow.cs:334:50:334:52 | this | LocalDataFlow.cs:334:56:334:60 | this access | | LocalDataFlow.cs:334:50:334:52 | value | LocalDataFlow.cs:334:64:334:68 | access to parameter value | diff --git a/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected b/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected index e33df037f81..2435c1a30f7 100644 --- a/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected +++ b/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected @@ -421,6 +421,8 @@ | LocalDataFlow.cs:243:30:243:37 | access to local variable nonSink0 | LocalDataFlow.cs:243:9:243:38 | call to method AppendLine | | LocalDataFlow.cs:247:13:247:52 | SSA def(taintedDataContract) | LocalDataFlow.cs:248:22:248:40 | access to local variable taintedDataContract | | LocalDataFlow.cs:247:13:247:52 | SSA qualifier def(taintedDataContract.AList) | LocalDataFlow.cs:250:22:250:46 | access to property AList | +| LocalDataFlow.cs:247:13:247:52 | SSA qualifier def(taintedDataContract.AString) | LocalDataFlow.cs:248:22:248:48 | access to property AString | +| LocalDataFlow.cs:247:13:247:52 | SSA qualifier def(taintedDataContract.AnInt) | LocalDataFlow.cs:257:20:257:44 | access to property AnInt | | LocalDataFlow.cs:247:35:247:52 | object creation of type DataContract | LocalDataFlow.cs:247:13:247:52 | SSA def(taintedDataContract) | | LocalDataFlow.cs:248:13:248:48 | SSA def(sink53) | LocalDataFlow.cs:249:15:249:20 | access to local variable sink53 | | LocalDataFlow.cs:248:22:248:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:250:22:250:40 | access to local variable taintedDataContract | @@ -437,6 +439,7 @@ | LocalDataFlow.cs:250:22:250:49 | access to indexer | LocalDataFlow.cs:250:22:250:57 | access to property AString | | LocalDataFlow.cs:250:22:250:57 | access to property AString | LocalDataFlow.cs:250:13:250:57 | SSA def(sink54) | | LocalDataFlow.cs:254:13:254:55 | SSA def(nonTaintedDataContract) | LocalDataFlow.cs:255:20:255:41 | access to local variable nonTaintedDataContract | +| LocalDataFlow.cs:254:13:254:55 | SSA qualifier def(nonTaintedDataContract.AString) | LocalDataFlow.cs:255:20:255:49 | access to property AString | | LocalDataFlow.cs:254:38:254:55 | object creation of type DataContract | LocalDataFlow.cs:254:13:254:55 | SSA def(nonTaintedDataContract) | | LocalDataFlow.cs:255:9:255:49 | SSA def(nonSink0) | LocalDataFlow.cs:256:15:256:22 | access to local variable nonSink0 | | LocalDataFlow.cs:255:20:255:41 | access to local variable nonTaintedDataContract | LocalDataFlow.cs:255:20:255:49 | access to property AString | @@ -450,11 +453,13 @@ | LocalDataFlow.cs:259:20:259:44 | access to property AList | LocalDataFlow.cs:259:20:259:47 | access to indexer | | LocalDataFlow.cs:259:20:259:53 | access to property AnInt | LocalDataFlow.cs:259:9:259:53 | SSA def(nonSink2) | | LocalDataFlow.cs:263:17:263:37 | SSA def(taintedTextBox) | LocalDataFlow.cs:264:22:264:35 | access to local variable taintedTextBox | +| LocalDataFlow.cs:263:17:263:37 | SSA qualifier def(taintedTextBox.Text) | LocalDataFlow.cs:264:22:264:40 | access to property Text | | LocalDataFlow.cs:263:34:263:37 | null | LocalDataFlow.cs:263:17:263:37 | SSA def(taintedTextBox) | | LocalDataFlow.cs:264:13:264:40 | SSA def(sink60) | LocalDataFlow.cs:265:15:265:20 | access to local variable sink60 | | LocalDataFlow.cs:264:22:264:35 | access to local variable taintedTextBox | LocalDataFlow.cs:264:22:264:40 | access to property Text | | LocalDataFlow.cs:264:22:264:40 | access to property Text | LocalDataFlow.cs:264:13:264:40 | SSA def(sink60) | | LocalDataFlow.cs:268:17:268:40 | SSA def(nonTaintedTextBox) | LocalDataFlow.cs:269:20:269:36 | access to local variable nonTaintedTextBox | +| LocalDataFlow.cs:268:17:268:40 | SSA qualifier def(nonTaintedTextBox.Text) | LocalDataFlow.cs:269:20:269:41 | access to property Text | | LocalDataFlow.cs:268:37:268:40 | null | LocalDataFlow.cs:268:17:268:40 | SSA def(nonTaintedTextBox) | | LocalDataFlow.cs:269:9:269:41 | SSA def(nonSink0) | LocalDataFlow.cs:270:15:270:22 | access to local variable nonSink0 | | LocalDataFlow.cs:269:20:269:36 | access to local variable nonTaintedTextBox | LocalDataFlow.cs:269:20:269:41 | access to property Text | @@ -505,6 +510,7 @@ | LocalDataFlow.cs:314:22:314:26 | access to local variable sink0 | LocalDataFlow.cs:314:22:314:38 | ... ?? ... | | LocalDataFlow.cs:314:22:314:38 | ... ?? ... | LocalDataFlow.cs:314:13:314:38 | SSA def(sink74) | | LocalDataFlow.cs:314:31:314:38 | access to local variable nonSink0 | LocalDataFlow.cs:314:22:314:38 | ... ?? ... | +| LocalDataFlow.cs:334:28:334:30 | SSA entry def(this.anInt) | LocalDataFlow.cs:334:41:334:45 | access to field anInt | | LocalDataFlow.cs:334:28:334:30 | this | LocalDataFlow.cs:334:41:334:45 | this access | | LocalDataFlow.cs:334:50:334:52 | this | LocalDataFlow.cs:334:56:334:60 | this access | | LocalDataFlow.cs:334:50:334:52 | value | LocalDataFlow.cs:334:64:334:68 | access to parameter value | diff --git a/csharp/ql/test/library-tests/dataflow/ssa/SsaDef.expected b/csharp/ql/test/library-tests/dataflow/ssa/SsaDef.expected index bc2b8dd23d9..8d5a2db71ab 100644 --- a/csharp/ql/test/library-tests/dataflow/ssa/SsaDef.expected +++ b/csharp/ql/test/library-tests/dataflow/ssa/SsaDef.expected @@ -193,11 +193,9 @@ | Fields.cs:33:19:33:22 | Fields.stat | Fields.cs:49:17:49:28 | SSA call def(Fields.stat) | | Fields.cs:33:19:33:22 | Fields.stat | Fields.cs:50:9:50:17 | SSA phi(Fields.stat) | | Fields.cs:33:19:33:22 | Fields.stat | Fields.cs:51:9:51:20 | SSA call def(Fields.stat) | -| Fields.cs:63:16:63:28 | this.VolatileField | Fields.cs:63:16:63:28 | SSA untracked def(this.VolatileField) | -| Fields.cs:63:16:63:28 | this.VolatileField | Fields.cs:69:21:69:33 | SSA untracked def(this.VolatileField) | | Fields.cs:65:24:65:32 | this.LoopField | Fields.cs:61:17:61:17 | SSA entry def(this.LoopField) | -| Fields.cs:71:17:71:35 | this.SingleAccessedField | Fields.cs:71:17:71:35 | SSA untracked def(this.SingleAccessedField) | -| Fields.cs:76:20:76:38 | this.SingleAccessedField | Fields.cs:76:20:76:38 | SSA untracked def(this.SingleAccessedField) | +| Fields.cs:71:17:71:35 | this.SingleAccessedField | Fields.cs:61:17:61:17 | SSA entry def(this.SingleAccessedField) | +| Fields.cs:76:20:76:38 | this.SingleAccessedField | Fields.cs:74:17:74:17 | SSA entry def(this.SingleAccessedField) | | Fields.cs:77:13:77:13 | f | Fields.cs:77:13:77:45 | SSA def(f) | | Fields.cs:77:13:77:13 | f | Fields.cs:78:27:78:54 | SSA capture def(f) | | Fields.cs:78:23:78:23 | a | Fields.cs:78:23:78:54 | SSA def(a) | @@ -283,8 +281,8 @@ | Properties.cs:61:23:61:23 | i | Properties.cs:63:16:63:16 | SSA phi(i) | | Properties.cs:61:23:61:23 | i | Properties.cs:63:16:63:18 | SSA def(i) | | Properties.cs:65:24:65:31 | this.LoopProp | Properties.cs:61:17:61:17 | SSA entry def(this.LoopProp) | -| Properties.cs:67:21:67:38 | this.SingleAccessedProp | Properties.cs:67:21:67:38 | SSA untracked def(this.SingleAccessedProp) | -| Properties.cs:72:20:72:37 | this.SingleAccessedProp | Properties.cs:72:20:72:37 | SSA untracked def(this.SingleAccessedProp) | +| Properties.cs:67:21:67:38 | this.SingleAccessedProp | Properties.cs:61:17:61:17 | SSA entry def(this.SingleAccessedProp) | +| Properties.cs:72:20:72:37 | this.SingleAccessedProp | Properties.cs:70:17:70:17 | SSA entry def(this.SingleAccessedProp) | | Properties.cs:73:13:73:13 | f | Properties.cs:73:13:73:32 | SSA def(f) | | Properties.cs:73:13:73:13 | f | Properties.cs:74:27:74:54 | SSA capture def(f) | | Properties.cs:74:23:74:23 | a | Properties.cs:74:23:74:54 | SSA def(a) | @@ -298,11 +296,6 @@ | Properties.cs:76:9:76:12 | f.xs | Properties.cs:84:9:84:25 | SSA def(f.xs) | | Properties.cs:78:9:78:15 | this.xs | Properties.cs:81:9:81:22 | SSA def(this.xs) | | Properties.cs:78:9:78:15 | this.xs | Properties.cs:83:9:83:22 | SSA def(this.xs) | -| Properties.cs:94:9:94:27 | this.NonTrivialProp | Properties.cs:95:20:95:38 | SSA untracked def(this.NonTrivialProp) | -| Properties.cs:97:9:97:24 | this.VirtualProp | Properties.cs:98:16:98:31 | SSA untracked def(this.VirtualProp) | -| Properties.cs:100:9:100:26 | this.VolatileField | Properties.cs:100:9:100:26 | SSA untracked def(this.VolatileField) | -| Properties.cs:100:9:100:26 | this.VolatileField | Properties.cs:101:21:101:38 | SSA untracked def(this.VolatileField) | -| Properties.cs:100:9:100:29 | this.VolatileField.xs | Properties.cs:101:21:101:41 | SSA untracked def(this.VolatileField.xs) | | Properties.cs:106:37:106:37 | p | Properties.cs:106:37:106:37 | SSA param(p) | | Properties.cs:114:20:114:29 | this.Props | Properties.cs:108:10:108:10 | SSA entry def(this.Props) | | Properties.cs:114:20:114:29 | this.Props | Properties.cs:113:9:113:22 | SSA call def(this.Props) | diff --git a/csharp/ql/test/library-tests/dataflow/ssa/SsaDefElement.expected b/csharp/ql/test/library-tests/dataflow/ssa/SsaDefElement.expected index bc176624df5..a5971b9070d 100644 --- a/csharp/ql/test/library-tests/dataflow/ssa/SsaDefElement.expected +++ b/csharp/ql/test/library-tests/dataflow/ssa/SsaDefElement.expected @@ -183,10 +183,8 @@ | Fields.cs:49:17:49:28 | SSA call def(Fields.stat) | Fields.cs:49:17:49:28 | object creation of type Fields | | Fields.cs:51:9:51:20 | SSA call def(Fields.stat) | Fields.cs:51:9:51:20 | object creation of type Fields | | Fields.cs:61:17:61:17 | SSA entry def(this.LoopField) | Fields.cs:61:17:61:17 | H | -| Fields.cs:63:16:63:28 | SSA untracked def(this.VolatileField) | Fields.cs:63:16:63:28 | this access | -| Fields.cs:69:21:69:33 | SSA untracked def(this.VolatileField) | Fields.cs:69:21:69:33 | this access | -| Fields.cs:71:17:71:35 | SSA untracked def(this.SingleAccessedField) | Fields.cs:71:17:71:35 | this access | -| Fields.cs:76:20:76:38 | SSA untracked def(this.SingleAccessedField) | Fields.cs:76:20:76:38 | this access | +| Fields.cs:61:17:61:17 | SSA entry def(this.SingleAccessedField) | Fields.cs:61:17:61:17 | H | +| Fields.cs:74:17:74:17 | SSA entry def(this.SingleAccessedField) | Fields.cs:74:17:74:17 | I | | Fields.cs:77:13:77:45 | SSA def(f) | Fields.cs:77:13:77:45 | Fields f = ... | | Fields.cs:78:23:78:54 | SSA def(a) | Fields.cs:78:23:78:54 | Action a = ... | | Fields.cs:78:27:78:54 | SSA capture def(f) | Fields.cs:78:27:78:54 | (...) => ... | @@ -264,10 +262,10 @@ | Properties.cs:49:17:49:32 | SSA call def(Properties.stat) | Properties.cs:49:17:49:32 | object creation of type Properties | | Properties.cs:51:9:51:24 | SSA call def(Properties.stat) | Properties.cs:51:9:51:24 | object creation of type Properties | | Properties.cs:61:17:61:17 | SSA entry def(this.LoopProp) | Properties.cs:61:17:61:17 | H | +| Properties.cs:61:17:61:17 | SSA entry def(this.SingleAccessedProp) | Properties.cs:61:17:61:17 | H | | Properties.cs:61:23:61:23 | SSA param(i) | Properties.cs:61:23:61:23 | i | | Properties.cs:63:16:63:18 | SSA def(i) | Properties.cs:63:16:63:18 | ...-- | -| Properties.cs:67:21:67:38 | SSA untracked def(this.SingleAccessedProp) | Properties.cs:67:21:67:38 | this access | -| Properties.cs:72:20:72:37 | SSA untracked def(this.SingleAccessedProp) | Properties.cs:72:20:72:37 | this access | +| Properties.cs:70:17:70:17 | SSA entry def(this.SingleAccessedProp) | Properties.cs:70:17:70:17 | I | | Properties.cs:73:13:73:32 | SSA def(f) | Properties.cs:73:13:73:32 | Properties f = ... | | Properties.cs:74:23:74:54 | SSA def(a) | Properties.cs:74:23:74:54 | Action a = ... | | Properties.cs:74:27:74:54 | SSA capture def(f) | Properties.cs:74:27:74:54 | (...) => ... | @@ -281,11 +279,6 @@ | Properties.cs:83:9:83:22 | SSA def(this.xs) | Properties.cs:83:9:83:22 | ... = ... | | Properties.cs:84:9:84:25 | SSA def(f.xs) | Properties.cs:84:9:84:25 | ... = ... | | Properties.cs:85:24:85:46 | SSA capture def(b) | Properties.cs:85:24:85:46 | (...) => ... | -| Properties.cs:95:20:95:38 | SSA untracked def(this.NonTrivialProp) | Properties.cs:95:20:95:23 | this access | -| Properties.cs:98:16:98:31 | SSA untracked def(this.VirtualProp) | Properties.cs:98:16:98:19 | this access | -| Properties.cs:100:9:100:26 | SSA untracked def(this.VolatileField) | Properties.cs:100:9:100:12 | this access | -| Properties.cs:101:21:101:38 | SSA untracked def(this.VolatileField) | Properties.cs:101:21:101:24 | this access | -| Properties.cs:101:21:101:41 | SSA untracked def(this.VolatileField.xs) | Properties.cs:101:21:101:38 | access to field VolatileField | | Properties.cs:106:37:106:37 | SSA param(p) | Properties.cs:106:37:106:37 | p | | Properties.cs:108:10:108:10 | SSA entry def(this.Props) | Properties.cs:108:10:108:10 | K | | Properties.cs:108:10:108:10 | SSA entry def(this.Props.Props) | Properties.cs:108:10:108:10 | K | diff --git a/csharp/ql/test/library-tests/dataflow/ssa/SsaDefLastRead.expected b/csharp/ql/test/library-tests/dataflow/ssa/SsaDefLastRead.expected index d9534f06ff1..35ad76fe651 100644 --- a/csharp/ql/test/library-tests/dataflow/ssa/SsaDefLastRead.expected +++ b/csharp/ql/test/library-tests/dataflow/ssa/SsaDefLastRead.expected @@ -151,6 +151,8 @@ | Fields.cs:33:19:33:22 | Fields.stat | Fields.cs:38:9:38:13 | SSA call def(Fields.stat) | Fields.cs:41:13:41:16 | access to field stat | | Fields.cs:33:19:33:22 | Fields.stat | Fields.cs:51:9:51:20 | SSA call def(Fields.stat) | Fields.cs:54:13:54:16 | access to field stat | | Fields.cs:65:24:65:32 | this.LoopField | Fields.cs:61:17:61:17 | SSA entry def(this.LoopField) | Fields.cs:65:24:65:32 | access to field LoopField | +| Fields.cs:71:17:71:35 | this.SingleAccessedField | Fields.cs:61:17:61:17 | SSA entry def(this.SingleAccessedField) | Fields.cs:71:17:71:35 | access to field SingleAccessedField | +| Fields.cs:76:20:76:38 | this.SingleAccessedField | Fields.cs:74:17:74:17 | SSA entry def(this.SingleAccessedField) | Fields.cs:76:20:76:38 | access to field SingleAccessedField | | Fields.cs:77:13:77:13 | f | Fields.cs:77:13:77:45 | SSA def(f) | Fields.cs:90:19:90:19 | access to local variable f | | Fields.cs:77:13:77:13 | f | Fields.cs:78:27:78:54 | SSA capture def(f) | Fields.cs:78:35:78:35 | access to local variable f | | Fields.cs:78:23:78:23 | a | Fields.cs:78:23:78:54 | SSA def(a) | Fields.cs:81:9:81:9 | access to local variable a | @@ -219,6 +221,8 @@ | Properties.cs:33:19:33:22 | Properties.stat | Properties.cs:51:9:51:24 | SSA call def(Properties.stat) | Properties.cs:54:13:54:16 | access to property stat | | Properties.cs:61:23:61:23 | i | Properties.cs:63:16:63:16 | SSA phi(i) | Properties.cs:63:16:63:16 | access to parameter i | | Properties.cs:65:24:65:31 | this.LoopProp | Properties.cs:61:17:61:17 | SSA entry def(this.LoopProp) | Properties.cs:65:24:65:31 | access to property LoopProp | +| Properties.cs:67:21:67:38 | this.SingleAccessedProp | Properties.cs:61:17:61:17 | SSA entry def(this.SingleAccessedProp) | Properties.cs:67:21:67:38 | access to property SingleAccessedProp | +| Properties.cs:72:20:72:37 | this.SingleAccessedProp | Properties.cs:70:17:70:17 | SSA entry def(this.SingleAccessedProp) | Properties.cs:72:20:72:37 | access to property SingleAccessedProp | | Properties.cs:73:13:73:13 | f | Properties.cs:73:13:73:32 | SSA def(f) | Properties.cs:86:19:86:19 | access to local variable f | | Properties.cs:73:13:73:13 | f | Properties.cs:74:27:74:54 | SSA capture def(f) | Properties.cs:74:35:74:35 | access to local variable f | | Properties.cs:74:23:74:23 | a | Properties.cs:74:23:74:54 | SSA def(a) | Properties.cs:77:9:77:9 | access to local variable a | diff --git a/csharp/ql/test/library-tests/dataflow/ssa/SsaRead.expected b/csharp/ql/test/library-tests/dataflow/ssa/SsaRead.expected index 13aad35a44a..d6a958b32d7 100644 --- a/csharp/ql/test/library-tests/dataflow/ssa/SsaRead.expected +++ b/csharp/ql/test/library-tests/dataflow/ssa/SsaRead.expected @@ -185,11 +185,9 @@ | Fields.cs:33:19:33:22 | Fields.stat | Fields.cs:34:9:34:16 | SSA call def(Fields.stat) | Fields.cs:37:13:37:16 | access to field stat | | Fields.cs:33:19:33:22 | Fields.stat | Fields.cs:38:9:38:13 | SSA call def(Fields.stat) | Fields.cs:41:13:41:16 | access to field stat | | Fields.cs:33:19:33:22 | Fields.stat | Fields.cs:51:9:51:20 | SSA call def(Fields.stat) | Fields.cs:54:13:54:16 | access to field stat | -| Fields.cs:63:16:63:28 | this.VolatileField | Fields.cs:63:16:63:28 | SSA untracked def(this.VolatileField) | Fields.cs:63:16:63:28 | access to field VolatileField | -| Fields.cs:63:16:63:28 | this.VolatileField | Fields.cs:69:21:69:33 | SSA untracked def(this.VolatileField) | Fields.cs:69:21:69:33 | access to field VolatileField | | Fields.cs:65:24:65:32 | this.LoopField | Fields.cs:61:17:61:17 | SSA entry def(this.LoopField) | Fields.cs:65:24:65:32 | access to field LoopField | -| Fields.cs:71:17:71:35 | this.SingleAccessedField | Fields.cs:71:17:71:35 | SSA untracked def(this.SingleAccessedField) | Fields.cs:71:17:71:35 | access to field SingleAccessedField | -| Fields.cs:76:20:76:38 | this.SingleAccessedField | Fields.cs:76:20:76:38 | SSA untracked def(this.SingleAccessedField) | Fields.cs:76:20:76:38 | access to field SingleAccessedField | +| Fields.cs:71:17:71:35 | this.SingleAccessedField | Fields.cs:61:17:61:17 | SSA entry def(this.SingleAccessedField) | Fields.cs:71:17:71:35 | access to field SingleAccessedField | +| Fields.cs:76:20:76:38 | this.SingleAccessedField | Fields.cs:74:17:74:17 | SSA entry def(this.SingleAccessedField) | Fields.cs:76:20:76:38 | access to field SingleAccessedField | | Fields.cs:77:13:77:13 | f | Fields.cs:77:13:77:45 | SSA def(f) | Fields.cs:80:9:80:9 | access to local variable f | | Fields.cs:77:13:77:13 | f | Fields.cs:77:13:77:45 | SSA def(f) | Fields.cs:82:19:82:19 | access to local variable f | | Fields.cs:77:13:77:13 | f | Fields.cs:77:13:77:45 | SSA def(f) | Fields.cs:83:9:83:9 | access to local variable f | @@ -302,8 +300,8 @@ | Properties.cs:33:19:33:22 | Properties.stat | Properties.cs:51:9:51:24 | SSA call def(Properties.stat) | Properties.cs:54:13:54:16 | access to property stat | | Properties.cs:61:23:61:23 | i | Properties.cs:63:16:63:16 | SSA phi(i) | Properties.cs:63:16:63:16 | access to parameter i | | Properties.cs:65:24:65:31 | this.LoopProp | Properties.cs:61:17:61:17 | SSA entry def(this.LoopProp) | Properties.cs:65:24:65:31 | access to property LoopProp | -| Properties.cs:67:21:67:38 | this.SingleAccessedProp | Properties.cs:67:21:67:38 | SSA untracked def(this.SingleAccessedProp) | Properties.cs:67:21:67:38 | access to property SingleAccessedProp | -| Properties.cs:72:20:72:37 | this.SingleAccessedProp | Properties.cs:72:20:72:37 | SSA untracked def(this.SingleAccessedProp) | Properties.cs:72:20:72:37 | access to property SingleAccessedProp | +| Properties.cs:67:21:67:38 | this.SingleAccessedProp | Properties.cs:61:17:61:17 | SSA entry def(this.SingleAccessedProp) | Properties.cs:67:21:67:38 | access to property SingleAccessedProp | +| Properties.cs:72:20:72:37 | this.SingleAccessedProp | Properties.cs:70:17:70:17 | SSA entry def(this.SingleAccessedProp) | Properties.cs:72:20:72:37 | access to property SingleAccessedProp | | Properties.cs:73:13:73:13 | f | Properties.cs:73:13:73:32 | SSA def(f) | Properties.cs:76:9:76:9 | access to local variable f | | Properties.cs:73:13:73:13 | f | Properties.cs:73:13:73:32 | SSA def(f) | Properties.cs:78:19:78:19 | access to local variable f | | Properties.cs:73:13:73:13 | f | Properties.cs:73:13:73:32 | SSA def(f) | Properties.cs:79:9:79:9 | access to local variable f | @@ -322,11 +320,6 @@ | Properties.cs:76:9:76:12 | f.xs | Properties.cs:84:9:84:25 | SSA def(f.xs) | Properties.cs:86:19:86:22 | access to property xs | | Properties.cs:78:9:78:15 | this.xs | Properties.cs:81:9:81:22 | SSA def(this.xs) | Properties.cs:82:9:82:15 | access to property xs | | Properties.cs:78:9:78:15 | this.xs | Properties.cs:83:9:83:22 | SSA def(this.xs) | Properties.cs:85:9:85:15 | access to property xs | -| Properties.cs:94:9:94:27 | this.NonTrivialProp | Properties.cs:95:20:95:38 | SSA untracked def(this.NonTrivialProp) | Properties.cs:95:20:95:38 | access to property NonTrivialProp | -| Properties.cs:97:9:97:24 | this.VirtualProp | Properties.cs:98:16:98:31 | SSA untracked def(this.VirtualProp) | Properties.cs:98:16:98:31 | access to property VirtualProp | -| Properties.cs:100:9:100:26 | this.VolatileField | Properties.cs:100:9:100:26 | SSA untracked def(this.VolatileField) | Properties.cs:100:9:100:26 | access to field VolatileField | -| Properties.cs:100:9:100:26 | this.VolatileField | Properties.cs:101:21:101:38 | SSA untracked def(this.VolatileField) | Properties.cs:101:21:101:38 | access to field VolatileField | -| Properties.cs:100:9:100:29 | this.VolatileField.xs | Properties.cs:101:21:101:41 | SSA untracked def(this.VolatileField.xs) | Properties.cs:101:21:101:41 | access to property xs | | Properties.cs:106:37:106:37 | p | Properties.cs:106:37:106:37 | SSA param(p) | Properties.cs:106:42:106:42 | access to parameter p | | Properties.cs:114:20:114:29 | this.Props | Properties.cs:113:9:113:22 | SSA call def(this.Props) | Properties.cs:114:20:114:29 | access to field Props | | Properties.cs:114:20:114:29 | this.Props | Properties.cs:113:9:113:22 | SSA call def(this.Props) | Properties.cs:115:21:115:30 | access to field Props | diff --git a/csharp/ql/test/library-tests/dataflow/ssa/SsaUltimateDef.expected b/csharp/ql/test/library-tests/dataflow/ssa/SsaUltimateDef.expected index f84d9f953a3..2d9f6d5e58d 100644 --- a/csharp/ql/test/library-tests/dataflow/ssa/SsaUltimateDef.expected +++ b/csharp/ql/test/library-tests/dataflow/ssa/SsaUltimateDef.expected @@ -247,11 +247,9 @@ | Fields.cs:33:19:33:22 | Fields.stat | Fields.cs:51:9:51:20 | SSA call def(Fields.stat) | Fields.cs:38:9:38:13 | SSA call def(Fields.stat) | | Fields.cs:33:19:33:22 | Fields.stat | Fields.cs:51:9:51:20 | SSA call def(Fields.stat) | Fields.cs:49:17:49:28 | SSA call def(Fields.stat) | | Fields.cs:33:19:33:22 | Fields.stat | Fields.cs:51:9:51:20 | SSA call def(Fields.stat) | Fields.cs:51:9:51:20 | SSA call def(Fields.stat) | -| Fields.cs:63:16:63:28 | this.VolatileField | Fields.cs:63:16:63:28 | SSA untracked def(this.VolatileField) | Fields.cs:63:16:63:28 | SSA untracked def(this.VolatileField) | -| Fields.cs:63:16:63:28 | this.VolatileField | Fields.cs:69:21:69:33 | SSA untracked def(this.VolatileField) | Fields.cs:69:21:69:33 | SSA untracked def(this.VolatileField) | | Fields.cs:65:24:65:32 | this.LoopField | Fields.cs:61:17:61:17 | SSA entry def(this.LoopField) | Fields.cs:61:17:61:17 | SSA entry def(this.LoopField) | -| Fields.cs:71:17:71:35 | this.SingleAccessedField | Fields.cs:71:17:71:35 | SSA untracked def(this.SingleAccessedField) | Fields.cs:71:17:71:35 | SSA untracked def(this.SingleAccessedField) | -| Fields.cs:76:20:76:38 | this.SingleAccessedField | Fields.cs:76:20:76:38 | SSA untracked def(this.SingleAccessedField) | Fields.cs:76:20:76:38 | SSA untracked def(this.SingleAccessedField) | +| Fields.cs:71:17:71:35 | this.SingleAccessedField | Fields.cs:61:17:61:17 | SSA entry def(this.SingleAccessedField) | Fields.cs:61:17:61:17 | SSA entry def(this.SingleAccessedField) | +| Fields.cs:76:20:76:38 | this.SingleAccessedField | Fields.cs:74:17:74:17 | SSA entry def(this.SingleAccessedField) | Fields.cs:74:17:74:17 | SSA entry def(this.SingleAccessedField) | | Fields.cs:77:13:77:13 | f | Fields.cs:77:13:77:45 | SSA def(f) | Fields.cs:77:13:77:45 | SSA def(f) | | Fields.cs:77:13:77:13 | f | Fields.cs:78:27:78:54 | SSA capture def(f) | Fields.cs:78:27:78:54 | SSA capture def(f) | | Fields.cs:78:23:78:23 | a | Fields.cs:78:23:78:54 | SSA def(a) | Fields.cs:78:23:78:54 | SSA def(a) | @@ -377,8 +375,8 @@ | Properties.cs:61:23:61:23 | i | Properties.cs:63:16:63:16 | SSA phi(i) | Properties.cs:63:16:63:18 | SSA def(i) | | Properties.cs:61:23:61:23 | i | Properties.cs:63:16:63:18 | SSA def(i) | Properties.cs:63:16:63:18 | SSA def(i) | | Properties.cs:65:24:65:31 | this.LoopProp | Properties.cs:61:17:61:17 | SSA entry def(this.LoopProp) | Properties.cs:61:17:61:17 | SSA entry def(this.LoopProp) | -| Properties.cs:67:21:67:38 | this.SingleAccessedProp | Properties.cs:67:21:67:38 | SSA untracked def(this.SingleAccessedProp) | Properties.cs:67:21:67:38 | SSA untracked def(this.SingleAccessedProp) | -| Properties.cs:72:20:72:37 | this.SingleAccessedProp | Properties.cs:72:20:72:37 | SSA untracked def(this.SingleAccessedProp) | Properties.cs:72:20:72:37 | SSA untracked def(this.SingleAccessedProp) | +| Properties.cs:67:21:67:38 | this.SingleAccessedProp | Properties.cs:61:17:61:17 | SSA entry def(this.SingleAccessedProp) | Properties.cs:61:17:61:17 | SSA entry def(this.SingleAccessedProp) | +| Properties.cs:72:20:72:37 | this.SingleAccessedProp | Properties.cs:70:17:70:17 | SSA entry def(this.SingleAccessedProp) | Properties.cs:70:17:70:17 | SSA entry def(this.SingleAccessedProp) | | Properties.cs:73:13:73:13 | f | Properties.cs:73:13:73:32 | SSA def(f) | Properties.cs:73:13:73:32 | SSA def(f) | | Properties.cs:73:13:73:13 | f | Properties.cs:74:27:74:54 | SSA capture def(f) | Properties.cs:74:27:74:54 | SSA capture def(f) | | Properties.cs:74:23:74:23 | a | Properties.cs:74:23:74:54 | SSA def(a) | Properties.cs:74:23:74:54 | SSA def(a) | @@ -394,11 +392,6 @@ | Properties.cs:76:9:76:12 | f.xs | Properties.cs:84:9:84:25 | SSA def(f.xs) | Properties.cs:84:9:84:25 | SSA def(f.xs) | | Properties.cs:78:9:78:15 | this.xs | Properties.cs:81:9:81:22 | SSA def(this.xs) | Properties.cs:81:9:81:22 | SSA def(this.xs) | | Properties.cs:78:9:78:15 | this.xs | Properties.cs:83:9:83:22 | SSA def(this.xs) | Properties.cs:83:9:83:22 | SSA def(this.xs) | -| Properties.cs:94:9:94:27 | this.NonTrivialProp | Properties.cs:95:20:95:38 | SSA untracked def(this.NonTrivialProp) | Properties.cs:95:20:95:38 | SSA untracked def(this.NonTrivialProp) | -| Properties.cs:97:9:97:24 | this.VirtualProp | Properties.cs:98:16:98:31 | SSA untracked def(this.VirtualProp) | Properties.cs:98:16:98:31 | SSA untracked def(this.VirtualProp) | -| Properties.cs:100:9:100:26 | this.VolatileField | Properties.cs:100:9:100:26 | SSA untracked def(this.VolatileField) | Properties.cs:100:9:100:26 | SSA untracked def(this.VolatileField) | -| Properties.cs:100:9:100:26 | this.VolatileField | Properties.cs:101:21:101:38 | SSA untracked def(this.VolatileField) | Properties.cs:101:21:101:38 | SSA untracked def(this.VolatileField) | -| Properties.cs:100:9:100:29 | this.VolatileField.xs | Properties.cs:101:21:101:41 | SSA untracked def(this.VolatileField.xs) | Properties.cs:101:21:101:41 | SSA untracked def(this.VolatileField.xs) | | Properties.cs:106:37:106:37 | p | Properties.cs:106:37:106:37 | SSA param(p) | Properties.cs:106:37:106:37 | SSA param(p) | | Properties.cs:114:20:114:29 | this.Props | Properties.cs:108:10:108:10 | SSA entry def(this.Props) | Properties.cs:108:10:108:10 | SSA entry def(this.Props) | | Properties.cs:114:20:114:29 | this.Props | Properties.cs:113:9:113:22 | SSA call def(this.Props) | Properties.cs:108:10:108:10 | SSA entry def(this.Props) | From 63f76b1b43e44c7ab33c51662062e5e5a313987d Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 21 Dec 2020 20:24:25 +0100 Subject: [PATCH 054/343] C#: Uniform treatment of all SSA definitions --- .../code/csharp/commons/ConsistencyChecks.qll | 2 +- .../code/csharp/controlflow/BasicBlocks.qll | 12 +- .../csharp/controlflow/ControlFlowGraph.qll | 2 +- .../src/semmle/code/csharp/dataflow/SSA.qll | 811 +++++++++--------- .../dataflow/defuse/useUseEquivalence.ql | 2 +- .../library-tests/dataflow/ssa/Capture.cs | 6 +- .../dataflow/ssa/PreSsaConsistency.ql | 4 +- .../dataflow/ssa/SsaDef.expected | 11 +- .../dataflow/ssa/SsaDefElement.expected | 7 +- .../dataflow/ssa/SsaExplicitDef.expected | 3 + .../ssa/SsaImplicitQualifier.expected | 4 + .../dataflow/ssa/SsaUltimateDef.expected | 19 +- .../DeadStoreOfLocal/DeadStoreOfLocal.cs | 4 +- .../DeadStoreOfLocal.expected | 2 - 14 files changed, 451 insertions(+), 438 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/commons/ConsistencyChecks.qll b/csharp/ql/src/semmle/code/csharp/commons/ConsistencyChecks.qll index aabdc030274..a4405a5a309 100644 --- a/csharp/ql/src/semmle/code/csharp/commons/ConsistencyChecks.qll +++ b/csharp/ql/src/semmle/code/csharp/commons/ConsistencyChecks.qll @@ -49,7 +49,7 @@ module SsaChecks { exists(Definition def, BasicBlock bb, ControlFlow::Node rnode, ControlFlow::Node dnode, int i | def.getAReadAtNode(rnode) = read | - def.definesAt(bb, i) and + def.definesAt(_, bb, i) and dnode = bb.getNode(max(int j | j = i or j = 0)) and not dnode.dominates(rnode) ) and diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/BasicBlocks.qll b/csharp/ql/src/semmle/code/csharp/controlflow/BasicBlocks.qll index 4e87ac445c8..8b20ccb3c22 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/BasicBlocks.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/BasicBlocks.qll @@ -377,7 +377,17 @@ private predicate entryBB(BasicBlock bb) { * an annotated exit node. */ class AnnotatedExitBasicBlock extends BasicBlock { - AnnotatedExitBasicBlock() { this.getANode() instanceof ControlFlow::Nodes::AnnotatedExitNode } + private boolean isNormal; + + AnnotatedExitBasicBlock() { + this.getANode() = + any(ControlFlow::Nodes::AnnotatedExitNode n | + if n.isNormal() then isNormal = true else isNormal = false + ) + } + + /** Holds if this block represents a normal exit. */ + predicate isNormal() { isNormal = true } } /** diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll index 9f4eda99838..061b7674810 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll @@ -270,7 +270,7 @@ module ControlFlow { /** Gets the callable that this exit applies to. */ Callable getCallable() { result = c } - /** Holds if this node represent a normal exit. */ + /** Holds if this node represents a normal exit. */ predicate isNormal() { normal = true } override BasicBlocks::AnnotatedExitBlock getBasicBlock() { diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/SSA.qll b/csharp/ql/src/semmle/code/csharp/dataflow/SSA.qll index 4b99882e167..24166d298e3 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/SSA.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/SSA.qll @@ -78,9 +78,27 @@ module Ssa { cached AssignableDefinition getADefinition(ExplicitDefinition def) { - exists(SourceVariable sv, AssignableDefinition ad | def = TSsaExplicitDef(sv, ad, _, _) | + exists(SourceVariable v, AssignableDefinition ad | explicitDefinition(def, v, ad) | result = ad or - result = getASameOutRefDefAfter(sv, ad) + result = getASameOutRefDefAfter(v, ad) + ) + } + + cached + predicate implicitEntryDefinition(ControlFlow::BasicBlocks::EntryBlock bb, SourceVariable v) { + exists(Callable c | + c = bb.getCallable() and + c = v.getEnclosingCallable() + | + // Captured variable + exists(LocalScopeVariable lsv | + v = any(LocalScopeSourceVariable lv | lsv = lv.getAssignable()) + | + lsv.getCallable() != c + ) + or + // Each tracked field and property has an implicit entry definition + v instanceof PlainFieldOrPropSourceVariable ) } } @@ -155,8 +173,10 @@ module Ssa { /** * Holds if the `i`th node of basic block `bb` is a (potential) write to source * variable `v`. The Boolean `certain` indicates whether the write is certain. + * + * This excludes implicit writes via calls. */ - private predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) { + predicate variableWriteDirect(BasicBlock bb, int i, SourceVariable v, boolean certain) { exists(AssignableDefinition ad | variableDefinition(bb, i, v, ad) | if any(AssignableDefinition ad0 | ad0 = ad or ad0 = getASameOutRefDefAfter(v, ad)) @@ -165,13 +185,17 @@ module Ssa { else certain = false ) or - variableWrite(bb, i, v.(QualifiedFieldOrPropSourceVariable).getQualifier(), certain) + variableWriteDirect(bb, i, v.(QualifiedFieldOrPropSourceVariable).getQualifier(), certain) + or + implicitEntryDefinition(bb, v) and + i = -1 and + certain = true } /** * A classification of variable reads. */ - newtype ReadKind = + newtype TReadKind = /** An actual read. */ ActualRead() or /** @@ -192,6 +216,10 @@ module Ssa { * as a write to a `ref` or `out` variable (see above). */ CapturedVarExitRead() or + /** + * A pseudo read for a captured variable via a call. + */ + CapturedVarCallRead() or /** * A pseudo read for a `ref` variable, just prior to an update of the referenced value. * A pseudo read is inserted to make assignments to the `ref` variable live, for example @@ -209,11 +237,35 @@ module Ssa { */ RefReadBeforeWrite() + class ReadKind extends TReadKind { + string toString() { + this = ActualRead() and + result = "ActualRead" + or + this = OutRefExitRead() and + result = "OutRefExitRead" + or + this = CapturedVarExitRead() and + result = "CapturedVarExitRead" + or + this = CapturedVarCallRead() and + result = "CapturedVarCallRead" + or + this = RefReadBeforeWrite() and + result = "RefReadBeforeWrite" + } + + /** Holds if this kind represents a pseudo read. */ + predicate isPseudo() { this != ActualRead() } + } + /** * Holds if the `i`th node `node` of basic block `bb` reads source variable `v`. * The read at `node` is of kind `rk`. + * + * This excludes implicit reads via calls. */ - predicate variableRead( + predicate variableReadDirect( BasicBlock bb, int i, SourceVariable v, ControlFlow::Node node, ReadKind rk ) { v.getAnAccess().(AssignableRead) = node.getElement() and @@ -223,34 +275,23 @@ module Ssa { outRefExitRead(bb, i, v, node) and rk = OutRefExitRead() or - capturedVarExitRead(bb, i, v, node) and - rk = CapturedVarExitRead() - or refReadBeforeWrite(bb, i, v, node) and rk = RefReadBeforeWrite() } private predicate outRefExitRead( - ControlFlow::BasicBlocks::ExitBlock ebb, int i, LocalScopeSourceVariable v, - ControlFlow::Nodes::ExitNode node + BasicBlock bb, int i, LocalScopeSourceVariable v, ControlFlow::Nodes::AnnotatedExitNode node ) { + node.isNormal() and exists(LocalScopeVariable lsv | lsv = v.getAssignable() and - ebb.getNode(i) = node and + bb.getNode(i) = node and node.getCallable() = lsv.getCallable() | - lsv.isRef() or lsv.(Parameter).isOut() - ) - } - - private predicate capturedVarExitRead( - ControlFlow::BasicBlocks::ExitBlock ebb, int i, LocalScopeSourceVariable v, - ControlFlow::Nodes::ExitNode node - ) { - exists(BasicBlock bb | variableDefinition(bb, _, v, _) | - ebb.getNode(i) = node and - bb.getCallable() = ebb.getCallable() and - bb.getCallable() != v.getAssignable().getCallable() + lsv.(Parameter).isOutOrRef() + or + lsv.isRef() and + strictcount(v.getAnAccess()) > 1 ) } @@ -261,7 +302,7 @@ module Ssa { def.getTarget() = lv and lv.isRef() and lv = v.getAssignable() and - node = def.getAControlFlowNode().getAPredecessor() and + node = def.getAControlFlowNode() and bb.getNode(i) = node ) } @@ -270,26 +311,54 @@ module Ssa { * A classification of variable references into reads (of a given kind) and * (certain or uncertain) writes. */ - newtype RefKind = + private newtype TRefKind = Read(ReadKind rk) or Write(boolean certain) { certain = true or certain = false } + private class RefKind extends TRefKind { + string toString() { + exists(ReadKind rk | this = Read(rk) and result = "read (" + rk + ")") + or + exists(boolean certain | this = Write(certain) and result = "write (" + certain + ")") + } + + int getOrder() { + this = Read(_) and + result = 0 + or + this = Write(_) and + result = 1 + } + } + /** - * Holds if the `i`th node of basic block `bb` is a reference to `v`, either a read - * (when `k` is `Read()`) or a write (when `k` is `UncertainWrite()` or `Write()`). + * Holds if the `i`th node of basic block `bb` is a reference to `v` of kind `k`. */ - predicate ref(BasicBlock bb, int i, SourceVariable v, RefKind k) { + private predicate ref(BasicBlock bb, int i, SourceVariable v, RefKind k) { exists(ReadKind rk | variableRead(bb, i, v, _, rk) | k = Read(rk)) or exists(boolean certain | variableWrite(bb, i, v, certain) | k = Write(certain)) } + private newtype TaggedRefIndex = + MkTaggedRefIndex(int i, int tag) { + exists(RefKind rk | ref(_, i, _, rk) | tag = rk.getOrder()) + } + /** * Gets the (1-based) rank of the reference to `v` at the `i`th node of basic block `bb`, * which has the given reference kind `k`. + * + * Reads are considered before writes when they happen at the same index. */ int refRank(BasicBlock bb, int i, SourceVariable v, RefKind k) { - i = rank[result](int j | ref(bb, j, v, _)) and + MkTaggedRefIndex(i, k.getOrder()) = + rank[result](int j, RefKind rk0, int tag | + ref(bb, j, v, rk0) and + tag = rk0.getOrder() + | + MkTaggedRefIndex(j, tag) order by j, tag + ) and ref(bb, i, v, k) } @@ -334,29 +403,23 @@ module Ssa { liveAtEntry(bb.getASuccessor(), v, rk) } - /** - * Holds if source variable `v` is likely to be live at any node inside basic - * block `bb`. This is an overestimate. - */ - predicate possiblyLiveAtAllNodes(BasicBlock bb, SourceVariable v) { - liveAtExit(bb, v, _) - or - ref(bb, _, v, Read(_)) - } - /** * Holds if variable `v` is live in basic block `bb` at index `i`. * The rank of `i` is `rnk` as defined by `refRank()`. */ - predicate liveAtRank(BasicBlock bb, int i, SourceVariable v, int rnk, ReadKind rk) { - rnk = refRank(bb, i, v, _) and - ( + private predicate liveAtRank(BasicBlock bb, int i, SourceVariable v, int rnk, ReadKind rk) { + exists(RefKind kind | rnk = refRank(bb, i, v, kind) | rnk = maxRefRank(bb, v) and liveAtExit(bb, v, rk) or - ref(bb, i, v, Read(rk)) + ref(bb, i, v, kind) and + kind = Read(rk) or - exists(int j | liveAtRank(bb, j, v, rnk + 1, rk) | not ref(bb, j, v, Write(true))) + exists(RefKind nextKind | + liveAtRank(bb, _, v, rnk + 1, rk) and + rnk + 1 = refRank(bb, _, v, nextKind) and + nextKind != Write(true) + ) ) } @@ -518,25 +581,44 @@ module Ssa { /** * A classification of SSA variable references into reads definitions. */ - private newtype SsaRefKind = + private newtype TSsaRefKind = SsaRead() or SsaDef() + private class SsaRefKind extends TSsaRefKind { + string toString() { + this = SsaRead() and + result = "SsaRead" + or + this = SsaDef() and + result = "SsaDef" + } + + int getOrder() { + this = SsaRead() and + result = 0 + or + this = SsaDef() and + result = 1 + } + } + /** * Holds if the `i`th node of basic block `bb` is a reference to `v`, * either a read (when `k` is `Read()`) or an SSA definition (when `k` * is `SsaDef()`). */ private predicate ssaRef(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) { - exists(ReadKind rk | variableRead(bb, i, v, _, rk) | - not rk instanceof RefReadBeforeWrite and - k = SsaRead() - ) + variableRead(bb, i, v, _, _) and + k = SsaRead() or - exists(Definition def | definesAt(def, bb, i, v)) and + exists(Definition def | def.definesAt(v, bb, i)) and k = SsaDef() } + private newtype TaggedSsaRefIndex = + MkTaggedSsaRefIndex(int i, SsaRefKind k) { ssaRef(_, i, _, k) } + /** * Gets the (1-based) rank of the reference to `v` at the `i`th node of basic * block `bb`, which has the given reference kind `k`. @@ -549,9 +631,16 @@ module Ssa { * ssaRefRank(bb, 2, v, Read()) = 2 // read at node 2 * ssaRefRank(bb, 5, v, SsaDef()) = 3 // definition at node 5 * ``` + * + * Reads are considered before writes when they happen at the same index. */ private int ssaRefRank(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) { - i = rank[result](int j | ssaRef(bb, j, v, _)) and + MkTaggedSsaRefIndex(i, k) = + rank[result](int j, SsaRefKind k0 | + ssaRef(bb, j, v, k0) + | + MkTaggedSsaRefIndex(j, k0) order by j, k0.getOrder() + ) and ssaRef(bb, i, v, k) } @@ -567,7 +656,7 @@ module Ssa { private predicate ssaDefReachesRank(BasicBlock bb, Definition def, int rankix, SourceVariable v) { exists(int i | rankix = ssaRefRank(bb, i, v, SsaDef()) and - definesAt(def, bb, i, v) + def.definesAt(v, bb, i) ) or ssaDefReachesRank(bb, def, rankix - 1, v) and @@ -599,31 +688,25 @@ module Ssa { exists(BasicBlock bb, int rankix, int i | ssaDefReachesRank(bb, def, rankix, v) and rankix = ssaRefRank(bb, i, v, SsaDef()) - 1 and - definesAt(redef, bb, i, v) + redef.definesAt(v, bb, i) ) } /** - * Same as `ssaRefRank()`, but restricted to actual reads of `def`, or - * `def` itself. + * Same as `ssaRefRank()`, but restricted to a particular SSA definition `def`. */ - private int ssaDefRank(Definition def, SourceVariable v, BasicBlock bb, int i) { + private int ssaDefRank(Definition def, SourceVariable v, BasicBlock bb, int i, SsaRefKind k) { v = def.getSourceVariable() and - result = ssaRefRank(bb, i, v, _) and + result = ssaRefRank(bb, i, v, k) and ( - ssaDefReachesRead(_, def, bb.getNode(i), ActualRead()) + ssaDefReachesRead(_, def, bb.getNode(i), _) or - definesAt(def, bb, i, _) + def.definesAt(_, bb, i) ) } - private int maxSsaDefRefRank(BasicBlock bb, SourceVariable v) { - result = ssaDefRank(_, v, bb, _) and - not result + 1 = ssaDefRank(_, v, bb, _) - } - private predicate varOccursInBlock(Definition def, BasicBlock bb, SourceVariable v) { - exists(ssaDefRank(def, v, bb, _)) + exists(ssaDefRank(def, v, bb, _, _)) } pragma[noinline] @@ -668,38 +751,38 @@ module Ssa { */ private predicate adjacentVarRead(Definition def, BasicBlock bb1, int i1, ControlFlow::Node cfn) { exists(int rankix, int i2 | - rankix = ssaDefRank(def, _, bb1, i1) and - rankix + 1 = ssaDefRank(def, _, bb1, i2) and + rankix = ssaDefRank(def, _, bb1, i1, _) and + rankix + 1 = ssaDefRank(def, _, bb1, i2, SsaRead()) and variableRead(bb1, i2, _, cfn, _) ) or - exists(SourceVariable v | ssaDefRank(def, v, bb1, i1) = maxSsaDefRefRank(bb1, v)) and + exists(SourceVariable v | ssaDefRank(def, v, bb1, i1, _) = maxSsaRefRank(bb1, v)) and varBlockReachesRead(def, bb1, cfn) } cached private module Cached { /** - * Holds if `cfn` is a last read of the SSA definition `def`. That is, `cfn` - * can reach the end of the enclosing callable, or another SSA definition for - * the underlying source variable, without passing through another read. + * Holds if the node at index `i` in `bb` is a last reference to SSA + * definition `def`. + * + * That is, the node can reach the end of the enclosing callable, or another + * SSA definition for the underlying source variable, without passing through + * another read. */ cached - predicate lastRead(Definition def, ControlFlow::Node cfn) { - exists(BasicBlock bb1, int i1, int rnk, SourceVariable v | - variableRead(bb1, i1, v, cfn, _) and - rnk = ssaDefRank(def, v, bb1, i1) - | - // Next reference to `v` inside `bb1` is a write - rnk + 1 = ssaRefRank(bb1, _, v, SsaDef()) + predicate lastRef(Definition def, BasicBlock bb, int i) { + exists(int rnk, SourceVariable v | rnk = ssaDefRank(def, v, bb, i, _) | + // Next reference to `v` inside `bb` is a write + rnk + 1 = ssaRefRank(bb, _, v, SsaDef()) or - // No more references to `v` inside `bb1` - rnk = maxSsaDefRefRank(bb1, def.getSourceVariable()) and + // No more references to `v` inside `bb` + rnk = maxSsaRefRank(bb, v) and ( // Can reach exit directly - bb1 instanceof ControlFlow::BasicBlocks::ExitBlock + bb instanceof ControlFlow::BasicBlocks::ExitBlock or - exists(BasicBlock bb2 | varBlockReaches(def, bb1, bb2) | + exists(BasicBlock bb2 | varBlockReaches(def, bb, bb2) | // Can reach a write using one or more steps 1 = ssaRefRank(bb2, _, def.getSourceVariable(), SsaDef()) or @@ -769,12 +852,25 @@ module Ssa { ssaDefReachesUncertainDefWithinBlock(v, def, redef) or exists(BasicBlock bb | - definesAt(redef, bb, _, v) and + redef.definesAt(v, bb, _) and ssaDefReachesEndOfBlock(bb.getAPredecessor(), def, v) and not ssaDefReachesUncertainDefWithinBlock(v, _, redef) ) } + /** Same as `adjacentVarRead`, but steps over pseudo reads. */ + private predicate adjacentVarActualRead( + Definition def, BasicBlock bb1, int i1, ControlFlow::Node cfn + ) { + adjacentVarRead(def, bb1, i1, cfn) + or + exists(ControlFlow::Node mid, BasicBlock bb2, int i2 | + adjacentVarActualRead(def, bb1, i1, mid) and + variableRead(bb2, i2, _, mid, any(ReadKind rk | rk.isPseudo())) and + adjacentVarRead(def, bb2, i2, cfn) + ) + } + /** * Holds if the value defined at SSA definition `def` can reach a read at `cfn`, * without passing through any other read. @@ -782,8 +878,9 @@ module Ssa { cached predicate firstReadSameVar(Definition def, ControlFlow::Node cfn) { exists(BasicBlock bb1, int i1 | - definesAt(def, bb1, i1, _) and - adjacentVarRead(def, bb1, i1, cfn) + def.definesAt(_, bb1, i1) and + adjacentVarActualRead(def, bb1, i1, cfn) and + variableRead(_, _, _, cfn, ActualRead()) ) } @@ -797,8 +894,28 @@ module Ssa { Definition def, ControlFlow::Node cfn1, ControlFlow::Node cfn2 ) { exists(BasicBlock bb1, int i1 | - variableRead(bb1, i1, _, cfn1, _) and - adjacentVarRead(def, bb1, i1, cfn2) + variableRead(bb1, i1, _, cfn1, ActualRead()) and + adjacentVarActualRead(def, bb1, i1, cfn2) and + variableRead(_, _, _, cfn2, ActualRead()) + ) + } + + private predicate reachesLastRef(Definition def, BasicBlock bb, int i) { + lastRef(def, bb, i) + or + exists(BasicBlock bb0, int i0, ControlFlow::Node cfn | + reachesLastRef(def, bb0, i0) and + variableRead(bb0, i0, _, cfn, any(ReadKind rk | rk.isPseudo())) and + adjacentVarRead(def, bb, i, cfn) + ) + } + + cached + predicate lastReadSameVar(Definition def, ControlFlow::Node cfn) { + exists(BasicBlock bb, int i | + reachesLastRef(def, bb, i) and + variableRead(bb, i, _, _, ActualRead()) and + cfn = bb.getNode(i) ) } } @@ -1095,10 +1212,10 @@ module Ssa { * `i`. */ private predicate updateCandidate(BasicBlock bb, int i, FieldOrPropSourceVariable fp, Call call) { - possiblyLiveAtAllNodes(bb, fp) and callAt(bb, i, call) and + call.getEnclosingCallable() = fp.getEnclosingCallable() and relevantDefinition(_, fp.getAssignable(), _) and - not ref(bb, i, fp, _) + not variableWriteDirect(bb, i, fp, _) } private predicate source( @@ -1169,7 +1286,7 @@ module Ssa { private predicate edgePlus(TCallableNode c1, TCallableNode c2) = fastTC(prunedEdge/2)(c1, c2) pragma[noopt] - private predicate updatesNamedFieldOrProp_( + private predicate updatesNamedFieldOrProp( FieldOrPropSourceVariable fps, Call call, Callable setter ) { exists(TCallableNode src, TCallableNode sink, FieldOrProp fp | @@ -1179,68 +1296,17 @@ module Ssa { ) } - private predicate updatesNamedFieldOrPropPossiblyLive( - BasicBlock bb, int i, FieldOrPropSourceVariable fp, Call call, Callable setter - ) { - updateCandidate(bb, i, fp, call) and - updatesNamedFieldOrProp_(fp, call, setter) - } - - private int firstRefAfterCall(BasicBlock bb, int i, FieldOrPropSourceVariable fp) { - updatesNamedFieldOrPropPossiblyLive(bb, i, fp, _, _) and - result = min(int k | k > i and ref(bb, k, fp, _)) - } - /** * Holds if `call` may change the value of field or property `fp`. The actual * update occurs in `setter`. */ cached - predicate updatesNamedFieldOrProp(Call c, FieldOrPropSourceVariable fp, Callable setter) { + predicate updatesNamedFieldOrProp( + BasicBlock bb, int i, Call c, FieldOrPropSourceVariable fp, Callable setter + ) { forceCachingInSameStage() and - exists(BasicBlock bb, int i | updatesNamedFieldOrPropPossiblyLive(bb, i, fp, c, setter) | - not exists(firstRefAfterCall(bb, i, fp)) and - liveAtExit(bb, fp, _) - or - exists(int j | j = firstRefAfterCall(bb, i, fp) | - liveAtRank(bb, j, fp, _, _) and - not ref(bb, j, fp, Write(true)) - ) - ) - } - - /** - * Same as `variableWrite()`, but extended to include implicit call definitions - * for fields and properties. - */ - private predicate variableWriteExt(BasicBlock bb, int i, SourceVariable v) { - ref(bb, i, v, Write(_)) - or - variableWriteExt(bb, i, v.(QualifiedFieldOrPropSourceVariable).getQualifier()) - or - exists(Call c | callAt(bb, i, c) | updatesNamedFieldOrProp(c, v, _)) - } - - private int firstRefAfterQualifiedDef(BasicBlock bb, int i, QualifiedFieldOrPropSourceVariable q) { - variableWriteExt(bb, i, q) and - result = min(int k | k > i and ref(bb, k, q, _)) - } - - /** - * Holds if qualified field or property `q` is live after the (certain or - * uncertain) write at index `i` inside basic block `bb`. - */ - predicate liveAfterWriteQualified(BasicBlock bb, int i, QualifiedFieldOrPropSourceVariable q) { - variableWriteExt(bb, i, q) and - ( - not exists(firstRefAfterQualifiedDef(bb, i, q)) and - liveAtExit(bb, q, _) - or - exists(int j | j = firstRefAfterQualifiedDef(bb, i, q) | - liveAtRank(bb, j, q, _, _) and - not ref(bb, j, q, Write(true)) - ) - ) + updateCandidate(bb, i, fp, c) and + updatesNamedFieldOrProp(fp, c, setter) } } @@ -1306,7 +1372,6 @@ module Ssa { exists(BasicBlock bb, int i, CapturedWrittenLocalScopeSourceVariable sv | vdef.getTarget() = v and vdef.getEnclosingCallable() = c and - liveAfterWrite(bb, i, sv, _) and // only works because `CapturedVarExitRead`s are inserted sv.getAssignable() = v and bb.getNode(i) = vdef.getAControlFlowNode() and c != v.getCallable() @@ -1321,8 +1386,8 @@ module Ssa { private predicate updateCandidate( BasicBlock bb, int i, CapturedWrittenLocalScopeSourceVariable v, Call call ) { - possiblyLiveAtAllNodes(bb, v) and callAt(bb, i, call) and + call.getEnclosingCallable() = v.getEnclosingCallable() and exists(Assignable a | a = v.getAssignable() and relevantDefinition(_, a, _) and @@ -1398,46 +1463,53 @@ module Ssa { * Holds if `call` may change the value of captured variable `v`. The actual * update occurs in `def`. */ - private predicate updatesCapturedVariablePossiblyLive( + cached + predicate updatesCapturedVariable( BasicBlock bb, int i, Call call, LocalScopeSourceVariable v, AssignableDefinition def, boolean additionalCalls ) { + forceCachingInSameStage() and updateCandidate(bb, i, v, call) and exists(Callable writer | relevantDefinition(writer, v.getAssignable(), def) | updatesCapturedVariableWriter(call, v, writer, additionalCalls) ) } - - private int firstRefAfter(BasicBlock bb, int i, CapturedWrittenLocalScopeSourceVariable v) { - updatesCapturedVariablePossiblyLive(bb, i, _, v, _, _) and - result = min(int k | k > i and ref(bb, k, v, _)) - } - - /** - * Holds if `call` may change the value of captured variable `v`. The actual - * update occurs in `def`. - */ - cached - predicate updatesCapturedVariable( - Call call, LocalScopeSourceVariable v, AssignableDefinition def, boolean additionalCalls - ) { - forceCachingInSameStage() and - exists(BasicBlock bb, int i | - updatesCapturedVariablePossiblyLive(bb, i, call, v, def, additionalCalls) - | - not exists(firstRefAfter(bb, i, v)) and - liveAtExit(bb, v, _) - or - exists(int j | j = firstRefAfter(bb, i, v) | - liveAtRank(bb, j, v, _, _) and - not ref(bb, j, v, Write(true)) - ) - ) - } } private import CapturedVariableImpl + /** + * Holds if the `i`th node of basic block `bb` is a (potential) write to source + * variable `v`. The Boolean `certain` indicates whether the write is certain. + * + * This includes implicit writes via calls. + */ + private predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) { + variableWriteDirect(bb, i, v, certain) + or + variableWriteQualifier(bb, i, v, certain) + or + updatesNamedFieldOrProp(bb, i, _, v, _) and + certain = false + or + updatesCapturedVariable(bb, i, _, v, _, _) and + certain = false + } + + cached + private predicate variableWriteQualifier( + BasicBlock bb, int i, QualifiedFieldOrPropSourceVariable v, boolean certain + ) { + forceCachingInSameStage() and + variableWrite(bb, i, v.getQualifier(), certain) and + // Eliminate corner case where a call definition can overlap with a + // qualifier definition: if method `M` updates field `F`, then a call + // to `M` is both an update of `x.M` and `x.M.M`, so the former call + // definition should not give rise to an implicit qualifier definition + // for `x.M.M`. + not updatesNamedFieldOrProp(bb, i, _, v, _) + } + /** * Liveness analysis to restrict the size of the SSA representation for * captured variables. @@ -1467,11 +1539,10 @@ module Ssa { * `c` may read the value of the captured variable. */ private predicate capturerReads(Callable c, LocalScopeVariable v) { - exists(ControlFlow::BasicBlocks::EntryBlock ebb, LocalScopeSourceVariable lssv | - liveAtEntry(ebb, lssv, _) - | - v = lssv.getAssignable() and - c = ebb.getCallable() and + exists(LocalScopeSourceVariable sv | + variableReadDirect(_, _, sv, _, _) and + c = sv.getEnclosingCallable() and + v = sv.getAssignable() and v.getCallable() != c ) } @@ -1489,52 +1560,17 @@ module Ssa { } } - private predicate capturedVariableWrite( - BasicBlock bb, int i, CapturedReadLocalScopeSourceVariable v - ) { - ref(bb, i, v, Write(_)) - } - /** - * Holds if the write to captured source variable `v` at index `i` in basic - * block `bb` may be read by a callable reachable from the call `c`. + * Holds if a write to captured source variable `v` may be read by a + * callable reachable from the call `c`. */ private predicate implicitReadCandidate( - BasicBlock bb, int i, CapturedReadLocalScopeSourceVariable v, - ControlFlow::Nodes::ElementNode c + CapturedReadLocalScopeSourceVariable v, ControlFlow::Nodes::ElementNode c ) { - c.getElement() instanceof Call and - exists(BasicBlock bb0, int i0 | bb0.getNode(i0) = c | - // `c` is in basic block `bb` - capturedVariableWrite(bb0, i, v) and - i < i0 and - not capturedVariableWrite(bb, any(int j | j in [i + 1 .. i0 - 1]), v) and - bb = bb0 + exists(BasicBlock bb, int i | variableWriteDirect(bb, i, v, _) | + c = bb.getNode(any(int j | j > i)) or - // `c` is in a basic block reachable from `bb` - not capturedVariableWrite(bb0, any(int j | j < i0), v) and - capturedVariableWrite(bb, i, v) and - capturedVariableWriteReachesStartOf(bb, i, bb0, v) - ) - } - - /** - * Holds if the write to captured source variable `v` at index `i` in basic - * block `bb` reaches the start of basic block `r`, without passing through - * another write. - */ - private predicate capturedVariableWriteReachesStartOf( - BasicBlock bb, int i, BasicBlock r, CapturedReadLocalScopeSourceVariable v - ) { - exists(int last | last = max(refRank(bb, _, v, Write(_))) | - last = refRank(bb, i, v, Write(_)) and - capturedVariableWrite(bb, i, v) and - r = bb.getASuccessor() - ) - or - exists(BasicBlock mid | capturedVariableWriteReachesStartOf(bb, i, mid, v) | - r = mid.getASuccessor() and - not capturedVariableWrite(mid, _, v) + c = bb.getASuccessor+().getANode() ) } @@ -1542,7 +1578,7 @@ module Ssa { ControlFlow::Nodes::ElementNode call, CapturedReadLocalScopeSourceVariable v, CapturedReadLocalScopeVariable captured, Callable c, boolean libraryDelegateCall ) { - implicitReadCandidate(_, _, v, call) and + implicitReadCandidate(v, call) and c = getARuntimeTarget(call.getElement(), libraryDelegateCall) and captured = v.getAssignable() and capturerReads(_, captured) @@ -1601,12 +1637,12 @@ module Ssa { } /** - * Holds if captured local scope variable `v` is live after the (certain or uncertain) - * write at index `i` inside basic block `bb`. + * Holds if captured local scope variable `v` is written inside the callable + * to which `bb` belongs, and the value may be read via `call` using zero or + * more additional calls (as indicated by `additionalCalls`). * - * The write is live because of the implicit call definition `def`, which reaches - * the write using zero or more additional calls (as indicated by `additionalCalls`). - * That is, data can flow from the write at index `i` out to the call `def`. + * In this case a pseudo-read is inserted at the exit node `node`, at index + * `i` in `bb`, in order to make the write live. * * Example: * @@ -1624,27 +1660,23 @@ module Ssa { * The write to `i` inside `M2` on line 4 is live because of the implicit call * definition on line 5. */ - predicate liveAfterWriteCapturedOut( - BasicBlock bb, int i, LocalScopeSourceVariable v, ImplicitCallDefinition def, - boolean additionalCalls + predicate capturedReadOut( + BasicBlock bb, int i, LocalScopeSourceVariable v, ControlFlow::Nodes::AnnotatedExitNode node, + LocalScopeSourceVariable outer, Call call, boolean additionalCalls ) { - exists(LocalScopeVariable lsv, AssignableDefinition adef | - def.getSourceVariable().getAssignable() = lsv - | - lsv = v.getAssignable() and - bb.getNode(i) = adef.getAControlFlowNode() and - updatesCapturedVariable(def.getCall(), _, adef, additionalCalls) + node.isNormal() and + exists(BasicBlock pred, AssignableDefinition adef | + variableDefinition(pred, _, v, adef) and + updatesCapturedVariable(_, _, call, outer, adef, additionalCalls) and + pred.getASuccessor*() = bb and + node = bb.getNode(i) ) } /** - * Holds if captured local scope variable `v` is live after the (certain or uncertain) - * write at index `i` inside basic block `bb`. - * - * The write is live because of the implicit entry definition `def`, which can be - * reached using one or more calls (as indicated by `additionalCalls`), starting - * from call `c`. That is, data can flow from the write at index `i` into the - * callable containing `def`. + * Holds if a value written to captured local scope variable `outer` may be + * read as `inner` via `call`, at index `i` in basic block `bb`, using one or + * more calls (as indicated by `additionalCalls`). * * Example: * @@ -1662,116 +1694,50 @@ module Ssa { * The write to `i` on line 5 is live because of the call to `M2` on line 6, which * reaches the entry definition for `i` in `M2` on line 4. */ - predicate liveAfterWriteCapturedIn( - BasicBlock bb, int i, LocalScopeSourceVariable v, ImplicitEntryDefinition def, - ControlFlow::Nodes::ElementNode c, boolean additionalCalls + predicate capturedReadIn( + BasicBlock bb, int i, LocalScopeSourceVariable outer, LocalScopeSourceVariable inner, + ControlFlow::Nodes::ElementNode call, boolean additionalCalls ) { - exists(Callable reader, SourceVariable sv | - implicitReadCandidate(bb, i, v, c) and - readsCapturedVariable(c, v, reader, additionalCalls) and - sv = def.getSourceVariable() and - reader = sv.getEnclosingCallable() and - v.getAssignable() = sv.getAssignable() + exists(Callable reader | + implicitReadCandidate(outer, call) and + readsCapturedVariable(call, outer, reader, additionalCalls) and + reader = inner.getEnclosingCallable() and + outer.getAssignable() = inner.getAssignable() and + call = bb.getNode(i) ) } - - /** - * Holds if captured local scope variable `v` is live after the (certain or uncertain) - * write at index `i` inside basic block `bb`. - */ - predicate liveAfterWriteCaptured(BasicBlock bb, int i, LocalScopeSourceVariable v) { - liveAfterWriteCapturedOut(bb, i, v, _, _) or - liveAfterWriteCapturedIn(bb, i, v, _, _, _) - } } private import CapturedVariableLivenessImpl + /** + * Holds if the `i`th node `node` of basic block `bb` reads source variable `v`. + * The read at `node` is of kind `rk`. + * + * This includes implicit reads via calls. + */ + private predicate variableRead( + BasicBlock bb, int i, SourceVariable v, ControlFlow::Node node, ReadKind rk + ) { + variableReadDirect(bb, i, v, node, rk) + or + capturedReadOut(bb, i, v, node, _, _, _) and + rk = CapturedVarExitRead() + or + capturedReadIn(bb, i, v, _, node, _) and + rk = CapturedVarCallRead() + } + cached private module SsaImpl { cached predicate forceCachingInSameStage() { any() } - /** - * A data type representing SSA definitions. - * - * We distinguish six kinds of SSA definitions: - * - * 1. Explicit definitions wrapping an `AssignableDefinition` node in the CFG. - * 2. Implicit initializations of variables at the entry point of a callable - * (captured variables and relevant fields or properties), represented by - * the callable entry point in the CFG. - * 3. Implicit indirect definitions of variables through calls (fields, - * properties, or captured variables). - * 4. Implicit indirect definitions of variables through qualifier definitions - * (fields or properties). - * 5. Phi nodes. - * - * SSA definitions are only introduced where necessary. That is, dead assignments - * have no associated SSA definitions. - */ cached newtype TDefinition = - TSsaExplicitDef(SourceVariable v, AssignableDefinition def, BasicBlock bb, int i) { - variableDefinition(bb, i, v, def) and - ( - exists(ReadKind rk | liveAfterWrite(bb, i, v, rk) | - // A `ref` assignment such as - // ```csharp - // ref int i = ref GetRef(); - // ``` - // is dead when there are no reads of or writes to `i`. - // That is, the read kind `rk` witnessing the liveness of the assignment - // must not be the pseudo read inserted at the end of the enclosing callable - not ( - rk = OutRefExitRead() and - def.(AssignableDefinitions::AssignmentDefinition).getSource() instanceof RefExpr - ) and - rk != CapturedVarExitRead() // Captured variables are handled below - ) - or - liveAfterWriteCaptured(bb, i, v) - ) - } or - TSsaImplicitEntryDef(SourceVariable v, ControlFlow::BasicBlocks::EntryBlock ebb) { - liveAtEntry(ebb, v, _) and - exists(Callable c | - c = ebb.getCallable() and - c = v.getEnclosingCallable() - | - // Captured variable - exists(LocalScopeVariable lsv | - v = any(LocalScopeSourceVariable lv | lsv = lv.getAssignable()) - | - lsv.getCallable() != c - ) - or - // Each tracked field and property has an implicit entry definition - v instanceof FieldOrPropSourceVariable - ) - } or - TSsaImplicitCallDef(SourceVariable v, Call c, BasicBlock bb, int i) { - bb.getNode(i) = c.getAControlFlowNode() and - ( - // Liveness of `v` after `c` is guaranteed by `updatesNamedFieldOrProp` - updatesNamedFieldOrProp(c, v, _) - or - // Liveness of `v` after `c` is guaranteed by `updatesCapturedVariable` - updatesCapturedVariable(c, v, _, _) - ) - } or - TSsaImplicitQualifierDef(SourceVariable v, Definition qdef) { - exists(BasicBlock bb, int i | - qdef.getSourceVariable() = v.getQualifier() and - qdef.definesAt(bb, i) and - liveAfterWriteQualified(bb, i, v) and - // Eliminate corner case where a call definition can overlap with a - // qualifier definition: if method `M` updates field `F`, then a call - // to `M` is both an update of `x.M` and `x.M.M`, so the former call - // definition should not give rise to an implicit qualifier definition - // for `x.M.M`. - not exists(TSsaImplicitCallDef(v, _, bb, i)) - ) + TWriteDef(SourceVariable v, BasicBlock bb, int i) { + variableWrite(bb, i, v, _) and + liveAfterWrite(bb, i, v, _) } or TPhiNode(SourceVariable v, ControlFlow::BasicBlocks::JoinBlock bb) { phiNodeMaybeLive(bb, v) and @@ -1780,48 +1746,20 @@ module Ssa { pragma[noinline] private predicate phiNodeMaybeLive(ControlFlow::BasicBlocks::JoinBlock bb, SourceVariable v) { - exists(Definition def, BasicBlock bb1 | definesAt(def, bb1, _, v) | + exists(Definition def, BasicBlock bb1 | def.definesAt(v, bb1, _) | bb1.inDominanceFrontier(bb) ) } - /** - * Holds if the SSA definition `def` defines source variable `v` at index `i` - * in basic block `bb`. Phi nodes and entry nodes (captured variables and - * fields/properties) are considered to be at index `-1`, while normal variable - * updates are at the index of the control flow node they wrap. - */ - cached - predicate definesAt(Definition def, BasicBlock bb, int i, SourceVariable v) { - def = TSsaExplicitDef(v, _, bb, i) - or - def = TSsaImplicitEntryDef(v, bb) and i = -1 - or - def = TSsaImplicitCallDef(v, _, bb, i) - or - exists(Definition qdef | def = TSsaImplicitQualifierDef(v, qdef) | definesAt(qdef, bb, i, _)) - or - def = TPhiNode(v, bb) and i = -1 - } - cached predicate isCapturedVariableDefinitionFlowIn( ExplicitDefinition def, ImplicitEntryDefinition edef, ControlFlow::Nodes::ElementNode c, boolean additionalCalls ) { - exists(BasicBlock bb, int i, LocalScopeSourceVariable v | definesAt(def, bb, i, v) | - liveAfterWriteCapturedIn(bb, i, v, edef, c, additionalCalls) - ) - } - - /** - * Holds if the SSA definition `def` assigns to captured local scope variable `v`, - * and the variable may remain unchanged throughout the rest of the enclosing - * callable. - */ - private predicate isLiveCapturedVariableDefinition(ExplicitDefinition def) { - exists(Definition def0 | def = def0.getAnUltimateDefinition() | - ssaDefReachesRead(_, def0, _, CapturedVarExitRead()) + exists(Definition def0 | + capturedReadIn(_, _, def.getSourceVariable(), edef.getSourceVariable(), c, additionalCalls) and + def = def0.getAnUltimateDefinition() and + ssaDefReachesRead(_, def0, c, CapturedVarCallRead()) ) } @@ -1829,9 +1767,19 @@ module Ssa { predicate isCapturedVariableDefinitionFlowOut( ExplicitDefinition def, ImplicitCallDefinition cdef, boolean additionalCalls ) { - exists(BasicBlock bb, int i, LocalScopeSourceVariable v | definesAt(def, bb, i, v) | - liveAfterWriteCapturedOut(bb, i, v, cdef, additionalCalls) and - isLiveCapturedVariableDefinition(def) + exists(Definition def0, BasicBlock bb, int i | + def = def0.getAnUltimateDefinition() and + lastRef(def0, bb, i) and + capturedReadOut(bb, i, def0.getSourceVariable(), _, cdef.getSourceVariable(), + cdef.getCall(), additionalCalls) + ) + } + + cached + predicate explicitDefinition(Definition def, SourceVariable v, AssignableDefinition ad) { + exists(BasicBlock bb, int i | + def = TWriteDef(v, bb, i) and + variableDefinition(bb, i, v, ad) ) } } @@ -1840,7 +1788,7 @@ module Ssa { private string getSplitString(Definition def) { exists(BasicBlock bb, int i, ControlFlow::Node cfn | - definesAt(def, bb, i, _) and + def.definesAt(_, bb, i) and result = cfn.(ControlFlow::Nodes::ElementNode).getSplitsString() | cfn = bb.getNode(i) @@ -1864,7 +1812,7 @@ module Ssa { */ class Definition extends TDefinition { /** Gets the source variable underlying this SSA definition. */ - SourceVariable getSourceVariable() { definesAt(this, _, _, result) } + SourceVariable getSourceVariable() { this.definesAt(result, _, _) } /** * Gets a read of the source variable underlying this SSA definition that @@ -1923,7 +1871,7 @@ module Ssa { * node between lines 9 and 10. */ AssignableRead getAReadAtNode(ControlFlow::Node cfn) { - ssaDefReachesRead(_, this, cfn, _) and + ssaDefReachesRead(_, this, cfn, ActualRead()) and result.getAControlFlowNode() = cfn } @@ -2061,7 +2009,7 @@ module Ssa { * between lines 9 and 10. */ AssignableRead getALastReadAtNode(ControlFlow::Node cfn) { - lastRead(this, cfn) and + lastReadSameVar(this, cfn) and result.getAControlFlowNode() = cfn } @@ -2116,15 +2064,24 @@ module Ssa { predicate isLiveAtEndOfBlock(BasicBlock bb) { ssaDefReachesEndOfBlock(bb, this, _) } /** - * Holds if this SSA definition is at index `i` in basic block `bb`. Phi nodes and - * entry nodes (captured variables and fields/properties) are considered to be at - * index `-1`, while normal variable updates are at the index of the control flow - * node they wrap. + * DEPRECATED: Use `definesAt/3` instead. */ - predicate definesAt(BasicBlock bb, int i) { definesAt(this, bb, i, _) } + deprecated predicate definesAt(BasicBlock bb, int i) { this.definesAt(_, bb, i) } + + /** + * Holds if this SSA definition defines `v` at index `i` in basic block `bb`. + * Phi nodes and entry nodes (captured variables and fields/properties) are + * considered to be at index `-1`, while normal variable updates are at the + * index of the control flow node they wrap. + */ + predicate definesAt(SourceVariable v, BasicBlock bb, int i) { + this = TWriteDef(v, bb, i) + or + this = TPhiNode(v, bb) and i = -1 + } /** Gets the basic block to which this SSA definition belongs. */ - BasicBlock getBasicBlock() { this.definesAt(result, _) } + BasicBlock getBasicBlock() { this.definesAt(_, result, _) } /** * Gets the control flow node of this SSA definition, if any. Phi nodes are examples @@ -2132,7 +2089,7 @@ module Ssa { * `-1` in the relevant basic block. */ ControlFlow::Node getControlFlowNode() { - exists(BasicBlock bb, int i | this.definesAt(bb, i) | result = bb.getNode(i)) + exists(BasicBlock bb, int i | this.definesAt(_, bb, i) | result = bb.getNode(i)) } /** @@ -2150,11 +2107,12 @@ module Ssa { * parameter may remain unchanged throughout the rest of the enclosing callable. */ predicate isLiveOutRefParameterDefinition(Parameter p) { - exists(Definition def, ControlFlow::Node read, SourceVariable v | - this = def.getAnUltimateDefinition() - | - ssaDefReachesRead(v, def, read, OutRefExitRead()) and - v.getAssignable() = p + p.isOutOrRef() and + exists(Definition def, BasicBlock bb, int i | + this = def.getAnUltimateDefinition() and + lastRef(def, bb, i) and + variableRead(bb, i, def.getSourceVariable(), _, OutRefExitRead()) and + p = def.getSourceVariable().getAssignable() ) } @@ -2168,11 +2126,11 @@ module Ssa { /** * An SSA definition that corresponds to an explicit assignable definition. */ - class ExplicitDefinition extends Definition, TSsaExplicitDef { + class ExplicitDefinition extends Definition, TWriteDef { SourceVariable sv; AssignableDefinition ad; - ExplicitDefinition() { this = TSsaExplicitDef(sv, ad, _, _) } + ExplicitDefinition() { explicitDefinition(this, sv, ad) } /** * Gets an underlying assignable definition. The result is always unique, @@ -2255,9 +2213,16 @@ module Ssa { */ class ImplicitDefinition extends Definition { ImplicitDefinition() { - this = TSsaImplicitEntryDef(_, _) or - this = TSsaImplicitCallDef(_, _, _, _) or - this = TSsaImplicitQualifierDef(_, _) + exists(BasicBlock bb, SourceVariable v, int i | this = TWriteDef(v, bb, i) | + implicitEntryDefinition(bb, v) and + i = -1 + or + updatesNamedFieldOrProp(bb, i, _, v, _) + or + updatesCapturedVariable(bb, i, _, v, _, _) + or + variableWriteQualifier(bb, i, v, _) + ) } } @@ -2266,12 +2231,19 @@ module Ssa { * at the beginning of a callable. Either the variable is a local scope variable * captured by the callable, or a field or property accessed inside the callable. */ - class ImplicitEntryDefinition extends ImplicitDefinition, TSsaImplicitEntryDef { + class ImplicitEntryDefinition extends ImplicitDefinition, TWriteDef { + ImplicitEntryDefinition() { + exists(BasicBlock bb, SourceVariable v | + this = TWriteDef(v, bb, -1) and + implicitEntryDefinition(bb, v) + ) + } + /** Gets the callable that this entry definition belongs to. */ Callable getCallable() { - exists(ControlFlow::BasicBlocks::EntryBlock ebb | - this = TSsaImplicitEntryDef(_, ebb) and - result = ebb.getCallable() + exists(BasicBlock bb | + this = TWriteDef(_, bb, _) and + result = bb.getCallable() ) } @@ -2290,8 +2262,18 @@ module Ssa { * An SSA definition representing the potential definition of a variable * via a call. */ - class ImplicitCallDefinition extends ImplicitDefinition, TSsaImplicitCallDef { - Call getCall() { this = TSsaImplicitCallDef(_, result, _, _) } + class ImplicitCallDefinition extends ImplicitDefinition, TWriteDef { + private Call c; + + ImplicitCallDefinition() { + exists(BasicBlock bb, SourceVariable v, int i | this = TWriteDef(v, bb, i) | + updatesNamedFieldOrProp(bb, i, c, v, _) + or + updatesCapturedVariable(bb, i, c, v, _, _) + ) + } + + Call getCall() { result = c } /** * Gets one of the definitions that may contribute to this implicit @@ -2300,12 +2282,12 @@ module Ssa { * and which targets the same assignable as this SSA definition. */ AssignableDefinition getAPossibleDefinition() { - exists(Callable setter | updatesNamedFieldOrProp(getCall(), _, setter) | + exists(Callable setter | updatesNamedFieldOrProp(_, _, getCall(), _, setter) | result.getEnclosingCallable() = setter and result.getTarget() = this.getSourceVariable().getAssignable() ) or - updatesCapturedVariable(getCall(), _, result, _) and + updatesCapturedVariable(_, _, getCall(), _, result, _) and result.getTarget() = this.getSourceVariable().getAssignable() } @@ -2320,9 +2302,20 @@ module Ssa { * An SSA definition representing the potential definition of a variable * via an SSA definition for the qualifier. */ - class ImplicitQualifierDefinition extends ImplicitDefinition, TSsaImplicitQualifierDef { + class ImplicitQualifierDefinition extends ImplicitDefinition, TWriteDef { + private Definition q; + + ImplicitQualifierDefinition() { + exists(BasicBlock bb, int i, QualifiedFieldOrPropSourceVariable v | + this = TWriteDef(v, bb, i) + | + variableWriteQualifier(bb, i, v, _) and + q.definesAt(v.getQualifier(), bb, i) + ) + } + /** Gets the SSA definition for the qualifier. */ - Definition getQualifierDefinition() { this = TSsaImplicitQualifierDef(_, result) } + Definition getQualifierDefinition() { result = q } override string toString() { result = getToStringPrefix(this) + "SSA qualifier def(" + getSourceVariable() + ")" @@ -2376,7 +2369,7 @@ module Ssa { */ override Definition getAnInput() { exists(BasicBlock bb, BasicBlock phiPred, SourceVariable v | - definesAt(this, bb, _, v) and + this.definesAt(v, bb, _) and bb.getAPredecessor() = phiPred and ssaDefReachesEndOfBlock(phiPred, result, v) ) diff --git a/csharp/ql/test/library-tests/dataflow/defuse/useUseEquivalence.ql b/csharp/ql/test/library-tests/dataflow/defuse/useUseEquivalence.ql index b7997b85384..4dbc77e922e 100644 --- a/csharp/ql/test/library-tests/dataflow/defuse/useUseEquivalence.ql +++ b/csharp/ql/test/library-tests/dataflow/defuse/useUseEquivalence.ql @@ -34,7 +34,7 @@ private TLocalScopeVariableReadOrSsaDef getANextReadOrDef(TLocalScopeVariableRea ssaDef.getARead() = read | pseudoDef.getAnInput() = ssaDef and - pseudoDef.definesAt(bb, i) and + pseudoDef.definesAt(_, bb, i) and cfn = read.getAReachableElement().getAControlFlowNode() and ( cfn = bb.getNode(i) diff --git a/csharp/ql/test/library-tests/dataflow/ssa/Capture.cs b/csharp/ql/test/library-tests/dataflow/ssa/Capture.cs index d11947afed6..a74d480668d 100644 --- a/csharp/ql/test/library-tests/dataflow/ssa/Capture.cs +++ b/csharp/ql/test/library-tests/dataflow/ssa/Capture.cs @@ -99,7 +99,7 @@ class Capture return x; }); - var z = 12; // Should *not* get an SSA definition + var z = 12; // Should *not* get an SSA definition, but currently does because it is considered live via the lambda fn(() => { z = 0; @@ -119,7 +119,7 @@ class Capture }; M1(); - var b = 12; // Should *not* get an SSA definition + var b = 12; // Should *not* get an SSA definition, but currently does because it is considered live via the lambda void M2() { b = 0; @@ -155,7 +155,7 @@ class Capture Use(f); void M6() { - f = 0; // Should *not* get an SSA definition (`f` is not read after `M6` is called) + f = 0; // Should *not* get an SSA definition (`f` is not read after `M6` is called), but currently does because it is considered live via the call to `M6` } M6(); diff --git a/csharp/ql/test/library-tests/dataflow/ssa/PreSsaConsistency.ql b/csharp/ql/test/library-tests/dataflow/ssa/PreSsaConsistency.ql index b740f89e91b..ab31244d07b 100644 --- a/csharp/ql/test/library-tests/dataflow/ssa/PreSsaConsistency.ql +++ b/csharp/ql/test/library-tests/dataflow/ssa/PreSsaConsistency.ql @@ -77,7 +77,7 @@ query predicate phiInconsistency( edef = phi.getAnUltimateDefinition() | edef.getADefinition() = adef and - phi.definesAt(bb, _) and + phi.definesAt(_, bb, _) and cfe = bb.getFirstNode().getElement() ) ) @@ -88,7 +88,7 @@ query predicate phiInconsistency( | edef = phi.getAnUltimateDefinition() and edef.getADefinition() = adef and - phi.definesAt(bb, _) and + phi.definesAt(_, bb, _) and cfe = bb.getFirstNode().getElement() and not exists(PreSsa::Definition def | adef = def.getAPhiInput+().getDefinition() and diff --git a/csharp/ql/test/library-tests/dataflow/ssa/SsaDef.expected b/csharp/ql/test/library-tests/dataflow/ssa/SsaDef.expected index 8d5a2db71ab..bf944248e67 100644 --- a/csharp/ql/test/library-tests/dataflow/ssa/SsaDef.expected +++ b/csharp/ql/test/library-tests/dataflow/ssa/SsaDef.expected @@ -49,10 +49,12 @@ | Capture.cs:94:13:94:13 | y | Capture.cs:94:13:94:18 | SSA def(y) | | Capture.cs:94:13:94:13 | y | Capture.cs:96:12:100:9 | SSA capture def(y) | | Capture.cs:98:17:98:17 | x | Capture.cs:98:17:98:21 | SSA def(x) | +| Capture.cs:102:13:102:13 | z | Capture.cs:102:13:102:18 | SSA def(z) | | Capture.cs:102:13:102:13 | z | Capture.cs:105:13:105:17 | SSA def(z) | | Capture.cs:114:13:114:13 | a | Capture.cs:114:13:114:18 | SSA def(a) | | Capture.cs:114:13:114:13 | a | Capture.cs:115:9:119:9 | SSA capture def(a) | | Capture.cs:117:17:117:17 | x | Capture.cs:117:17:117:21 | SSA def(x) | +| Capture.cs:122:13:122:13 | b | Capture.cs:122:13:122:18 | SSA def(b) | | Capture.cs:122:13:122:13 | b | Capture.cs:125:13:125:17 | SSA def(b) | | Capture.cs:130:13:130:13 | c | Capture.cs:130:13:130:18 | SSA def(c) | | Capture.cs:130:13:130:13 | c | Capture.cs:133:13:133:17 | SSA def(c) | @@ -62,6 +64,7 @@ | Capture.cs:139:13:139:13 | d | Capture.cs:144:9:144:12 | SSA call def(d) | | Capture.cs:147:13:147:13 | e | Capture.cs:148:9:152:9 | SSA capture def(e) | | Capture.cs:154:13:154:13 | f | Capture.cs:154:13:154:18 | SSA def(f) | +| Capture.cs:154:13:154:13 | f | Capture.cs:158:13:158:17 | SSA def(f) | | Capture.cs:162:13:162:13 | g | Capture.cs:163:9:166:9 | SSA capture def(g) | | Capture.cs:168:13:168:13 | h | Capture.cs:171:13:171:17 | SSA def(h) | | Capture.cs:168:13:168:13 | h | Capture.cs:174:17:174:21 | SSA def(h) | @@ -218,9 +221,9 @@ | Fields.cs:107:33:107:33 | f | Fields.cs:107:33:107:33 | SSA param(f) | | Fields.cs:115:20:115:29 | this.Field | Fields.cs:109:10:109:10 | SSA entry def(this.Field) | | Fields.cs:115:20:115:29 | this.Field | Fields.cs:114:9:114:22 | SSA call def(this.Field) | -| Fields.cs:115:20:115:35 | this.Field.Field | Fields.cs:109:10:109:10 | SSA entry def(this.Field.Field) | +| Fields.cs:115:20:115:35 | this.Field.Field | Fields.cs:109:10:109:10 | SSA qualifier def(this.Field.Field) | | Fields.cs:115:20:115:35 | this.Field.Field | Fields.cs:114:9:114:22 | SSA call def(this.Field.Field) | -| Fields.cs:116:21:116:39 | this.Field.Field.xs | Fields.cs:109:10:109:10 | SSA entry def(this.Field.Field.xs) | +| Fields.cs:116:21:116:39 | this.Field.Field.xs | Fields.cs:109:10:109:10 | SSA qualifier def(this.Field.Field.xs) | | Fields.cs:116:21:116:39 | this.Field.Field.xs | Fields.cs:114:9:114:22 | SSA qualifier def(this.Field.Field.xs) | | OutRef.cs:9:13:9:13 | j | OutRef.cs:9:13:9:17 | SSA def(j) | | OutRef.cs:9:13:9:13 | j | OutRef.cs:10:32:10:32 | SSA def(j) | @@ -299,9 +302,9 @@ | Properties.cs:106:37:106:37 | p | Properties.cs:106:37:106:37 | SSA param(p) | | Properties.cs:114:20:114:29 | this.Props | Properties.cs:108:10:108:10 | SSA entry def(this.Props) | | Properties.cs:114:20:114:29 | this.Props | Properties.cs:113:9:113:22 | SSA call def(this.Props) | -| Properties.cs:114:20:114:35 | this.Props.Props | Properties.cs:108:10:108:10 | SSA entry def(this.Props.Props) | +| Properties.cs:114:20:114:35 | this.Props.Props | Properties.cs:108:10:108:10 | SSA qualifier def(this.Props.Props) | | Properties.cs:114:20:114:35 | this.Props.Props | Properties.cs:113:9:113:22 | SSA call def(this.Props.Props) | -| Properties.cs:115:21:115:39 | this.Props.Props.xs | Properties.cs:108:10:108:10 | SSA entry def(this.Props.Props.xs) | +| Properties.cs:115:21:115:39 | this.Props.Props.xs | Properties.cs:108:10:108:10 | SSA qualifier def(this.Props.Props.xs) | | Properties.cs:115:21:115:39 | this.Props.Props.xs | Properties.cs:113:9:113:22 | SSA qualifier def(this.Props.Props.xs) | | Splitting.cs:3:18:3:18 | b | Splitting.cs:3:18:3:18 | SSA param(b) | | Splitting.cs:5:13:5:13 | x | Splitting.cs:7:13:7:19 | [b (line 3): true] SSA def(x) | diff --git a/csharp/ql/test/library-tests/dataflow/ssa/SsaDefElement.expected b/csharp/ql/test/library-tests/dataflow/ssa/SsaDefElement.expected index a5971b9070d..a259546f403 100644 --- a/csharp/ql/test/library-tests/dataflow/ssa/SsaDefElement.expected +++ b/csharp/ql/test/library-tests/dataflow/ssa/SsaDefElement.expected @@ -49,10 +49,12 @@ | Capture.cs:94:13:94:18 | SSA def(y) | Capture.cs:94:13:94:18 | Int32 y = ... | | Capture.cs:96:12:100:9 | SSA capture def(y) | Capture.cs:96:12:100:9 | (...) => ... | | Capture.cs:98:17:98:21 | SSA def(x) | Capture.cs:98:17:98:21 | Int32 x = ... | +| Capture.cs:102:13:102:18 | SSA def(z) | Capture.cs:102:13:102:18 | Int32 z = ... | | Capture.cs:105:13:105:17 | SSA def(z) | Capture.cs:105:13:105:17 | ... = ... | | Capture.cs:114:13:114:18 | SSA def(a) | Capture.cs:114:13:114:18 | Int32 a = ... | | Capture.cs:115:9:119:9 | SSA capture def(a) | Capture.cs:115:9:119:9 | M1 | | Capture.cs:117:17:117:21 | SSA def(x) | Capture.cs:117:17:117:21 | Int32 x = ... | +| Capture.cs:122:13:122:18 | SSA def(b) | Capture.cs:122:13:122:18 | Int32 b = ... | | Capture.cs:125:13:125:17 | SSA def(b) | Capture.cs:125:13:125:17 | ... = ... | | Capture.cs:130:13:130:18 | SSA def(c) | Capture.cs:130:13:130:18 | Int32 c = ... | | Capture.cs:133:13:133:17 | SSA def(c) | Capture.cs:133:13:133:17 | ... = ... | @@ -62,6 +64,7 @@ | Capture.cs:144:9:144:12 | SSA call def(d) | Capture.cs:144:9:144:12 | call to local function M4 | | Capture.cs:148:9:152:9 | SSA capture def(e) | Capture.cs:148:9:152:9 | M5 | | Capture.cs:154:13:154:18 | SSA def(f) | Capture.cs:154:13:154:18 | Int32 f = ... | +| Capture.cs:158:13:158:17 | SSA def(f) | Capture.cs:158:13:158:17 | ... = ... | | Capture.cs:163:9:166:9 | SSA capture def(g) | Capture.cs:163:9:166:9 | M7 | | Capture.cs:171:13:171:17 | SSA def(h) | Capture.cs:171:13:171:17 | ... = ... | | Capture.cs:174:17:174:21 | SSA def(h) | Capture.cs:174:17:174:21 | ... = ... | @@ -206,8 +209,6 @@ | Fields.cs:102:9:102:28 | SSA def(this.Field) | Fields.cs:102:9:102:28 | ... = ... | | Fields.cs:107:33:107:33 | SSA param(f) | Fields.cs:107:33:107:33 | f | | Fields.cs:109:10:109:10 | SSA entry def(this.Field) | Fields.cs:109:10:109:10 | K | -| Fields.cs:109:10:109:10 | SSA entry def(this.Field.Field) | Fields.cs:109:10:109:10 | K | -| Fields.cs:109:10:109:10 | SSA entry def(this.Field.Field.xs) | Fields.cs:109:10:109:10 | K | | Fields.cs:114:9:114:22 | SSA call def(this.Field) | Fields.cs:114:9:114:22 | call to method SetField | | Fields.cs:114:9:114:22 | SSA call def(this.Field.Field) | Fields.cs:114:9:114:22 | call to method SetField | | Fields.cs:114:9:114:22 | SSA qualifier def(this.Field.Field.xs) | Fields.cs:114:9:114:22 | call to method SetField | @@ -281,8 +282,6 @@ | Properties.cs:85:24:85:46 | SSA capture def(b) | Properties.cs:85:24:85:46 | (...) => ... | | Properties.cs:106:37:106:37 | SSA param(p) | Properties.cs:106:37:106:37 | p | | Properties.cs:108:10:108:10 | SSA entry def(this.Props) | Properties.cs:108:10:108:10 | K | -| Properties.cs:108:10:108:10 | SSA entry def(this.Props.Props) | Properties.cs:108:10:108:10 | K | -| Properties.cs:108:10:108:10 | SSA entry def(this.Props.Props.xs) | Properties.cs:108:10:108:10 | K | | Properties.cs:113:9:113:22 | SSA call def(this.Props) | Properties.cs:113:9:113:22 | call to method SetProps | | Properties.cs:113:9:113:22 | SSA call def(this.Props.Props) | Properties.cs:113:9:113:22 | call to method SetProps | | Properties.cs:113:9:113:22 | SSA qualifier def(this.Props.Props.xs) | Properties.cs:113:9:113:22 | call to method SetProps | diff --git a/csharp/ql/test/library-tests/dataflow/ssa/SsaExplicitDef.expected b/csharp/ql/test/library-tests/dataflow/ssa/SsaExplicitDef.expected index 6f5c8a4238b..45f023ec4ef 100644 --- a/csharp/ql/test/library-tests/dataflow/ssa/SsaExplicitDef.expected +++ b/csharp/ql/test/library-tests/dataflow/ssa/SsaExplicitDef.expected @@ -33,15 +33,18 @@ | Capture.cs:92:18:92:18 | d | Capture.cs:92:18:92:18 | SSA param(d) | Capture.cs:92:18:92:18 | d | | Capture.cs:94:13:94:13 | y | Capture.cs:94:13:94:18 | SSA def(y) | Capture.cs:94:13:94:18 | Int32 y = ... | | Capture.cs:98:17:98:17 | x | Capture.cs:98:17:98:21 | SSA def(x) | Capture.cs:98:17:98:21 | Int32 x = ... | +| Capture.cs:102:13:102:13 | z | Capture.cs:102:13:102:18 | SSA def(z) | Capture.cs:102:13:102:18 | Int32 z = ... | | Capture.cs:102:13:102:13 | z | Capture.cs:105:13:105:17 | SSA def(z) | Capture.cs:105:13:105:17 | ... = ... | | Capture.cs:114:13:114:13 | a | Capture.cs:114:13:114:18 | SSA def(a) | Capture.cs:114:13:114:18 | Int32 a = ... | | Capture.cs:117:17:117:17 | x | Capture.cs:117:17:117:21 | SSA def(x) | Capture.cs:117:17:117:21 | Int32 x = ... | +| Capture.cs:122:13:122:13 | b | Capture.cs:122:13:122:18 | SSA def(b) | Capture.cs:122:13:122:18 | Int32 b = ... | | Capture.cs:122:13:122:13 | b | Capture.cs:125:13:125:17 | SSA def(b) | Capture.cs:125:13:125:17 | ... = ... | | Capture.cs:130:13:130:13 | c | Capture.cs:130:13:130:18 | SSA def(c) | Capture.cs:130:13:130:18 | Int32 c = ... | | Capture.cs:130:13:130:13 | c | Capture.cs:133:13:133:17 | SSA def(c) | Capture.cs:133:13:133:17 | ... = ... | | Capture.cs:139:13:139:13 | d | Capture.cs:139:13:139:18 | SSA def(d) | Capture.cs:139:13:139:18 | Int32 d = ... | | Capture.cs:139:13:139:13 | d | Capture.cs:142:13:142:17 | SSA def(d) | Capture.cs:142:13:142:17 | ... = ... | | Capture.cs:154:13:154:13 | f | Capture.cs:154:13:154:18 | SSA def(f) | Capture.cs:154:13:154:18 | Int32 f = ... | +| Capture.cs:154:13:154:13 | f | Capture.cs:158:13:158:17 | SSA def(f) | Capture.cs:158:13:158:17 | ... = ... | | Capture.cs:168:13:168:13 | h | Capture.cs:171:13:171:17 | SSA def(h) | Capture.cs:171:13:171:17 | ... = ... | | Capture.cs:168:13:168:13 | h | Capture.cs:174:17:174:21 | SSA def(h) | Capture.cs:174:17:174:21 | ... = ... | | Capture.cs:182:17:182:17 | i | Capture.cs:182:17:182:21 | SSA def(i) | Capture.cs:182:17:182:21 | Int32 i = ... | diff --git a/csharp/ql/test/library-tests/dataflow/ssa/SsaImplicitQualifier.expected b/csharp/ql/test/library-tests/dataflow/ssa/SsaImplicitQualifier.expected index 2b3febca122..c64c419cb48 100644 --- a/csharp/ql/test/library-tests/dataflow/ssa/SsaImplicitQualifier.expected +++ b/csharp/ql/test/library-tests/dataflow/ssa/SsaImplicitQualifier.expected @@ -4,8 +4,12 @@ | Fields.cs:98:20:98:32 | f.Field.Field | Fields.cs:97:9:97:30 | SSA qualifier def(f.Field.Field) | Fields.cs:97:9:97:30 | SSA def(f.Field) | | Fields.cs:99:16:99:34 | f.Field.Field.Field | Fields.cs:97:9:97:30 | SSA qualifier def(f.Field.Field.Field) | Fields.cs:97:9:97:30 | SSA qualifier def(f.Field.Field) | | Fields.cs:100:16:100:40 | f.Field.Field.Field.Field | Fields.cs:97:9:97:30 | SSA qualifier def(f.Field.Field.Field.Field) | Fields.cs:97:9:97:30 | SSA qualifier def(f.Field.Field.Field) | +| Fields.cs:115:20:115:35 | this.Field.Field | Fields.cs:109:10:109:10 | SSA qualifier def(this.Field.Field) | Fields.cs:109:10:109:10 | SSA entry def(this.Field) | +| Fields.cs:116:21:116:39 | this.Field.Field.xs | Fields.cs:109:10:109:10 | SSA qualifier def(this.Field.Field.xs) | Fields.cs:109:10:109:10 | SSA qualifier def(this.Field.Field) | | Fields.cs:116:21:116:39 | this.Field.Field.xs | Fields.cs:114:9:114:22 | SSA qualifier def(this.Field.Field.xs) | Fields.cs:114:9:114:22 | SSA call def(this.Field.Field) | | OutRef.cs:19:32:19:38 | t.Field | OutRef.cs:18:13:18:28 | SSA qualifier def(t.Field) | OutRef.cs:18:13:18:28 | SSA def(t) | | Properties.cs:31:19:31:22 | f.xs | Properties.cs:30:13:30:32 | SSA qualifier def(f.xs) | Properties.cs:30:13:30:32 | SSA def(f) | | Properties.cs:31:19:31:22 | f.xs | Properties.cs:49:13:49:32 | SSA qualifier def(f.xs) | Properties.cs:49:13:49:32 | SSA def(f) | +| Properties.cs:114:20:114:35 | this.Props.Props | Properties.cs:108:10:108:10 | SSA qualifier def(this.Props.Props) | Properties.cs:108:10:108:10 | SSA entry def(this.Props) | +| Properties.cs:115:21:115:39 | this.Props.Props.xs | Properties.cs:108:10:108:10 | SSA qualifier def(this.Props.Props.xs) | Properties.cs:108:10:108:10 | SSA qualifier def(this.Props.Props) | | Properties.cs:115:21:115:39 | this.Props.Props.xs | Properties.cs:113:9:113:22 | SSA qualifier def(this.Props.Props.xs) | Properties.cs:113:9:113:22 | SSA call def(this.Props.Props) | diff --git a/csharp/ql/test/library-tests/dataflow/ssa/SsaUltimateDef.expected b/csharp/ql/test/library-tests/dataflow/ssa/SsaUltimateDef.expected index 2d9f6d5e58d..f3bb6f1461d 100644 --- a/csharp/ql/test/library-tests/dataflow/ssa/SsaUltimateDef.expected +++ b/csharp/ql/test/library-tests/dataflow/ssa/SsaUltimateDef.expected @@ -56,10 +56,12 @@ | Capture.cs:94:13:94:13 | y | Capture.cs:94:13:94:18 | SSA def(y) | Capture.cs:94:13:94:18 | SSA def(y) | | Capture.cs:94:13:94:13 | y | Capture.cs:96:12:100:9 | SSA capture def(y) | Capture.cs:96:12:100:9 | SSA capture def(y) | | Capture.cs:98:17:98:17 | x | Capture.cs:98:17:98:21 | SSA def(x) | Capture.cs:98:17:98:21 | SSA def(x) | +| Capture.cs:102:13:102:13 | z | Capture.cs:102:13:102:18 | SSA def(z) | Capture.cs:102:13:102:18 | SSA def(z) | | Capture.cs:102:13:102:13 | z | Capture.cs:105:13:105:17 | SSA def(z) | Capture.cs:105:13:105:17 | SSA def(z) | | Capture.cs:114:13:114:13 | a | Capture.cs:114:13:114:18 | SSA def(a) | Capture.cs:114:13:114:18 | SSA def(a) | | Capture.cs:114:13:114:13 | a | Capture.cs:115:9:119:9 | SSA capture def(a) | Capture.cs:115:9:119:9 | SSA capture def(a) | | Capture.cs:117:17:117:17 | x | Capture.cs:117:17:117:21 | SSA def(x) | Capture.cs:117:17:117:21 | SSA def(x) | +| Capture.cs:122:13:122:13 | b | Capture.cs:122:13:122:18 | SSA def(b) | Capture.cs:122:13:122:18 | SSA def(b) | | Capture.cs:122:13:122:13 | b | Capture.cs:125:13:125:17 | SSA def(b) | Capture.cs:125:13:125:17 | SSA def(b) | | Capture.cs:130:13:130:13 | c | Capture.cs:130:13:130:18 | SSA def(c) | Capture.cs:130:13:130:18 | SSA def(c) | | Capture.cs:130:13:130:13 | c | Capture.cs:133:13:133:17 | SSA def(c) | Capture.cs:133:13:133:17 | SSA def(c) | @@ -71,6 +73,7 @@ | Capture.cs:139:13:139:13 | d | Capture.cs:144:9:144:12 | SSA call def(d) | Capture.cs:144:9:144:12 | SSA call def(d) | | Capture.cs:147:13:147:13 | e | Capture.cs:148:9:152:9 | SSA capture def(e) | Capture.cs:148:9:152:9 | SSA capture def(e) | | Capture.cs:154:13:154:13 | f | Capture.cs:154:13:154:18 | SSA def(f) | Capture.cs:154:13:154:18 | SSA def(f) | +| Capture.cs:154:13:154:13 | f | Capture.cs:158:13:158:17 | SSA def(f) | Capture.cs:158:13:158:17 | SSA def(f) | | Capture.cs:162:13:162:13 | g | Capture.cs:163:9:166:9 | SSA capture def(g) | Capture.cs:163:9:166:9 | SSA capture def(g) | | Capture.cs:168:13:168:13 | h | Capture.cs:171:13:171:17 | SSA def(h) | Capture.cs:171:13:171:17 | SSA def(h) | | Capture.cs:168:13:168:13 | h | Capture.cs:174:17:174:21 | SSA def(h) | Capture.cs:174:17:174:21 | SSA def(h) | @@ -275,11 +278,11 @@ | Fields.cs:115:20:115:29 | this.Field | Fields.cs:109:10:109:10 | SSA entry def(this.Field) | Fields.cs:109:10:109:10 | SSA entry def(this.Field) | | Fields.cs:115:20:115:29 | this.Field | Fields.cs:114:9:114:22 | SSA call def(this.Field) | Fields.cs:109:10:109:10 | SSA entry def(this.Field) | | Fields.cs:115:20:115:29 | this.Field | Fields.cs:114:9:114:22 | SSA call def(this.Field) | Fields.cs:114:9:114:22 | SSA call def(this.Field) | -| Fields.cs:115:20:115:35 | this.Field.Field | Fields.cs:109:10:109:10 | SSA entry def(this.Field.Field) | Fields.cs:109:10:109:10 | SSA entry def(this.Field.Field) | -| Fields.cs:115:20:115:35 | this.Field.Field | Fields.cs:114:9:114:22 | SSA call def(this.Field.Field) | Fields.cs:109:10:109:10 | SSA entry def(this.Field.Field) | +| Fields.cs:115:20:115:35 | this.Field.Field | Fields.cs:109:10:109:10 | SSA qualifier def(this.Field.Field) | Fields.cs:109:10:109:10 | SSA qualifier def(this.Field.Field) | +| Fields.cs:115:20:115:35 | this.Field.Field | Fields.cs:114:9:114:22 | SSA call def(this.Field.Field) | Fields.cs:109:10:109:10 | SSA qualifier def(this.Field.Field) | | Fields.cs:115:20:115:35 | this.Field.Field | Fields.cs:114:9:114:22 | SSA call def(this.Field.Field) | Fields.cs:114:9:114:22 | SSA call def(this.Field.Field) | -| Fields.cs:116:21:116:39 | this.Field.Field.xs | Fields.cs:109:10:109:10 | SSA entry def(this.Field.Field.xs) | Fields.cs:109:10:109:10 | SSA entry def(this.Field.Field.xs) | -| Fields.cs:116:21:116:39 | this.Field.Field.xs | Fields.cs:114:9:114:22 | SSA qualifier def(this.Field.Field.xs) | Fields.cs:109:10:109:10 | SSA entry def(this.Field.Field.xs) | +| Fields.cs:116:21:116:39 | this.Field.Field.xs | Fields.cs:109:10:109:10 | SSA qualifier def(this.Field.Field.xs) | Fields.cs:109:10:109:10 | SSA qualifier def(this.Field.Field.xs) | +| Fields.cs:116:21:116:39 | this.Field.Field.xs | Fields.cs:114:9:114:22 | SSA qualifier def(this.Field.Field.xs) | Fields.cs:109:10:109:10 | SSA qualifier def(this.Field.Field.xs) | | Fields.cs:116:21:116:39 | this.Field.Field.xs | Fields.cs:114:9:114:22 | SSA qualifier def(this.Field.Field.xs) | Fields.cs:114:9:114:22 | SSA qualifier def(this.Field.Field.xs) | | OutRef.cs:9:13:9:13 | j | OutRef.cs:9:13:9:17 | SSA def(j) | OutRef.cs:9:13:9:17 | SSA def(j) | | OutRef.cs:9:13:9:13 | j | OutRef.cs:10:32:10:32 | SSA def(j) | OutRef.cs:10:32:10:32 | SSA def(j) | @@ -396,11 +399,11 @@ | Properties.cs:114:20:114:29 | this.Props | Properties.cs:108:10:108:10 | SSA entry def(this.Props) | Properties.cs:108:10:108:10 | SSA entry def(this.Props) | | Properties.cs:114:20:114:29 | this.Props | Properties.cs:113:9:113:22 | SSA call def(this.Props) | Properties.cs:108:10:108:10 | SSA entry def(this.Props) | | Properties.cs:114:20:114:29 | this.Props | Properties.cs:113:9:113:22 | SSA call def(this.Props) | Properties.cs:113:9:113:22 | SSA call def(this.Props) | -| Properties.cs:114:20:114:35 | this.Props.Props | Properties.cs:108:10:108:10 | SSA entry def(this.Props.Props) | Properties.cs:108:10:108:10 | SSA entry def(this.Props.Props) | -| Properties.cs:114:20:114:35 | this.Props.Props | Properties.cs:113:9:113:22 | SSA call def(this.Props.Props) | Properties.cs:108:10:108:10 | SSA entry def(this.Props.Props) | +| Properties.cs:114:20:114:35 | this.Props.Props | Properties.cs:108:10:108:10 | SSA qualifier def(this.Props.Props) | Properties.cs:108:10:108:10 | SSA qualifier def(this.Props.Props) | +| Properties.cs:114:20:114:35 | this.Props.Props | Properties.cs:113:9:113:22 | SSA call def(this.Props.Props) | Properties.cs:108:10:108:10 | SSA qualifier def(this.Props.Props) | | Properties.cs:114:20:114:35 | this.Props.Props | Properties.cs:113:9:113:22 | SSA call def(this.Props.Props) | Properties.cs:113:9:113:22 | SSA call def(this.Props.Props) | -| Properties.cs:115:21:115:39 | this.Props.Props.xs | Properties.cs:108:10:108:10 | SSA entry def(this.Props.Props.xs) | Properties.cs:108:10:108:10 | SSA entry def(this.Props.Props.xs) | -| Properties.cs:115:21:115:39 | this.Props.Props.xs | Properties.cs:113:9:113:22 | SSA qualifier def(this.Props.Props.xs) | Properties.cs:108:10:108:10 | SSA entry def(this.Props.Props.xs) | +| Properties.cs:115:21:115:39 | this.Props.Props.xs | Properties.cs:108:10:108:10 | SSA qualifier def(this.Props.Props.xs) | Properties.cs:108:10:108:10 | SSA qualifier def(this.Props.Props.xs) | +| Properties.cs:115:21:115:39 | this.Props.Props.xs | Properties.cs:113:9:113:22 | SSA qualifier def(this.Props.Props.xs) | Properties.cs:108:10:108:10 | SSA qualifier def(this.Props.Props.xs) | | Properties.cs:115:21:115:39 | this.Props.Props.xs | Properties.cs:113:9:113:22 | SSA qualifier def(this.Props.Props.xs) | Properties.cs:113:9:113:22 | SSA qualifier def(this.Props.Props.xs) | | Splitting.cs:3:18:3:18 | b | Splitting.cs:3:18:3:18 | SSA param(b) | Splitting.cs:3:18:3:18 | SSA param(b) | | Splitting.cs:5:13:5:13 | x | Splitting.cs:7:13:7:19 | [b (line 3): true] SSA def(x) | Splitting.cs:7:13:7:19 | [b (line 3): true] SSA def(x) | diff --git a/csharp/ql/test/query-tests/Dead Code/DeadStoreOfLocal/DeadStoreOfLocal.cs b/csharp/ql/test/query-tests/Dead Code/DeadStoreOfLocal/DeadStoreOfLocal.cs index b787401f941..64f903f80ea 100644 --- a/csharp/ql/test/query-tests/Dead Code/DeadStoreOfLocal/DeadStoreOfLocal.cs +++ b/csharp/ql/test/query-tests/Dead Code/DeadStoreOfLocal/DeadStoreOfLocal.cs @@ -194,7 +194,7 @@ public class Captured void M2() { - var x = M6(); // BAD + var x = M6(); // BAD [FALSE NEGATIVE] Action a = () => { x = 1; // GOOD @@ -208,7 +208,7 @@ public class Captured int x; Action a = () => { - x = 1; // BAD + x = 1; // BAD [FALSE NEGATIVE] }; a(); } diff --git a/csharp/ql/test/query-tests/Dead Code/DeadStoreOfLocal/DeadStoreOfLocal.expected b/csharp/ql/test/query-tests/Dead Code/DeadStoreOfLocal/DeadStoreOfLocal.expected index 9720249c28d..9fe67ecf854 100644 --- a/csharp/ql/test/query-tests/Dead Code/DeadStoreOfLocal/DeadStoreOfLocal.expected +++ b/csharp/ql/test/query-tests/Dead Code/DeadStoreOfLocal/DeadStoreOfLocal.expected @@ -7,8 +7,6 @@ | DeadStoreOfLocal.cs:101:13:101:37 | ... = ... | This assignment to $@ is useless, since its value is never read. | DeadStoreOfLocal.cs:94:40:94:44 | extra | extra | | DeadStoreOfLocal.cs:104:13:104:37 | ... = ... | This assignment to $@ is useless, since its value is never read. | DeadStoreOfLocal.cs:94:16:94:20 | info1 | info1 | | DeadStoreOfLocal.cs:142:26:142:27 | Exception ex | This assignment to $@ is useless, since its value is never read. | DeadStoreOfLocal.cs:142:26:142:27 | ex | ex | -| DeadStoreOfLocal.cs:197:13:197:20 | Int32 x = ... | This assignment to $@ is useless, since its value is never read. | DeadStoreOfLocal.cs:197:13:197:13 | x | x | -| DeadStoreOfLocal.cs:211:13:211:17 | ... = ... | This assignment to $@ is useless, since its value is never read. | DeadStoreOfLocal.cs:208:13:208:13 | x | x | | DeadStoreOfLocal.cs:246:17:246:24 | Int32 y = ... | This assignment to $@ is useless, since its value is never read. | DeadStoreOfLocal.cs:246:17:246:17 | y | y | | DeadStoreOfLocal.cs:261:17:261:21 | Int32 x = ... | This assignment to $@ is useless, since its value is never read. | DeadStoreOfLocal.cs:261:17:261:17 | x | x | | DeadStoreOfLocal.cs:289:23:289:28 | Object v1 | This assignment to $@ is useless, since its value is never read. | DeadStoreOfLocal.cs:289:27:289:28 | v1 | v1 | From 056dbe31d59d8c93ee3c48cf85efe483f0dc416d Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Thu, 7 Jan 2021 13:40:44 +0100 Subject: [PATCH 055/343] C#: Remove throw completion from StringLiteral --- .../controlflow/internal/Completion.qll | 3 - .../controlflow/graph/BasicBlock.expected | 46 +-- .../controlflow/graph/Condition.expected | 46 +-- .../controlflow/graph/Dominance.expected | 286 ++---------------- .../graph/EnclosingCallable.expected | 70 ----- .../controlflow/graph/ExitElement.expected | 51 ---- .../controlflow/graph/NodeGraph.expected | 57 ---- .../controlflow/graph/Nodes.expected | 28 -- .../exceptions/Exceptions1.expected | 1 - 9 files changed, 38 insertions(+), 550 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/internal/Completion.qll b/csharp/ql/src/semmle/code/csharp/controlflow/internal/Completion.qll index 34cc23791e0..8f61d0f7c25 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/internal/Completion.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/internal/Completion.qll @@ -354,9 +354,6 @@ private class TriedControlFlowElement extends ControlFlowElement { or this instanceof DynamicExpr and result instanceof SystemExceptionClass - or - this instanceof StringLiteral and - result instanceof SystemOutOfMemoryExceptionClass } private CoreLib getCoreLibFromACatchClause() { diff --git a/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected b/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected index 47ab064fe76..d9fc6b0c1f6 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected @@ -418,47 +418,35 @@ | Extensions.cs:10:24:10:29 | enter ToBool | Extensions.cs:10:24:10:29 | exit ToBool | 8 | | Extensions.cs:15:23:15:33 | enter CallToInt32 | Extensions.cs:15:23:15:33 | exit CallToInt32 | 5 | | Extensions.cs:20:17:20:20 | enter Main | Extensions.cs:20:17:20:20 | exit Main | 20 | -| Finally.cs:7:10:7:11 | enter M1 | Finally.cs:11:31:11:36 | "Try1" | 6 | +| Finally.cs:7:10:7:11 | enter M1 | Finally.cs:11:13:11:37 | call to method WriteLine | 7 | | Finally.cs:7:10:7:11 | exit M1 | Finally.cs:7:10:7:11 | exit M1 | 1 | -| Finally.cs:7:10:7:11 | exit M1 (abnormal) | Finally.cs:7:10:7:11 | exit M1 (abnormal) | 1 | -| Finally.cs:11:13:11:37 | call to method WriteLine | Finally.cs:11:13:11:37 | call to method WriteLine | 1 | -| Finally.cs:14:9:16:9 | [finally: exception(Exception)] {...} | Finally.cs:15:13:15:40 | [finally: exception(Exception)] call to method WriteLine | 4 | -| Finally.cs:14:9:16:9 | [finally: exception(OutOfMemoryException)] {...} | Finally.cs:15:13:15:40 | [finally: exception(OutOfMemoryException)] call to method WriteLine | 4 | +| Finally.cs:14:9:16:9 | [finally: exception(Exception)] {...} | Finally.cs:7:10:7:11 | exit M1 (abnormal) | 5 | | Finally.cs:14:9:16:9 | {...} | Finally.cs:7:10:7:11 | exit M1 (normal) | 5 | -| Finally.cs:19:10:19:11 | enter M2 | Finally.cs:23:31:23:36 | "Try2" | 6 | +| Finally.cs:19:10:19:11 | enter M2 | Finally.cs:23:13:23:37 | call to method WriteLine | 7 | | Finally.cs:19:10:19:11 | exit M2 | Finally.cs:19:10:19:11 | exit M2 | 1 | | Finally.cs:19:10:19:11 | exit M2 (abnormal) | Finally.cs:19:10:19:11 | exit M2 (abnormal) | 1 | | Finally.cs:19:10:19:11 | exit M2 (normal) | Finally.cs:19:10:19:11 | exit M2 (normal) | 1 | -| Finally.cs:23:13:23:37 | call to method WriteLine | Finally.cs:23:13:23:37 | call to method WriteLine | 1 | | Finally.cs:24:13:24:19 | return ...; | Finally.cs:50:13:50:40 | [finally: return] call to method WriteLine | 5 | | Finally.cs:26:9:29:9 | [exception: Exception] catch (...) {...} | Finally.cs:26:9:29:9 | [exception: Exception] catch (...) {...} | 1 | -| Finally.cs:26:9:29:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:26:9:29:9 | [exception: OutOfMemoryException] catch (...) {...} | 1 | | Finally.cs:26:38:26:39 | [exception: Exception] IOException ex | Finally.cs:26:48:26:51 | [exception: Exception] true | 2 | | Finally.cs:27:9:29:9 | {...} | Finally.cs:50:13:50:40 | [finally: exception(IOException)] call to method WriteLine | 6 | | Finally.cs:30:9:40:9 | [exception: Exception] catch (...) {...} | Finally.cs:30:9:40:9 | [exception: Exception] catch (...) {...} | 1 | -| Finally.cs:30:9:40:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:30:9:40:9 | [exception: OutOfMemoryException] catch (...) {...} | 1 | | Finally.cs:30:41:30:42 | [exception: Exception] ArgumentException ex | Finally.cs:34:21:34:24 | true | 6 | | Finally.cs:34:27:34:32 | throw ...; | Finally.cs:50:13:50:40 | [finally: exception(Exception)] call to method WriteLine | 9 | | Finally.cs:41:9:43:9 | [exception: Exception] catch (...) {...} | Finally.cs:41:9:43:9 | [exception: Exception] catch (...) {...} | 1 | -| Finally.cs:41:9:43:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:41:9:43:9 | [exception: OutOfMemoryException] catch (...) {...} | 1 | | Finally.cs:42:9:43:9 | {...} | Finally.cs:50:13:50:40 | call to method WriteLine | 5 | -| Finally.cs:54:10:54:11 | enter M3 | Finally.cs:58:31:58:36 | "Try3" | 6 | +| Finally.cs:54:10:54:11 | enter M3 | Finally.cs:58:13:58:37 | call to method WriteLine | 7 | | Finally.cs:54:10:54:11 | exit M3 | Finally.cs:54:10:54:11 | exit M3 | 1 | | Finally.cs:54:10:54:11 | exit M3 (abnormal) | Finally.cs:54:10:54:11 | exit M3 (abnormal) | 1 | | Finally.cs:54:10:54:11 | exit M3 (normal) | Finally.cs:54:10:54:11 | exit M3 (normal) | 1 | -| Finally.cs:58:13:58:37 | call to method WriteLine | Finally.cs:58:13:58:37 | call to method WriteLine | 1 | | Finally.cs:59:13:59:19 | return ...; | Finally.cs:70:13:70:40 | [finally: return] call to method WriteLine | 5 | | Finally.cs:61:9:64:9 | [exception: Exception] catch (...) {...} | Finally.cs:61:9:64:9 | [exception: Exception] catch (...) {...} | 1 | -| Finally.cs:61:9:64:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:61:9:64:9 | [exception: OutOfMemoryException] catch (...) {...} | 1 | | Finally.cs:61:38:61:39 | [exception: Exception] IOException ex | Finally.cs:61:48:61:51 | [exception: Exception] true | 2 | | Finally.cs:62:9:64:9 | {...} | Finally.cs:70:13:70:40 | [finally: exception(IOException)] call to method WriteLine | 6 | | Finally.cs:65:9:67:9 | [exception: Exception] catch (...) {...} | Finally.cs:65:9:67:9 | [exception: Exception] catch (...) {...} | 1 | -| Finally.cs:65:9:67:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:65:9:67:9 | [exception: OutOfMemoryException] catch (...) {...} | 1 | | Finally.cs:65:26:65:26 | [exception: Exception] Exception e | Finally.cs:65:35:65:51 | [exception: Exception] ... != ... | 5 | -| Finally.cs:65:26:65:26 | [exception: OutOfMemoryException] Exception e | Finally.cs:65:35:65:51 | [exception: OutOfMemoryException] ... != ... | 5 | | Finally.cs:66:9:67:9 | {...} | Finally.cs:70:13:70:40 | call to method WriteLine | 5 | | Finally.cs:69:9:71:9 | [finally: exception(Exception)] {...} | Finally.cs:70:13:70:40 | [finally: exception(Exception)] call to method WriteLine | 4 | -| Finally.cs:69:9:71:9 | [finally: exception(OutOfMemoryException)] {...} | Finally.cs:70:13:70:40 | [finally: exception(OutOfMemoryException)] call to method WriteLine | 4 | | Finally.cs:74:10:74:11 | enter M4 | Finally.cs:77:9:100:9 | while (...) ... | 6 | | Finally.cs:74:10:74:11 | exit M4 | Finally.cs:74:10:74:11 | exit M4 | 1 | | Finally.cs:74:10:74:11 | exit M4 (abnormal) | Finally.cs:74:10:74:11 | exit M4 (abnormal) | 1 | @@ -528,11 +516,9 @@ | Finally.cs:117:17:117:37 | [finally: exception(OutOfMemoryException)] ...; | Finally.cs:117:17:117:36 | [finally: exception(OutOfMemoryException)] call to method WriteLine | 3 | | Finally.cs:117:17:117:37 | [finally: return] ...; | Finally.cs:117:17:117:36 | [finally: return] call to method WriteLine | 3 | | Finally.cs:121:10:121:11 | enter M6 | Finally.cs:121:10:121:11 | exit M6 | 12 | -| Finally.cs:133:10:133:11 | enter M7 | Finally.cs:137:31:137:35 | "Try" | 6 | +| Finally.cs:133:10:133:11 | enter M7 | Finally.cs:137:13:137:36 | call to method WriteLine | 7 | | Finally.cs:133:10:133:11 | exit M7 (abnormal) | Finally.cs:133:10:133:11 | exit M7 | 2 | -| Finally.cs:137:13:137:36 | call to method WriteLine | Finally.cs:137:13:137:36 | call to method WriteLine | 1 | | Finally.cs:140:9:143:9 | [finally: exception(Exception)] {...} | Finally.cs:141:13:141:44 | [finally: exception(Exception)] throw ...; | 4 | -| Finally.cs:140:9:143:9 | [finally: exception(OutOfMemoryException)] {...} | Finally.cs:141:13:141:44 | [finally: exception(OutOfMemoryException)] throw ...; | 4 | | Finally.cs:140:9:143:9 | {...} | Finally.cs:141:13:141:44 | throw ...; | 4 | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:151:17:151:28 | ... == ... | 8 | | Finally.cs:147:10:147:11 | exit M8 | Finally.cs:147:10:147:11 | exit M8 | 1 | @@ -548,30 +534,21 @@ | Finally.cs:159:21:159:45 | [finally: exception(ArgumentNullException)] throw ...; | Finally.cs:159:21:159:45 | [finally: exception(ArgumentNullException)] throw ...; | 1 | | Finally.cs:159:21:159:45 | [finally: exception(Exception)] throw ...; | Finally.cs:159:21:159:45 | [finally: exception(Exception)] throw ...; | 1 | | Finally.cs:159:21:159:45 | throw ...; | Finally.cs:159:21:159:45 | throw ...; | 1 | -| Finally.cs:159:27:159:44 | [finally: exception(ArgumentNullException)] object creation of type Exception | Finally.cs:159:27:159:44 | [finally: exception(ArgumentNullException)] object creation of type Exception | 1 | -| Finally.cs:159:27:159:44 | [finally: exception(Exception)] object creation of type Exception | Finally.cs:159:27:159:44 | [finally: exception(Exception)] object creation of type Exception | 1 | -| Finally.cs:159:27:159:44 | object creation of type Exception | Finally.cs:159:27:159:44 | object creation of type Exception | 1 | -| Finally.cs:159:41:159:43 | "1" | Finally.cs:159:41:159:43 | "1" | 1 | -| Finally.cs:159:41:159:43 | [finally: exception(ArgumentNullException)] "1" | Finally.cs:159:41:159:43 | [finally: exception(ArgumentNullException)] "1" | 1 | -| Finally.cs:159:41:159:43 | [finally: exception(Exception)] "1" | Finally.cs:159:41:159:43 | [finally: exception(Exception)] "1" | 1 | +| Finally.cs:159:41:159:43 | "1" | Finally.cs:159:27:159:44 | object creation of type Exception | 2 | +| Finally.cs:159:41:159:43 | [finally: exception(ArgumentNullException)] "1" | Finally.cs:159:27:159:44 | [finally: exception(ArgumentNullException)] object creation of type Exception | 2 | +| Finally.cs:159:41:159:43 | [finally: exception(Exception)] "1" | Finally.cs:159:27:159:44 | [finally: exception(Exception)] object creation of type Exception | 2 | | Finally.cs:161:13:164:13 | [exception: Exception] catch (...) {...} | Finally.cs:161:13:164:13 | [exception: Exception] catch (...) {...} | 1 | | Finally.cs:161:13:164:13 | [exception: NullReferenceException] catch (...) {...} | Finally.cs:161:13:164:13 | [exception: NullReferenceException] catch (...) {...} | 1 | -| Finally.cs:161:13:164:13 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:161:13:164:13 | [exception: OutOfMemoryException] catch (...) {...} | 1 | | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: Exception] catch (...) {...} | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: Exception] catch (...) {...} | 1 | | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: NullReferenceException] catch (...) {...} | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: NullReferenceException] catch (...) {...} | 1 | -| Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] catch (...) {...} | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] catch (...) {...} | 1 | | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: Exception] catch (...) {...} | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: Exception] catch (...) {...} | 1 | | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: NullReferenceException] catch (...) {...} | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: NullReferenceException] catch (...) {...} | 1 | -| Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: OutOfMemoryException] catch (...) {...} | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: OutOfMemoryException] catch (...) {...} | 1 | | Finally.cs:161:30:161:30 | [exception: Exception] Exception e | Finally.cs:161:39:161:54 | [exception: Exception] ... == ... | 5 | | Finally.cs:161:30:161:30 | [exception: NullReferenceException] Exception e | Finally.cs:161:39:161:54 | [exception: NullReferenceException] ... == ... | 5 | -| Finally.cs:161:30:161:30 | [exception: OutOfMemoryException] Exception e | Finally.cs:161:39:161:54 | [exception: OutOfMemoryException] ... == ... | 5 | | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: Exception] Exception e | Finally.cs:161:39:161:54 | [finally: exception(ArgumentNullException), exception: Exception] ... == ... | 5 | | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: NullReferenceException] Exception e | Finally.cs:161:39:161:54 | [finally: exception(ArgumentNullException), exception: NullReferenceException] ... == ... | 5 | -| Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] Exception e | Finally.cs:161:39:161:54 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] ... == ... | 5 | | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: Exception] Exception e | Finally.cs:161:39:161:54 | [finally: exception(Exception), exception: Exception] ... == ... | 5 | | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: NullReferenceException] Exception e | Finally.cs:161:39:161:54 | [finally: exception(Exception), exception: NullReferenceException] ... == ... | 5 | -| Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: OutOfMemoryException] Exception e | Finally.cs:161:39:161:54 | [finally: exception(Exception), exception: OutOfMemoryException] ... == ... | 5 | | Finally.cs:162:13:164:13 | [finally: exception(ArgumentNullException)] {...} | Finally.cs:163:17:163:42 | [finally: exception(ArgumentNullException)] call to method WriteLine | 6 | | Finally.cs:162:13:164:13 | [finally: exception(Exception)] {...} | Finally.cs:163:17:163:42 | [finally: exception(Exception)] call to method WriteLine | 6 | | Finally.cs:162:13:164:13 | {...} | Finally.cs:163:17:163:42 | call to method WriteLine | 6 | @@ -637,8 +614,7 @@ | Finally.cs:211:13:211:29 | ...; | Finally.cs:195:10:195:12 | exit M10 (normal) | 9 | | Finally.cs:211:13:211:29 | [finally: exception(Exception)] ...; | Finally.cs:211:13:211:28 | [finally: exception(Exception)] ... = ... | 4 | | Finally.cs:211:13:211:29 | [finally: exception(ExceptionA)] ...; | Finally.cs:211:13:211:28 | [finally: exception(ExceptionA)] ... = ... | 4 | -| Finally.cs:216:10:216:12 | enter M11 | Finally.cs:220:31:220:35 | "Try" | 6 | -| Finally.cs:220:13:220:36 | call to method WriteLine | Finally.cs:220:13:220:36 | call to method WriteLine | 1 | +| Finally.cs:216:10:216:12 | enter M11 | Finally.cs:220:13:220:36 | call to method WriteLine | 7 | | Finally.cs:222:9:225:9 | catch {...} | Finally.cs:224:13:224:38 | call to method WriteLine | 5 | | Finally.cs:227:9:229:9 | {...} | Finally.cs:216:10:216:12 | exit M11 | 9 | | Finally.cs:233:10:233:12 | enter M12 | Finally.cs:239:21:239:22 | access to parameter b1 | 8 | @@ -659,11 +635,9 @@ | Finally.cs:250:17:252:17 | [finally: exception(Exception)] {...} | Finally.cs:251:21:251:54 | [finally: exception(Exception)] call to method WriteLine | 4 | | Finally.cs:250:17:252:17 | [finally: exception(ExceptionA), finally(1): exception(Exception)] {...} | Finally.cs:251:21:251:54 | [finally: exception(ExceptionA), finally(1): exception(Exception)] call to method WriteLine | 4 | | Finally.cs:250:17:252:17 | [finally: exception(ExceptionA)] {...} | Finally.cs:251:21:251:54 | [finally: exception(ExceptionA)] call to method WriteLine | 4 | -| Finally.cs:250:17:252:17 | {...} | Finally.cs:254:31:254:43 | "Mid finally" | 6 | -| Finally.cs:254:13:254:44 | call to method WriteLine | Finally.cs:254:13:254:44 | call to method WriteLine | 1 | +| Finally.cs:250:17:252:17 | {...} | Finally.cs:254:13:254:44 | call to method WriteLine | 7 | | Finally.cs:257:9:259:9 | [finally: exception(Exception)] {...} | Finally.cs:258:13:258:46 | [finally: exception(Exception)] call to method WriteLine | 4 | | Finally.cs:257:9:259:9 | [finally: exception(ExceptionA)] {...} | Finally.cs:258:13:258:46 | [finally: exception(ExceptionA)] call to method WriteLine | 4 | -| Finally.cs:257:9:259:9 | [finally: exception(OutOfMemoryException)] {...} | Finally.cs:258:13:258:46 | [finally: exception(OutOfMemoryException)] call to method WriteLine | 4 | | Finally.cs:257:9:259:9 | {...} | Finally.cs:233:10:233:12 | exit M12 (normal) | 8 | | Foreach.cs:6:10:6:11 | enter M1 | Foreach.cs:8:29:8:32 | access to parameter args | 3 | | Foreach.cs:6:10:6:11 | exit M1 (normal) | Foreach.cs:6:10:6:11 | exit M1 | 2 | diff --git a/csharp/ql/test/library-tests/controlflow/graph/Condition.expected b/csharp/ql/test/library-tests/controlflow/graph/Condition.expected index 9be08ab1041..3f1653363c8 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Condition.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/Condition.expected @@ -1326,27 +1326,25 @@ conditionBlock | Finally.cs:26:9:29:9 | [exception: Exception] catch (...) {...} | Finally.cs:30:41:30:42 | [exception: Exception] ArgumentException ex | false | | Finally.cs:26:9:29:9 | [exception: Exception] catch (...) {...} | Finally.cs:34:27:34:32 | throw ...; | false | | Finally.cs:26:9:29:9 | [exception: Exception] catch (...) {...} | Finally.cs:41:9:43:9 | [exception: Exception] catch (...) {...} | false | -| Finally.cs:26:9:29:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:30:9:40:9 | [exception: OutOfMemoryException] catch (...) {...} | false | -| Finally.cs:26:9:29:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:41:9:43:9 | [exception: OutOfMemoryException] catch (...) {...} | false | +| Finally.cs:26:9:29:9 | [exception: Exception] catch (...) {...} | Finally.cs:42:9:43:9 | {...} | false | | Finally.cs:26:38:26:39 | [exception: Exception] IOException ex | Finally.cs:27:9:29:9 | {...} | true | | Finally.cs:30:9:40:9 | [exception: Exception] catch (...) {...} | Finally.cs:30:41:30:42 | [exception: Exception] ArgumentException ex | true | | Finally.cs:30:9:40:9 | [exception: Exception] catch (...) {...} | Finally.cs:34:27:34:32 | throw ...; | true | | Finally.cs:30:9:40:9 | [exception: Exception] catch (...) {...} | Finally.cs:41:9:43:9 | [exception: Exception] catch (...) {...} | false | -| Finally.cs:30:9:40:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:41:9:43:9 | [exception: OutOfMemoryException] catch (...) {...} | false | +| Finally.cs:30:9:40:9 | [exception: Exception] catch (...) {...} | Finally.cs:42:9:43:9 | {...} | false | | Finally.cs:30:41:30:42 | [exception: Exception] ArgumentException ex | Finally.cs:34:27:34:32 | throw ...; | true | +| Finally.cs:41:9:43:9 | [exception: Exception] catch (...) {...} | Finally.cs:42:9:43:9 | {...} | true | | Finally.cs:61:9:64:9 | [exception: Exception] catch (...) {...} | Finally.cs:61:38:61:39 | [exception: Exception] IOException ex | true | | Finally.cs:61:9:64:9 | [exception: Exception] catch (...) {...} | Finally.cs:62:9:64:9 | {...} | true | | Finally.cs:61:9:64:9 | [exception: Exception] catch (...) {...} | Finally.cs:65:9:67:9 | [exception: Exception] catch (...) {...} | false | | Finally.cs:61:9:64:9 | [exception: Exception] catch (...) {...} | Finally.cs:65:26:65:26 | [exception: Exception] Exception e | false | +| Finally.cs:61:9:64:9 | [exception: Exception] catch (...) {...} | Finally.cs:66:9:67:9 | {...} | false | | Finally.cs:61:9:64:9 | [exception: Exception] catch (...) {...} | Finally.cs:69:9:71:9 | [finally: exception(Exception)] {...} | false | -| Finally.cs:61:9:64:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:65:9:67:9 | [exception: OutOfMemoryException] catch (...) {...} | false | -| Finally.cs:61:9:64:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:65:26:65:26 | [exception: OutOfMemoryException] Exception e | false | -| Finally.cs:61:9:64:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:69:9:71:9 | [finally: exception(OutOfMemoryException)] {...} | false | | Finally.cs:61:38:61:39 | [exception: Exception] IOException ex | Finally.cs:62:9:64:9 | {...} | true | | Finally.cs:65:9:67:9 | [exception: Exception] catch (...) {...} | Finally.cs:65:26:65:26 | [exception: Exception] Exception e | true | +| Finally.cs:65:9:67:9 | [exception: Exception] catch (...) {...} | Finally.cs:66:9:67:9 | {...} | true | | Finally.cs:65:9:67:9 | [exception: Exception] catch (...) {...} | Finally.cs:69:9:71:9 | [finally: exception(Exception)] {...} | true | -| Finally.cs:65:9:67:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:65:26:65:26 | [exception: OutOfMemoryException] Exception e | true | -| Finally.cs:65:9:67:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:69:9:71:9 | [finally: exception(OutOfMemoryException)] {...} | true | +| Finally.cs:65:26:65:26 | [exception: Exception] Exception e | Finally.cs:66:9:67:9 | {...} | true | | Finally.cs:77:16:77:16 | access to local variable i | Finally.cs:74:10:74:11 | exit M4 (abnormal) | true | | Finally.cs:77:16:77:16 | access to local variable i | Finally.cs:78:9:100:9 | {...} | true | | Finally.cs:77:16:77:16 | access to local variable i | Finally.cs:82:21:82:27 | return ...; | true | @@ -1507,30 +1505,21 @@ conditionBlock | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:159:21:159:45 | [finally: exception(ArgumentNullException)] throw ...; | true | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:159:21:159:45 | [finally: exception(Exception)] throw ...; | true | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:159:21:159:45 | throw ...; | false | -| Finally.cs:147:10:147:11 | enter M8 | Finally.cs:159:27:159:44 | [finally: exception(ArgumentNullException)] object creation of type Exception | true | -| Finally.cs:147:10:147:11 | enter M8 | Finally.cs:159:27:159:44 | [finally: exception(Exception)] object creation of type Exception | true | -| Finally.cs:147:10:147:11 | enter M8 | Finally.cs:159:27:159:44 | object creation of type Exception | false | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:159:41:159:43 | "1" | false | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:159:41:159:43 | [finally: exception(ArgumentNullException)] "1" | true | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:159:41:159:43 | [finally: exception(Exception)] "1" | true | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:161:13:164:13 | [exception: Exception] catch (...) {...} | false | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:161:13:164:13 | [exception: NullReferenceException] catch (...) {...} | false | -| Finally.cs:147:10:147:11 | enter M8 | Finally.cs:161:13:164:13 | [exception: OutOfMemoryException] catch (...) {...} | false | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: Exception] catch (...) {...} | true | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: NullReferenceException] catch (...) {...} | true | -| Finally.cs:147:10:147:11 | enter M8 | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] catch (...) {...} | true | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: Exception] catch (...) {...} | true | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: NullReferenceException] catch (...) {...} | true | -| Finally.cs:147:10:147:11 | enter M8 | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: OutOfMemoryException] catch (...) {...} | true | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:161:30:161:30 | [exception: Exception] Exception e | false | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:161:30:161:30 | [exception: NullReferenceException] Exception e | false | -| Finally.cs:147:10:147:11 | enter M8 | Finally.cs:161:30:161:30 | [exception: OutOfMemoryException] Exception e | false | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: Exception] Exception e | true | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: NullReferenceException] Exception e | true | -| Finally.cs:147:10:147:11 | enter M8 | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] Exception e | true | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: Exception] Exception e | true | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: NullReferenceException] Exception e | true | -| Finally.cs:147:10:147:11 | enter M8 | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: OutOfMemoryException] Exception e | true | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:162:13:164:13 | [finally: exception(ArgumentNullException)] {...} | true | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:162:13:164:13 | [finally: exception(Exception)] {...} | true | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:162:13:164:13 | {...} | false | @@ -1538,29 +1527,17 @@ conditionBlock | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:165:13:168:13 | [finally: exception(Exception)] catch {...} | true | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:165:13:168:13 | catch {...} | false | | Finally.cs:158:36:158:36 | 1 | Finally.cs:159:21:159:45 | throw ...; | true | -| Finally.cs:158:36:158:36 | 1 | Finally.cs:159:27:159:44 | object creation of type Exception | true | | Finally.cs:158:36:158:36 | 1 | Finally.cs:159:41:159:43 | "1" | true | -| Finally.cs:158:36:158:36 | 1 | Finally.cs:161:13:164:13 | [exception: OutOfMemoryException] catch (...) {...} | true | -| Finally.cs:158:36:158:36 | 1 | Finally.cs:161:30:161:30 | [exception: OutOfMemoryException] Exception e | true | | Finally.cs:158:36:158:36 | [finally: exception(ArgumentNullException)] 1 | Finally.cs:159:21:159:45 | [finally: exception(ArgumentNullException)] throw ...; | true | -| Finally.cs:158:36:158:36 | [finally: exception(ArgumentNullException)] 1 | Finally.cs:159:27:159:44 | [finally: exception(ArgumentNullException)] object creation of type Exception | true | | Finally.cs:158:36:158:36 | [finally: exception(ArgumentNullException)] 1 | Finally.cs:159:41:159:43 | [finally: exception(ArgumentNullException)] "1" | true | -| Finally.cs:158:36:158:36 | [finally: exception(ArgumentNullException)] 1 | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] catch (...) {...} | true | -| Finally.cs:158:36:158:36 | [finally: exception(ArgumentNullException)] 1 | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] Exception e | true | | Finally.cs:158:36:158:36 | [finally: exception(Exception)] 1 | Finally.cs:159:21:159:45 | [finally: exception(Exception)] throw ...; | true | -| Finally.cs:158:36:158:36 | [finally: exception(Exception)] 1 | Finally.cs:159:27:159:44 | [finally: exception(Exception)] object creation of type Exception | true | | Finally.cs:158:36:158:36 | [finally: exception(Exception)] 1 | Finally.cs:159:41:159:43 | [finally: exception(Exception)] "1" | true | -| Finally.cs:158:36:158:36 | [finally: exception(Exception)] 1 | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: OutOfMemoryException] catch (...) {...} | true | -| Finally.cs:158:36:158:36 | [finally: exception(Exception)] 1 | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: OutOfMemoryException] Exception e | true | | Finally.cs:161:13:164:13 | [exception: Exception] catch (...) {...} | Finally.cs:161:30:161:30 | [exception: Exception] Exception e | true | | Finally.cs:161:13:164:13 | [exception: NullReferenceException] catch (...) {...} | Finally.cs:161:30:161:30 | [exception: NullReferenceException] Exception e | true | -| Finally.cs:161:13:164:13 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:161:30:161:30 | [exception: OutOfMemoryException] Exception e | true | | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: Exception] catch (...) {...} | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: Exception] Exception e | true | | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: NullReferenceException] catch (...) {...} | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: NullReferenceException] Exception e | true | -| Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] catch (...) {...} | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] Exception e | true | | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: Exception] catch (...) {...} | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: Exception] Exception e | true | | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: NullReferenceException] catch (...) {...} | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: NullReferenceException] Exception e | true | -| Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: OutOfMemoryException] catch (...) {...} | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: OutOfMemoryException] Exception e | true | | Finally.cs:176:10:176:11 | enter M9 | Finally.cs:176:10:176:11 | exit M9 (normal) | false | | Finally.cs:176:10:176:11 | enter M9 | Finally.cs:180:21:180:43 | [b1 (line 176): true] throw ...; | true | | Finally.cs:176:10:176:11 | enter M9 | Finally.cs:180:27:180:42 | [b1 (line 176): true] object creation of type ExceptionA | true | @@ -1694,8 +1671,6 @@ conditionBlock | Finally.cs:233:10:233:12 | enter M12 | Finally.cs:250:17:252:17 | [finally: exception(ExceptionA), finally(1): exception(Exception)] {...} | true | | Finally.cs:233:10:233:12 | enter M12 | Finally.cs:250:17:252:17 | [finally: exception(ExceptionA)] {...} | true | | Finally.cs:233:10:233:12 | enter M12 | Finally.cs:250:17:252:17 | {...} | false | -| Finally.cs:233:10:233:12 | enter M12 | Finally.cs:254:13:254:44 | call to method WriteLine | false | -| Finally.cs:233:10:233:12 | enter M12 | Finally.cs:257:9:259:9 | [finally: exception(OutOfMemoryException)] {...} | false | | Finally.cs:233:10:233:12 | enter M12 | Finally.cs:257:9:259:9 | {...} | false | | Finally.cs:240:21:240:43 | throw ...; | Finally.cs:247:25:247:47 | [finally: exception(ExceptionA)] throw ...; | true | | Finally.cs:240:21:240:43 | throw ...; | Finally.cs:247:31:247:46 | [finally: exception(ExceptionA)] object creation of type ExceptionA | true | @@ -1709,8 +1684,6 @@ conditionBlock | Finally.cs:243:13:253:13 | {...} | Finally.cs:247:31:247:46 | object creation of type ExceptionA | true | | Finally.cs:243:13:253:13 | {...} | Finally.cs:250:17:252:17 | [finally(1): exception(Exception)] {...} | true | | Finally.cs:243:13:253:13 | {...} | Finally.cs:250:17:252:17 | {...} | false | -| Finally.cs:243:13:253:13 | {...} | Finally.cs:254:13:254:44 | call to method WriteLine | false | -| Finally.cs:243:13:253:13 | {...} | Finally.cs:257:9:259:9 | [finally: exception(OutOfMemoryException)] {...} | false | | Finally.cs:243:13:253:13 | {...} | Finally.cs:257:9:259:9 | {...} | false | | Foreach.cs:8:9:9:13 | foreach (... ... in ...) ... | Foreach.cs:6:10:6:11 | exit M1 (normal) | true | | Foreach.cs:8:9:9:13 | foreach (... ... in ...) ... | Foreach.cs:8:22:8:24 | String arg | false | @@ -2594,7 +2567,6 @@ conditionFlow | Finally.cs:34:21:34:24 | true | Finally.cs:34:27:34:32 | throw ...; | true | | Finally.cs:61:48:61:51 | [exception: Exception] true | Finally.cs:62:9:64:9 | {...} | true | | Finally.cs:65:35:65:51 | [exception: Exception] ... != ... | Finally.cs:66:9:67:9 | {...} | true | -| Finally.cs:65:35:65:51 | [exception: OutOfMemoryException] ... != ... | Finally.cs:66:9:67:9 | {...} | true | | Finally.cs:77:16:77:20 | ... > ... | Finally.cs:74:10:74:11 | exit M4 (normal) | false | | Finally.cs:77:16:77:20 | ... > ... | Finally.cs:78:9:100:9 | {...} | true | | Finally.cs:81:21:81:26 | ... == ... | Finally.cs:82:21:82:27 | return ...; | true | @@ -2651,20 +2623,14 @@ conditionFlow | Finally.cs:161:39:161:54 | [exception: Exception] ... == ... | Finally.cs:165:13:168:13 | catch {...} | false | | Finally.cs:161:39:161:54 | [exception: NullReferenceException] ... == ... | Finally.cs:162:13:164:13 | {...} | true | | Finally.cs:161:39:161:54 | [exception: NullReferenceException] ... == ... | Finally.cs:165:13:168:13 | catch {...} | false | -| Finally.cs:161:39:161:54 | [exception: OutOfMemoryException] ... == ... | Finally.cs:162:13:164:13 | {...} | true | -| Finally.cs:161:39:161:54 | [exception: OutOfMemoryException] ... == ... | Finally.cs:165:13:168:13 | catch {...} | false | | Finally.cs:161:39:161:54 | [finally: exception(ArgumentNullException), exception: Exception] ... == ... | Finally.cs:162:13:164:13 | [finally: exception(ArgumentNullException)] {...} | true | | Finally.cs:161:39:161:54 | [finally: exception(ArgumentNullException), exception: Exception] ... == ... | Finally.cs:165:13:168:13 | [finally: exception(ArgumentNullException)] catch {...} | false | | Finally.cs:161:39:161:54 | [finally: exception(ArgumentNullException), exception: NullReferenceException] ... == ... | Finally.cs:162:13:164:13 | [finally: exception(ArgumentNullException)] {...} | true | | Finally.cs:161:39:161:54 | [finally: exception(ArgumentNullException), exception: NullReferenceException] ... == ... | Finally.cs:165:13:168:13 | [finally: exception(ArgumentNullException)] catch {...} | false | -| Finally.cs:161:39:161:54 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] ... == ... | Finally.cs:162:13:164:13 | [finally: exception(ArgumentNullException)] {...} | true | -| Finally.cs:161:39:161:54 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] ... == ... | Finally.cs:165:13:168:13 | [finally: exception(ArgumentNullException)] catch {...} | false | | Finally.cs:161:39:161:54 | [finally: exception(Exception), exception: Exception] ... == ... | Finally.cs:162:13:164:13 | [finally: exception(Exception)] {...} | true | | Finally.cs:161:39:161:54 | [finally: exception(Exception), exception: Exception] ... == ... | Finally.cs:165:13:168:13 | [finally: exception(Exception)] catch {...} | false | | Finally.cs:161:39:161:54 | [finally: exception(Exception), exception: NullReferenceException] ... == ... | Finally.cs:162:13:164:13 | [finally: exception(Exception)] {...} | true | | Finally.cs:161:39:161:54 | [finally: exception(Exception), exception: NullReferenceException] ... == ... | Finally.cs:165:13:168:13 | [finally: exception(Exception)] catch {...} | false | -| Finally.cs:161:39:161:54 | [finally: exception(Exception), exception: OutOfMemoryException] ... == ... | Finally.cs:162:13:164:13 | [finally: exception(Exception)] {...} | true | -| Finally.cs:161:39:161:54 | [finally: exception(Exception), exception: OutOfMemoryException] ... == ... | Finally.cs:165:13:168:13 | [finally: exception(Exception)] catch {...} | false | | Finally.cs:180:17:180:18 | access to parameter b1 | Finally.cs:180:27:180:42 | [b1 (line 176): true] object creation of type ExceptionA | true | | Finally.cs:180:17:180:18 | access to parameter b1 | Finally.cs:183:9:192:9 | [b1 (line 176): false] {...} | false | | Finally.cs:186:21:186:22 | [b1 (line 176): false] access to parameter b2 | Finally.cs:176:10:176:11 | exit M9 (normal) | false | diff --git a/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected b/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected index 64faed12b0c..b9f51a64281 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected @@ -1688,17 +1688,14 @@ dominance | Finally.cs:11:13:11:37 | call to method WriteLine | Finally.cs:14:9:16:9 | {...} | | Finally.cs:11:13:11:38 | ...; | Finally.cs:11:31:11:36 | "Try1" | | Finally.cs:11:31:11:36 | "Try1" | Finally.cs:11:13:11:37 | call to method WriteLine | -| Finally.cs:11:31:11:36 | "Try1" | Finally.cs:14:9:16:9 | [finally: exception(OutOfMemoryException)] {...} | | Finally.cs:14:9:16:9 | [finally: exception(Exception)] {...} | Finally.cs:15:13:15:41 | [finally: exception(Exception)] ...; | -| Finally.cs:14:9:16:9 | [finally: exception(OutOfMemoryException)] {...} | Finally.cs:15:13:15:41 | [finally: exception(OutOfMemoryException)] ...; | | Finally.cs:14:9:16:9 | {...} | Finally.cs:15:13:15:41 | ...; | +| Finally.cs:15:13:15:40 | [finally: exception(Exception)] call to method WriteLine | Finally.cs:7:10:7:11 | exit M1 (abnormal) | | Finally.cs:15:13:15:40 | call to method WriteLine | Finally.cs:7:10:7:11 | exit M1 (normal) | | Finally.cs:15:13:15:41 | ...; | Finally.cs:15:31:15:39 | "Finally" | | Finally.cs:15:13:15:41 | [finally: exception(Exception)] ...; | Finally.cs:15:31:15:39 | [finally: exception(Exception)] "Finally" | -| Finally.cs:15:13:15:41 | [finally: exception(OutOfMemoryException)] ...; | Finally.cs:15:31:15:39 | [finally: exception(OutOfMemoryException)] "Finally" | | Finally.cs:15:31:15:39 | "Finally" | Finally.cs:15:13:15:40 | call to method WriteLine | | Finally.cs:15:31:15:39 | [finally: exception(Exception)] "Finally" | Finally.cs:15:13:15:40 | [finally: exception(Exception)] call to method WriteLine | -| Finally.cs:15:31:15:39 | [finally: exception(OutOfMemoryException)] "Finally" | Finally.cs:15:13:15:40 | [finally: exception(OutOfMemoryException)] call to method WriteLine | | Finally.cs:19:10:19:11 | enter M2 | Finally.cs:20:5:52:5 | {...} | | Finally.cs:20:5:52:5 | {...} | Finally.cs:21:9:51:9 | try {...} ... | | Finally.cs:21:9:51:9 | try {...} ... | Finally.cs:22:9:25:9 | {...} | @@ -1707,18 +1704,15 @@ dominance | Finally.cs:23:13:23:37 | call to method WriteLine | Finally.cs:26:9:29:9 | [exception: Exception] catch (...) {...} | | Finally.cs:23:13:23:38 | ...; | Finally.cs:23:31:23:36 | "Try2" | | Finally.cs:23:31:23:36 | "Try2" | Finally.cs:23:13:23:37 | call to method WriteLine | -| Finally.cs:23:31:23:36 | "Try2" | Finally.cs:26:9:29:9 | [exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:24:13:24:19 | return ...; | Finally.cs:49:9:51:9 | [finally: return] {...} | | Finally.cs:26:9:29:9 | [exception: Exception] catch (...) {...} | Finally.cs:26:38:26:39 | [exception: Exception] IOException ex | | Finally.cs:26:9:29:9 | [exception: Exception] catch (...) {...} | Finally.cs:30:9:40:9 | [exception: Exception] catch (...) {...} | -| Finally.cs:26:9:29:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:30:9:40:9 | [exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:26:38:26:39 | [exception: Exception] IOException ex | Finally.cs:26:48:26:51 | [exception: Exception] true | | Finally.cs:26:48:26:51 | [exception: Exception] true | Finally.cs:27:9:29:9 | {...} | | Finally.cs:27:9:29:9 | {...} | Finally.cs:28:13:28:18 | throw ...; | | Finally.cs:28:13:28:18 | throw ...; | Finally.cs:49:9:51:9 | [finally: exception(IOException)] {...} | | Finally.cs:30:9:40:9 | [exception: Exception] catch (...) {...} | Finally.cs:30:41:30:42 | [exception: Exception] ArgumentException ex | | Finally.cs:30:9:40:9 | [exception: Exception] catch (...) {...} | Finally.cs:41:9:43:9 | [exception: Exception] catch (...) {...} | -| Finally.cs:30:9:40:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:41:9:43:9 | [exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:30:41:30:42 | [exception: Exception] ArgumentException ex | Finally.cs:31:9:40:9 | {...} | | Finally.cs:31:9:40:9 | {...} | Finally.cs:32:13:39:13 | try {...} ... | | Finally.cs:32:13:39:13 | try {...} ... | Finally.cs:33:13:35:13 | {...} | @@ -1730,6 +1724,7 @@ dominance | Finally.cs:38:17:38:44 | [finally: exception(ArgumentException)] throw ...; | Finally.cs:49:9:51:9 | [finally: exception(Exception)] {...} | | Finally.cs:38:23:38:43 | [finally: exception(ArgumentException)] object creation of type Exception | Finally.cs:38:17:38:44 | [finally: exception(ArgumentException)] throw ...; | | Finally.cs:38:37:38:42 | [finally: exception(ArgumentException)] "Boo!" | Finally.cs:38:23:38:43 | [finally: exception(ArgumentException)] object creation of type Exception | +| Finally.cs:41:9:43:9 | [exception: Exception] catch (...) {...} | Finally.cs:42:9:43:9 | {...} | | Finally.cs:42:9:43:9 | {...} | Finally.cs:49:9:51:9 | {...} | | Finally.cs:49:9:51:9 | [finally: exception(Exception)] {...} | Finally.cs:50:13:50:41 | [finally: exception(Exception)] ...; | | Finally.cs:49:9:51:9 | [finally: exception(IOException)] {...} | Finally.cs:50:13:50:41 | [finally: exception(IOException)] ...; | @@ -1751,42 +1746,32 @@ dominance | Finally.cs:58:13:58:37 | call to method WriteLine | Finally.cs:61:9:64:9 | [exception: Exception] catch (...) {...} | | Finally.cs:58:13:58:38 | ...; | Finally.cs:58:31:58:36 | "Try3" | | Finally.cs:58:31:58:36 | "Try3" | Finally.cs:58:13:58:37 | call to method WriteLine | -| Finally.cs:58:31:58:36 | "Try3" | Finally.cs:61:9:64:9 | [exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:59:13:59:19 | return ...; | Finally.cs:69:9:71:9 | [finally: return] {...} | | Finally.cs:61:9:64:9 | [exception: Exception] catch (...) {...} | Finally.cs:61:38:61:39 | [exception: Exception] IOException ex | | Finally.cs:61:9:64:9 | [exception: Exception] catch (...) {...} | Finally.cs:65:9:67:9 | [exception: Exception] catch (...) {...} | -| Finally.cs:61:9:64:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:65:9:67:9 | [exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:61:38:61:39 | [exception: Exception] IOException ex | Finally.cs:61:48:61:51 | [exception: Exception] true | | Finally.cs:61:48:61:51 | [exception: Exception] true | Finally.cs:62:9:64:9 | {...} | | Finally.cs:62:9:64:9 | {...} | Finally.cs:63:13:63:18 | throw ...; | | Finally.cs:63:13:63:18 | throw ...; | Finally.cs:69:9:71:9 | [finally: exception(IOException)] {...} | | Finally.cs:65:9:67:9 | [exception: Exception] catch (...) {...} | Finally.cs:65:26:65:26 | [exception: Exception] Exception e | -| Finally.cs:65:9:67:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:65:26:65:26 | [exception: OutOfMemoryException] Exception e | | Finally.cs:65:26:65:26 | [exception: Exception] Exception e | Finally.cs:65:35:65:35 | [exception: Exception] access to local variable e | -| Finally.cs:65:26:65:26 | [exception: OutOfMemoryException] Exception e | Finally.cs:65:35:65:35 | [exception: OutOfMemoryException] access to local variable e | | Finally.cs:65:35:65:35 | [exception: Exception] access to local variable e | Finally.cs:65:35:65:43 | [exception: Exception] access to property Message | -| Finally.cs:65:35:65:35 | [exception: OutOfMemoryException] access to local variable e | Finally.cs:65:35:65:43 | [exception: OutOfMemoryException] access to property Message | | Finally.cs:65:35:65:43 | [exception: Exception] access to property Message | Finally.cs:65:48:65:51 | [exception: Exception] null | -| Finally.cs:65:35:65:43 | [exception: OutOfMemoryException] access to property Message | Finally.cs:65:48:65:51 | [exception: OutOfMemoryException] null | +| Finally.cs:65:35:65:51 | [exception: Exception] ... != ... | Finally.cs:66:9:67:9 | {...} | | Finally.cs:65:35:65:51 | [exception: Exception] ... != ... | Finally.cs:69:9:71:9 | [finally: exception(Exception)] {...} | -| Finally.cs:65:35:65:51 | [exception: OutOfMemoryException] ... != ... | Finally.cs:69:9:71:9 | [finally: exception(OutOfMemoryException)] {...} | | Finally.cs:65:48:65:51 | [exception: Exception] null | Finally.cs:65:35:65:51 | [exception: Exception] ... != ... | -| Finally.cs:65:48:65:51 | [exception: OutOfMemoryException] null | Finally.cs:65:35:65:51 | [exception: OutOfMemoryException] ... != ... | | Finally.cs:66:9:67:9 | {...} | Finally.cs:69:9:71:9 | {...} | | Finally.cs:69:9:71:9 | [finally: exception(Exception)] {...} | Finally.cs:70:13:70:41 | [finally: exception(Exception)] ...; | | Finally.cs:69:9:71:9 | [finally: exception(IOException)] {...} | Finally.cs:70:13:70:41 | [finally: exception(IOException)] ...; | -| Finally.cs:69:9:71:9 | [finally: exception(OutOfMemoryException)] {...} | Finally.cs:70:13:70:41 | [finally: exception(OutOfMemoryException)] ...; | | Finally.cs:69:9:71:9 | [finally: return] {...} | Finally.cs:70:13:70:41 | [finally: return] ...; | | Finally.cs:69:9:71:9 | {...} | Finally.cs:70:13:70:41 | ...; | | Finally.cs:70:13:70:41 | ...; | Finally.cs:70:31:70:39 | "Finally" | | Finally.cs:70:13:70:41 | [finally: exception(Exception)] ...; | Finally.cs:70:31:70:39 | [finally: exception(Exception)] "Finally" | | Finally.cs:70:13:70:41 | [finally: exception(IOException)] ...; | Finally.cs:70:31:70:39 | [finally: exception(IOException)] "Finally" | -| Finally.cs:70:13:70:41 | [finally: exception(OutOfMemoryException)] ...; | Finally.cs:70:31:70:39 | [finally: exception(OutOfMemoryException)] "Finally" | | Finally.cs:70:13:70:41 | [finally: return] ...; | Finally.cs:70:31:70:39 | [finally: return] "Finally" | | Finally.cs:70:31:70:39 | "Finally" | Finally.cs:70:13:70:40 | call to method WriteLine | | Finally.cs:70:31:70:39 | [finally: exception(Exception)] "Finally" | Finally.cs:70:13:70:40 | [finally: exception(Exception)] call to method WriteLine | | Finally.cs:70:31:70:39 | [finally: exception(IOException)] "Finally" | Finally.cs:70:13:70:40 | [finally: exception(IOException)] call to method WriteLine | -| Finally.cs:70:31:70:39 | [finally: exception(OutOfMemoryException)] "Finally" | Finally.cs:70:13:70:40 | [finally: exception(OutOfMemoryException)] call to method WriteLine | | Finally.cs:70:31:70:39 | [finally: return] "Finally" | Finally.cs:70:13:70:40 | [finally: return] call to method WriteLine | | Finally.cs:74:10:74:11 | enter M4 | Finally.cs:75:5:101:5 | {...} | | Finally.cs:75:5:101:5 | {...} | Finally.cs:76:9:76:19 | ... ...; | @@ -2026,16 +2011,12 @@ dominance | Finally.cs:137:13:137:36 | call to method WriteLine | Finally.cs:140:9:143:9 | {...} | | Finally.cs:137:13:137:37 | ...; | Finally.cs:137:31:137:35 | "Try" | | Finally.cs:137:31:137:35 | "Try" | Finally.cs:137:13:137:36 | call to method WriteLine | -| Finally.cs:137:31:137:35 | "Try" | Finally.cs:140:9:143:9 | [finally: exception(OutOfMemoryException)] {...} | | Finally.cs:140:9:143:9 | [finally: exception(Exception)] {...} | Finally.cs:141:41:141:42 | [finally: exception(Exception)] "" | -| Finally.cs:140:9:143:9 | [finally: exception(OutOfMemoryException)] {...} | Finally.cs:141:41:141:42 | [finally: exception(OutOfMemoryException)] "" | | Finally.cs:140:9:143:9 | {...} | Finally.cs:141:41:141:42 | "" | | Finally.cs:141:19:141:43 | [finally: exception(Exception)] object creation of type ArgumentException | Finally.cs:141:13:141:44 | [finally: exception(Exception)] throw ...; | -| Finally.cs:141:19:141:43 | [finally: exception(OutOfMemoryException)] object creation of type ArgumentException | Finally.cs:141:13:141:44 | [finally: exception(OutOfMemoryException)] throw ...; | | Finally.cs:141:19:141:43 | object creation of type ArgumentException | Finally.cs:141:13:141:44 | throw ...; | | Finally.cs:141:41:141:42 | "" | Finally.cs:141:19:141:43 | object creation of type ArgumentException | | Finally.cs:141:41:141:42 | [finally: exception(Exception)] "" | Finally.cs:141:19:141:43 | [finally: exception(Exception)] object creation of type ArgumentException | -| Finally.cs:141:41:141:42 | [finally: exception(OutOfMemoryException)] "" | Finally.cs:141:19:141:43 | [finally: exception(OutOfMemoryException)] object creation of type ArgumentException | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:148:5:170:5 | {...} | | Finally.cs:148:5:170:5 | {...} | Finally.cs:149:9:169:9 | try {...} ... | | Finally.cs:149:9:169:9 | try {...} ... | Finally.cs:150:9:153:9 | {...} | @@ -2082,56 +2063,38 @@ dominance | Finally.cs:159:27:159:44 | [finally: exception(Exception)] object creation of type Exception | Finally.cs:159:21:159:45 | [finally: exception(Exception)] throw ...; | | Finally.cs:159:27:159:44 | object creation of type Exception | Finally.cs:159:21:159:45 | throw ...; | | Finally.cs:159:41:159:43 | "1" | Finally.cs:159:27:159:44 | object creation of type Exception | -| Finally.cs:159:41:159:43 | "1" | Finally.cs:161:13:164:13 | [exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:159:41:159:43 | [finally: exception(ArgumentNullException)] "1" | Finally.cs:159:27:159:44 | [finally: exception(ArgumentNullException)] object creation of type Exception | -| Finally.cs:159:41:159:43 | [finally: exception(ArgumentNullException)] "1" | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:159:41:159:43 | [finally: exception(Exception)] "1" | Finally.cs:159:27:159:44 | [finally: exception(Exception)] object creation of type Exception | -| Finally.cs:159:41:159:43 | [finally: exception(Exception)] "1" | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:161:13:164:13 | [exception: Exception] catch (...) {...} | Finally.cs:161:30:161:30 | [exception: Exception] Exception e | | Finally.cs:161:13:164:13 | [exception: NullReferenceException] catch (...) {...} | Finally.cs:161:30:161:30 | [exception: NullReferenceException] Exception e | -| Finally.cs:161:13:164:13 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:161:30:161:30 | [exception: OutOfMemoryException] Exception e | | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: Exception] catch (...) {...} | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: Exception] Exception e | | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: NullReferenceException] catch (...) {...} | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: NullReferenceException] Exception e | -| Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] catch (...) {...} | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] Exception e | | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: Exception] catch (...) {...} | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: Exception] Exception e | | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: NullReferenceException] catch (...) {...} | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: NullReferenceException] Exception e | -| Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: OutOfMemoryException] catch (...) {...} | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: OutOfMemoryException] Exception e | | Finally.cs:161:30:161:30 | [exception: Exception] Exception e | Finally.cs:161:39:161:39 | [exception: Exception] access to local variable e | | Finally.cs:161:30:161:30 | [exception: NullReferenceException] Exception e | Finally.cs:161:39:161:39 | [exception: NullReferenceException] access to local variable e | -| Finally.cs:161:30:161:30 | [exception: OutOfMemoryException] Exception e | Finally.cs:161:39:161:39 | [exception: OutOfMemoryException] access to local variable e | | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: Exception] Exception e | Finally.cs:161:39:161:39 | [finally: exception(ArgumentNullException), exception: Exception] access to local variable e | | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: NullReferenceException] Exception e | Finally.cs:161:39:161:39 | [finally: exception(ArgumentNullException), exception: NullReferenceException] access to local variable e | -| Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] Exception e | Finally.cs:161:39:161:39 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] access to local variable e | | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: Exception] Exception e | Finally.cs:161:39:161:39 | [finally: exception(Exception), exception: Exception] access to local variable e | | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: NullReferenceException] Exception e | Finally.cs:161:39:161:39 | [finally: exception(Exception), exception: NullReferenceException] access to local variable e | -| Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: OutOfMemoryException] Exception e | Finally.cs:161:39:161:39 | [finally: exception(Exception), exception: OutOfMemoryException] access to local variable e | | Finally.cs:161:39:161:39 | [exception: Exception] access to local variable e | Finally.cs:161:39:161:47 | [exception: Exception] access to property Message | | Finally.cs:161:39:161:39 | [exception: NullReferenceException] access to local variable e | Finally.cs:161:39:161:47 | [exception: NullReferenceException] access to property Message | -| Finally.cs:161:39:161:39 | [exception: OutOfMemoryException] access to local variable e | Finally.cs:161:39:161:47 | [exception: OutOfMemoryException] access to property Message | | Finally.cs:161:39:161:39 | [finally: exception(ArgumentNullException), exception: Exception] access to local variable e | Finally.cs:161:39:161:47 | [finally: exception(ArgumentNullException), exception: Exception] access to property Message | | Finally.cs:161:39:161:39 | [finally: exception(ArgumentNullException), exception: NullReferenceException] access to local variable e | Finally.cs:161:39:161:47 | [finally: exception(ArgumentNullException), exception: NullReferenceException] access to property Message | -| Finally.cs:161:39:161:39 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] access to local variable e | Finally.cs:161:39:161:47 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] access to property Message | | Finally.cs:161:39:161:39 | [finally: exception(Exception), exception: Exception] access to local variable e | Finally.cs:161:39:161:47 | [finally: exception(Exception), exception: Exception] access to property Message | | Finally.cs:161:39:161:39 | [finally: exception(Exception), exception: NullReferenceException] access to local variable e | Finally.cs:161:39:161:47 | [finally: exception(Exception), exception: NullReferenceException] access to property Message | -| Finally.cs:161:39:161:39 | [finally: exception(Exception), exception: OutOfMemoryException] access to local variable e | Finally.cs:161:39:161:47 | [finally: exception(Exception), exception: OutOfMemoryException] access to property Message | | Finally.cs:161:39:161:47 | [exception: Exception] access to property Message | Finally.cs:161:52:161:54 | [exception: Exception] "1" | | Finally.cs:161:39:161:47 | [exception: NullReferenceException] access to property Message | Finally.cs:161:52:161:54 | [exception: NullReferenceException] "1" | -| Finally.cs:161:39:161:47 | [exception: OutOfMemoryException] access to property Message | Finally.cs:161:52:161:54 | [exception: OutOfMemoryException] "1" | | Finally.cs:161:39:161:47 | [finally: exception(ArgumentNullException), exception: Exception] access to property Message | Finally.cs:161:52:161:54 | [finally: exception(ArgumentNullException), exception: Exception] "1" | | Finally.cs:161:39:161:47 | [finally: exception(ArgumentNullException), exception: NullReferenceException] access to property Message | Finally.cs:161:52:161:54 | [finally: exception(ArgumentNullException), exception: NullReferenceException] "1" | -| Finally.cs:161:39:161:47 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] access to property Message | Finally.cs:161:52:161:54 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] "1" | | Finally.cs:161:39:161:47 | [finally: exception(Exception), exception: Exception] access to property Message | Finally.cs:161:52:161:54 | [finally: exception(Exception), exception: Exception] "1" | | Finally.cs:161:39:161:47 | [finally: exception(Exception), exception: NullReferenceException] access to property Message | Finally.cs:161:52:161:54 | [finally: exception(Exception), exception: NullReferenceException] "1" | -| Finally.cs:161:39:161:47 | [finally: exception(Exception), exception: OutOfMemoryException] access to property Message | Finally.cs:161:52:161:54 | [finally: exception(Exception), exception: OutOfMemoryException] "1" | | Finally.cs:161:52:161:54 | [exception: Exception] "1" | Finally.cs:161:39:161:54 | [exception: Exception] ... == ... | | Finally.cs:161:52:161:54 | [exception: NullReferenceException] "1" | Finally.cs:161:39:161:54 | [exception: NullReferenceException] ... == ... | -| Finally.cs:161:52:161:54 | [exception: OutOfMemoryException] "1" | Finally.cs:161:39:161:54 | [exception: OutOfMemoryException] ... == ... | | Finally.cs:161:52:161:54 | [finally: exception(ArgumentNullException), exception: Exception] "1" | Finally.cs:161:39:161:54 | [finally: exception(ArgumentNullException), exception: Exception] ... == ... | | Finally.cs:161:52:161:54 | [finally: exception(ArgumentNullException), exception: NullReferenceException] "1" | Finally.cs:161:39:161:54 | [finally: exception(ArgumentNullException), exception: NullReferenceException] ... == ... | -| Finally.cs:161:52:161:54 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] "1" | Finally.cs:161:39:161:54 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] ... == ... | | Finally.cs:161:52:161:54 | [finally: exception(Exception), exception: Exception] "1" | Finally.cs:161:39:161:54 | [finally: exception(Exception), exception: Exception] ... == ... | | Finally.cs:161:52:161:54 | [finally: exception(Exception), exception: NullReferenceException] "1" | Finally.cs:161:39:161:54 | [finally: exception(Exception), exception: NullReferenceException] ... == ... | -| Finally.cs:161:52:161:54 | [finally: exception(Exception), exception: OutOfMemoryException] "1" | Finally.cs:161:39:161:54 | [finally: exception(Exception), exception: OutOfMemoryException] ... == ... | | Finally.cs:162:13:164:13 | [finally: exception(ArgumentNullException)] {...} | Finally.cs:163:17:163:43 | [finally: exception(ArgumentNullException)] ...; | | Finally.cs:162:13:164:13 | [finally: exception(Exception)] {...} | Finally.cs:163:17:163:43 | [finally: exception(Exception)] ...; | | Finally.cs:162:13:164:13 | {...} | Finally.cs:163:17:163:43 | ...; | @@ -2305,9 +2268,10 @@ dominance | Finally.cs:217:5:231:5 | {...} | Finally.cs:218:9:229:9 | try {...} ... | | Finally.cs:218:9:229:9 | try {...} ... | Finally.cs:219:9:221:9 | {...} | | Finally.cs:219:9:221:9 | {...} | Finally.cs:220:13:220:37 | ...; | +| Finally.cs:220:13:220:36 | call to method WriteLine | Finally.cs:222:9:225:9 | catch {...} | +| Finally.cs:220:13:220:36 | call to method WriteLine | Finally.cs:227:9:229:9 | {...} | | Finally.cs:220:13:220:37 | ...; | Finally.cs:220:31:220:35 | "Try" | | Finally.cs:220:31:220:35 | "Try" | Finally.cs:220:13:220:36 | call to method WriteLine | -| Finally.cs:220:31:220:35 | "Try" | Finally.cs:222:9:225:9 | catch {...} | | Finally.cs:222:9:225:9 | catch {...} | Finally.cs:223:9:225:9 | {...} | | Finally.cs:223:9:225:9 | {...} | Finally.cs:224:13:224:39 | ...; | | Finally.cs:224:13:224:39 | ...; | Finally.cs:224:31:224:37 | "Catch" | @@ -2389,20 +2353,16 @@ dominance | Finally.cs:254:13:254:44 | call to method WriteLine | Finally.cs:257:9:259:9 | {...} | | Finally.cs:254:13:254:45 | ...; | Finally.cs:254:31:254:43 | "Mid finally" | | Finally.cs:254:31:254:43 | "Mid finally" | Finally.cs:254:13:254:44 | call to method WriteLine | -| Finally.cs:254:31:254:43 | "Mid finally" | Finally.cs:257:9:259:9 | [finally: exception(OutOfMemoryException)] {...} | | Finally.cs:257:9:259:9 | [finally: exception(Exception)] {...} | Finally.cs:258:13:258:47 | [finally: exception(Exception)] ...; | | Finally.cs:257:9:259:9 | [finally: exception(ExceptionA)] {...} | Finally.cs:258:13:258:47 | [finally: exception(ExceptionA)] ...; | -| Finally.cs:257:9:259:9 | [finally: exception(OutOfMemoryException)] {...} | Finally.cs:258:13:258:47 | [finally: exception(OutOfMemoryException)] ...; | | Finally.cs:257:9:259:9 | {...} | Finally.cs:258:13:258:47 | ...; | | Finally.cs:258:13:258:46 | call to method WriteLine | Finally.cs:260:9:260:34 | ...; | | Finally.cs:258:13:258:47 | ...; | Finally.cs:258:31:258:45 | "Outer finally" | | Finally.cs:258:13:258:47 | [finally: exception(Exception)] ...; | Finally.cs:258:31:258:45 | [finally: exception(Exception)] "Outer finally" | | Finally.cs:258:13:258:47 | [finally: exception(ExceptionA)] ...; | Finally.cs:258:31:258:45 | [finally: exception(ExceptionA)] "Outer finally" | -| Finally.cs:258:13:258:47 | [finally: exception(OutOfMemoryException)] ...; | Finally.cs:258:31:258:45 | [finally: exception(OutOfMemoryException)] "Outer finally" | | Finally.cs:258:31:258:45 | "Outer finally" | Finally.cs:258:13:258:46 | call to method WriteLine | | Finally.cs:258:31:258:45 | [finally: exception(Exception)] "Outer finally" | Finally.cs:258:13:258:46 | [finally: exception(Exception)] call to method WriteLine | | Finally.cs:258:31:258:45 | [finally: exception(ExceptionA)] "Outer finally" | Finally.cs:258:13:258:46 | [finally: exception(ExceptionA)] call to method WriteLine | -| Finally.cs:258:31:258:45 | [finally: exception(OutOfMemoryException)] "Outer finally" | Finally.cs:258:13:258:46 | [finally: exception(OutOfMemoryException)] call to method WriteLine | | Finally.cs:260:9:260:33 | call to method WriteLine | Finally.cs:233:10:233:12 | exit M12 (normal) | | Finally.cs:260:9:260:34 | ...; | Finally.cs:260:27:260:32 | "Done" | | Finally.cs:260:27:260:32 | "Done" | Finally.cs:260:9:260:33 | call to method WriteLine | @@ -5773,6 +5733,7 @@ postDominance | Extensions.cs:25:9:25:34 | ...; | Extensions.cs:24:9:24:45 | call to method ToBool | | Extensions.cs:25:23:25:32 | access to method Parse | Extensions.cs:25:9:25:14 | "true" | | Extensions.cs:25:23:25:32 | delegate creation of type Func | Extensions.cs:25:23:25:32 | access to method Parse | +| Finally.cs:7:10:7:11 | exit M1 (abnormal) | Finally.cs:15:13:15:40 | [finally: exception(Exception)] call to method WriteLine | | Finally.cs:7:10:7:11 | exit M1 (normal) | Finally.cs:15:13:15:40 | call to method WriteLine | | Finally.cs:8:5:17:5 | {...} | Finally.cs:7:10:7:11 | enter M1 | | Finally.cs:9:9:16:9 | try {...} ... | Finally.cs:8:5:17:5 | {...} | @@ -5782,25 +5743,22 @@ postDominance | Finally.cs:11:31:11:36 | "Try1" | Finally.cs:11:13:11:38 | ...; | | Finally.cs:14:9:16:9 | {...} | Finally.cs:11:13:11:37 | call to method WriteLine | | Finally.cs:15:13:15:40 | [finally: exception(Exception)] call to method WriteLine | Finally.cs:15:31:15:39 | [finally: exception(Exception)] "Finally" | -| Finally.cs:15:13:15:40 | [finally: exception(OutOfMemoryException)] call to method WriteLine | Finally.cs:15:31:15:39 | [finally: exception(OutOfMemoryException)] "Finally" | | Finally.cs:15:13:15:40 | call to method WriteLine | Finally.cs:15:31:15:39 | "Finally" | | Finally.cs:15:13:15:41 | ...; | Finally.cs:14:9:16:9 | {...} | | Finally.cs:15:13:15:41 | [finally: exception(Exception)] ...; | Finally.cs:14:9:16:9 | [finally: exception(Exception)] {...} | -| Finally.cs:15:13:15:41 | [finally: exception(OutOfMemoryException)] ...; | Finally.cs:14:9:16:9 | [finally: exception(OutOfMemoryException)] {...} | | Finally.cs:15:31:15:39 | "Finally" | Finally.cs:15:13:15:41 | ...; | | Finally.cs:15:31:15:39 | [finally: exception(Exception)] "Finally" | Finally.cs:15:13:15:41 | [finally: exception(Exception)] ...; | -| Finally.cs:15:31:15:39 | [finally: exception(OutOfMemoryException)] "Finally" | Finally.cs:15:13:15:41 | [finally: exception(OutOfMemoryException)] ...; | | Finally.cs:19:10:19:11 | exit M2 (normal) | Finally.cs:50:13:50:40 | [finally: return] call to method WriteLine | | Finally.cs:19:10:19:11 | exit M2 (normal) | Finally.cs:50:13:50:40 | call to method WriteLine | | Finally.cs:20:5:52:5 | {...} | Finally.cs:19:10:19:11 | enter M2 | | Finally.cs:21:9:51:9 | try {...} ... | Finally.cs:20:5:52:5 | {...} | | Finally.cs:22:9:25:9 | {...} | Finally.cs:21:9:51:9 | try {...} ... | +| Finally.cs:23:13:23:37 | call to method WriteLine | Finally.cs:23:31:23:36 | "Try2" | | Finally.cs:23:13:23:38 | ...; | Finally.cs:22:9:25:9 | {...} | | Finally.cs:23:31:23:36 | "Try2" | Finally.cs:23:13:23:38 | ...; | | Finally.cs:26:48:26:51 | [exception: Exception] true | Finally.cs:26:38:26:39 | [exception: Exception] IOException ex | | Finally.cs:28:13:28:18 | throw ...; | Finally.cs:27:9:29:9 | {...} | | Finally.cs:30:9:40:9 | [exception: Exception] catch (...) {...} | Finally.cs:26:9:29:9 | [exception: Exception] catch (...) {...} | -| Finally.cs:30:9:40:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:26:9:29:9 | [exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:31:9:40:9 | {...} | Finally.cs:30:41:30:42 | [exception: Exception] ArgumentException ex | | Finally.cs:32:13:39:13 | try {...} ... | Finally.cs:31:9:40:9 | {...} | | Finally.cs:33:13:35:13 | {...} | Finally.cs:32:13:39:13 | try {...} ... | @@ -5811,9 +5769,7 @@ postDominance | Finally.cs:38:23:38:43 | [finally: exception(ArgumentException)] object creation of type Exception | Finally.cs:38:37:38:42 | [finally: exception(ArgumentException)] "Boo!" | | Finally.cs:38:37:38:42 | [finally: exception(ArgumentException)] "Boo!" | Finally.cs:37:13:39:13 | [finally: exception(ArgumentException)] {...} | | Finally.cs:41:9:43:9 | [exception: Exception] catch (...) {...} | Finally.cs:30:9:40:9 | [exception: Exception] catch (...) {...} | -| Finally.cs:41:9:43:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:30:9:40:9 | [exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:42:9:43:9 | {...} | Finally.cs:41:9:43:9 | [exception: Exception] catch (...) {...} | -| Finally.cs:42:9:43:9 | {...} | Finally.cs:41:9:43:9 | [exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:49:9:51:9 | [finally: exception(Exception)] {...} | Finally.cs:38:17:38:44 | [finally: exception(ArgumentException)] throw ...; | | Finally.cs:49:9:51:9 | [finally: exception(IOException)] {...} | Finally.cs:28:13:28:18 | throw ...; | | Finally.cs:49:9:51:9 | [finally: return] {...} | Finally.cs:24:13:24:19 | return ...; | @@ -5835,41 +5791,32 @@ postDominance | Finally.cs:55:5:72:5 | {...} | Finally.cs:54:10:54:11 | enter M3 | | Finally.cs:56:9:71:9 | try {...} ... | Finally.cs:55:5:72:5 | {...} | | Finally.cs:57:9:60:9 | {...} | Finally.cs:56:9:71:9 | try {...} ... | +| Finally.cs:58:13:58:37 | call to method WriteLine | Finally.cs:58:31:58:36 | "Try3" | | Finally.cs:58:13:58:38 | ...; | Finally.cs:57:9:60:9 | {...} | | Finally.cs:58:31:58:36 | "Try3" | Finally.cs:58:13:58:38 | ...; | | Finally.cs:61:48:61:51 | [exception: Exception] true | Finally.cs:61:38:61:39 | [exception: Exception] IOException ex | | Finally.cs:63:13:63:18 | throw ...; | Finally.cs:62:9:64:9 | {...} | | Finally.cs:65:9:67:9 | [exception: Exception] catch (...) {...} | Finally.cs:61:9:64:9 | [exception: Exception] catch (...) {...} | -| Finally.cs:65:9:67:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:61:9:64:9 | [exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:65:26:65:26 | [exception: Exception] Exception e | Finally.cs:65:9:67:9 | [exception: Exception] catch (...) {...} | -| Finally.cs:65:26:65:26 | [exception: OutOfMemoryException] Exception e | Finally.cs:65:9:67:9 | [exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:65:35:65:35 | [exception: Exception] access to local variable e | Finally.cs:65:26:65:26 | [exception: Exception] Exception e | -| Finally.cs:65:35:65:35 | [exception: OutOfMemoryException] access to local variable e | Finally.cs:65:26:65:26 | [exception: OutOfMemoryException] Exception e | | Finally.cs:65:35:65:43 | [exception: Exception] access to property Message | Finally.cs:65:35:65:35 | [exception: Exception] access to local variable e | -| Finally.cs:65:35:65:43 | [exception: OutOfMemoryException] access to property Message | Finally.cs:65:35:65:35 | [exception: OutOfMemoryException] access to local variable e | | Finally.cs:65:35:65:51 | [exception: Exception] ... != ... | Finally.cs:65:48:65:51 | [exception: Exception] null | -| Finally.cs:65:35:65:51 | [exception: OutOfMemoryException] ... != ... | Finally.cs:65:48:65:51 | [exception: OutOfMemoryException] null | | Finally.cs:65:48:65:51 | [exception: Exception] null | Finally.cs:65:35:65:43 | [exception: Exception] access to property Message | -| Finally.cs:65:48:65:51 | [exception: OutOfMemoryException] null | Finally.cs:65:35:65:43 | [exception: OutOfMemoryException] access to property Message | | Finally.cs:66:9:67:9 | {...} | Finally.cs:65:35:65:51 | [exception: Exception] ... != ... | -| Finally.cs:66:9:67:9 | {...} | Finally.cs:65:35:65:51 | [exception: OutOfMemoryException] ... != ... | | Finally.cs:69:9:71:9 | [finally: exception(IOException)] {...} | Finally.cs:63:13:63:18 | throw ...; | | Finally.cs:69:9:71:9 | [finally: return] {...} | Finally.cs:59:13:59:19 | return ...; | | Finally.cs:69:9:71:9 | {...} | Finally.cs:66:9:67:9 | {...} | | Finally.cs:70:13:70:40 | [finally: exception(Exception)] call to method WriteLine | Finally.cs:70:31:70:39 | [finally: exception(Exception)] "Finally" | | Finally.cs:70:13:70:40 | [finally: exception(IOException)] call to method WriteLine | Finally.cs:70:31:70:39 | [finally: exception(IOException)] "Finally" | -| Finally.cs:70:13:70:40 | [finally: exception(OutOfMemoryException)] call to method WriteLine | Finally.cs:70:31:70:39 | [finally: exception(OutOfMemoryException)] "Finally" | | Finally.cs:70:13:70:40 | [finally: return] call to method WriteLine | Finally.cs:70:31:70:39 | [finally: return] "Finally" | | Finally.cs:70:13:70:40 | call to method WriteLine | Finally.cs:70:31:70:39 | "Finally" | | Finally.cs:70:13:70:41 | ...; | Finally.cs:69:9:71:9 | {...} | | Finally.cs:70:13:70:41 | [finally: exception(Exception)] ...; | Finally.cs:69:9:71:9 | [finally: exception(Exception)] {...} | | Finally.cs:70:13:70:41 | [finally: exception(IOException)] ...; | Finally.cs:69:9:71:9 | [finally: exception(IOException)] {...} | -| Finally.cs:70:13:70:41 | [finally: exception(OutOfMemoryException)] ...; | Finally.cs:69:9:71:9 | [finally: exception(OutOfMemoryException)] {...} | | Finally.cs:70:13:70:41 | [finally: return] ...; | Finally.cs:69:9:71:9 | [finally: return] {...} | | Finally.cs:70:31:70:39 | "Finally" | Finally.cs:70:13:70:41 | ...; | | Finally.cs:70:31:70:39 | [finally: exception(Exception)] "Finally" | Finally.cs:70:13:70:41 | [finally: exception(Exception)] ...; | | Finally.cs:70:31:70:39 | [finally: exception(IOException)] "Finally" | Finally.cs:70:13:70:41 | [finally: exception(IOException)] ...; | -| Finally.cs:70:31:70:39 | [finally: exception(OutOfMemoryException)] "Finally" | Finally.cs:70:13:70:41 | [finally: exception(OutOfMemoryException)] ...; | | Finally.cs:70:31:70:39 | [finally: return] "Finally" | Finally.cs:70:13:70:41 | [finally: return] ...; | | Finally.cs:74:10:74:11 | exit M4 (normal) | Finally.cs:77:16:77:20 | ... > ... | | Finally.cs:74:10:74:11 | exit M4 (normal) | Finally.cs:97:21:97:23 | [finally: break] ...-- | @@ -6073,17 +6020,15 @@ postDominance | Finally.cs:134:5:145:5 | {...} | Finally.cs:133:10:133:11 | enter M7 | | Finally.cs:135:9:143:9 | try {...} ... | Finally.cs:134:5:145:5 | {...} | | Finally.cs:136:9:138:9 | {...} | Finally.cs:135:9:143:9 | try {...} ... | +| Finally.cs:137:13:137:36 | call to method WriteLine | Finally.cs:137:31:137:35 | "Try" | | Finally.cs:137:13:137:37 | ...; | Finally.cs:136:9:138:9 | {...} | | Finally.cs:137:31:137:35 | "Try" | Finally.cs:137:13:137:37 | ...; | | Finally.cs:141:13:141:44 | [finally: exception(Exception)] throw ...; | Finally.cs:141:19:141:43 | [finally: exception(Exception)] object creation of type ArgumentException | -| Finally.cs:141:13:141:44 | [finally: exception(OutOfMemoryException)] throw ...; | Finally.cs:141:19:141:43 | [finally: exception(OutOfMemoryException)] object creation of type ArgumentException | | Finally.cs:141:13:141:44 | throw ...; | Finally.cs:141:19:141:43 | object creation of type ArgumentException | | Finally.cs:141:19:141:43 | [finally: exception(Exception)] object creation of type ArgumentException | Finally.cs:141:41:141:42 | [finally: exception(Exception)] "" | -| Finally.cs:141:19:141:43 | [finally: exception(OutOfMemoryException)] object creation of type ArgumentException | Finally.cs:141:41:141:42 | [finally: exception(OutOfMemoryException)] "" | | Finally.cs:141:19:141:43 | object creation of type ArgumentException | Finally.cs:141:41:141:42 | "" | | Finally.cs:141:41:141:42 | "" | Finally.cs:140:9:143:9 | {...} | | Finally.cs:141:41:141:42 | [finally: exception(Exception)] "" | Finally.cs:140:9:143:9 | [finally: exception(Exception)] {...} | -| Finally.cs:141:41:141:42 | [finally: exception(OutOfMemoryException)] "" | Finally.cs:140:9:143:9 | [finally: exception(OutOfMemoryException)] {...} | | Finally.cs:147:10:147:11 | exit M8 (normal) | Finally.cs:158:21:158:36 | ... == ... | | Finally.cs:147:10:147:11 | exit M8 (normal) | Finally.cs:163:17:163:42 | call to method WriteLine | | Finally.cs:147:10:147:11 | exit M8 (normal) | Finally.cs:167:17:167:37 | call to method WriteLine | @@ -6114,47 +6059,37 @@ postDominance | Finally.cs:158:21:158:36 | ... == ... | Finally.cs:158:36:158:36 | 1 | | Finally.cs:158:21:158:36 | [finally: exception(ArgumentNullException)] ... == ... | Finally.cs:158:36:158:36 | [finally: exception(ArgumentNullException)] 1 | | Finally.cs:158:21:158:36 | [finally: exception(Exception)] ... == ... | Finally.cs:158:36:158:36 | [finally: exception(Exception)] 1 | +| Finally.cs:159:27:159:44 | [finally: exception(ArgumentNullException)] object creation of type Exception | Finally.cs:159:41:159:43 | [finally: exception(ArgumentNullException)] "1" | +| Finally.cs:159:27:159:44 | [finally: exception(Exception)] object creation of type Exception | Finally.cs:159:41:159:43 | [finally: exception(Exception)] "1" | +| Finally.cs:159:27:159:44 | object creation of type Exception | Finally.cs:159:41:159:43 | "1" | | Finally.cs:161:13:164:13 | [exception: Exception] catch (...) {...} | Finally.cs:159:21:159:45 | throw ...; | | Finally.cs:161:13:164:13 | [exception: Exception] catch (...) {...} | Finally.cs:159:27:159:44 | object creation of type Exception | | Finally.cs:161:30:161:30 | [exception: Exception] Exception e | Finally.cs:161:13:164:13 | [exception: Exception] catch (...) {...} | | Finally.cs:161:30:161:30 | [exception: NullReferenceException] Exception e | Finally.cs:161:13:164:13 | [exception: NullReferenceException] catch (...) {...} | -| Finally.cs:161:30:161:30 | [exception: OutOfMemoryException] Exception e | Finally.cs:161:13:164:13 | [exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:161:39:161:39 | [exception: Exception] access to local variable e | Finally.cs:161:30:161:30 | [exception: Exception] Exception e | | Finally.cs:161:39:161:39 | [exception: NullReferenceException] access to local variable e | Finally.cs:161:30:161:30 | [exception: NullReferenceException] Exception e | -| Finally.cs:161:39:161:39 | [exception: OutOfMemoryException] access to local variable e | Finally.cs:161:30:161:30 | [exception: OutOfMemoryException] Exception e | | Finally.cs:161:39:161:39 | [finally: exception(ArgumentNullException), exception: Exception] access to local variable e | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: Exception] Exception e | | Finally.cs:161:39:161:39 | [finally: exception(ArgumentNullException), exception: NullReferenceException] access to local variable e | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: NullReferenceException] Exception e | -| Finally.cs:161:39:161:39 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] access to local variable e | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] Exception e | | Finally.cs:161:39:161:39 | [finally: exception(Exception), exception: Exception] access to local variable e | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: Exception] Exception e | | Finally.cs:161:39:161:39 | [finally: exception(Exception), exception: NullReferenceException] access to local variable e | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: NullReferenceException] Exception e | -| Finally.cs:161:39:161:39 | [finally: exception(Exception), exception: OutOfMemoryException] access to local variable e | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: OutOfMemoryException] Exception e | | Finally.cs:161:39:161:47 | [exception: Exception] access to property Message | Finally.cs:161:39:161:39 | [exception: Exception] access to local variable e | | Finally.cs:161:39:161:47 | [exception: NullReferenceException] access to property Message | Finally.cs:161:39:161:39 | [exception: NullReferenceException] access to local variable e | -| Finally.cs:161:39:161:47 | [exception: OutOfMemoryException] access to property Message | Finally.cs:161:39:161:39 | [exception: OutOfMemoryException] access to local variable e | | Finally.cs:161:39:161:47 | [finally: exception(ArgumentNullException), exception: Exception] access to property Message | Finally.cs:161:39:161:39 | [finally: exception(ArgumentNullException), exception: Exception] access to local variable e | | Finally.cs:161:39:161:47 | [finally: exception(ArgumentNullException), exception: NullReferenceException] access to property Message | Finally.cs:161:39:161:39 | [finally: exception(ArgumentNullException), exception: NullReferenceException] access to local variable e | -| Finally.cs:161:39:161:47 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] access to property Message | Finally.cs:161:39:161:39 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] access to local variable e | | Finally.cs:161:39:161:47 | [finally: exception(Exception), exception: Exception] access to property Message | Finally.cs:161:39:161:39 | [finally: exception(Exception), exception: Exception] access to local variable e | | Finally.cs:161:39:161:47 | [finally: exception(Exception), exception: NullReferenceException] access to property Message | Finally.cs:161:39:161:39 | [finally: exception(Exception), exception: NullReferenceException] access to local variable e | -| Finally.cs:161:39:161:47 | [finally: exception(Exception), exception: OutOfMemoryException] access to property Message | Finally.cs:161:39:161:39 | [finally: exception(Exception), exception: OutOfMemoryException] access to local variable e | | Finally.cs:161:39:161:54 | [exception: Exception] ... == ... | Finally.cs:161:52:161:54 | [exception: Exception] "1" | | Finally.cs:161:39:161:54 | [exception: NullReferenceException] ... == ... | Finally.cs:161:52:161:54 | [exception: NullReferenceException] "1" | -| Finally.cs:161:39:161:54 | [exception: OutOfMemoryException] ... == ... | Finally.cs:161:52:161:54 | [exception: OutOfMemoryException] "1" | | Finally.cs:161:39:161:54 | [finally: exception(ArgumentNullException), exception: Exception] ... == ... | Finally.cs:161:52:161:54 | [finally: exception(ArgumentNullException), exception: Exception] "1" | | Finally.cs:161:39:161:54 | [finally: exception(ArgumentNullException), exception: NullReferenceException] ... == ... | Finally.cs:161:52:161:54 | [finally: exception(ArgumentNullException), exception: NullReferenceException] "1" | -| Finally.cs:161:39:161:54 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] ... == ... | Finally.cs:161:52:161:54 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] "1" | | Finally.cs:161:39:161:54 | [finally: exception(Exception), exception: Exception] ... == ... | Finally.cs:161:52:161:54 | [finally: exception(Exception), exception: Exception] "1" | | Finally.cs:161:39:161:54 | [finally: exception(Exception), exception: NullReferenceException] ... == ... | Finally.cs:161:52:161:54 | [finally: exception(Exception), exception: NullReferenceException] "1" | -| Finally.cs:161:39:161:54 | [finally: exception(Exception), exception: OutOfMemoryException] ... == ... | Finally.cs:161:52:161:54 | [finally: exception(Exception), exception: OutOfMemoryException] "1" | | Finally.cs:161:52:161:54 | [exception: Exception] "1" | Finally.cs:161:39:161:47 | [exception: Exception] access to property Message | | Finally.cs:161:52:161:54 | [exception: NullReferenceException] "1" | Finally.cs:161:39:161:47 | [exception: NullReferenceException] access to property Message | -| Finally.cs:161:52:161:54 | [exception: OutOfMemoryException] "1" | Finally.cs:161:39:161:47 | [exception: OutOfMemoryException] access to property Message | | Finally.cs:161:52:161:54 | [finally: exception(ArgumentNullException), exception: Exception] "1" | Finally.cs:161:39:161:47 | [finally: exception(ArgumentNullException), exception: Exception] access to property Message | | Finally.cs:161:52:161:54 | [finally: exception(ArgumentNullException), exception: NullReferenceException] "1" | Finally.cs:161:39:161:47 | [finally: exception(ArgumentNullException), exception: NullReferenceException] access to property Message | -| Finally.cs:161:52:161:54 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] "1" | Finally.cs:161:39:161:47 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] access to property Message | | Finally.cs:161:52:161:54 | [finally: exception(Exception), exception: Exception] "1" | Finally.cs:161:39:161:47 | [finally: exception(Exception), exception: Exception] access to property Message | | Finally.cs:161:52:161:54 | [finally: exception(Exception), exception: NullReferenceException] "1" | Finally.cs:161:39:161:47 | [finally: exception(Exception), exception: NullReferenceException] access to property Message | -| Finally.cs:161:52:161:54 | [finally: exception(Exception), exception: OutOfMemoryException] "1" | Finally.cs:161:39:161:47 | [finally: exception(Exception), exception: OutOfMemoryException] access to property Message | | Finally.cs:163:17:163:42 | [finally: exception(ArgumentNullException)] call to method WriteLine | Finally.cs:163:35:163:41 | [finally: exception(ArgumentNullException)] access to array element | | Finally.cs:163:17:163:42 | [finally: exception(Exception)] call to method WriteLine | Finally.cs:163:35:163:41 | [finally: exception(Exception)] access to array element | | Finally.cs:163:17:163:42 | call to method WriteLine | Finally.cs:163:35:163:41 | access to array element | @@ -6288,6 +6223,7 @@ postDominance | Finally.cs:217:5:231:5 | {...} | Finally.cs:216:10:216:12 | enter M11 | | Finally.cs:218:9:229:9 | try {...} ... | Finally.cs:217:5:231:5 | {...} | | Finally.cs:219:9:221:9 | {...} | Finally.cs:218:9:229:9 | try {...} ... | +| Finally.cs:220:13:220:36 | call to method WriteLine | Finally.cs:220:31:220:35 | "Try" | | Finally.cs:220:13:220:37 | ...; | Finally.cs:219:9:221:9 | {...} | | Finally.cs:220:31:220:35 | "Try" | Finally.cs:220:13:220:37 | ...; | | Finally.cs:223:9:225:9 | {...} | Finally.cs:222:9:225:9 | catch {...} | @@ -6361,16 +6297,13 @@ postDominance | Finally.cs:257:9:259:9 | {...} | Finally.cs:254:13:254:44 | call to method WriteLine | | Finally.cs:258:13:258:46 | [finally: exception(Exception)] call to method WriteLine | Finally.cs:258:31:258:45 | [finally: exception(Exception)] "Outer finally" | | Finally.cs:258:13:258:46 | [finally: exception(ExceptionA)] call to method WriteLine | Finally.cs:258:31:258:45 | [finally: exception(ExceptionA)] "Outer finally" | -| Finally.cs:258:13:258:46 | [finally: exception(OutOfMemoryException)] call to method WriteLine | Finally.cs:258:31:258:45 | [finally: exception(OutOfMemoryException)] "Outer finally" | | Finally.cs:258:13:258:46 | call to method WriteLine | Finally.cs:258:31:258:45 | "Outer finally" | | Finally.cs:258:13:258:47 | ...; | Finally.cs:257:9:259:9 | {...} | | Finally.cs:258:13:258:47 | [finally: exception(Exception)] ...; | Finally.cs:257:9:259:9 | [finally: exception(Exception)] {...} | | Finally.cs:258:13:258:47 | [finally: exception(ExceptionA)] ...; | Finally.cs:257:9:259:9 | [finally: exception(ExceptionA)] {...} | -| Finally.cs:258:13:258:47 | [finally: exception(OutOfMemoryException)] ...; | Finally.cs:257:9:259:9 | [finally: exception(OutOfMemoryException)] {...} | | Finally.cs:258:31:258:45 | "Outer finally" | Finally.cs:258:13:258:47 | ...; | | Finally.cs:258:31:258:45 | [finally: exception(Exception)] "Outer finally" | Finally.cs:258:13:258:47 | [finally: exception(Exception)] ...; | | Finally.cs:258:31:258:45 | [finally: exception(ExceptionA)] "Outer finally" | Finally.cs:258:13:258:47 | [finally: exception(ExceptionA)] ...; | -| Finally.cs:258:31:258:45 | [finally: exception(OutOfMemoryException)] "Outer finally" | Finally.cs:258:13:258:47 | [finally: exception(OutOfMemoryException)] ...; | | Finally.cs:260:9:260:33 | call to method WriteLine | Finally.cs:260:27:260:32 | "Done" | | Finally.cs:260:9:260:34 | ...; | Finally.cs:258:13:258:46 | call to method WriteLine | | Finally.cs:260:27:260:32 | "Done" | Finally.cs:260:9:260:34 | ...; | @@ -9983,49 +9916,27 @@ blockDominance | Extensions.cs:20:17:20:20 | enter Main | Extensions.cs:20:17:20:20 | enter Main | | Finally.cs:7:10:7:11 | enter M1 | Finally.cs:7:10:7:11 | enter M1 | | Finally.cs:7:10:7:11 | enter M1 | Finally.cs:7:10:7:11 | exit M1 | -| Finally.cs:7:10:7:11 | enter M1 | Finally.cs:7:10:7:11 | exit M1 (abnormal) | -| Finally.cs:7:10:7:11 | enter M1 | Finally.cs:11:13:11:37 | call to method WriteLine | | Finally.cs:7:10:7:11 | enter M1 | Finally.cs:14:9:16:9 | [finally: exception(Exception)] {...} | -| Finally.cs:7:10:7:11 | enter M1 | Finally.cs:14:9:16:9 | [finally: exception(OutOfMemoryException)] {...} | | Finally.cs:7:10:7:11 | enter M1 | Finally.cs:14:9:16:9 | {...} | | Finally.cs:7:10:7:11 | exit M1 | Finally.cs:7:10:7:11 | exit M1 | -| Finally.cs:7:10:7:11 | exit M1 (abnormal) | Finally.cs:7:10:7:11 | exit M1 (abnormal) | -| Finally.cs:11:13:11:37 | call to method WriteLine | Finally.cs:11:13:11:37 | call to method WriteLine | -| Finally.cs:11:13:11:37 | call to method WriteLine | Finally.cs:14:9:16:9 | [finally: exception(Exception)] {...} | -| Finally.cs:11:13:11:37 | call to method WriteLine | Finally.cs:14:9:16:9 | {...} | | Finally.cs:14:9:16:9 | [finally: exception(Exception)] {...} | Finally.cs:14:9:16:9 | [finally: exception(Exception)] {...} | -| Finally.cs:14:9:16:9 | [finally: exception(OutOfMemoryException)] {...} | Finally.cs:14:9:16:9 | [finally: exception(OutOfMemoryException)] {...} | | Finally.cs:14:9:16:9 | {...} | Finally.cs:14:9:16:9 | {...} | | Finally.cs:19:10:19:11 | enter M2 | Finally.cs:19:10:19:11 | enter M2 | | Finally.cs:19:10:19:11 | enter M2 | Finally.cs:19:10:19:11 | exit M2 | | Finally.cs:19:10:19:11 | enter M2 | Finally.cs:19:10:19:11 | exit M2 (abnormal) | | Finally.cs:19:10:19:11 | enter M2 | Finally.cs:19:10:19:11 | exit M2 (normal) | -| Finally.cs:19:10:19:11 | enter M2 | Finally.cs:23:13:23:37 | call to method WriteLine | | Finally.cs:19:10:19:11 | enter M2 | Finally.cs:24:13:24:19 | return ...; | | Finally.cs:19:10:19:11 | enter M2 | Finally.cs:26:9:29:9 | [exception: Exception] catch (...) {...} | -| Finally.cs:19:10:19:11 | enter M2 | Finally.cs:26:9:29:9 | [exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:19:10:19:11 | enter M2 | Finally.cs:26:38:26:39 | [exception: Exception] IOException ex | | Finally.cs:19:10:19:11 | enter M2 | Finally.cs:27:9:29:9 | {...} | | Finally.cs:19:10:19:11 | enter M2 | Finally.cs:30:9:40:9 | [exception: Exception] catch (...) {...} | -| Finally.cs:19:10:19:11 | enter M2 | Finally.cs:30:9:40:9 | [exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:19:10:19:11 | enter M2 | Finally.cs:30:41:30:42 | [exception: Exception] ArgumentException ex | | Finally.cs:19:10:19:11 | enter M2 | Finally.cs:34:27:34:32 | throw ...; | | Finally.cs:19:10:19:11 | enter M2 | Finally.cs:41:9:43:9 | [exception: Exception] catch (...) {...} | -| Finally.cs:19:10:19:11 | enter M2 | Finally.cs:41:9:43:9 | [exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:19:10:19:11 | enter M2 | Finally.cs:42:9:43:9 | {...} | | Finally.cs:19:10:19:11 | exit M2 | Finally.cs:19:10:19:11 | exit M2 | | Finally.cs:19:10:19:11 | exit M2 (abnormal) | Finally.cs:19:10:19:11 | exit M2 (abnormal) | | Finally.cs:19:10:19:11 | exit M2 (normal) | Finally.cs:19:10:19:11 | exit M2 (normal) | -| Finally.cs:23:13:23:37 | call to method WriteLine | Finally.cs:19:10:19:11 | exit M2 (abnormal) | -| Finally.cs:23:13:23:37 | call to method WriteLine | Finally.cs:23:13:23:37 | call to method WriteLine | -| Finally.cs:23:13:23:37 | call to method WriteLine | Finally.cs:24:13:24:19 | return ...; | -| Finally.cs:23:13:23:37 | call to method WriteLine | Finally.cs:26:9:29:9 | [exception: Exception] catch (...) {...} | -| Finally.cs:23:13:23:37 | call to method WriteLine | Finally.cs:26:38:26:39 | [exception: Exception] IOException ex | -| Finally.cs:23:13:23:37 | call to method WriteLine | Finally.cs:27:9:29:9 | {...} | -| Finally.cs:23:13:23:37 | call to method WriteLine | Finally.cs:30:9:40:9 | [exception: Exception] catch (...) {...} | -| Finally.cs:23:13:23:37 | call to method WriteLine | Finally.cs:30:41:30:42 | [exception: Exception] ArgumentException ex | -| Finally.cs:23:13:23:37 | call to method WriteLine | Finally.cs:34:27:34:32 | throw ...; | -| Finally.cs:23:13:23:37 | call to method WriteLine | Finally.cs:41:9:43:9 | [exception: Exception] catch (...) {...} | | Finally.cs:24:13:24:19 | return ...; | Finally.cs:24:13:24:19 | return ...; | | Finally.cs:26:9:29:9 | [exception: Exception] catch (...) {...} | Finally.cs:19:10:19:11 | exit M2 (abnormal) | | Finally.cs:26:9:29:9 | [exception: Exception] catch (...) {...} | Finally.cs:26:9:29:9 | [exception: Exception] catch (...) {...} | @@ -10035,9 +9946,7 @@ blockDominance | Finally.cs:26:9:29:9 | [exception: Exception] catch (...) {...} | Finally.cs:30:41:30:42 | [exception: Exception] ArgumentException ex | | Finally.cs:26:9:29:9 | [exception: Exception] catch (...) {...} | Finally.cs:34:27:34:32 | throw ...; | | Finally.cs:26:9:29:9 | [exception: Exception] catch (...) {...} | Finally.cs:41:9:43:9 | [exception: Exception] catch (...) {...} | -| Finally.cs:26:9:29:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:26:9:29:9 | [exception: OutOfMemoryException] catch (...) {...} | -| Finally.cs:26:9:29:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:30:9:40:9 | [exception: OutOfMemoryException] catch (...) {...} | -| Finally.cs:26:9:29:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:41:9:43:9 | [exception: OutOfMemoryException] catch (...) {...} | +| Finally.cs:26:9:29:9 | [exception: Exception] catch (...) {...} | Finally.cs:42:9:43:9 | {...} | | Finally.cs:26:38:26:39 | [exception: Exception] IOException ex | Finally.cs:26:38:26:39 | [exception: Exception] IOException ex | | Finally.cs:26:38:26:39 | [exception: Exception] IOException ex | Finally.cs:27:9:29:9 | {...} | | Finally.cs:27:9:29:9 | {...} | Finally.cs:27:9:29:9 | {...} | @@ -10045,69 +9954,49 @@ blockDominance | Finally.cs:30:9:40:9 | [exception: Exception] catch (...) {...} | Finally.cs:30:41:30:42 | [exception: Exception] ArgumentException ex | | Finally.cs:30:9:40:9 | [exception: Exception] catch (...) {...} | Finally.cs:34:27:34:32 | throw ...; | | Finally.cs:30:9:40:9 | [exception: Exception] catch (...) {...} | Finally.cs:41:9:43:9 | [exception: Exception] catch (...) {...} | -| Finally.cs:30:9:40:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:30:9:40:9 | [exception: OutOfMemoryException] catch (...) {...} | -| Finally.cs:30:9:40:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:41:9:43:9 | [exception: OutOfMemoryException] catch (...) {...} | +| Finally.cs:30:9:40:9 | [exception: Exception] catch (...) {...} | Finally.cs:42:9:43:9 | {...} | | Finally.cs:30:41:30:42 | [exception: Exception] ArgumentException ex | Finally.cs:30:41:30:42 | [exception: Exception] ArgumentException ex | | Finally.cs:30:41:30:42 | [exception: Exception] ArgumentException ex | Finally.cs:34:27:34:32 | throw ...; | | Finally.cs:34:27:34:32 | throw ...; | Finally.cs:34:27:34:32 | throw ...; | | Finally.cs:41:9:43:9 | [exception: Exception] catch (...) {...} | Finally.cs:41:9:43:9 | [exception: Exception] catch (...) {...} | -| Finally.cs:41:9:43:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:41:9:43:9 | [exception: OutOfMemoryException] catch (...) {...} | +| Finally.cs:41:9:43:9 | [exception: Exception] catch (...) {...} | Finally.cs:42:9:43:9 | {...} | | Finally.cs:42:9:43:9 | {...} | Finally.cs:42:9:43:9 | {...} | | Finally.cs:54:10:54:11 | enter M3 | Finally.cs:54:10:54:11 | enter M3 | | Finally.cs:54:10:54:11 | enter M3 | Finally.cs:54:10:54:11 | exit M3 | | Finally.cs:54:10:54:11 | enter M3 | Finally.cs:54:10:54:11 | exit M3 (abnormal) | | Finally.cs:54:10:54:11 | enter M3 | Finally.cs:54:10:54:11 | exit M3 (normal) | -| Finally.cs:54:10:54:11 | enter M3 | Finally.cs:58:13:58:37 | call to method WriteLine | | Finally.cs:54:10:54:11 | enter M3 | Finally.cs:59:13:59:19 | return ...; | | Finally.cs:54:10:54:11 | enter M3 | Finally.cs:61:9:64:9 | [exception: Exception] catch (...) {...} | -| Finally.cs:54:10:54:11 | enter M3 | Finally.cs:61:9:64:9 | [exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:54:10:54:11 | enter M3 | Finally.cs:61:38:61:39 | [exception: Exception] IOException ex | | Finally.cs:54:10:54:11 | enter M3 | Finally.cs:62:9:64:9 | {...} | | Finally.cs:54:10:54:11 | enter M3 | Finally.cs:65:9:67:9 | [exception: Exception] catch (...) {...} | -| Finally.cs:54:10:54:11 | enter M3 | Finally.cs:65:9:67:9 | [exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:54:10:54:11 | enter M3 | Finally.cs:65:26:65:26 | [exception: Exception] Exception e | -| Finally.cs:54:10:54:11 | enter M3 | Finally.cs:65:26:65:26 | [exception: OutOfMemoryException] Exception e | | Finally.cs:54:10:54:11 | enter M3 | Finally.cs:66:9:67:9 | {...} | | Finally.cs:54:10:54:11 | enter M3 | Finally.cs:69:9:71:9 | [finally: exception(Exception)] {...} | -| Finally.cs:54:10:54:11 | enter M3 | Finally.cs:69:9:71:9 | [finally: exception(OutOfMemoryException)] {...} | | Finally.cs:54:10:54:11 | exit M3 | Finally.cs:54:10:54:11 | exit M3 | | Finally.cs:54:10:54:11 | exit M3 (abnormal) | Finally.cs:54:10:54:11 | exit M3 (abnormal) | | Finally.cs:54:10:54:11 | exit M3 (normal) | Finally.cs:54:10:54:11 | exit M3 (normal) | -| Finally.cs:58:13:58:37 | call to method WriteLine | Finally.cs:58:13:58:37 | call to method WriteLine | -| Finally.cs:58:13:58:37 | call to method WriteLine | Finally.cs:59:13:59:19 | return ...; | -| Finally.cs:58:13:58:37 | call to method WriteLine | Finally.cs:61:9:64:9 | [exception: Exception] catch (...) {...} | -| Finally.cs:58:13:58:37 | call to method WriteLine | Finally.cs:61:38:61:39 | [exception: Exception] IOException ex | -| Finally.cs:58:13:58:37 | call to method WriteLine | Finally.cs:62:9:64:9 | {...} | -| Finally.cs:58:13:58:37 | call to method WriteLine | Finally.cs:65:9:67:9 | [exception: Exception] catch (...) {...} | -| Finally.cs:58:13:58:37 | call to method WriteLine | Finally.cs:65:26:65:26 | [exception: Exception] Exception e | -| Finally.cs:58:13:58:37 | call to method WriteLine | Finally.cs:69:9:71:9 | [finally: exception(Exception)] {...} | | Finally.cs:59:13:59:19 | return ...; | Finally.cs:59:13:59:19 | return ...; | +| Finally.cs:61:9:64:9 | [exception: Exception] catch (...) {...} | Finally.cs:54:10:54:11 | exit M3 (abnormal) | | Finally.cs:61:9:64:9 | [exception: Exception] catch (...) {...} | Finally.cs:61:9:64:9 | [exception: Exception] catch (...) {...} | | Finally.cs:61:9:64:9 | [exception: Exception] catch (...) {...} | Finally.cs:61:38:61:39 | [exception: Exception] IOException ex | | Finally.cs:61:9:64:9 | [exception: Exception] catch (...) {...} | Finally.cs:62:9:64:9 | {...} | | Finally.cs:61:9:64:9 | [exception: Exception] catch (...) {...} | Finally.cs:65:9:67:9 | [exception: Exception] catch (...) {...} | | Finally.cs:61:9:64:9 | [exception: Exception] catch (...) {...} | Finally.cs:65:26:65:26 | [exception: Exception] Exception e | +| Finally.cs:61:9:64:9 | [exception: Exception] catch (...) {...} | Finally.cs:66:9:67:9 | {...} | | Finally.cs:61:9:64:9 | [exception: Exception] catch (...) {...} | Finally.cs:69:9:71:9 | [finally: exception(Exception)] {...} | -| Finally.cs:61:9:64:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:61:9:64:9 | [exception: OutOfMemoryException] catch (...) {...} | -| Finally.cs:61:9:64:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:65:9:67:9 | [exception: OutOfMemoryException] catch (...) {...} | -| Finally.cs:61:9:64:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:65:26:65:26 | [exception: OutOfMemoryException] Exception e | -| Finally.cs:61:9:64:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:69:9:71:9 | [finally: exception(OutOfMemoryException)] {...} | | Finally.cs:61:38:61:39 | [exception: Exception] IOException ex | Finally.cs:61:38:61:39 | [exception: Exception] IOException ex | | Finally.cs:61:38:61:39 | [exception: Exception] IOException ex | Finally.cs:62:9:64:9 | {...} | | Finally.cs:62:9:64:9 | {...} | Finally.cs:62:9:64:9 | {...} | | Finally.cs:65:9:67:9 | [exception: Exception] catch (...) {...} | Finally.cs:65:9:67:9 | [exception: Exception] catch (...) {...} | | Finally.cs:65:9:67:9 | [exception: Exception] catch (...) {...} | Finally.cs:65:26:65:26 | [exception: Exception] Exception e | +| Finally.cs:65:9:67:9 | [exception: Exception] catch (...) {...} | Finally.cs:66:9:67:9 | {...} | | Finally.cs:65:9:67:9 | [exception: Exception] catch (...) {...} | Finally.cs:69:9:71:9 | [finally: exception(Exception)] {...} | -| Finally.cs:65:9:67:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:65:9:67:9 | [exception: OutOfMemoryException] catch (...) {...} | -| Finally.cs:65:9:67:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:65:26:65:26 | [exception: OutOfMemoryException] Exception e | -| Finally.cs:65:9:67:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:69:9:71:9 | [finally: exception(OutOfMemoryException)] {...} | | Finally.cs:65:26:65:26 | [exception: Exception] Exception e | Finally.cs:65:26:65:26 | [exception: Exception] Exception e | +| Finally.cs:65:26:65:26 | [exception: Exception] Exception e | Finally.cs:66:9:67:9 | {...} | | Finally.cs:65:26:65:26 | [exception: Exception] Exception e | Finally.cs:69:9:71:9 | [finally: exception(Exception)] {...} | -| Finally.cs:65:26:65:26 | [exception: OutOfMemoryException] Exception e | Finally.cs:65:26:65:26 | [exception: OutOfMemoryException] Exception e | -| Finally.cs:65:26:65:26 | [exception: OutOfMemoryException] Exception e | Finally.cs:69:9:71:9 | [finally: exception(OutOfMemoryException)] {...} | | Finally.cs:66:9:67:9 | {...} | Finally.cs:66:9:67:9 | {...} | | Finally.cs:69:9:71:9 | [finally: exception(Exception)] {...} | Finally.cs:69:9:71:9 | [finally: exception(Exception)] {...} | -| Finally.cs:69:9:71:9 | [finally: exception(OutOfMemoryException)] {...} | Finally.cs:69:9:71:9 | [finally: exception(OutOfMemoryException)] {...} | | Finally.cs:74:10:74:11 | enter M4 | Finally.cs:74:10:74:11 | enter M4 | | Finally.cs:74:10:74:11 | enter M4 | Finally.cs:74:10:74:11 | exit M4 | | Finally.cs:74:10:74:11 | enter M4 | Finally.cs:74:10:74:11 | exit M4 (abnormal) | @@ -10480,16 +10369,10 @@ blockDominance | Finally.cs:121:10:121:11 | enter M6 | Finally.cs:121:10:121:11 | enter M6 | | Finally.cs:133:10:133:11 | enter M7 | Finally.cs:133:10:133:11 | enter M7 | | Finally.cs:133:10:133:11 | enter M7 | Finally.cs:133:10:133:11 | exit M7 (abnormal) | -| Finally.cs:133:10:133:11 | enter M7 | Finally.cs:137:13:137:36 | call to method WriteLine | | Finally.cs:133:10:133:11 | enter M7 | Finally.cs:140:9:143:9 | [finally: exception(Exception)] {...} | -| Finally.cs:133:10:133:11 | enter M7 | Finally.cs:140:9:143:9 | [finally: exception(OutOfMemoryException)] {...} | | Finally.cs:133:10:133:11 | enter M7 | Finally.cs:140:9:143:9 | {...} | | Finally.cs:133:10:133:11 | exit M7 (abnormal) | Finally.cs:133:10:133:11 | exit M7 (abnormal) | -| Finally.cs:137:13:137:36 | call to method WriteLine | Finally.cs:137:13:137:36 | call to method WriteLine | -| Finally.cs:137:13:137:36 | call to method WriteLine | Finally.cs:140:9:143:9 | [finally: exception(Exception)] {...} | -| Finally.cs:137:13:137:36 | call to method WriteLine | Finally.cs:140:9:143:9 | {...} | | Finally.cs:140:9:143:9 | [finally: exception(Exception)] {...} | Finally.cs:140:9:143:9 | [finally: exception(Exception)] {...} | -| Finally.cs:140:9:143:9 | [finally: exception(OutOfMemoryException)] {...} | Finally.cs:140:9:143:9 | [finally: exception(OutOfMemoryException)] {...} | | Finally.cs:140:9:143:9 | {...} | Finally.cs:140:9:143:9 | {...} | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:147:10:147:11 | enter M8 | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:147:10:147:11 | exit M8 | @@ -10505,30 +10388,21 @@ blockDominance | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:159:21:159:45 | [finally: exception(ArgumentNullException)] throw ...; | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:159:21:159:45 | [finally: exception(Exception)] throw ...; | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:159:21:159:45 | throw ...; | -| Finally.cs:147:10:147:11 | enter M8 | Finally.cs:159:27:159:44 | [finally: exception(ArgumentNullException)] object creation of type Exception | -| Finally.cs:147:10:147:11 | enter M8 | Finally.cs:159:27:159:44 | [finally: exception(Exception)] object creation of type Exception | -| Finally.cs:147:10:147:11 | enter M8 | Finally.cs:159:27:159:44 | object creation of type Exception | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:159:41:159:43 | "1" | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:159:41:159:43 | [finally: exception(ArgumentNullException)] "1" | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:159:41:159:43 | [finally: exception(Exception)] "1" | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:161:13:164:13 | [exception: Exception] catch (...) {...} | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:161:13:164:13 | [exception: NullReferenceException] catch (...) {...} | -| Finally.cs:147:10:147:11 | enter M8 | Finally.cs:161:13:164:13 | [exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: Exception] catch (...) {...} | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: NullReferenceException] catch (...) {...} | -| Finally.cs:147:10:147:11 | enter M8 | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: Exception] catch (...) {...} | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: NullReferenceException] catch (...) {...} | -| Finally.cs:147:10:147:11 | enter M8 | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:161:30:161:30 | [exception: Exception] Exception e | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:161:30:161:30 | [exception: NullReferenceException] Exception e | -| Finally.cs:147:10:147:11 | enter M8 | Finally.cs:161:30:161:30 | [exception: OutOfMemoryException] Exception e | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: Exception] Exception e | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: NullReferenceException] Exception e | -| Finally.cs:147:10:147:11 | enter M8 | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] Exception e | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: Exception] Exception e | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: NullReferenceException] Exception e | -| Finally.cs:147:10:147:11 | enter M8 | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: OutOfMemoryException] Exception e | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:162:13:164:13 | [finally: exception(ArgumentNullException)] {...} | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:162:13:164:13 | [finally: exception(Exception)] {...} | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:162:13:164:13 | {...} | @@ -10541,14 +10415,11 @@ blockDominance | Finally.cs:152:17:152:50 | throw ...; | Finally.cs:152:17:152:50 | throw ...; | | Finally.cs:152:17:152:50 | throw ...; | Finally.cs:158:36:158:36 | [finally: exception(ArgumentNullException)] 1 | | Finally.cs:152:17:152:50 | throw ...; | Finally.cs:159:21:159:45 | [finally: exception(ArgumentNullException)] throw ...; | -| Finally.cs:152:17:152:50 | throw ...; | Finally.cs:159:27:159:44 | [finally: exception(ArgumentNullException)] object creation of type Exception | | Finally.cs:152:17:152:50 | throw ...; | Finally.cs:159:41:159:43 | [finally: exception(ArgumentNullException)] "1" | | Finally.cs:152:17:152:50 | throw ...; | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: Exception] catch (...) {...} | | Finally.cs:152:17:152:50 | throw ...; | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: NullReferenceException] catch (...) {...} | -| Finally.cs:152:17:152:50 | throw ...; | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:152:17:152:50 | throw ...; | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: Exception] Exception e | | Finally.cs:152:17:152:50 | throw ...; | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: NullReferenceException] Exception e | -| Finally.cs:152:17:152:50 | throw ...; | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] Exception e | | Finally.cs:152:17:152:50 | throw ...; | Finally.cs:162:13:164:13 | [finally: exception(ArgumentNullException)] {...} | | Finally.cs:152:17:152:50 | throw ...; | Finally.cs:165:13:168:13 | [finally: exception(ArgumentNullException)] catch {...} | | Finally.cs:152:23:152:49 | object creation of type ArgumentNullException | Finally.cs:147:10:147:11 | exit M8 (abnormal) | @@ -10559,22 +10430,16 @@ blockDominance | Finally.cs:152:23:152:49 | object creation of type ArgumentNullException | Finally.cs:158:36:158:36 | [finally: exception(Exception)] 1 | | Finally.cs:152:23:152:49 | object creation of type ArgumentNullException | Finally.cs:159:21:159:45 | [finally: exception(ArgumentNullException)] throw ...; | | Finally.cs:152:23:152:49 | object creation of type ArgumentNullException | Finally.cs:159:21:159:45 | [finally: exception(Exception)] throw ...; | -| Finally.cs:152:23:152:49 | object creation of type ArgumentNullException | Finally.cs:159:27:159:44 | [finally: exception(ArgumentNullException)] object creation of type Exception | -| Finally.cs:152:23:152:49 | object creation of type ArgumentNullException | Finally.cs:159:27:159:44 | [finally: exception(Exception)] object creation of type Exception | | Finally.cs:152:23:152:49 | object creation of type ArgumentNullException | Finally.cs:159:41:159:43 | [finally: exception(ArgumentNullException)] "1" | | Finally.cs:152:23:152:49 | object creation of type ArgumentNullException | Finally.cs:159:41:159:43 | [finally: exception(Exception)] "1" | | Finally.cs:152:23:152:49 | object creation of type ArgumentNullException | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: Exception] catch (...) {...} | | Finally.cs:152:23:152:49 | object creation of type ArgumentNullException | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: NullReferenceException] catch (...) {...} | -| Finally.cs:152:23:152:49 | object creation of type ArgumentNullException | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:152:23:152:49 | object creation of type ArgumentNullException | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: Exception] catch (...) {...} | | Finally.cs:152:23:152:49 | object creation of type ArgumentNullException | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: NullReferenceException] catch (...) {...} | -| Finally.cs:152:23:152:49 | object creation of type ArgumentNullException | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:152:23:152:49 | object creation of type ArgumentNullException | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: Exception] Exception e | | Finally.cs:152:23:152:49 | object creation of type ArgumentNullException | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: NullReferenceException] Exception e | -| Finally.cs:152:23:152:49 | object creation of type ArgumentNullException | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] Exception e | | Finally.cs:152:23:152:49 | object creation of type ArgumentNullException | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: Exception] Exception e | | Finally.cs:152:23:152:49 | object creation of type ArgumentNullException | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: NullReferenceException] Exception e | -| Finally.cs:152:23:152:49 | object creation of type ArgumentNullException | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: OutOfMemoryException] Exception e | | Finally.cs:152:23:152:49 | object creation of type ArgumentNullException | Finally.cs:162:13:164:13 | [finally: exception(ArgumentNullException)] {...} | | Finally.cs:152:23:152:49 | object creation of type ArgumentNullException | Finally.cs:162:13:164:13 | [finally: exception(Exception)] {...} | | Finally.cs:152:23:152:49 | object creation of type ArgumentNullException | Finally.cs:165:13:168:13 | [finally: exception(ArgumentNullException)] catch {...} | @@ -10582,99 +10447,60 @@ blockDominance | Finally.cs:155:9:169:9 | [finally: exception(Exception)] {...} | Finally.cs:155:9:169:9 | [finally: exception(Exception)] {...} | | Finally.cs:155:9:169:9 | [finally: exception(Exception)] {...} | Finally.cs:158:36:158:36 | [finally: exception(Exception)] 1 | | Finally.cs:155:9:169:9 | [finally: exception(Exception)] {...} | Finally.cs:159:21:159:45 | [finally: exception(Exception)] throw ...; | -| Finally.cs:155:9:169:9 | [finally: exception(Exception)] {...} | Finally.cs:159:27:159:44 | [finally: exception(Exception)] object creation of type Exception | | Finally.cs:155:9:169:9 | [finally: exception(Exception)] {...} | Finally.cs:159:41:159:43 | [finally: exception(Exception)] "1" | | Finally.cs:155:9:169:9 | [finally: exception(Exception)] {...} | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: Exception] catch (...) {...} | | Finally.cs:155:9:169:9 | [finally: exception(Exception)] {...} | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: NullReferenceException] catch (...) {...} | -| Finally.cs:155:9:169:9 | [finally: exception(Exception)] {...} | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:155:9:169:9 | [finally: exception(Exception)] {...} | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: Exception] Exception e | | Finally.cs:155:9:169:9 | [finally: exception(Exception)] {...} | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: NullReferenceException] Exception e | -| Finally.cs:155:9:169:9 | [finally: exception(Exception)] {...} | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: OutOfMemoryException] Exception e | | Finally.cs:155:9:169:9 | [finally: exception(Exception)] {...} | Finally.cs:162:13:164:13 | [finally: exception(Exception)] {...} | | Finally.cs:155:9:169:9 | [finally: exception(Exception)] {...} | Finally.cs:165:13:168:13 | [finally: exception(Exception)] catch {...} | | Finally.cs:155:9:169:9 | {...} | Finally.cs:147:10:147:11 | exit M8 (normal) | | Finally.cs:155:9:169:9 | {...} | Finally.cs:155:9:169:9 | {...} | | Finally.cs:155:9:169:9 | {...} | Finally.cs:158:36:158:36 | 1 | | Finally.cs:155:9:169:9 | {...} | Finally.cs:159:21:159:45 | throw ...; | -| Finally.cs:155:9:169:9 | {...} | Finally.cs:159:27:159:44 | object creation of type Exception | | Finally.cs:155:9:169:9 | {...} | Finally.cs:159:41:159:43 | "1" | | Finally.cs:155:9:169:9 | {...} | Finally.cs:161:13:164:13 | [exception: Exception] catch (...) {...} | | Finally.cs:155:9:169:9 | {...} | Finally.cs:161:13:164:13 | [exception: NullReferenceException] catch (...) {...} | -| Finally.cs:155:9:169:9 | {...} | Finally.cs:161:13:164:13 | [exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:155:9:169:9 | {...} | Finally.cs:161:30:161:30 | [exception: Exception] Exception e | | Finally.cs:155:9:169:9 | {...} | Finally.cs:161:30:161:30 | [exception: NullReferenceException] Exception e | -| Finally.cs:155:9:169:9 | {...} | Finally.cs:161:30:161:30 | [exception: OutOfMemoryException] Exception e | | Finally.cs:155:9:169:9 | {...} | Finally.cs:162:13:164:13 | {...} | | Finally.cs:155:9:169:9 | {...} | Finally.cs:165:13:168:13 | catch {...} | | Finally.cs:158:36:158:36 | 1 | Finally.cs:158:36:158:36 | 1 | | Finally.cs:158:36:158:36 | 1 | Finally.cs:159:21:159:45 | throw ...; | -| Finally.cs:158:36:158:36 | 1 | Finally.cs:159:27:159:44 | object creation of type Exception | | Finally.cs:158:36:158:36 | 1 | Finally.cs:159:41:159:43 | "1" | -| Finally.cs:158:36:158:36 | 1 | Finally.cs:161:13:164:13 | [exception: OutOfMemoryException] catch (...) {...} | -| Finally.cs:158:36:158:36 | 1 | Finally.cs:161:30:161:30 | [exception: OutOfMemoryException] Exception e | | Finally.cs:158:36:158:36 | [finally: exception(ArgumentNullException)] 1 | Finally.cs:158:36:158:36 | [finally: exception(ArgumentNullException)] 1 | | Finally.cs:158:36:158:36 | [finally: exception(ArgumentNullException)] 1 | Finally.cs:159:21:159:45 | [finally: exception(ArgumentNullException)] throw ...; | -| Finally.cs:158:36:158:36 | [finally: exception(ArgumentNullException)] 1 | Finally.cs:159:27:159:44 | [finally: exception(ArgumentNullException)] object creation of type Exception | | Finally.cs:158:36:158:36 | [finally: exception(ArgumentNullException)] 1 | Finally.cs:159:41:159:43 | [finally: exception(ArgumentNullException)] "1" | -| Finally.cs:158:36:158:36 | [finally: exception(ArgumentNullException)] 1 | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] catch (...) {...} | -| Finally.cs:158:36:158:36 | [finally: exception(ArgumentNullException)] 1 | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] Exception e | | Finally.cs:158:36:158:36 | [finally: exception(Exception)] 1 | Finally.cs:158:36:158:36 | [finally: exception(Exception)] 1 | | Finally.cs:158:36:158:36 | [finally: exception(Exception)] 1 | Finally.cs:159:21:159:45 | [finally: exception(Exception)] throw ...; | -| Finally.cs:158:36:158:36 | [finally: exception(Exception)] 1 | Finally.cs:159:27:159:44 | [finally: exception(Exception)] object creation of type Exception | | Finally.cs:158:36:158:36 | [finally: exception(Exception)] 1 | Finally.cs:159:41:159:43 | [finally: exception(Exception)] "1" | -| Finally.cs:158:36:158:36 | [finally: exception(Exception)] 1 | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: OutOfMemoryException] catch (...) {...} | -| Finally.cs:158:36:158:36 | [finally: exception(Exception)] 1 | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: OutOfMemoryException] Exception e | | Finally.cs:159:21:159:45 | [finally: exception(ArgumentNullException)] throw ...; | Finally.cs:159:21:159:45 | [finally: exception(ArgumentNullException)] throw ...; | | Finally.cs:159:21:159:45 | [finally: exception(Exception)] throw ...; | Finally.cs:159:21:159:45 | [finally: exception(Exception)] throw ...; | | Finally.cs:159:21:159:45 | throw ...; | Finally.cs:159:21:159:45 | throw ...; | -| Finally.cs:159:27:159:44 | [finally: exception(ArgumentNullException)] object creation of type Exception | Finally.cs:159:21:159:45 | [finally: exception(ArgumentNullException)] throw ...; | -| Finally.cs:159:27:159:44 | [finally: exception(ArgumentNullException)] object creation of type Exception | Finally.cs:159:27:159:44 | [finally: exception(ArgumentNullException)] object creation of type Exception | -| Finally.cs:159:27:159:44 | [finally: exception(Exception)] object creation of type Exception | Finally.cs:159:21:159:45 | [finally: exception(Exception)] throw ...; | -| Finally.cs:159:27:159:44 | [finally: exception(Exception)] object creation of type Exception | Finally.cs:159:27:159:44 | [finally: exception(Exception)] object creation of type Exception | -| Finally.cs:159:27:159:44 | object creation of type Exception | Finally.cs:159:21:159:45 | throw ...; | -| Finally.cs:159:27:159:44 | object creation of type Exception | Finally.cs:159:27:159:44 | object creation of type Exception | | Finally.cs:159:41:159:43 | "1" | Finally.cs:159:21:159:45 | throw ...; | -| Finally.cs:159:41:159:43 | "1" | Finally.cs:159:27:159:44 | object creation of type Exception | | Finally.cs:159:41:159:43 | "1" | Finally.cs:159:41:159:43 | "1" | -| Finally.cs:159:41:159:43 | "1" | Finally.cs:161:13:164:13 | [exception: OutOfMemoryException] catch (...) {...} | -| Finally.cs:159:41:159:43 | "1" | Finally.cs:161:30:161:30 | [exception: OutOfMemoryException] Exception e | | Finally.cs:159:41:159:43 | [finally: exception(ArgumentNullException)] "1" | Finally.cs:159:21:159:45 | [finally: exception(ArgumentNullException)] throw ...; | -| Finally.cs:159:41:159:43 | [finally: exception(ArgumentNullException)] "1" | Finally.cs:159:27:159:44 | [finally: exception(ArgumentNullException)] object creation of type Exception | | Finally.cs:159:41:159:43 | [finally: exception(ArgumentNullException)] "1" | Finally.cs:159:41:159:43 | [finally: exception(ArgumentNullException)] "1" | -| Finally.cs:159:41:159:43 | [finally: exception(ArgumentNullException)] "1" | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] catch (...) {...} | -| Finally.cs:159:41:159:43 | [finally: exception(ArgumentNullException)] "1" | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] Exception e | | Finally.cs:159:41:159:43 | [finally: exception(Exception)] "1" | Finally.cs:159:21:159:45 | [finally: exception(Exception)] throw ...; | -| Finally.cs:159:41:159:43 | [finally: exception(Exception)] "1" | Finally.cs:159:27:159:44 | [finally: exception(Exception)] object creation of type Exception | | Finally.cs:159:41:159:43 | [finally: exception(Exception)] "1" | Finally.cs:159:41:159:43 | [finally: exception(Exception)] "1" | -| Finally.cs:159:41:159:43 | [finally: exception(Exception)] "1" | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: OutOfMemoryException] catch (...) {...} | -| Finally.cs:159:41:159:43 | [finally: exception(Exception)] "1" | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: OutOfMemoryException] Exception e | | Finally.cs:161:13:164:13 | [exception: Exception] catch (...) {...} | Finally.cs:161:13:164:13 | [exception: Exception] catch (...) {...} | | Finally.cs:161:13:164:13 | [exception: Exception] catch (...) {...} | Finally.cs:161:30:161:30 | [exception: Exception] Exception e | | Finally.cs:161:13:164:13 | [exception: NullReferenceException] catch (...) {...} | Finally.cs:161:13:164:13 | [exception: NullReferenceException] catch (...) {...} | | Finally.cs:161:13:164:13 | [exception: NullReferenceException] catch (...) {...} | Finally.cs:161:30:161:30 | [exception: NullReferenceException] Exception e | -| Finally.cs:161:13:164:13 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:161:13:164:13 | [exception: OutOfMemoryException] catch (...) {...} | -| Finally.cs:161:13:164:13 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:161:30:161:30 | [exception: OutOfMemoryException] Exception e | | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: Exception] catch (...) {...} | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: Exception] catch (...) {...} | | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: Exception] catch (...) {...} | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: Exception] Exception e | | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: NullReferenceException] catch (...) {...} | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: NullReferenceException] catch (...) {...} | | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: NullReferenceException] catch (...) {...} | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: NullReferenceException] Exception e | -| Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] catch (...) {...} | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] catch (...) {...} | -| Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] catch (...) {...} | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] Exception e | | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: Exception] catch (...) {...} | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: Exception] catch (...) {...} | | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: Exception] catch (...) {...} | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: Exception] Exception e | | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: NullReferenceException] catch (...) {...} | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: NullReferenceException] catch (...) {...} | | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: NullReferenceException] catch (...) {...} | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: NullReferenceException] Exception e | -| Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: OutOfMemoryException] catch (...) {...} | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: OutOfMemoryException] catch (...) {...} | -| Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: OutOfMemoryException] catch (...) {...} | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: OutOfMemoryException] Exception e | | Finally.cs:161:30:161:30 | [exception: Exception] Exception e | Finally.cs:161:30:161:30 | [exception: Exception] Exception e | | Finally.cs:161:30:161:30 | [exception: NullReferenceException] Exception e | Finally.cs:161:30:161:30 | [exception: NullReferenceException] Exception e | -| Finally.cs:161:30:161:30 | [exception: OutOfMemoryException] Exception e | Finally.cs:161:30:161:30 | [exception: OutOfMemoryException] Exception e | | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: Exception] Exception e | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: Exception] Exception e | | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: NullReferenceException] Exception e | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: NullReferenceException] Exception e | -| Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] Exception e | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] Exception e | | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: Exception] Exception e | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: Exception] Exception e | | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: NullReferenceException] Exception e | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: NullReferenceException] Exception e | -| Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: OutOfMemoryException] Exception e | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: OutOfMemoryException] Exception e | | Finally.cs:162:13:164:13 | [finally: exception(ArgumentNullException)] {...} | Finally.cs:162:13:164:13 | [finally: exception(ArgumentNullException)] {...} | | Finally.cs:162:13:164:13 | [finally: exception(Exception)] {...} | Finally.cs:162:13:164:13 | [finally: exception(Exception)] {...} | | Finally.cs:162:13:164:13 | {...} | Finally.cs:162:13:164:13 | {...} | @@ -10926,10 +10752,8 @@ blockDominance | Finally.cs:211:13:211:29 | [finally: exception(Exception)] ...; | Finally.cs:211:13:211:29 | [finally: exception(Exception)] ...; | | Finally.cs:211:13:211:29 | [finally: exception(ExceptionA)] ...; | Finally.cs:211:13:211:29 | [finally: exception(ExceptionA)] ...; | | Finally.cs:216:10:216:12 | enter M11 | Finally.cs:216:10:216:12 | enter M11 | -| Finally.cs:216:10:216:12 | enter M11 | Finally.cs:220:13:220:36 | call to method WriteLine | | Finally.cs:216:10:216:12 | enter M11 | Finally.cs:222:9:225:9 | catch {...} | | Finally.cs:216:10:216:12 | enter M11 | Finally.cs:227:9:229:9 | {...} | -| Finally.cs:220:13:220:36 | call to method WriteLine | Finally.cs:220:13:220:36 | call to method WriteLine | | Finally.cs:222:9:225:9 | catch {...} | Finally.cs:222:9:225:9 | catch {...} | | Finally.cs:227:9:229:9 | {...} | Finally.cs:227:9:229:9 | {...} | | Finally.cs:233:10:233:12 | enter M12 | Finally.cs:233:10:233:12 | enter M12 | @@ -10951,10 +10775,8 @@ blockDominance | Finally.cs:233:10:233:12 | enter M12 | Finally.cs:250:17:252:17 | [finally: exception(ExceptionA), finally(1): exception(Exception)] {...} | | Finally.cs:233:10:233:12 | enter M12 | Finally.cs:250:17:252:17 | [finally: exception(ExceptionA)] {...} | | Finally.cs:233:10:233:12 | enter M12 | Finally.cs:250:17:252:17 | {...} | -| Finally.cs:233:10:233:12 | enter M12 | Finally.cs:254:13:254:44 | call to method WriteLine | | Finally.cs:233:10:233:12 | enter M12 | Finally.cs:257:9:259:9 | [finally: exception(Exception)] {...} | | Finally.cs:233:10:233:12 | enter M12 | Finally.cs:257:9:259:9 | [finally: exception(ExceptionA)] {...} | -| Finally.cs:233:10:233:12 | enter M12 | Finally.cs:257:9:259:9 | [finally: exception(OutOfMemoryException)] {...} | | Finally.cs:233:10:233:12 | enter M12 | Finally.cs:257:9:259:9 | {...} | | Finally.cs:233:10:233:12 | exit M12 | Finally.cs:233:10:233:12 | exit M12 | | Finally.cs:233:10:233:12 | exit M12 (abnormal) | Finally.cs:233:10:233:12 | exit M12 (abnormal) | @@ -10984,8 +10806,6 @@ blockDominance | Finally.cs:243:13:253:13 | {...} | Finally.cs:247:31:247:46 | object creation of type ExceptionA | | Finally.cs:243:13:253:13 | {...} | Finally.cs:250:17:252:17 | [finally(1): exception(Exception)] {...} | | Finally.cs:243:13:253:13 | {...} | Finally.cs:250:17:252:17 | {...} | -| Finally.cs:243:13:253:13 | {...} | Finally.cs:254:13:254:44 | call to method WriteLine | -| Finally.cs:243:13:253:13 | {...} | Finally.cs:257:9:259:9 | [finally: exception(OutOfMemoryException)] {...} | | Finally.cs:243:13:253:13 | {...} | Finally.cs:257:9:259:9 | {...} | | Finally.cs:247:25:247:47 | [finally: exception(Exception)] throw ...; | Finally.cs:247:25:247:47 | [finally: exception(Exception)] throw ...; | | Finally.cs:247:25:247:47 | [finally: exception(ExceptionA)] throw ...; | Finally.cs:247:25:247:47 | [finally: exception(ExceptionA)] throw ...; | @@ -11005,14 +10825,9 @@ blockDominance | Finally.cs:250:17:252:17 | [finally: exception(ExceptionA), finally(1): exception(Exception)] {...} | Finally.cs:250:17:252:17 | [finally: exception(ExceptionA), finally(1): exception(Exception)] {...} | | Finally.cs:250:17:252:17 | [finally: exception(ExceptionA)] {...} | Finally.cs:250:17:252:17 | [finally: exception(ExceptionA)] {...} | | Finally.cs:250:17:252:17 | {...} | Finally.cs:250:17:252:17 | {...} | -| Finally.cs:250:17:252:17 | {...} | Finally.cs:254:13:254:44 | call to method WriteLine | -| Finally.cs:250:17:252:17 | {...} | Finally.cs:257:9:259:9 | [finally: exception(OutOfMemoryException)] {...} | | Finally.cs:250:17:252:17 | {...} | Finally.cs:257:9:259:9 | {...} | -| Finally.cs:254:13:254:44 | call to method WriteLine | Finally.cs:254:13:254:44 | call to method WriteLine | -| Finally.cs:254:13:254:44 | call to method WriteLine | Finally.cs:257:9:259:9 | {...} | | Finally.cs:257:9:259:9 | [finally: exception(Exception)] {...} | Finally.cs:257:9:259:9 | [finally: exception(Exception)] {...} | | Finally.cs:257:9:259:9 | [finally: exception(ExceptionA)] {...} | Finally.cs:257:9:259:9 | [finally: exception(ExceptionA)] {...} | -| Finally.cs:257:9:259:9 | [finally: exception(OutOfMemoryException)] {...} | Finally.cs:257:9:259:9 | [finally: exception(OutOfMemoryException)] {...} | | Finally.cs:257:9:259:9 | {...} | Finally.cs:257:9:259:9 | {...} | | Foreach.cs:6:10:6:11 | enter M1 | Foreach.cs:6:10:6:11 | enter M1 | | Foreach.cs:6:10:6:11 | enter M1 | Foreach.cs:6:10:6:11 | exit M1 (normal) | @@ -14007,92 +13822,58 @@ postBlockDominance | Extensions.cs:20:17:20:20 | enter Main | Extensions.cs:20:17:20:20 | enter Main | | Finally.cs:7:10:7:11 | enter M1 | Finally.cs:7:10:7:11 | enter M1 | | Finally.cs:7:10:7:11 | exit M1 | Finally.cs:7:10:7:11 | exit M1 | -| Finally.cs:7:10:7:11 | exit M1 (abnormal) | Finally.cs:7:10:7:11 | exit M1 (abnormal) | -| Finally.cs:11:13:11:37 | call to method WriteLine | Finally.cs:7:10:7:11 | enter M1 | -| Finally.cs:11:13:11:37 | call to method WriteLine | Finally.cs:11:13:11:37 | call to method WriteLine | | Finally.cs:14:9:16:9 | [finally: exception(Exception)] {...} | Finally.cs:14:9:16:9 | [finally: exception(Exception)] {...} | -| Finally.cs:14:9:16:9 | [finally: exception(OutOfMemoryException)] {...} | Finally.cs:14:9:16:9 | [finally: exception(OutOfMemoryException)] {...} | | Finally.cs:14:9:16:9 | {...} | Finally.cs:7:10:7:11 | enter M1 | -| Finally.cs:14:9:16:9 | {...} | Finally.cs:11:13:11:37 | call to method WriteLine | | Finally.cs:14:9:16:9 | {...} | Finally.cs:14:9:16:9 | {...} | | Finally.cs:19:10:19:11 | enter M2 | Finally.cs:19:10:19:11 | enter M2 | | Finally.cs:19:10:19:11 | exit M2 | Finally.cs:19:10:19:11 | exit M2 | | Finally.cs:19:10:19:11 | exit M2 (abnormal) | Finally.cs:19:10:19:11 | exit M2 (abnormal) | | Finally.cs:19:10:19:11 | exit M2 (normal) | Finally.cs:19:10:19:11 | enter M2 | | Finally.cs:19:10:19:11 | exit M2 (normal) | Finally.cs:19:10:19:11 | exit M2 (normal) | -| Finally.cs:19:10:19:11 | exit M2 (normal) | Finally.cs:23:13:23:37 | call to method WriteLine | | Finally.cs:19:10:19:11 | exit M2 (normal) | Finally.cs:24:13:24:19 | return ...; | | Finally.cs:19:10:19:11 | exit M2 (normal) | Finally.cs:26:9:29:9 | [exception: Exception] catch (...) {...} | -| Finally.cs:19:10:19:11 | exit M2 (normal) | Finally.cs:26:9:29:9 | [exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:19:10:19:11 | exit M2 (normal) | Finally.cs:30:9:40:9 | [exception: Exception] catch (...) {...} | -| Finally.cs:19:10:19:11 | exit M2 (normal) | Finally.cs:30:9:40:9 | [exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:19:10:19:11 | exit M2 (normal) | Finally.cs:41:9:43:9 | [exception: Exception] catch (...) {...} | -| Finally.cs:19:10:19:11 | exit M2 (normal) | Finally.cs:41:9:43:9 | [exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:19:10:19:11 | exit M2 (normal) | Finally.cs:42:9:43:9 | {...} | -| Finally.cs:23:13:23:37 | call to method WriteLine | Finally.cs:23:13:23:37 | call to method WriteLine | | Finally.cs:24:13:24:19 | return ...; | Finally.cs:24:13:24:19 | return ...; | | Finally.cs:26:9:29:9 | [exception: Exception] catch (...) {...} | Finally.cs:26:9:29:9 | [exception: Exception] catch (...) {...} | -| Finally.cs:26:9:29:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:26:9:29:9 | [exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:26:38:26:39 | [exception: Exception] IOException ex | Finally.cs:26:38:26:39 | [exception: Exception] IOException ex | | Finally.cs:27:9:29:9 | {...} | Finally.cs:27:9:29:9 | {...} | | Finally.cs:30:9:40:9 | [exception: Exception] catch (...) {...} | Finally.cs:26:9:29:9 | [exception: Exception] catch (...) {...} | | Finally.cs:30:9:40:9 | [exception: Exception] catch (...) {...} | Finally.cs:30:9:40:9 | [exception: Exception] catch (...) {...} | -| Finally.cs:30:9:40:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:26:9:29:9 | [exception: OutOfMemoryException] catch (...) {...} | -| Finally.cs:30:9:40:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:30:9:40:9 | [exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:30:41:30:42 | [exception: Exception] ArgumentException ex | Finally.cs:30:41:30:42 | [exception: Exception] ArgumentException ex | | Finally.cs:34:27:34:32 | throw ...; | Finally.cs:34:27:34:32 | throw ...; | | Finally.cs:41:9:43:9 | [exception: Exception] catch (...) {...} | Finally.cs:26:9:29:9 | [exception: Exception] catch (...) {...} | | Finally.cs:41:9:43:9 | [exception: Exception] catch (...) {...} | Finally.cs:30:9:40:9 | [exception: Exception] catch (...) {...} | | Finally.cs:41:9:43:9 | [exception: Exception] catch (...) {...} | Finally.cs:41:9:43:9 | [exception: Exception] catch (...) {...} | -| Finally.cs:41:9:43:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:26:9:29:9 | [exception: OutOfMemoryException] catch (...) {...} | -| Finally.cs:41:9:43:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:30:9:40:9 | [exception: OutOfMemoryException] catch (...) {...} | -| Finally.cs:41:9:43:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:41:9:43:9 | [exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:42:9:43:9 | {...} | Finally.cs:26:9:29:9 | [exception: Exception] catch (...) {...} | -| Finally.cs:42:9:43:9 | {...} | Finally.cs:26:9:29:9 | [exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:42:9:43:9 | {...} | Finally.cs:30:9:40:9 | [exception: Exception] catch (...) {...} | -| Finally.cs:42:9:43:9 | {...} | Finally.cs:30:9:40:9 | [exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:42:9:43:9 | {...} | Finally.cs:41:9:43:9 | [exception: Exception] catch (...) {...} | -| Finally.cs:42:9:43:9 | {...} | Finally.cs:41:9:43:9 | [exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:42:9:43:9 | {...} | Finally.cs:42:9:43:9 | {...} | | Finally.cs:54:10:54:11 | enter M3 | Finally.cs:54:10:54:11 | enter M3 | | Finally.cs:54:10:54:11 | exit M3 | Finally.cs:54:10:54:11 | exit M3 | | Finally.cs:54:10:54:11 | exit M3 (abnormal) | Finally.cs:54:10:54:11 | exit M3 (abnormal) | | Finally.cs:54:10:54:11 | exit M3 (normal) | Finally.cs:54:10:54:11 | enter M3 | | Finally.cs:54:10:54:11 | exit M3 (normal) | Finally.cs:54:10:54:11 | exit M3 (normal) | -| Finally.cs:54:10:54:11 | exit M3 (normal) | Finally.cs:58:13:58:37 | call to method WriteLine | | Finally.cs:54:10:54:11 | exit M3 (normal) | Finally.cs:59:13:59:19 | return ...; | | Finally.cs:54:10:54:11 | exit M3 (normal) | Finally.cs:61:9:64:9 | [exception: Exception] catch (...) {...} | -| Finally.cs:54:10:54:11 | exit M3 (normal) | Finally.cs:61:9:64:9 | [exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:54:10:54:11 | exit M3 (normal) | Finally.cs:65:9:67:9 | [exception: Exception] catch (...) {...} | -| Finally.cs:54:10:54:11 | exit M3 (normal) | Finally.cs:65:9:67:9 | [exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:54:10:54:11 | exit M3 (normal) | Finally.cs:65:26:65:26 | [exception: Exception] Exception e | -| Finally.cs:54:10:54:11 | exit M3 (normal) | Finally.cs:65:26:65:26 | [exception: OutOfMemoryException] Exception e | | Finally.cs:54:10:54:11 | exit M3 (normal) | Finally.cs:66:9:67:9 | {...} | -| Finally.cs:58:13:58:37 | call to method WriteLine | Finally.cs:58:13:58:37 | call to method WriteLine | | Finally.cs:59:13:59:19 | return ...; | Finally.cs:59:13:59:19 | return ...; | | Finally.cs:61:9:64:9 | [exception: Exception] catch (...) {...} | Finally.cs:61:9:64:9 | [exception: Exception] catch (...) {...} | -| Finally.cs:61:9:64:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:61:9:64:9 | [exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:61:38:61:39 | [exception: Exception] IOException ex | Finally.cs:61:38:61:39 | [exception: Exception] IOException ex | | Finally.cs:62:9:64:9 | {...} | Finally.cs:62:9:64:9 | {...} | | Finally.cs:65:9:67:9 | [exception: Exception] catch (...) {...} | Finally.cs:61:9:64:9 | [exception: Exception] catch (...) {...} | | Finally.cs:65:9:67:9 | [exception: Exception] catch (...) {...} | Finally.cs:65:9:67:9 | [exception: Exception] catch (...) {...} | -| Finally.cs:65:9:67:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:61:9:64:9 | [exception: OutOfMemoryException] catch (...) {...} | -| Finally.cs:65:9:67:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:65:9:67:9 | [exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:65:26:65:26 | [exception: Exception] Exception e | Finally.cs:61:9:64:9 | [exception: Exception] catch (...) {...} | | Finally.cs:65:26:65:26 | [exception: Exception] Exception e | Finally.cs:65:9:67:9 | [exception: Exception] catch (...) {...} | | Finally.cs:65:26:65:26 | [exception: Exception] Exception e | Finally.cs:65:26:65:26 | [exception: Exception] Exception e | -| Finally.cs:65:26:65:26 | [exception: OutOfMemoryException] Exception e | Finally.cs:61:9:64:9 | [exception: OutOfMemoryException] catch (...) {...} | -| Finally.cs:65:26:65:26 | [exception: OutOfMemoryException] Exception e | Finally.cs:65:9:67:9 | [exception: OutOfMemoryException] catch (...) {...} | -| Finally.cs:65:26:65:26 | [exception: OutOfMemoryException] Exception e | Finally.cs:65:26:65:26 | [exception: OutOfMemoryException] Exception e | | Finally.cs:66:9:67:9 | {...} | Finally.cs:61:9:64:9 | [exception: Exception] catch (...) {...} | -| Finally.cs:66:9:67:9 | {...} | Finally.cs:61:9:64:9 | [exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:66:9:67:9 | {...} | Finally.cs:65:9:67:9 | [exception: Exception] catch (...) {...} | -| Finally.cs:66:9:67:9 | {...} | Finally.cs:65:9:67:9 | [exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:66:9:67:9 | {...} | Finally.cs:65:26:65:26 | [exception: Exception] Exception e | -| Finally.cs:66:9:67:9 | {...} | Finally.cs:65:26:65:26 | [exception: OutOfMemoryException] Exception e | | Finally.cs:66:9:67:9 | {...} | Finally.cs:66:9:67:9 | {...} | | Finally.cs:69:9:71:9 | [finally: exception(Exception)] {...} | Finally.cs:69:9:71:9 | [finally: exception(Exception)] {...} | -| Finally.cs:69:9:71:9 | [finally: exception(OutOfMemoryException)] {...} | Finally.cs:69:9:71:9 | [finally: exception(OutOfMemoryException)] {...} | | Finally.cs:74:10:74:11 | enter M4 | Finally.cs:74:10:74:11 | enter M4 | | Finally.cs:74:10:74:11 | exit M4 | Finally.cs:74:10:74:11 | exit M4 | | Finally.cs:74:10:74:11 | exit M4 (abnormal) | Finally.cs:74:10:74:11 | exit M4 (abnormal) | @@ -14226,9 +14007,7 @@ postBlockDominance | Finally.cs:121:10:121:11 | enter M6 | Finally.cs:121:10:121:11 | enter M6 | | Finally.cs:133:10:133:11 | enter M7 | Finally.cs:133:10:133:11 | enter M7 | | Finally.cs:133:10:133:11 | exit M7 (abnormal) | Finally.cs:133:10:133:11 | exit M7 (abnormal) | -| Finally.cs:137:13:137:36 | call to method WriteLine | Finally.cs:137:13:137:36 | call to method WriteLine | | Finally.cs:140:9:143:9 | [finally: exception(Exception)] {...} | Finally.cs:140:9:143:9 | [finally: exception(Exception)] {...} | -| Finally.cs:140:9:143:9 | [finally: exception(OutOfMemoryException)] {...} | Finally.cs:140:9:143:9 | [finally: exception(OutOfMemoryException)] {...} | | Finally.cs:140:9:143:9 | {...} | Finally.cs:140:9:143:9 | {...} | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:147:10:147:11 | enter M8 | | Finally.cs:147:10:147:11 | exit M8 | Finally.cs:147:10:147:11 | exit M8 | @@ -14238,14 +14017,11 @@ postBlockDominance | Finally.cs:147:10:147:11 | exit M8 (normal) | Finally.cs:155:9:169:9 | {...} | | Finally.cs:147:10:147:11 | exit M8 (normal) | Finally.cs:158:36:158:36 | 1 | | Finally.cs:147:10:147:11 | exit M8 (normal) | Finally.cs:159:21:159:45 | throw ...; | -| Finally.cs:147:10:147:11 | exit M8 (normal) | Finally.cs:159:27:159:44 | object creation of type Exception | | Finally.cs:147:10:147:11 | exit M8 (normal) | Finally.cs:159:41:159:43 | "1" | | Finally.cs:147:10:147:11 | exit M8 (normal) | Finally.cs:161:13:164:13 | [exception: Exception] catch (...) {...} | | Finally.cs:147:10:147:11 | exit M8 (normal) | Finally.cs:161:13:164:13 | [exception: NullReferenceException] catch (...) {...} | -| Finally.cs:147:10:147:11 | exit M8 (normal) | Finally.cs:161:13:164:13 | [exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:147:10:147:11 | exit M8 (normal) | Finally.cs:161:30:161:30 | [exception: Exception] Exception e | | Finally.cs:147:10:147:11 | exit M8 (normal) | Finally.cs:161:30:161:30 | [exception: NullReferenceException] Exception e | -| Finally.cs:147:10:147:11 | exit M8 (normal) | Finally.cs:161:30:161:30 | [exception: OutOfMemoryException] Exception e | | Finally.cs:147:10:147:11 | exit M8 (normal) | Finally.cs:162:13:164:13 | {...} | | Finally.cs:147:10:147:11 | exit M8 (normal) | Finally.cs:165:13:168:13 | catch {...} | | Finally.cs:152:17:152:50 | throw ...; | Finally.cs:152:17:152:50 | throw ...; | @@ -14259,37 +14035,27 @@ postBlockDominance | Finally.cs:159:21:159:45 | [finally: exception(ArgumentNullException)] throw ...; | Finally.cs:159:21:159:45 | [finally: exception(ArgumentNullException)] throw ...; | | Finally.cs:159:21:159:45 | [finally: exception(Exception)] throw ...; | Finally.cs:159:21:159:45 | [finally: exception(Exception)] throw ...; | | Finally.cs:159:21:159:45 | throw ...; | Finally.cs:159:21:159:45 | throw ...; | -| Finally.cs:159:27:159:44 | [finally: exception(ArgumentNullException)] object creation of type Exception | Finally.cs:159:27:159:44 | [finally: exception(ArgumentNullException)] object creation of type Exception | -| Finally.cs:159:27:159:44 | [finally: exception(Exception)] object creation of type Exception | Finally.cs:159:27:159:44 | [finally: exception(Exception)] object creation of type Exception | -| Finally.cs:159:27:159:44 | object creation of type Exception | Finally.cs:159:27:159:44 | object creation of type Exception | | Finally.cs:159:41:159:43 | "1" | Finally.cs:159:41:159:43 | "1" | | Finally.cs:159:41:159:43 | [finally: exception(ArgumentNullException)] "1" | Finally.cs:159:41:159:43 | [finally: exception(ArgumentNullException)] "1" | | Finally.cs:159:41:159:43 | [finally: exception(Exception)] "1" | Finally.cs:159:41:159:43 | [finally: exception(Exception)] "1" | | Finally.cs:161:13:164:13 | [exception: Exception] catch (...) {...} | Finally.cs:159:21:159:45 | throw ...; | -| Finally.cs:161:13:164:13 | [exception: Exception] catch (...) {...} | Finally.cs:159:27:159:44 | object creation of type Exception | +| Finally.cs:161:13:164:13 | [exception: Exception] catch (...) {...} | Finally.cs:159:41:159:43 | "1" | | Finally.cs:161:13:164:13 | [exception: Exception] catch (...) {...} | Finally.cs:161:13:164:13 | [exception: Exception] catch (...) {...} | | Finally.cs:161:13:164:13 | [exception: NullReferenceException] catch (...) {...} | Finally.cs:161:13:164:13 | [exception: NullReferenceException] catch (...) {...} | -| Finally.cs:161:13:164:13 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:161:13:164:13 | [exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: Exception] catch (...) {...} | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: Exception] catch (...) {...} | | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: NullReferenceException] catch (...) {...} | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: NullReferenceException] catch (...) {...} | -| Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] catch (...) {...} | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: Exception] catch (...) {...} | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: Exception] catch (...) {...} | | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: NullReferenceException] catch (...) {...} | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: NullReferenceException] catch (...) {...} | -| Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: OutOfMemoryException] catch (...) {...} | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: OutOfMemoryException] catch (...) {...} | | Finally.cs:161:30:161:30 | [exception: Exception] Exception e | Finally.cs:159:21:159:45 | throw ...; | -| Finally.cs:161:30:161:30 | [exception: Exception] Exception e | Finally.cs:159:27:159:44 | object creation of type Exception | +| Finally.cs:161:30:161:30 | [exception: Exception] Exception e | Finally.cs:159:41:159:43 | "1" | | Finally.cs:161:30:161:30 | [exception: Exception] Exception e | Finally.cs:161:13:164:13 | [exception: Exception] catch (...) {...} | | Finally.cs:161:30:161:30 | [exception: Exception] Exception e | Finally.cs:161:30:161:30 | [exception: Exception] Exception e | | Finally.cs:161:30:161:30 | [exception: NullReferenceException] Exception e | Finally.cs:161:13:164:13 | [exception: NullReferenceException] catch (...) {...} | | Finally.cs:161:30:161:30 | [exception: NullReferenceException] Exception e | Finally.cs:161:30:161:30 | [exception: NullReferenceException] Exception e | -| Finally.cs:161:30:161:30 | [exception: OutOfMemoryException] Exception e | Finally.cs:161:13:164:13 | [exception: OutOfMemoryException] catch (...) {...} | -| Finally.cs:161:30:161:30 | [exception: OutOfMemoryException] Exception e | Finally.cs:161:30:161:30 | [exception: OutOfMemoryException] Exception e | | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: Exception] Exception e | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: Exception] Exception e | | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: NullReferenceException] Exception e | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: NullReferenceException] Exception e | -| Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] Exception e | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] Exception e | | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: Exception] Exception e | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: Exception] Exception e | | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: NullReferenceException] Exception e | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: NullReferenceException] Exception e | -| Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: OutOfMemoryException] Exception e | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: OutOfMemoryException] Exception e | | Finally.cs:162:13:164:13 | [finally: exception(ArgumentNullException)] {...} | Finally.cs:162:13:164:13 | [finally: exception(ArgumentNullException)] {...} | | Finally.cs:162:13:164:13 | [finally: exception(Exception)] {...} | Finally.cs:162:13:164:13 | [finally: exception(Exception)] {...} | | Finally.cs:162:13:164:13 | {...} | Finally.cs:162:13:164:13 | {...} | @@ -14378,10 +14144,8 @@ postBlockDominance | Finally.cs:211:13:211:29 | [finally: exception(Exception)] ...; | Finally.cs:211:13:211:29 | [finally: exception(Exception)] ...; | | Finally.cs:211:13:211:29 | [finally: exception(ExceptionA)] ...; | Finally.cs:211:13:211:29 | [finally: exception(ExceptionA)] ...; | | Finally.cs:216:10:216:12 | enter M11 | Finally.cs:216:10:216:12 | enter M11 | -| Finally.cs:220:13:220:36 | call to method WriteLine | Finally.cs:220:13:220:36 | call to method WriteLine | | Finally.cs:222:9:225:9 | catch {...} | Finally.cs:222:9:225:9 | catch {...} | | Finally.cs:227:9:229:9 | {...} | Finally.cs:216:10:216:12 | enter M11 | -| Finally.cs:227:9:229:9 | {...} | Finally.cs:220:13:220:36 | call to method WriteLine | | Finally.cs:227:9:229:9 | {...} | Finally.cs:222:9:225:9 | catch {...} | | Finally.cs:227:9:229:9 | {...} | Finally.cs:227:9:229:9 | {...} | | Finally.cs:233:10:233:12 | enter M12 | Finally.cs:233:10:233:12 | enter M12 | @@ -14406,17 +14170,11 @@ postBlockDominance | Finally.cs:250:17:252:17 | {...} | Finally.cs:233:10:233:12 | enter M12 | | Finally.cs:250:17:252:17 | {...} | Finally.cs:243:13:253:13 | {...} | | Finally.cs:250:17:252:17 | {...} | Finally.cs:250:17:252:17 | {...} | -| Finally.cs:254:13:254:44 | call to method WriteLine | Finally.cs:233:10:233:12 | enter M12 | -| Finally.cs:254:13:254:44 | call to method WriteLine | Finally.cs:243:13:253:13 | {...} | -| Finally.cs:254:13:254:44 | call to method WriteLine | Finally.cs:250:17:252:17 | {...} | -| Finally.cs:254:13:254:44 | call to method WriteLine | Finally.cs:254:13:254:44 | call to method WriteLine | | Finally.cs:257:9:259:9 | [finally: exception(Exception)] {...} | Finally.cs:257:9:259:9 | [finally: exception(Exception)] {...} | | Finally.cs:257:9:259:9 | [finally: exception(ExceptionA)] {...} | Finally.cs:257:9:259:9 | [finally: exception(ExceptionA)] {...} | -| Finally.cs:257:9:259:9 | [finally: exception(OutOfMemoryException)] {...} | Finally.cs:257:9:259:9 | [finally: exception(OutOfMemoryException)] {...} | | Finally.cs:257:9:259:9 | {...} | Finally.cs:233:10:233:12 | enter M12 | | Finally.cs:257:9:259:9 | {...} | Finally.cs:243:13:253:13 | {...} | | Finally.cs:257:9:259:9 | {...} | Finally.cs:250:17:252:17 | {...} | -| Finally.cs:257:9:259:9 | {...} | Finally.cs:254:13:254:44 | call to method WriteLine | | Finally.cs:257:9:259:9 | {...} | Finally.cs:257:9:259:9 | {...} | | Foreach.cs:6:10:6:11 | enter M1 | Foreach.cs:6:10:6:11 | enter M1 | | Foreach.cs:6:10:6:11 | exit M1 (normal) | Foreach.cs:6:10:6:11 | enter M1 | diff --git a/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected b/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected index 9803e2dec8d..c6d70953677 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected @@ -1830,17 +1830,13 @@ nodeEnclosing | Finally.cs:11:13:11:38 | ...; | Finally.cs:7:10:7:11 | M1 | | Finally.cs:11:31:11:36 | "Try1" | Finally.cs:7:10:7:11 | M1 | | Finally.cs:14:9:16:9 | [finally: exception(Exception)] {...} | Finally.cs:7:10:7:11 | M1 | -| Finally.cs:14:9:16:9 | [finally: exception(OutOfMemoryException)] {...} | Finally.cs:7:10:7:11 | M1 | | Finally.cs:14:9:16:9 | {...} | Finally.cs:7:10:7:11 | M1 | | Finally.cs:15:13:15:40 | [finally: exception(Exception)] call to method WriteLine | Finally.cs:7:10:7:11 | M1 | -| Finally.cs:15:13:15:40 | [finally: exception(OutOfMemoryException)] call to method WriteLine | Finally.cs:7:10:7:11 | M1 | | Finally.cs:15:13:15:40 | call to method WriteLine | Finally.cs:7:10:7:11 | M1 | | Finally.cs:15:13:15:41 | ...; | Finally.cs:7:10:7:11 | M1 | | Finally.cs:15:13:15:41 | [finally: exception(Exception)] ...; | Finally.cs:7:10:7:11 | M1 | -| Finally.cs:15:13:15:41 | [finally: exception(OutOfMemoryException)] ...; | Finally.cs:7:10:7:11 | M1 | | Finally.cs:15:31:15:39 | "Finally" | Finally.cs:7:10:7:11 | M1 | | Finally.cs:15:31:15:39 | [finally: exception(Exception)] "Finally" | Finally.cs:7:10:7:11 | M1 | -| Finally.cs:15:31:15:39 | [finally: exception(OutOfMemoryException)] "Finally" | Finally.cs:7:10:7:11 | M1 | | Finally.cs:19:10:19:11 | enter M2 | Finally.cs:19:10:19:11 | M2 | | Finally.cs:19:10:19:11 | exit M2 | Finally.cs:19:10:19:11 | M2 | | Finally.cs:19:10:19:11 | exit M2 (abnormal) | Finally.cs:19:10:19:11 | M2 | @@ -1853,13 +1849,11 @@ nodeEnclosing | Finally.cs:23:31:23:36 | "Try2" | Finally.cs:19:10:19:11 | M2 | | Finally.cs:24:13:24:19 | return ...; | Finally.cs:19:10:19:11 | M2 | | Finally.cs:26:9:29:9 | [exception: Exception] catch (...) {...} | Finally.cs:19:10:19:11 | M2 | -| Finally.cs:26:9:29:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:19:10:19:11 | M2 | | Finally.cs:26:38:26:39 | [exception: Exception] IOException ex | Finally.cs:19:10:19:11 | M2 | | Finally.cs:26:48:26:51 | [exception: Exception] true | Finally.cs:19:10:19:11 | M2 | | Finally.cs:27:9:29:9 | {...} | Finally.cs:19:10:19:11 | M2 | | Finally.cs:28:13:28:18 | throw ...; | Finally.cs:19:10:19:11 | M2 | | Finally.cs:30:9:40:9 | [exception: Exception] catch (...) {...} | Finally.cs:19:10:19:11 | M2 | -| Finally.cs:30:9:40:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:19:10:19:11 | M2 | | Finally.cs:30:41:30:42 | [exception: Exception] ArgumentException ex | Finally.cs:19:10:19:11 | M2 | | Finally.cs:31:9:40:9 | {...} | Finally.cs:19:10:19:11 | M2 | | Finally.cs:32:13:39:13 | try {...} ... | Finally.cs:19:10:19:11 | M2 | @@ -1872,7 +1866,6 @@ nodeEnclosing | Finally.cs:38:23:38:43 | [finally: exception(ArgumentException)] object creation of type Exception | Finally.cs:19:10:19:11 | M2 | | Finally.cs:38:37:38:42 | [finally: exception(ArgumentException)] "Boo!" | Finally.cs:19:10:19:11 | M2 | | Finally.cs:41:9:43:9 | [exception: Exception] catch (...) {...} | Finally.cs:19:10:19:11 | M2 | -| Finally.cs:41:9:43:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:19:10:19:11 | M2 | | Finally.cs:42:9:43:9 | {...} | Finally.cs:19:10:19:11 | M2 | | Finally.cs:49:9:51:9 | [finally: exception(Exception)] {...} | Finally.cs:19:10:19:11 | M2 | | Finally.cs:49:9:51:9 | [finally: exception(IOException)] {...} | Finally.cs:19:10:19:11 | M2 | @@ -1902,43 +1895,32 @@ nodeEnclosing | Finally.cs:58:31:58:36 | "Try3" | Finally.cs:54:10:54:11 | M3 | | Finally.cs:59:13:59:19 | return ...; | Finally.cs:54:10:54:11 | M3 | | Finally.cs:61:9:64:9 | [exception: Exception] catch (...) {...} | Finally.cs:54:10:54:11 | M3 | -| Finally.cs:61:9:64:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:54:10:54:11 | M3 | | Finally.cs:61:38:61:39 | [exception: Exception] IOException ex | Finally.cs:54:10:54:11 | M3 | | Finally.cs:61:48:61:51 | [exception: Exception] true | Finally.cs:54:10:54:11 | M3 | | Finally.cs:62:9:64:9 | {...} | Finally.cs:54:10:54:11 | M3 | | Finally.cs:63:13:63:18 | throw ...; | Finally.cs:54:10:54:11 | M3 | | Finally.cs:65:9:67:9 | [exception: Exception] catch (...) {...} | Finally.cs:54:10:54:11 | M3 | -| Finally.cs:65:9:67:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:54:10:54:11 | M3 | | Finally.cs:65:26:65:26 | [exception: Exception] Exception e | Finally.cs:54:10:54:11 | M3 | -| Finally.cs:65:26:65:26 | [exception: OutOfMemoryException] Exception e | Finally.cs:54:10:54:11 | M3 | | Finally.cs:65:35:65:35 | [exception: Exception] access to local variable e | Finally.cs:54:10:54:11 | M3 | -| Finally.cs:65:35:65:35 | [exception: OutOfMemoryException] access to local variable e | Finally.cs:54:10:54:11 | M3 | | Finally.cs:65:35:65:43 | [exception: Exception] access to property Message | Finally.cs:54:10:54:11 | M3 | -| Finally.cs:65:35:65:43 | [exception: OutOfMemoryException] access to property Message | Finally.cs:54:10:54:11 | M3 | | Finally.cs:65:35:65:51 | [exception: Exception] ... != ... | Finally.cs:54:10:54:11 | M3 | -| Finally.cs:65:35:65:51 | [exception: OutOfMemoryException] ... != ... | Finally.cs:54:10:54:11 | M3 | | Finally.cs:65:48:65:51 | [exception: Exception] null | Finally.cs:54:10:54:11 | M3 | -| Finally.cs:65:48:65:51 | [exception: OutOfMemoryException] null | Finally.cs:54:10:54:11 | M3 | | Finally.cs:66:9:67:9 | {...} | Finally.cs:54:10:54:11 | M3 | | Finally.cs:69:9:71:9 | [finally: exception(Exception)] {...} | Finally.cs:54:10:54:11 | M3 | | Finally.cs:69:9:71:9 | [finally: exception(IOException)] {...} | Finally.cs:54:10:54:11 | M3 | -| Finally.cs:69:9:71:9 | [finally: exception(OutOfMemoryException)] {...} | Finally.cs:54:10:54:11 | M3 | | Finally.cs:69:9:71:9 | [finally: return] {...} | Finally.cs:54:10:54:11 | M3 | | Finally.cs:69:9:71:9 | {...} | Finally.cs:54:10:54:11 | M3 | | Finally.cs:70:13:70:40 | [finally: exception(Exception)] call to method WriteLine | Finally.cs:54:10:54:11 | M3 | | Finally.cs:70:13:70:40 | [finally: exception(IOException)] call to method WriteLine | Finally.cs:54:10:54:11 | M3 | -| Finally.cs:70:13:70:40 | [finally: exception(OutOfMemoryException)] call to method WriteLine | Finally.cs:54:10:54:11 | M3 | | Finally.cs:70:13:70:40 | [finally: return] call to method WriteLine | Finally.cs:54:10:54:11 | M3 | | Finally.cs:70:13:70:40 | call to method WriteLine | Finally.cs:54:10:54:11 | M3 | | Finally.cs:70:13:70:41 | ...; | Finally.cs:54:10:54:11 | M3 | | Finally.cs:70:13:70:41 | [finally: exception(Exception)] ...; | Finally.cs:54:10:54:11 | M3 | | Finally.cs:70:13:70:41 | [finally: exception(IOException)] ...; | Finally.cs:54:10:54:11 | M3 | -| Finally.cs:70:13:70:41 | [finally: exception(OutOfMemoryException)] ...; | Finally.cs:54:10:54:11 | M3 | | Finally.cs:70:13:70:41 | [finally: return] ...; | Finally.cs:54:10:54:11 | M3 | | Finally.cs:70:31:70:39 | "Finally" | Finally.cs:54:10:54:11 | M3 | | Finally.cs:70:31:70:39 | [finally: exception(Exception)] "Finally" | Finally.cs:54:10:54:11 | M3 | | Finally.cs:70:31:70:39 | [finally: exception(IOException)] "Finally" | Finally.cs:54:10:54:11 | M3 | -| Finally.cs:70:31:70:39 | [finally: exception(OutOfMemoryException)] "Finally" | Finally.cs:54:10:54:11 | M3 | | Finally.cs:70:31:70:39 | [finally: return] "Finally" | Finally.cs:54:10:54:11 | M3 | | Finally.cs:74:10:74:11 | enter M4 | Finally.cs:74:10:74:11 | M4 | | Finally.cs:74:10:74:11 | exit M4 | Finally.cs:74:10:74:11 | M4 | @@ -2192,17 +2174,13 @@ nodeEnclosing | Finally.cs:137:13:137:37 | ...; | Finally.cs:133:10:133:11 | M7 | | Finally.cs:137:31:137:35 | "Try" | Finally.cs:133:10:133:11 | M7 | | Finally.cs:140:9:143:9 | [finally: exception(Exception)] {...} | Finally.cs:133:10:133:11 | M7 | -| Finally.cs:140:9:143:9 | [finally: exception(OutOfMemoryException)] {...} | Finally.cs:133:10:133:11 | M7 | | Finally.cs:140:9:143:9 | {...} | Finally.cs:133:10:133:11 | M7 | | Finally.cs:141:13:141:44 | [finally: exception(Exception)] throw ...; | Finally.cs:133:10:133:11 | M7 | -| Finally.cs:141:13:141:44 | [finally: exception(OutOfMemoryException)] throw ...; | Finally.cs:133:10:133:11 | M7 | | Finally.cs:141:13:141:44 | throw ...; | Finally.cs:133:10:133:11 | M7 | | Finally.cs:141:19:141:43 | [finally: exception(Exception)] object creation of type ArgumentException | Finally.cs:133:10:133:11 | M7 | -| Finally.cs:141:19:141:43 | [finally: exception(OutOfMemoryException)] object creation of type ArgumentException | Finally.cs:133:10:133:11 | M7 | | Finally.cs:141:19:141:43 | object creation of type ArgumentException | Finally.cs:133:10:133:11 | M7 | | Finally.cs:141:41:141:42 | "" | Finally.cs:133:10:133:11 | M7 | | Finally.cs:141:41:141:42 | [finally: exception(Exception)] "" | Finally.cs:133:10:133:11 | M7 | -| Finally.cs:141:41:141:42 | [finally: exception(OutOfMemoryException)] "" | Finally.cs:133:10:133:11 | M7 | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:147:10:147:11 | M8 | | Finally.cs:147:10:147:11 | exit M8 | Finally.cs:147:10:147:11 | M8 | | Finally.cs:147:10:147:11 | exit M8 (abnormal) | Finally.cs:147:10:147:11 | M8 | @@ -2251,58 +2229,40 @@ nodeEnclosing | Finally.cs:159:41:159:43 | [finally: exception(Exception)] "1" | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:13:164:13 | [exception: Exception] catch (...) {...} | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:13:164:13 | [exception: NullReferenceException] catch (...) {...} | Finally.cs:147:10:147:11 | M8 | -| Finally.cs:161:13:164:13 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: Exception] catch (...) {...} | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: NullReferenceException] catch (...) {...} | Finally.cs:147:10:147:11 | M8 | -| Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] catch (...) {...} | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: Exception] catch (...) {...} | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: NullReferenceException] catch (...) {...} | Finally.cs:147:10:147:11 | M8 | -| Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: OutOfMemoryException] catch (...) {...} | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:30:161:30 | [exception: Exception] Exception e | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:30:161:30 | [exception: NullReferenceException] Exception e | Finally.cs:147:10:147:11 | M8 | -| Finally.cs:161:30:161:30 | [exception: OutOfMemoryException] Exception e | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: Exception] Exception e | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: NullReferenceException] Exception e | Finally.cs:147:10:147:11 | M8 | -| Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] Exception e | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: Exception] Exception e | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: NullReferenceException] Exception e | Finally.cs:147:10:147:11 | M8 | -| Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: OutOfMemoryException] Exception e | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:39:161:39 | [exception: Exception] access to local variable e | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:39:161:39 | [exception: NullReferenceException] access to local variable e | Finally.cs:147:10:147:11 | M8 | -| Finally.cs:161:39:161:39 | [exception: OutOfMemoryException] access to local variable e | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:39:161:39 | [finally: exception(ArgumentNullException), exception: Exception] access to local variable e | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:39:161:39 | [finally: exception(ArgumentNullException), exception: NullReferenceException] access to local variable e | Finally.cs:147:10:147:11 | M8 | -| Finally.cs:161:39:161:39 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] access to local variable e | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:39:161:39 | [finally: exception(Exception), exception: Exception] access to local variable e | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:39:161:39 | [finally: exception(Exception), exception: NullReferenceException] access to local variable e | Finally.cs:147:10:147:11 | M8 | -| Finally.cs:161:39:161:39 | [finally: exception(Exception), exception: OutOfMemoryException] access to local variable e | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:39:161:47 | [exception: Exception] access to property Message | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:39:161:47 | [exception: NullReferenceException] access to property Message | Finally.cs:147:10:147:11 | M8 | -| Finally.cs:161:39:161:47 | [exception: OutOfMemoryException] access to property Message | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:39:161:47 | [finally: exception(ArgumentNullException), exception: Exception] access to property Message | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:39:161:47 | [finally: exception(ArgumentNullException), exception: NullReferenceException] access to property Message | Finally.cs:147:10:147:11 | M8 | -| Finally.cs:161:39:161:47 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] access to property Message | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:39:161:47 | [finally: exception(Exception), exception: Exception] access to property Message | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:39:161:47 | [finally: exception(Exception), exception: NullReferenceException] access to property Message | Finally.cs:147:10:147:11 | M8 | -| Finally.cs:161:39:161:47 | [finally: exception(Exception), exception: OutOfMemoryException] access to property Message | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:39:161:54 | [exception: Exception] ... == ... | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:39:161:54 | [exception: NullReferenceException] ... == ... | Finally.cs:147:10:147:11 | M8 | -| Finally.cs:161:39:161:54 | [exception: OutOfMemoryException] ... == ... | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:39:161:54 | [finally: exception(ArgumentNullException), exception: Exception] ... == ... | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:39:161:54 | [finally: exception(ArgumentNullException), exception: NullReferenceException] ... == ... | Finally.cs:147:10:147:11 | M8 | -| Finally.cs:161:39:161:54 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] ... == ... | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:39:161:54 | [finally: exception(Exception), exception: Exception] ... == ... | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:39:161:54 | [finally: exception(Exception), exception: NullReferenceException] ... == ... | Finally.cs:147:10:147:11 | M8 | -| Finally.cs:161:39:161:54 | [finally: exception(Exception), exception: OutOfMemoryException] ... == ... | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:52:161:54 | [exception: Exception] "1" | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:52:161:54 | [exception: NullReferenceException] "1" | Finally.cs:147:10:147:11 | M8 | -| Finally.cs:161:52:161:54 | [exception: OutOfMemoryException] "1" | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:52:161:54 | [finally: exception(ArgumentNullException), exception: Exception] "1" | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:52:161:54 | [finally: exception(ArgumentNullException), exception: NullReferenceException] "1" | Finally.cs:147:10:147:11 | M8 | -| Finally.cs:161:52:161:54 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] "1" | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:52:161:54 | [finally: exception(Exception), exception: Exception] "1" | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:52:161:54 | [finally: exception(Exception), exception: NullReferenceException] "1" | Finally.cs:147:10:147:11 | M8 | -| Finally.cs:161:52:161:54 | [finally: exception(Exception), exception: OutOfMemoryException] "1" | Finally.cs:147:10:147:11 | M8 | | Finally.cs:162:13:164:13 | [finally: exception(ArgumentNullException)] {...} | Finally.cs:147:10:147:11 | M8 | | Finally.cs:162:13:164:13 | [finally: exception(Exception)] {...} | Finally.cs:147:10:147:11 | M8 | | Finally.cs:162:13:164:13 | {...} | Finally.cs:147:10:147:11 | M8 | @@ -2582,20 +2542,16 @@ nodeEnclosing | Finally.cs:254:31:254:43 | "Mid finally" | Finally.cs:233:10:233:12 | M12 | | Finally.cs:257:9:259:9 | [finally: exception(Exception)] {...} | Finally.cs:233:10:233:12 | M12 | | Finally.cs:257:9:259:9 | [finally: exception(ExceptionA)] {...} | Finally.cs:233:10:233:12 | M12 | -| Finally.cs:257:9:259:9 | [finally: exception(OutOfMemoryException)] {...} | Finally.cs:233:10:233:12 | M12 | | Finally.cs:257:9:259:9 | {...} | Finally.cs:233:10:233:12 | M12 | | Finally.cs:258:13:258:46 | [finally: exception(Exception)] call to method WriteLine | Finally.cs:233:10:233:12 | M12 | | Finally.cs:258:13:258:46 | [finally: exception(ExceptionA)] call to method WriteLine | Finally.cs:233:10:233:12 | M12 | -| Finally.cs:258:13:258:46 | [finally: exception(OutOfMemoryException)] call to method WriteLine | Finally.cs:233:10:233:12 | M12 | | Finally.cs:258:13:258:46 | call to method WriteLine | Finally.cs:233:10:233:12 | M12 | | Finally.cs:258:13:258:47 | ...; | Finally.cs:233:10:233:12 | M12 | | Finally.cs:258:13:258:47 | [finally: exception(Exception)] ...; | Finally.cs:233:10:233:12 | M12 | | Finally.cs:258:13:258:47 | [finally: exception(ExceptionA)] ...; | Finally.cs:233:10:233:12 | M12 | -| Finally.cs:258:13:258:47 | [finally: exception(OutOfMemoryException)] ...; | Finally.cs:233:10:233:12 | M12 | | Finally.cs:258:31:258:45 | "Outer finally" | Finally.cs:233:10:233:12 | M12 | | Finally.cs:258:31:258:45 | [finally: exception(Exception)] "Outer finally" | Finally.cs:233:10:233:12 | M12 | | Finally.cs:258:31:258:45 | [finally: exception(ExceptionA)] "Outer finally" | Finally.cs:233:10:233:12 | M12 | -| Finally.cs:258:31:258:45 | [finally: exception(OutOfMemoryException)] "Outer finally" | Finally.cs:233:10:233:12 | M12 | | Finally.cs:260:9:260:33 | call to method WriteLine | Finally.cs:233:10:233:12 | M12 | | Finally.cs:260:9:260:34 | ...; | Finally.cs:233:10:233:12 | M12 | | Finally.cs:260:27:260:32 | "Done" | Finally.cs:233:10:233:12 | M12 | @@ -5135,45 +5091,33 @@ blockEnclosing | Extensions.cs:20:17:20:20 | enter Main | Extensions.cs:20:17:20:20 | Main | | Finally.cs:7:10:7:11 | enter M1 | Finally.cs:7:10:7:11 | M1 | | Finally.cs:7:10:7:11 | exit M1 | Finally.cs:7:10:7:11 | M1 | -| Finally.cs:7:10:7:11 | exit M1 (abnormal) | Finally.cs:7:10:7:11 | M1 | -| Finally.cs:11:13:11:37 | call to method WriteLine | Finally.cs:7:10:7:11 | M1 | | Finally.cs:14:9:16:9 | [finally: exception(Exception)] {...} | Finally.cs:7:10:7:11 | M1 | -| Finally.cs:14:9:16:9 | [finally: exception(OutOfMemoryException)] {...} | Finally.cs:7:10:7:11 | M1 | | Finally.cs:14:9:16:9 | {...} | Finally.cs:7:10:7:11 | M1 | | Finally.cs:19:10:19:11 | enter M2 | Finally.cs:19:10:19:11 | M2 | | Finally.cs:19:10:19:11 | exit M2 | Finally.cs:19:10:19:11 | M2 | | Finally.cs:19:10:19:11 | exit M2 (abnormal) | Finally.cs:19:10:19:11 | M2 | | Finally.cs:19:10:19:11 | exit M2 (normal) | Finally.cs:19:10:19:11 | M2 | -| Finally.cs:23:13:23:37 | call to method WriteLine | Finally.cs:19:10:19:11 | M2 | | Finally.cs:24:13:24:19 | return ...; | Finally.cs:19:10:19:11 | M2 | | Finally.cs:26:9:29:9 | [exception: Exception] catch (...) {...} | Finally.cs:19:10:19:11 | M2 | -| Finally.cs:26:9:29:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:19:10:19:11 | M2 | | Finally.cs:26:38:26:39 | [exception: Exception] IOException ex | Finally.cs:19:10:19:11 | M2 | | Finally.cs:27:9:29:9 | {...} | Finally.cs:19:10:19:11 | M2 | | Finally.cs:30:9:40:9 | [exception: Exception] catch (...) {...} | Finally.cs:19:10:19:11 | M2 | -| Finally.cs:30:9:40:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:19:10:19:11 | M2 | | Finally.cs:30:41:30:42 | [exception: Exception] ArgumentException ex | Finally.cs:19:10:19:11 | M2 | | Finally.cs:34:27:34:32 | throw ...; | Finally.cs:19:10:19:11 | M2 | | Finally.cs:41:9:43:9 | [exception: Exception] catch (...) {...} | Finally.cs:19:10:19:11 | M2 | -| Finally.cs:41:9:43:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:19:10:19:11 | M2 | | Finally.cs:42:9:43:9 | {...} | Finally.cs:19:10:19:11 | M2 | | Finally.cs:54:10:54:11 | enter M3 | Finally.cs:54:10:54:11 | M3 | | Finally.cs:54:10:54:11 | exit M3 | Finally.cs:54:10:54:11 | M3 | | Finally.cs:54:10:54:11 | exit M3 (abnormal) | Finally.cs:54:10:54:11 | M3 | | Finally.cs:54:10:54:11 | exit M3 (normal) | Finally.cs:54:10:54:11 | M3 | -| Finally.cs:58:13:58:37 | call to method WriteLine | Finally.cs:54:10:54:11 | M3 | | Finally.cs:59:13:59:19 | return ...; | Finally.cs:54:10:54:11 | M3 | | Finally.cs:61:9:64:9 | [exception: Exception] catch (...) {...} | Finally.cs:54:10:54:11 | M3 | -| Finally.cs:61:9:64:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:54:10:54:11 | M3 | | Finally.cs:61:38:61:39 | [exception: Exception] IOException ex | Finally.cs:54:10:54:11 | M3 | | Finally.cs:62:9:64:9 | {...} | Finally.cs:54:10:54:11 | M3 | | Finally.cs:65:9:67:9 | [exception: Exception] catch (...) {...} | Finally.cs:54:10:54:11 | M3 | -| Finally.cs:65:9:67:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:54:10:54:11 | M3 | | Finally.cs:65:26:65:26 | [exception: Exception] Exception e | Finally.cs:54:10:54:11 | M3 | -| Finally.cs:65:26:65:26 | [exception: OutOfMemoryException] Exception e | Finally.cs:54:10:54:11 | M3 | | Finally.cs:66:9:67:9 | {...} | Finally.cs:54:10:54:11 | M3 | | Finally.cs:69:9:71:9 | [finally: exception(Exception)] {...} | Finally.cs:54:10:54:11 | M3 | -| Finally.cs:69:9:71:9 | [finally: exception(OutOfMemoryException)] {...} | Finally.cs:54:10:54:11 | M3 | | Finally.cs:74:10:74:11 | enter M4 | Finally.cs:74:10:74:11 | M4 | | Finally.cs:74:10:74:11 | exit M4 | Finally.cs:74:10:74:11 | M4 | | Finally.cs:74:10:74:11 | exit M4 (abnormal) | Finally.cs:74:10:74:11 | M4 | @@ -5245,9 +5189,7 @@ blockEnclosing | Finally.cs:121:10:121:11 | enter M6 | Finally.cs:121:10:121:11 | M6 | | Finally.cs:133:10:133:11 | enter M7 | Finally.cs:133:10:133:11 | M7 | | Finally.cs:133:10:133:11 | exit M7 (abnormal) | Finally.cs:133:10:133:11 | M7 | -| Finally.cs:137:13:137:36 | call to method WriteLine | Finally.cs:133:10:133:11 | M7 | | Finally.cs:140:9:143:9 | [finally: exception(Exception)] {...} | Finally.cs:133:10:133:11 | M7 | -| Finally.cs:140:9:143:9 | [finally: exception(OutOfMemoryException)] {...} | Finally.cs:133:10:133:11 | M7 | | Finally.cs:140:9:143:9 | {...} | Finally.cs:133:10:133:11 | M7 | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:147:10:147:11 | M8 | | Finally.cs:147:10:147:11 | exit M8 | Finally.cs:147:10:147:11 | M8 | @@ -5263,30 +5205,21 @@ blockEnclosing | Finally.cs:159:21:159:45 | [finally: exception(ArgumentNullException)] throw ...; | Finally.cs:147:10:147:11 | M8 | | Finally.cs:159:21:159:45 | [finally: exception(Exception)] throw ...; | Finally.cs:147:10:147:11 | M8 | | Finally.cs:159:21:159:45 | throw ...; | Finally.cs:147:10:147:11 | M8 | -| Finally.cs:159:27:159:44 | [finally: exception(ArgumentNullException)] object creation of type Exception | Finally.cs:147:10:147:11 | M8 | -| Finally.cs:159:27:159:44 | [finally: exception(Exception)] object creation of type Exception | Finally.cs:147:10:147:11 | M8 | -| Finally.cs:159:27:159:44 | object creation of type Exception | Finally.cs:147:10:147:11 | M8 | | Finally.cs:159:41:159:43 | "1" | Finally.cs:147:10:147:11 | M8 | | Finally.cs:159:41:159:43 | [finally: exception(ArgumentNullException)] "1" | Finally.cs:147:10:147:11 | M8 | | Finally.cs:159:41:159:43 | [finally: exception(Exception)] "1" | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:13:164:13 | [exception: Exception] catch (...) {...} | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:13:164:13 | [exception: NullReferenceException] catch (...) {...} | Finally.cs:147:10:147:11 | M8 | -| Finally.cs:161:13:164:13 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: Exception] catch (...) {...} | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: NullReferenceException] catch (...) {...} | Finally.cs:147:10:147:11 | M8 | -| Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] catch (...) {...} | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: Exception] catch (...) {...} | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: NullReferenceException] catch (...) {...} | Finally.cs:147:10:147:11 | M8 | -| Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: OutOfMemoryException] catch (...) {...} | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:30:161:30 | [exception: Exception] Exception e | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:30:161:30 | [exception: NullReferenceException] Exception e | Finally.cs:147:10:147:11 | M8 | -| Finally.cs:161:30:161:30 | [exception: OutOfMemoryException] Exception e | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: Exception] Exception e | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: NullReferenceException] Exception e | Finally.cs:147:10:147:11 | M8 | -| Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] Exception e | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: Exception] Exception e | Finally.cs:147:10:147:11 | M8 | | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: NullReferenceException] Exception e | Finally.cs:147:10:147:11 | M8 | -| Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: OutOfMemoryException] Exception e | Finally.cs:147:10:147:11 | M8 | | Finally.cs:162:13:164:13 | [finally: exception(ArgumentNullException)] {...} | Finally.cs:147:10:147:11 | M8 | | Finally.cs:162:13:164:13 | [finally: exception(Exception)] {...} | Finally.cs:147:10:147:11 | M8 | | Finally.cs:162:13:164:13 | {...} | Finally.cs:147:10:147:11 | M8 | @@ -5353,7 +5286,6 @@ blockEnclosing | Finally.cs:211:13:211:29 | [finally: exception(Exception)] ...; | Finally.cs:195:10:195:12 | M10 | | Finally.cs:211:13:211:29 | [finally: exception(ExceptionA)] ...; | Finally.cs:195:10:195:12 | M10 | | Finally.cs:216:10:216:12 | enter M11 | Finally.cs:216:10:216:12 | M11 | -| Finally.cs:220:13:220:36 | call to method WriteLine | Finally.cs:216:10:216:12 | M11 | | Finally.cs:222:9:225:9 | catch {...} | Finally.cs:216:10:216:12 | M11 | | Finally.cs:227:9:229:9 | {...} | Finally.cs:216:10:216:12 | M11 | | Finally.cs:233:10:233:12 | enter M12 | Finally.cs:233:10:233:12 | M12 | @@ -5375,10 +5307,8 @@ blockEnclosing | Finally.cs:250:17:252:17 | [finally: exception(ExceptionA), finally(1): exception(Exception)] {...} | Finally.cs:233:10:233:12 | M12 | | Finally.cs:250:17:252:17 | [finally: exception(ExceptionA)] {...} | Finally.cs:233:10:233:12 | M12 | | Finally.cs:250:17:252:17 | {...} | Finally.cs:233:10:233:12 | M12 | -| Finally.cs:254:13:254:44 | call to method WriteLine | Finally.cs:233:10:233:12 | M12 | | Finally.cs:257:9:259:9 | [finally: exception(Exception)] {...} | Finally.cs:233:10:233:12 | M12 | | Finally.cs:257:9:259:9 | [finally: exception(ExceptionA)] {...} | Finally.cs:233:10:233:12 | M12 | -| Finally.cs:257:9:259:9 | [finally: exception(OutOfMemoryException)] {...} | Finally.cs:233:10:233:12 | M12 | | Finally.cs:257:9:259:9 | {...} | Finally.cs:233:10:233:12 | M12 | | Foreach.cs:6:10:6:11 | enter M1 | Foreach.cs:6:10:6:11 | M1 | | Foreach.cs:6:10:6:11 | exit M1 (normal) | Foreach.cs:6:10:6:11 | M1 | diff --git a/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected b/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected index f389324db3b..9a657596235 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected @@ -982,25 +982,19 @@ | CompileTimeOperators.cs:22:23:22:23 | access to parameter i | CompileTimeOperators.cs:22:23:22:23 | access to parameter i | normal | | CompileTimeOperators.cs:29:5:41:5 | {...} | CompileTimeOperators.cs:37:13:37:40 | call to method WriteLine | goto(End) [normal] (0) | | CompileTimeOperators.cs:29:5:41:5 | {...} | CompileTimeOperators.cs:37:13:37:40 | call to method WriteLine | throw(Exception) [normal] (0) | -| CompileTimeOperators.cs:29:5:41:5 | {...} | CompileTimeOperators.cs:37:13:37:40 | call to method WriteLine | throw(OutOfMemoryException) [normal] (0) | | CompileTimeOperators.cs:29:5:41:5 | {...} | CompileTimeOperators.cs:40:14:40:37 | call to method WriteLine | normal | | CompileTimeOperators.cs:30:9:38:9 | try {...} ... | CompileTimeOperators.cs:37:13:37:40 | call to method WriteLine | goto(End) [normal] (0) | | CompileTimeOperators.cs:30:9:38:9 | try {...} ... | CompileTimeOperators.cs:37:13:37:40 | call to method WriteLine | normal | | CompileTimeOperators.cs:30:9:38:9 | try {...} ... | CompileTimeOperators.cs:37:13:37:40 | call to method WriteLine | throw(Exception) [normal] (0) | -| CompileTimeOperators.cs:30:9:38:9 | try {...} ... | CompileTimeOperators.cs:37:13:37:40 | call to method WriteLine | throw(OutOfMemoryException) [normal] (0) | | CompileTimeOperators.cs:31:9:34:9 | {...} | CompileTimeOperators.cs:32:13:32:21 | goto ...; | goto(End) | | CompileTimeOperators.cs:31:9:34:9 | {...} | CompileTimeOperators.cs:33:13:33:37 | call to method WriteLine | normal | | CompileTimeOperators.cs:31:9:34:9 | {...} | CompileTimeOperators.cs:33:13:33:37 | call to method WriteLine | throw(Exception) | -| CompileTimeOperators.cs:31:9:34:9 | {...} | CompileTimeOperators.cs:33:31:33:36 | "Dead" | throw(OutOfMemoryException) | | CompileTimeOperators.cs:32:13:32:21 | goto ...; | CompileTimeOperators.cs:32:13:32:21 | goto ...; | goto(End) | | CompileTimeOperators.cs:33:13:33:37 | call to method WriteLine | CompileTimeOperators.cs:33:13:33:37 | call to method WriteLine | normal | | CompileTimeOperators.cs:33:13:33:37 | call to method WriteLine | CompileTimeOperators.cs:33:13:33:37 | call to method WriteLine | throw(Exception) | -| CompileTimeOperators.cs:33:13:33:37 | call to method WriteLine | CompileTimeOperators.cs:33:31:33:36 | "Dead" | throw(OutOfMemoryException) | | CompileTimeOperators.cs:33:13:33:38 | ...; | CompileTimeOperators.cs:33:13:33:37 | call to method WriteLine | normal | | CompileTimeOperators.cs:33:13:33:38 | ...; | CompileTimeOperators.cs:33:13:33:37 | call to method WriteLine | throw(Exception) | -| CompileTimeOperators.cs:33:13:33:38 | ...; | CompileTimeOperators.cs:33:31:33:36 | "Dead" | throw(OutOfMemoryException) | | CompileTimeOperators.cs:33:31:33:36 | "Dead" | CompileTimeOperators.cs:33:31:33:36 | "Dead" | normal | -| CompileTimeOperators.cs:33:31:33:36 | "Dead" | CompileTimeOperators.cs:33:31:33:36 | "Dead" | throw(OutOfMemoryException) | | CompileTimeOperators.cs:36:9:38:9 | {...} | CompileTimeOperators.cs:37:13:37:40 | call to method WriteLine | normal | | CompileTimeOperators.cs:37:13:37:40 | call to method WriteLine | CompileTimeOperators.cs:37:13:37:40 | call to method WriteLine | normal | | CompileTimeOperators.cs:37:13:37:41 | ...; | CompileTimeOperators.cs:37:13:37:40 | call to method WriteLine | normal | @@ -1635,21 +1629,15 @@ | Extensions.cs:25:23:25:32 | delegate creation of type Func | Extensions.cs:25:23:25:32 | delegate creation of type Func | normal | | Finally.cs:8:5:17:5 | {...} | Finally.cs:15:13:15:40 | call to method WriteLine | normal | | Finally.cs:8:5:17:5 | {...} | Finally.cs:15:13:15:40 | call to method WriteLine | throw(Exception) [normal] (0) | -| Finally.cs:8:5:17:5 | {...} | Finally.cs:15:13:15:40 | call to method WriteLine | throw(OutOfMemoryException) [normal] (0) | | Finally.cs:9:9:16:9 | try {...} ... | Finally.cs:15:13:15:40 | call to method WriteLine | normal | | Finally.cs:9:9:16:9 | try {...} ... | Finally.cs:15:13:15:40 | call to method WriteLine | throw(Exception) [normal] (0) | -| Finally.cs:9:9:16:9 | try {...} ... | Finally.cs:15:13:15:40 | call to method WriteLine | throw(OutOfMemoryException) [normal] (0) | | Finally.cs:10:9:12:9 | {...} | Finally.cs:11:13:11:37 | call to method WriteLine | normal | | Finally.cs:10:9:12:9 | {...} | Finally.cs:11:13:11:37 | call to method WriteLine | throw(Exception) | -| Finally.cs:10:9:12:9 | {...} | Finally.cs:11:31:11:36 | "Try1" | throw(OutOfMemoryException) | | Finally.cs:11:13:11:37 | call to method WriteLine | Finally.cs:11:13:11:37 | call to method WriteLine | normal | | Finally.cs:11:13:11:37 | call to method WriteLine | Finally.cs:11:13:11:37 | call to method WriteLine | throw(Exception) | -| Finally.cs:11:13:11:37 | call to method WriteLine | Finally.cs:11:31:11:36 | "Try1" | throw(OutOfMemoryException) | | Finally.cs:11:13:11:38 | ...; | Finally.cs:11:13:11:37 | call to method WriteLine | normal | | Finally.cs:11:13:11:38 | ...; | Finally.cs:11:13:11:37 | call to method WriteLine | throw(Exception) | -| Finally.cs:11:13:11:38 | ...; | Finally.cs:11:31:11:36 | "Try1" | throw(OutOfMemoryException) | | Finally.cs:11:31:11:36 | "Try1" | Finally.cs:11:31:11:36 | "Try1" | normal | -| Finally.cs:11:31:11:36 | "Try1" | Finally.cs:11:31:11:36 | "Try1" | throw(OutOfMemoryException) | | Finally.cs:14:9:16:9 | {...} | Finally.cs:15:13:15:40 | call to method WriteLine | normal | | Finally.cs:15:13:15:40 | call to method WriteLine | Finally.cs:15:13:15:40 | call to method WriteLine | normal | | Finally.cs:15:13:15:41 | ...; | Finally.cs:15:13:15:40 | call to method WriteLine | normal | @@ -1663,16 +1651,12 @@ | Finally.cs:21:9:51:9 | try {...} ... | Finally.cs:50:13:50:40 | call to method WriteLine | throw(Exception) [normal] (0) | | Finally.cs:21:9:51:9 | try {...} ... | Finally.cs:50:13:50:40 | call to method WriteLine | throw(IOException) [normal] (0) | | Finally.cs:22:9:25:9 | {...} | Finally.cs:23:13:23:37 | call to method WriteLine | throw(Exception) | -| Finally.cs:22:9:25:9 | {...} | Finally.cs:23:31:23:36 | "Try2" | throw(OutOfMemoryException) | | Finally.cs:22:9:25:9 | {...} | Finally.cs:24:13:24:19 | return ...; | return | | Finally.cs:23:13:23:37 | call to method WriteLine | Finally.cs:23:13:23:37 | call to method WriteLine | normal | | Finally.cs:23:13:23:37 | call to method WriteLine | Finally.cs:23:13:23:37 | call to method WriteLine | throw(Exception) | -| Finally.cs:23:13:23:37 | call to method WriteLine | Finally.cs:23:31:23:36 | "Try2" | throw(OutOfMemoryException) | | Finally.cs:23:13:23:38 | ...; | Finally.cs:23:13:23:37 | call to method WriteLine | normal | | Finally.cs:23:13:23:38 | ...; | Finally.cs:23:13:23:37 | call to method WriteLine | throw(Exception) | -| Finally.cs:23:13:23:38 | ...; | Finally.cs:23:31:23:36 | "Try2" | throw(OutOfMemoryException) | | Finally.cs:23:31:23:36 | "Try2" | Finally.cs:23:31:23:36 | "Try2" | normal | -| Finally.cs:23:31:23:36 | "Try2" | Finally.cs:23:31:23:36 | "Try2" | throw(OutOfMemoryException) | | Finally.cs:24:13:24:19 | return ...; | Finally.cs:24:13:24:19 | return ...; | return | | Finally.cs:26:9:29:9 | catch (...) {...} | Finally.cs:26:9:29:9 | catch (...) {...} | no-match | | Finally.cs:26:9:29:9 | catch (...) {...} | Finally.cs:28:13:28:18 | throw ...; | throw(IOException) | @@ -1707,23 +1691,17 @@ | Finally.cs:55:5:72:5 | {...} | Finally.cs:70:13:70:40 | call to method WriteLine | return [normal] (0) | | Finally.cs:55:5:72:5 | {...} | Finally.cs:70:13:70:40 | call to method WriteLine | throw(Exception) [normal] (0) | | Finally.cs:55:5:72:5 | {...} | Finally.cs:70:13:70:40 | call to method WriteLine | throw(IOException) [normal] (0) | -| Finally.cs:55:5:72:5 | {...} | Finally.cs:70:13:70:40 | call to method WriteLine | throw(OutOfMemoryException) [normal] (0) | | Finally.cs:56:9:71:9 | try {...} ... | Finally.cs:70:13:70:40 | call to method WriteLine | normal | | Finally.cs:56:9:71:9 | try {...} ... | Finally.cs:70:13:70:40 | call to method WriteLine | return [normal] (0) | | Finally.cs:56:9:71:9 | try {...} ... | Finally.cs:70:13:70:40 | call to method WriteLine | throw(Exception) [normal] (0) | | Finally.cs:56:9:71:9 | try {...} ... | Finally.cs:70:13:70:40 | call to method WriteLine | throw(IOException) [normal] (0) | -| Finally.cs:56:9:71:9 | try {...} ... | Finally.cs:70:13:70:40 | call to method WriteLine | throw(OutOfMemoryException) [normal] (0) | | Finally.cs:57:9:60:9 | {...} | Finally.cs:58:13:58:37 | call to method WriteLine | throw(Exception) | -| Finally.cs:57:9:60:9 | {...} | Finally.cs:58:31:58:36 | "Try3" | throw(OutOfMemoryException) | | Finally.cs:57:9:60:9 | {...} | Finally.cs:59:13:59:19 | return ...; | return | | Finally.cs:58:13:58:37 | call to method WriteLine | Finally.cs:58:13:58:37 | call to method WriteLine | normal | | Finally.cs:58:13:58:37 | call to method WriteLine | Finally.cs:58:13:58:37 | call to method WriteLine | throw(Exception) | -| Finally.cs:58:13:58:37 | call to method WriteLine | Finally.cs:58:31:58:36 | "Try3" | throw(OutOfMemoryException) | | Finally.cs:58:13:58:38 | ...; | Finally.cs:58:13:58:37 | call to method WriteLine | normal | | Finally.cs:58:13:58:38 | ...; | Finally.cs:58:13:58:37 | call to method WriteLine | throw(Exception) | -| Finally.cs:58:13:58:38 | ...; | Finally.cs:58:31:58:36 | "Try3" | throw(OutOfMemoryException) | | Finally.cs:58:31:58:36 | "Try3" | Finally.cs:58:31:58:36 | "Try3" | normal | -| Finally.cs:58:31:58:36 | "Try3" | Finally.cs:58:31:58:36 | "Try3" | throw(OutOfMemoryException) | | Finally.cs:59:13:59:19 | return ...; | Finally.cs:59:13:59:19 | return ...; | return | | Finally.cs:61:9:64:9 | catch (...) {...} | Finally.cs:61:9:64:9 | catch (...) {...} | no-match | | Finally.cs:61:9:64:9 | catch (...) {...} | Finally.cs:63:13:63:18 | throw ...; | throw(IOException) | @@ -1732,9 +1710,7 @@ | Finally.cs:62:9:64:9 | {...} | Finally.cs:63:13:63:18 | throw ...; | throw(IOException) | | Finally.cs:63:13:63:18 | throw ...; | Finally.cs:63:13:63:18 | throw ...; | throw(IOException) | | Finally.cs:65:9:67:9 | catch (...) {...} | Finally.cs:65:9:67:9 | catch (...) {...} | throw(Exception) [no-match] (0) | -| Finally.cs:65:9:67:9 | catch (...) {...} | Finally.cs:65:9:67:9 | catch (...) {...} | throw(OutOfMemoryException) [no-match] (0) | | Finally.cs:65:9:67:9 | catch (...) {...} | Finally.cs:65:35:65:51 | ... != ... | throw(Exception) [false] (0) | -| Finally.cs:65:9:67:9 | catch (...) {...} | Finally.cs:65:35:65:51 | ... != ... | throw(OutOfMemoryException) [false] (0) | | Finally.cs:65:9:67:9 | catch (...) {...} | Finally.cs:66:9:67:9 | {...} | normal | | Finally.cs:65:26:65:26 | Exception e | Finally.cs:65:26:65:26 | Exception e | normal | | Finally.cs:65:35:65:35 | access to local variable e | Finally.cs:65:35:65:35 | access to local variable e | normal | @@ -1934,23 +1910,17 @@ | Finally.cs:129:13:129:13 | ; | Finally.cs:129:13:129:13 | ; | normal | | Finally.cs:134:5:145:5 | {...} | Finally.cs:141:13:141:44 | throw ...; | throw(ArgumentException) | | Finally.cs:134:5:145:5 | {...} | Finally.cs:142:13:142:37 | call to method WriteLine | throw(Exception) [normal] (0) | -| Finally.cs:134:5:145:5 | {...} | Finally.cs:142:13:142:37 | call to method WriteLine | throw(OutOfMemoryException) [normal] (0) | | Finally.cs:134:5:145:5 | {...} | Finally.cs:144:9:144:33 | call to method WriteLine | normal | | Finally.cs:135:9:143:9 | try {...} ... | Finally.cs:141:13:141:44 | throw ...; | throw(ArgumentException) | | Finally.cs:135:9:143:9 | try {...} ... | Finally.cs:142:13:142:37 | call to method WriteLine | normal | | Finally.cs:135:9:143:9 | try {...} ... | Finally.cs:142:13:142:37 | call to method WriteLine | throw(Exception) [normal] (0) | -| Finally.cs:135:9:143:9 | try {...} ... | Finally.cs:142:13:142:37 | call to method WriteLine | throw(OutOfMemoryException) [normal] (0) | | Finally.cs:136:9:138:9 | {...} | Finally.cs:137:13:137:36 | call to method WriteLine | normal | | Finally.cs:136:9:138:9 | {...} | Finally.cs:137:13:137:36 | call to method WriteLine | throw(Exception) | -| Finally.cs:136:9:138:9 | {...} | Finally.cs:137:31:137:35 | "Try" | throw(OutOfMemoryException) | | Finally.cs:137:13:137:36 | call to method WriteLine | Finally.cs:137:13:137:36 | call to method WriteLine | normal | | Finally.cs:137:13:137:36 | call to method WriteLine | Finally.cs:137:13:137:36 | call to method WriteLine | throw(Exception) | -| Finally.cs:137:13:137:36 | call to method WriteLine | Finally.cs:137:31:137:35 | "Try" | throw(OutOfMemoryException) | | Finally.cs:137:13:137:37 | ...; | Finally.cs:137:13:137:36 | call to method WriteLine | normal | | Finally.cs:137:13:137:37 | ...; | Finally.cs:137:13:137:36 | call to method WriteLine | throw(Exception) | -| Finally.cs:137:13:137:37 | ...; | Finally.cs:137:31:137:35 | "Try" | throw(OutOfMemoryException) | | Finally.cs:137:31:137:35 | "Try" | Finally.cs:137:31:137:35 | "Try" | normal | -| Finally.cs:137:31:137:35 | "Try" | Finally.cs:137:31:137:35 | "Try" | throw(OutOfMemoryException) | | Finally.cs:140:9:143:9 | {...} | Finally.cs:141:13:141:44 | throw ...; | throw(ArgumentException) | | Finally.cs:140:9:143:9 | {...} | Finally.cs:142:13:142:37 | call to method WriteLine | normal | | Finally.cs:141:13:141:44 | throw ...; | Finally.cs:141:13:141:44 | throw ...; | throw(ArgumentException) | @@ -2005,13 +1975,11 @@ | Finally.cs:157:13:160:13 | {...} | Finally.cs:158:21:158:36 | ... == ... | false | | Finally.cs:157:13:160:13 | {...} | Finally.cs:159:21:159:45 | throw ...; | throw(Exception) | | Finally.cs:157:13:160:13 | {...} | Finally.cs:159:27:159:44 | object creation of type Exception | throw(Exception) | -| Finally.cs:157:13:160:13 | {...} | Finally.cs:159:41:159:43 | "1" | throw(OutOfMemoryException) | | Finally.cs:158:17:159:45 | if (...) ... | Finally.cs:158:21:158:31 | access to property Length | throw(Exception) | | Finally.cs:158:17:159:45 | if (...) ... | Finally.cs:158:21:158:31 | access to property Length | throw(NullReferenceException) | | Finally.cs:158:17:159:45 | if (...) ... | Finally.cs:158:21:158:36 | ... == ... | false | | Finally.cs:158:17:159:45 | if (...) ... | Finally.cs:159:21:159:45 | throw ...; | throw(Exception) | | Finally.cs:158:17:159:45 | if (...) ... | Finally.cs:159:27:159:44 | object creation of type Exception | throw(Exception) | -| Finally.cs:158:17:159:45 | if (...) ... | Finally.cs:159:41:159:43 | "1" | throw(OutOfMemoryException) | | Finally.cs:158:21:158:24 | access to parameter args | Finally.cs:158:21:158:24 | access to parameter args | normal | | Finally.cs:158:21:158:31 | access to property Length | Finally.cs:158:21:158:31 | access to property Length | normal | | Finally.cs:158:21:158:31 | access to property Length | Finally.cs:158:21:158:31 | access to property Length | throw(Exception) | @@ -2023,12 +1991,9 @@ | Finally.cs:158:36:158:36 | 1 | Finally.cs:158:36:158:36 | 1 | normal | | Finally.cs:159:21:159:45 | throw ...; | Finally.cs:159:21:159:45 | throw ...; | throw(Exception) | | Finally.cs:159:21:159:45 | throw ...; | Finally.cs:159:27:159:44 | object creation of type Exception | throw(Exception) | -| Finally.cs:159:21:159:45 | throw ...; | Finally.cs:159:41:159:43 | "1" | throw(OutOfMemoryException) | | Finally.cs:159:27:159:44 | object creation of type Exception | Finally.cs:159:27:159:44 | object creation of type Exception | normal | | Finally.cs:159:27:159:44 | object creation of type Exception | Finally.cs:159:27:159:44 | object creation of type Exception | throw(Exception) | -| Finally.cs:159:27:159:44 | object creation of type Exception | Finally.cs:159:41:159:43 | "1" | throw(OutOfMemoryException) | | Finally.cs:159:41:159:43 | "1" | Finally.cs:159:41:159:43 | "1" | normal | -| Finally.cs:159:41:159:43 | "1" | Finally.cs:159:41:159:43 | "1" | throw(OutOfMemoryException) | | Finally.cs:161:13:164:13 | catch (...) {...} | Finally.cs:161:13:164:13 | catch (...) {...} | no-match | | Finally.cs:161:13:164:13 | catch (...) {...} | Finally.cs:161:39:161:54 | ... == ... | false | | Finally.cs:161:13:164:13 | catch (...) {...} | Finally.cs:163:17:163:42 | call to method WriteLine | normal | @@ -2191,15 +2156,11 @@ | Finally.cs:218:9:229:9 | try {...} ... | Finally.cs:228:13:228:40 | call to method WriteLine | normal | | Finally.cs:219:9:221:9 | {...} | Finally.cs:220:13:220:36 | call to method WriteLine | normal | | Finally.cs:219:9:221:9 | {...} | Finally.cs:220:13:220:36 | call to method WriteLine | throw(Exception) | -| Finally.cs:219:9:221:9 | {...} | Finally.cs:220:31:220:35 | "Try" | throw(OutOfMemoryException) | | Finally.cs:220:13:220:36 | call to method WriteLine | Finally.cs:220:13:220:36 | call to method WriteLine | normal | | Finally.cs:220:13:220:36 | call to method WriteLine | Finally.cs:220:13:220:36 | call to method WriteLine | throw(Exception) | -| Finally.cs:220:13:220:36 | call to method WriteLine | Finally.cs:220:31:220:35 | "Try" | throw(OutOfMemoryException) | | Finally.cs:220:13:220:37 | ...; | Finally.cs:220:13:220:36 | call to method WriteLine | normal | | Finally.cs:220:13:220:37 | ...; | Finally.cs:220:13:220:36 | call to method WriteLine | throw(Exception) | -| Finally.cs:220:13:220:37 | ...; | Finally.cs:220:31:220:35 | "Try" | throw(OutOfMemoryException) | | Finally.cs:220:31:220:35 | "Try" | Finally.cs:220:31:220:35 | "Try" | normal | -| Finally.cs:220:31:220:35 | "Try" | Finally.cs:220:31:220:35 | "Try" | throw(OutOfMemoryException) | | Finally.cs:222:9:225:9 | catch {...} | Finally.cs:224:13:224:38 | call to method WriteLine | normal | | Finally.cs:223:9:225:9 | {...} | Finally.cs:224:13:224:38 | call to method WriteLine | normal | | Finally.cs:224:13:224:38 | call to method WriteLine | Finally.cs:224:13:224:38 | call to method WriteLine | normal | @@ -2214,19 +2175,16 @@ | Finally.cs:230:27:230:32 | "Done" | Finally.cs:230:27:230:32 | "Done" | normal | | Finally.cs:234:5:261:5 | {...} | Finally.cs:258:13:258:46 | call to method WriteLine | throw(Exception) [normal] (0) | | Finally.cs:234:5:261:5 | {...} | Finally.cs:258:13:258:46 | call to method WriteLine | throw(ExceptionA) [normal] (0) | -| Finally.cs:234:5:261:5 | {...} | Finally.cs:258:13:258:46 | call to method WriteLine | throw(OutOfMemoryException) [normal] (0) | | Finally.cs:234:5:261:5 | {...} | Finally.cs:260:9:260:33 | call to method WriteLine | normal | | Finally.cs:235:9:259:9 | try {...} ... | Finally.cs:258:13:258:46 | call to method WriteLine | normal | | Finally.cs:235:9:259:9 | try {...} ... | Finally.cs:258:13:258:46 | call to method WriteLine | throw(Exception) [normal] (0) | | Finally.cs:235:9:259:9 | try {...} ... | Finally.cs:258:13:258:46 | call to method WriteLine | throw(ExceptionA) [normal] (0) | -| Finally.cs:235:9:259:9 | try {...} ... | Finally.cs:258:13:258:46 | call to method WriteLine | throw(OutOfMemoryException) [normal] (0) | | Finally.cs:236:9:255:9 | {...} | Finally.cs:251:21:251:54 | call to method WriteLine | throw(Exception) [normal] (0) | | Finally.cs:236:9:255:9 | {...} | Finally.cs:251:21:251:54 | call to method WriteLine | throw(Exception) [normal] (1) | | Finally.cs:236:9:255:9 | {...} | Finally.cs:251:21:251:54 | call to method WriteLine | throw(ExceptionA) [normal] (0) | | Finally.cs:236:9:255:9 | {...} | Finally.cs:251:21:251:54 | call to method WriteLine | throw(ExceptionA) [normal] (1) | | Finally.cs:236:9:255:9 | {...} | Finally.cs:254:13:254:44 | call to method WriteLine | normal | | Finally.cs:236:9:255:9 | {...} | Finally.cs:254:13:254:44 | call to method WriteLine | throw(Exception) | -| Finally.cs:236:9:255:9 | {...} | Finally.cs:254:31:254:43 | "Mid finally" | throw(OutOfMemoryException) | | Finally.cs:237:13:253:13 | try {...} ... | Finally.cs:251:21:251:54 | call to method WriteLine | normal | | Finally.cs:237:13:253:13 | try {...} ... | Finally.cs:251:21:251:54 | call to method WriteLine | throw(Exception) [normal] (0) | | Finally.cs:237:13:253:13 | try {...} ... | Finally.cs:251:21:251:54 | call to method WriteLine | throw(Exception) [normal] (1) | @@ -2268,12 +2226,9 @@ | Finally.cs:251:39:251:53 | "Inner finally" | Finally.cs:251:39:251:53 | "Inner finally" | normal | | Finally.cs:254:13:254:44 | call to method WriteLine | Finally.cs:254:13:254:44 | call to method WriteLine | normal | | Finally.cs:254:13:254:44 | call to method WriteLine | Finally.cs:254:13:254:44 | call to method WriteLine | throw(Exception) | -| Finally.cs:254:13:254:44 | call to method WriteLine | Finally.cs:254:31:254:43 | "Mid finally" | throw(OutOfMemoryException) | | Finally.cs:254:13:254:45 | ...; | Finally.cs:254:13:254:44 | call to method WriteLine | normal | | Finally.cs:254:13:254:45 | ...; | Finally.cs:254:13:254:44 | call to method WriteLine | throw(Exception) | -| Finally.cs:254:13:254:45 | ...; | Finally.cs:254:31:254:43 | "Mid finally" | throw(OutOfMemoryException) | | Finally.cs:254:31:254:43 | "Mid finally" | Finally.cs:254:31:254:43 | "Mid finally" | normal | -| Finally.cs:254:31:254:43 | "Mid finally" | Finally.cs:254:31:254:43 | "Mid finally" | throw(OutOfMemoryException) | | Finally.cs:257:9:259:9 | {...} | Finally.cs:258:13:258:46 | call to method WriteLine | normal | | Finally.cs:258:13:258:46 | call to method WriteLine | Finally.cs:258:13:258:46 | call to method WriteLine | normal | | Finally.cs:258:13:258:47 | ...; | Finally.cs:258:13:258:46 | call to method WriteLine | normal | @@ -4112,7 +4067,6 @@ | cflow.cs:262:5:277:5 | {...} | cflow.cs:275:13:275:41 | call to method WriteLine | normal | | cflow.cs:262:5:277:5 | {...} | cflow.cs:275:13:275:41 | call to method WriteLine | return [normal] (0) | | cflow.cs:262:5:277:5 | {...} | cflow.cs:275:13:275:41 | call to method WriteLine | throw(Exception) [normal] (0) | -| cflow.cs:262:5:277:5 | {...} | cflow.cs:275:13:275:41 | call to method WriteLine | throw(OutOfMemoryException) [normal] (0) | | cflow.cs:263:9:263:23 | yield return ...; | cflow.cs:263:9:263:23 | yield return ...; | normal | | cflow.cs:263:22:263:22 | 0 | cflow.cs:263:22:263:22 | 0 | normal | | cflow.cs:264:9:267:9 | for (...;...;...) ... | cflow.cs:264:25:264:30 | ... < ... | false | @@ -4130,20 +4084,15 @@ | cflow.cs:268:9:276:9 | try {...} ... | cflow.cs:275:13:275:41 | call to method WriteLine | normal | | cflow.cs:268:9:276:9 | try {...} ... | cflow.cs:275:13:275:41 | call to method WriteLine | return [normal] (0) | | cflow.cs:268:9:276:9 | try {...} ... | cflow.cs:275:13:275:41 | call to method WriteLine | throw(Exception) [normal] (0) | -| cflow.cs:268:9:276:9 | try {...} ... | cflow.cs:275:13:275:41 | call to method WriteLine | throw(OutOfMemoryException) [normal] (0) | | cflow.cs:269:9:272:9 | {...} | cflow.cs:270:13:270:24 | yield break; | return | | cflow.cs:269:9:272:9 | {...} | cflow.cs:271:13:271:42 | call to method WriteLine | normal | | cflow.cs:269:9:272:9 | {...} | cflow.cs:271:13:271:42 | call to method WriteLine | throw(Exception) | -| cflow.cs:269:9:272:9 | {...} | cflow.cs:271:31:271:41 | "dead code" | throw(OutOfMemoryException) | | cflow.cs:270:13:270:24 | yield break; | cflow.cs:270:13:270:24 | yield break; | return | | cflow.cs:271:13:271:42 | call to method WriteLine | cflow.cs:271:13:271:42 | call to method WriteLine | normal | | cflow.cs:271:13:271:42 | call to method WriteLine | cflow.cs:271:13:271:42 | call to method WriteLine | throw(Exception) | -| cflow.cs:271:13:271:42 | call to method WriteLine | cflow.cs:271:31:271:41 | "dead code" | throw(OutOfMemoryException) | | cflow.cs:271:13:271:43 | ...; | cflow.cs:271:13:271:42 | call to method WriteLine | normal | | cflow.cs:271:13:271:43 | ...; | cflow.cs:271:13:271:42 | call to method WriteLine | throw(Exception) | -| cflow.cs:271:13:271:43 | ...; | cflow.cs:271:31:271:41 | "dead code" | throw(OutOfMemoryException) | | cflow.cs:271:31:271:41 | "dead code" | cflow.cs:271:31:271:41 | "dead code" | normal | -| cflow.cs:271:31:271:41 | "dead code" | cflow.cs:271:31:271:41 | "dead code" | throw(OutOfMemoryException) | | cflow.cs:274:9:276:9 | {...} | cflow.cs:275:13:275:41 | call to method WriteLine | normal | | cflow.cs:275:13:275:41 | call to method WriteLine | cflow.cs:275:13:275:41 | call to method WriteLine | normal | | cflow.cs:275:13:275:42 | ...; | cflow.cs:275:13:275:41 | call to method WriteLine | normal | diff --git a/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected b/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected index 15c97dd2c42..f3fabcfe6bb 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected @@ -1859,19 +1859,14 @@ | Finally.cs:11:13:11:37 | call to method WriteLine | Finally.cs:14:9:16:9 | {...} | semmle.label | successor | | Finally.cs:11:13:11:38 | ...; | Finally.cs:11:31:11:36 | "Try1" | semmle.label | successor | | Finally.cs:11:31:11:36 | "Try1" | Finally.cs:11:13:11:37 | call to method WriteLine | semmle.label | successor | -| Finally.cs:11:31:11:36 | "Try1" | Finally.cs:14:9:16:9 | [finally: exception(OutOfMemoryException)] {...} | semmle.label | exception(OutOfMemoryException) | | Finally.cs:14:9:16:9 | [finally: exception(Exception)] {...} | Finally.cs:15:13:15:41 | [finally: exception(Exception)] ...; | semmle.label | successor | -| Finally.cs:14:9:16:9 | [finally: exception(OutOfMemoryException)] {...} | Finally.cs:15:13:15:41 | [finally: exception(OutOfMemoryException)] ...; | semmle.label | successor | | Finally.cs:14:9:16:9 | {...} | Finally.cs:15:13:15:41 | ...; | semmle.label | successor | | Finally.cs:15:13:15:40 | [finally: exception(Exception)] call to method WriteLine | Finally.cs:7:10:7:11 | exit M1 (abnormal) | semmle.label | exception(Exception) | -| Finally.cs:15:13:15:40 | [finally: exception(OutOfMemoryException)] call to method WriteLine | Finally.cs:7:10:7:11 | exit M1 (abnormal) | semmle.label | exception(OutOfMemoryException) | | Finally.cs:15:13:15:40 | call to method WriteLine | Finally.cs:7:10:7:11 | exit M1 (normal) | semmle.label | successor | | Finally.cs:15:13:15:41 | ...; | Finally.cs:15:31:15:39 | "Finally" | semmle.label | successor | | Finally.cs:15:13:15:41 | [finally: exception(Exception)] ...; | Finally.cs:15:31:15:39 | [finally: exception(Exception)] "Finally" | semmle.label | successor | -| Finally.cs:15:13:15:41 | [finally: exception(OutOfMemoryException)] ...; | Finally.cs:15:31:15:39 | [finally: exception(OutOfMemoryException)] "Finally" | semmle.label | successor | | Finally.cs:15:31:15:39 | "Finally" | Finally.cs:15:13:15:40 | call to method WriteLine | semmle.label | successor | | Finally.cs:15:31:15:39 | [finally: exception(Exception)] "Finally" | Finally.cs:15:13:15:40 | [finally: exception(Exception)] call to method WriteLine | semmle.label | successor | -| Finally.cs:15:31:15:39 | [finally: exception(OutOfMemoryException)] "Finally" | Finally.cs:15:13:15:40 | [finally: exception(OutOfMemoryException)] call to method WriteLine | semmle.label | successor | | Finally.cs:19:10:19:11 | enter M2 | Finally.cs:20:5:52:5 | {...} | semmle.label | successor | | Finally.cs:19:10:19:11 | exit M2 (abnormal) | Finally.cs:19:10:19:11 | exit M2 | semmle.label | successor | | Finally.cs:19:10:19:11 | exit M2 (normal) | Finally.cs:19:10:19:11 | exit M2 | semmle.label | successor | @@ -1882,18 +1877,15 @@ | Finally.cs:23:13:23:37 | call to method WriteLine | Finally.cs:26:9:29:9 | [exception: Exception] catch (...) {...} | semmle.label | exception(Exception) | | Finally.cs:23:13:23:38 | ...; | Finally.cs:23:31:23:36 | "Try2" | semmle.label | successor | | Finally.cs:23:31:23:36 | "Try2" | Finally.cs:23:13:23:37 | call to method WriteLine | semmle.label | successor | -| Finally.cs:23:31:23:36 | "Try2" | Finally.cs:26:9:29:9 | [exception: OutOfMemoryException] catch (...) {...} | semmle.label | exception(OutOfMemoryException) | | Finally.cs:24:13:24:19 | return ...; | Finally.cs:49:9:51:9 | [finally: return] {...} | semmle.label | return | | Finally.cs:26:9:29:9 | [exception: Exception] catch (...) {...} | Finally.cs:26:38:26:39 | [exception: Exception] IOException ex | semmle.label | match | | Finally.cs:26:9:29:9 | [exception: Exception] catch (...) {...} | Finally.cs:30:9:40:9 | [exception: Exception] catch (...) {...} | semmle.label | no-match | -| Finally.cs:26:9:29:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:30:9:40:9 | [exception: OutOfMemoryException] catch (...) {...} | semmle.label | no-match | | Finally.cs:26:38:26:39 | [exception: Exception] IOException ex | Finally.cs:26:48:26:51 | [exception: Exception] true | semmle.label | successor | | Finally.cs:26:48:26:51 | [exception: Exception] true | Finally.cs:27:9:29:9 | {...} | semmle.label | true | | Finally.cs:27:9:29:9 | {...} | Finally.cs:28:13:28:18 | throw ...; | semmle.label | successor | | Finally.cs:28:13:28:18 | throw ...; | Finally.cs:49:9:51:9 | [finally: exception(IOException)] {...} | semmle.label | exception(IOException) | | Finally.cs:30:9:40:9 | [exception: Exception] catch (...) {...} | Finally.cs:30:41:30:42 | [exception: Exception] ArgumentException ex | semmle.label | match | | Finally.cs:30:9:40:9 | [exception: Exception] catch (...) {...} | Finally.cs:41:9:43:9 | [exception: Exception] catch (...) {...} | semmle.label | no-match | -| Finally.cs:30:9:40:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:41:9:43:9 | [exception: OutOfMemoryException] catch (...) {...} | semmle.label | no-match | | Finally.cs:30:41:30:42 | [exception: Exception] ArgumentException ex | Finally.cs:31:9:40:9 | {...} | semmle.label | successor | | Finally.cs:31:9:40:9 | {...} | Finally.cs:32:13:39:13 | try {...} ... | semmle.label | successor | | Finally.cs:32:13:39:13 | try {...} ... | Finally.cs:33:13:35:13 | {...} | semmle.label | successor | @@ -1906,7 +1898,6 @@ | Finally.cs:38:23:38:43 | [finally: exception(ArgumentException)] object creation of type Exception | Finally.cs:38:17:38:44 | [finally: exception(ArgumentException)] throw ...; | semmle.label | successor | | Finally.cs:38:37:38:42 | [finally: exception(ArgumentException)] "Boo!" | Finally.cs:38:23:38:43 | [finally: exception(ArgumentException)] object creation of type Exception | semmle.label | successor | | Finally.cs:41:9:43:9 | [exception: Exception] catch (...) {...} | Finally.cs:42:9:43:9 | {...} | semmle.label | match | -| Finally.cs:41:9:43:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:42:9:43:9 | {...} | semmle.label | match | | Finally.cs:42:9:43:9 | {...} | Finally.cs:49:9:51:9 | {...} | semmle.label | successor | | Finally.cs:49:9:51:9 | [finally: exception(Exception)] {...} | Finally.cs:50:13:50:41 | [finally: exception(Exception)] ...; | semmle.label | successor | | Finally.cs:49:9:51:9 | [finally: exception(IOException)] {...} | Finally.cs:50:13:50:41 | [finally: exception(IOException)] ...; | semmle.label | successor | @@ -1934,49 +1925,36 @@ | Finally.cs:58:13:58:37 | call to method WriteLine | Finally.cs:61:9:64:9 | [exception: Exception] catch (...) {...} | semmle.label | exception(Exception) | | Finally.cs:58:13:58:38 | ...; | Finally.cs:58:31:58:36 | "Try3" | semmle.label | successor | | Finally.cs:58:31:58:36 | "Try3" | Finally.cs:58:13:58:37 | call to method WriteLine | semmle.label | successor | -| Finally.cs:58:31:58:36 | "Try3" | Finally.cs:61:9:64:9 | [exception: OutOfMemoryException] catch (...) {...} | semmle.label | exception(OutOfMemoryException) | | Finally.cs:59:13:59:19 | return ...; | Finally.cs:69:9:71:9 | [finally: return] {...} | semmle.label | return | | Finally.cs:61:9:64:9 | [exception: Exception] catch (...) {...} | Finally.cs:61:38:61:39 | [exception: Exception] IOException ex | semmle.label | match | | Finally.cs:61:9:64:9 | [exception: Exception] catch (...) {...} | Finally.cs:65:9:67:9 | [exception: Exception] catch (...) {...} | semmle.label | no-match | -| Finally.cs:61:9:64:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:65:9:67:9 | [exception: OutOfMemoryException] catch (...) {...} | semmle.label | no-match | | Finally.cs:61:38:61:39 | [exception: Exception] IOException ex | Finally.cs:61:48:61:51 | [exception: Exception] true | semmle.label | successor | | Finally.cs:61:48:61:51 | [exception: Exception] true | Finally.cs:62:9:64:9 | {...} | semmle.label | true | | Finally.cs:62:9:64:9 | {...} | Finally.cs:63:13:63:18 | throw ...; | semmle.label | successor | | Finally.cs:63:13:63:18 | throw ...; | Finally.cs:69:9:71:9 | [finally: exception(IOException)] {...} | semmle.label | exception(IOException) | | Finally.cs:65:9:67:9 | [exception: Exception] catch (...) {...} | Finally.cs:65:26:65:26 | [exception: Exception] Exception e | semmle.label | match | -| Finally.cs:65:9:67:9 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:65:26:65:26 | [exception: OutOfMemoryException] Exception e | semmle.label | match | | Finally.cs:65:26:65:26 | [exception: Exception] Exception e | Finally.cs:65:35:65:35 | [exception: Exception] access to local variable e | semmle.label | successor | -| Finally.cs:65:26:65:26 | [exception: OutOfMemoryException] Exception e | Finally.cs:65:35:65:35 | [exception: OutOfMemoryException] access to local variable e | semmle.label | successor | | Finally.cs:65:35:65:35 | [exception: Exception] access to local variable e | Finally.cs:65:35:65:43 | [exception: Exception] access to property Message | semmle.label | successor | -| Finally.cs:65:35:65:35 | [exception: OutOfMemoryException] access to local variable e | Finally.cs:65:35:65:43 | [exception: OutOfMemoryException] access to property Message | semmle.label | successor | | Finally.cs:65:35:65:43 | [exception: Exception] access to property Message | Finally.cs:65:48:65:51 | [exception: Exception] null | semmle.label | successor | -| Finally.cs:65:35:65:43 | [exception: OutOfMemoryException] access to property Message | Finally.cs:65:48:65:51 | [exception: OutOfMemoryException] null | semmle.label | successor | | Finally.cs:65:35:65:51 | [exception: Exception] ... != ... | Finally.cs:66:9:67:9 | {...} | semmle.label | true | | Finally.cs:65:35:65:51 | [exception: Exception] ... != ... | Finally.cs:69:9:71:9 | [finally: exception(Exception)] {...} | semmle.label | exception(Exception) | -| Finally.cs:65:35:65:51 | [exception: OutOfMemoryException] ... != ... | Finally.cs:66:9:67:9 | {...} | semmle.label | true | -| Finally.cs:65:35:65:51 | [exception: OutOfMemoryException] ... != ... | Finally.cs:69:9:71:9 | [finally: exception(OutOfMemoryException)] {...} | semmle.label | exception(OutOfMemoryException) | | Finally.cs:65:48:65:51 | [exception: Exception] null | Finally.cs:65:35:65:51 | [exception: Exception] ... != ... | semmle.label | successor | -| Finally.cs:65:48:65:51 | [exception: OutOfMemoryException] null | Finally.cs:65:35:65:51 | [exception: OutOfMemoryException] ... != ... | semmle.label | successor | | Finally.cs:66:9:67:9 | {...} | Finally.cs:69:9:71:9 | {...} | semmle.label | successor | | Finally.cs:69:9:71:9 | [finally: exception(Exception)] {...} | Finally.cs:70:13:70:41 | [finally: exception(Exception)] ...; | semmle.label | successor | | Finally.cs:69:9:71:9 | [finally: exception(IOException)] {...} | Finally.cs:70:13:70:41 | [finally: exception(IOException)] ...; | semmle.label | successor | -| Finally.cs:69:9:71:9 | [finally: exception(OutOfMemoryException)] {...} | Finally.cs:70:13:70:41 | [finally: exception(OutOfMemoryException)] ...; | semmle.label | successor | | Finally.cs:69:9:71:9 | [finally: return] {...} | Finally.cs:70:13:70:41 | [finally: return] ...; | semmle.label | successor | | Finally.cs:69:9:71:9 | {...} | Finally.cs:70:13:70:41 | ...; | semmle.label | successor | | Finally.cs:70:13:70:40 | [finally: exception(Exception)] call to method WriteLine | Finally.cs:54:10:54:11 | exit M3 (abnormal) | semmle.label | exception(Exception) | | Finally.cs:70:13:70:40 | [finally: exception(IOException)] call to method WriteLine | Finally.cs:54:10:54:11 | exit M3 (abnormal) | semmle.label | exception(IOException) | -| Finally.cs:70:13:70:40 | [finally: exception(OutOfMemoryException)] call to method WriteLine | Finally.cs:54:10:54:11 | exit M3 (abnormal) | semmle.label | exception(OutOfMemoryException) | | Finally.cs:70:13:70:40 | [finally: return] call to method WriteLine | Finally.cs:54:10:54:11 | exit M3 (normal) | semmle.label | return | | Finally.cs:70:13:70:40 | call to method WriteLine | Finally.cs:54:10:54:11 | exit M3 (normal) | semmle.label | successor | | Finally.cs:70:13:70:41 | ...; | Finally.cs:70:31:70:39 | "Finally" | semmle.label | successor | | Finally.cs:70:13:70:41 | [finally: exception(Exception)] ...; | Finally.cs:70:31:70:39 | [finally: exception(Exception)] "Finally" | semmle.label | successor | | Finally.cs:70:13:70:41 | [finally: exception(IOException)] ...; | Finally.cs:70:31:70:39 | [finally: exception(IOException)] "Finally" | semmle.label | successor | -| Finally.cs:70:13:70:41 | [finally: exception(OutOfMemoryException)] ...; | Finally.cs:70:31:70:39 | [finally: exception(OutOfMemoryException)] "Finally" | semmle.label | successor | | Finally.cs:70:13:70:41 | [finally: return] ...; | Finally.cs:70:31:70:39 | [finally: return] "Finally" | semmle.label | successor | | Finally.cs:70:31:70:39 | "Finally" | Finally.cs:70:13:70:40 | call to method WriteLine | semmle.label | successor | | Finally.cs:70:31:70:39 | [finally: exception(Exception)] "Finally" | Finally.cs:70:13:70:40 | [finally: exception(Exception)] call to method WriteLine | semmle.label | successor | | Finally.cs:70:31:70:39 | [finally: exception(IOException)] "Finally" | Finally.cs:70:13:70:40 | [finally: exception(IOException)] call to method WriteLine | semmle.label | successor | -| Finally.cs:70:31:70:39 | [finally: exception(OutOfMemoryException)] "Finally" | Finally.cs:70:13:70:40 | [finally: exception(OutOfMemoryException)] call to method WriteLine | semmle.label | successor | | Finally.cs:70:31:70:39 | [finally: return] "Finally" | Finally.cs:70:13:70:40 | [finally: return] call to method WriteLine | semmle.label | successor | | Finally.cs:74:10:74:11 | enter M4 | Finally.cs:75:5:101:5 | {...} | semmle.label | successor | | Finally.cs:74:10:74:11 | exit M4 (abnormal) | Finally.cs:74:10:74:11 | exit M4 | semmle.label | successor | @@ -2257,19 +2235,14 @@ | Finally.cs:137:13:137:36 | call to method WriteLine | Finally.cs:140:9:143:9 | {...} | semmle.label | successor | | Finally.cs:137:13:137:37 | ...; | Finally.cs:137:31:137:35 | "Try" | semmle.label | successor | | Finally.cs:137:31:137:35 | "Try" | Finally.cs:137:13:137:36 | call to method WriteLine | semmle.label | successor | -| Finally.cs:137:31:137:35 | "Try" | Finally.cs:140:9:143:9 | [finally: exception(OutOfMemoryException)] {...} | semmle.label | exception(OutOfMemoryException) | | Finally.cs:140:9:143:9 | [finally: exception(Exception)] {...} | Finally.cs:141:41:141:42 | [finally: exception(Exception)] "" | semmle.label | successor | -| Finally.cs:140:9:143:9 | [finally: exception(OutOfMemoryException)] {...} | Finally.cs:141:41:141:42 | [finally: exception(OutOfMemoryException)] "" | semmle.label | successor | | Finally.cs:140:9:143:9 | {...} | Finally.cs:141:41:141:42 | "" | semmle.label | successor | | Finally.cs:141:13:141:44 | [finally: exception(Exception)] throw ...; | Finally.cs:133:10:133:11 | exit M7 (abnormal) | semmle.label | exception(ArgumentException) | -| Finally.cs:141:13:141:44 | [finally: exception(OutOfMemoryException)] throw ...; | Finally.cs:133:10:133:11 | exit M7 (abnormal) | semmle.label | exception(ArgumentException) | | Finally.cs:141:13:141:44 | throw ...; | Finally.cs:133:10:133:11 | exit M7 (abnormal) | semmle.label | exception(ArgumentException) | | Finally.cs:141:19:141:43 | [finally: exception(Exception)] object creation of type ArgumentException | Finally.cs:141:13:141:44 | [finally: exception(Exception)] throw ...; | semmle.label | successor | -| Finally.cs:141:19:141:43 | [finally: exception(OutOfMemoryException)] object creation of type ArgumentException | Finally.cs:141:13:141:44 | [finally: exception(OutOfMemoryException)] throw ...; | semmle.label | successor | | Finally.cs:141:19:141:43 | object creation of type ArgumentException | Finally.cs:141:13:141:44 | throw ...; | semmle.label | successor | | Finally.cs:141:41:141:42 | "" | Finally.cs:141:19:141:43 | object creation of type ArgumentException | semmle.label | successor | | Finally.cs:141:41:141:42 | [finally: exception(Exception)] "" | Finally.cs:141:19:141:43 | [finally: exception(Exception)] object creation of type ArgumentException | semmle.label | successor | -| Finally.cs:141:41:141:42 | [finally: exception(OutOfMemoryException)] "" | Finally.cs:141:19:141:43 | [finally: exception(OutOfMemoryException)] object creation of type ArgumentException | semmle.label | successor | | Finally.cs:147:10:147:11 | enter M8 | Finally.cs:148:5:170:5 | {...} | semmle.label | successor | | Finally.cs:147:10:147:11 | exit M8 (abnormal) | Finally.cs:147:10:147:11 | exit M8 | semmle.label | successor | | Finally.cs:147:10:147:11 | exit M8 (normal) | Finally.cs:147:10:147:11 | exit M8 | semmle.label | successor | @@ -2327,74 +2300,50 @@ | Finally.cs:159:27:159:44 | object creation of type Exception | Finally.cs:159:21:159:45 | throw ...; | semmle.label | successor | | Finally.cs:159:27:159:44 | object creation of type Exception | Finally.cs:161:13:164:13 | [exception: Exception] catch (...) {...} | semmle.label | exception(Exception) | | Finally.cs:159:41:159:43 | "1" | Finally.cs:159:27:159:44 | object creation of type Exception | semmle.label | successor | -| Finally.cs:159:41:159:43 | "1" | Finally.cs:161:13:164:13 | [exception: OutOfMemoryException] catch (...) {...} | semmle.label | exception(OutOfMemoryException) | | Finally.cs:159:41:159:43 | [finally: exception(ArgumentNullException)] "1" | Finally.cs:159:27:159:44 | [finally: exception(ArgumentNullException)] object creation of type Exception | semmle.label | successor | -| Finally.cs:159:41:159:43 | [finally: exception(ArgumentNullException)] "1" | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] catch (...) {...} | semmle.label | exception(OutOfMemoryException) | | Finally.cs:159:41:159:43 | [finally: exception(Exception)] "1" | Finally.cs:159:27:159:44 | [finally: exception(Exception)] object creation of type Exception | semmle.label | successor | -| Finally.cs:159:41:159:43 | [finally: exception(Exception)] "1" | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: OutOfMemoryException] catch (...) {...} | semmle.label | exception(OutOfMemoryException) | | Finally.cs:161:13:164:13 | [exception: Exception] catch (...) {...} | Finally.cs:161:30:161:30 | [exception: Exception] Exception e | semmle.label | match | | Finally.cs:161:13:164:13 | [exception: NullReferenceException] catch (...) {...} | Finally.cs:161:30:161:30 | [exception: NullReferenceException] Exception e | semmle.label | match | -| Finally.cs:161:13:164:13 | [exception: OutOfMemoryException] catch (...) {...} | Finally.cs:161:30:161:30 | [exception: OutOfMemoryException] Exception e | semmle.label | match | | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: Exception] catch (...) {...} | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: Exception] Exception e | semmle.label | match | | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: NullReferenceException] catch (...) {...} | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: NullReferenceException] Exception e | semmle.label | match | -| Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] catch (...) {...} | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] Exception e | semmle.label | match | | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: Exception] catch (...) {...} | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: Exception] Exception e | semmle.label | match | | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: NullReferenceException] catch (...) {...} | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: NullReferenceException] Exception e | semmle.label | match | -| Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: OutOfMemoryException] catch (...) {...} | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: OutOfMemoryException] Exception e | semmle.label | match | | Finally.cs:161:30:161:30 | [exception: Exception] Exception e | Finally.cs:161:39:161:39 | [exception: Exception] access to local variable e | semmle.label | successor | | Finally.cs:161:30:161:30 | [exception: NullReferenceException] Exception e | Finally.cs:161:39:161:39 | [exception: NullReferenceException] access to local variable e | semmle.label | successor | -| Finally.cs:161:30:161:30 | [exception: OutOfMemoryException] Exception e | Finally.cs:161:39:161:39 | [exception: OutOfMemoryException] access to local variable e | semmle.label | successor | | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: Exception] Exception e | Finally.cs:161:39:161:39 | [finally: exception(ArgumentNullException), exception: Exception] access to local variable e | semmle.label | successor | | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: NullReferenceException] Exception e | Finally.cs:161:39:161:39 | [finally: exception(ArgumentNullException), exception: NullReferenceException] access to local variable e | semmle.label | successor | -| Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] Exception e | Finally.cs:161:39:161:39 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] access to local variable e | semmle.label | successor | | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: Exception] Exception e | Finally.cs:161:39:161:39 | [finally: exception(Exception), exception: Exception] access to local variable e | semmle.label | successor | | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: NullReferenceException] Exception e | Finally.cs:161:39:161:39 | [finally: exception(Exception), exception: NullReferenceException] access to local variable e | semmle.label | successor | -| Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: OutOfMemoryException] Exception e | Finally.cs:161:39:161:39 | [finally: exception(Exception), exception: OutOfMemoryException] access to local variable e | semmle.label | successor | | Finally.cs:161:39:161:39 | [exception: Exception] access to local variable e | Finally.cs:161:39:161:47 | [exception: Exception] access to property Message | semmle.label | successor | | Finally.cs:161:39:161:39 | [exception: NullReferenceException] access to local variable e | Finally.cs:161:39:161:47 | [exception: NullReferenceException] access to property Message | semmle.label | successor | -| Finally.cs:161:39:161:39 | [exception: OutOfMemoryException] access to local variable e | Finally.cs:161:39:161:47 | [exception: OutOfMemoryException] access to property Message | semmle.label | successor | | Finally.cs:161:39:161:39 | [finally: exception(ArgumentNullException), exception: Exception] access to local variable e | Finally.cs:161:39:161:47 | [finally: exception(ArgumentNullException), exception: Exception] access to property Message | semmle.label | successor | | Finally.cs:161:39:161:39 | [finally: exception(ArgumentNullException), exception: NullReferenceException] access to local variable e | Finally.cs:161:39:161:47 | [finally: exception(ArgumentNullException), exception: NullReferenceException] access to property Message | semmle.label | successor | -| Finally.cs:161:39:161:39 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] access to local variable e | Finally.cs:161:39:161:47 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] access to property Message | semmle.label | successor | | Finally.cs:161:39:161:39 | [finally: exception(Exception), exception: Exception] access to local variable e | Finally.cs:161:39:161:47 | [finally: exception(Exception), exception: Exception] access to property Message | semmle.label | successor | | Finally.cs:161:39:161:39 | [finally: exception(Exception), exception: NullReferenceException] access to local variable e | Finally.cs:161:39:161:47 | [finally: exception(Exception), exception: NullReferenceException] access to property Message | semmle.label | successor | -| Finally.cs:161:39:161:39 | [finally: exception(Exception), exception: OutOfMemoryException] access to local variable e | Finally.cs:161:39:161:47 | [finally: exception(Exception), exception: OutOfMemoryException] access to property Message | semmle.label | successor | | Finally.cs:161:39:161:47 | [exception: Exception] access to property Message | Finally.cs:161:52:161:54 | [exception: Exception] "1" | semmle.label | successor | | Finally.cs:161:39:161:47 | [exception: NullReferenceException] access to property Message | Finally.cs:161:52:161:54 | [exception: NullReferenceException] "1" | semmle.label | successor | -| Finally.cs:161:39:161:47 | [exception: OutOfMemoryException] access to property Message | Finally.cs:161:52:161:54 | [exception: OutOfMemoryException] "1" | semmle.label | successor | | Finally.cs:161:39:161:47 | [finally: exception(ArgumentNullException), exception: Exception] access to property Message | Finally.cs:161:52:161:54 | [finally: exception(ArgumentNullException), exception: Exception] "1" | semmle.label | successor | | Finally.cs:161:39:161:47 | [finally: exception(ArgumentNullException), exception: NullReferenceException] access to property Message | Finally.cs:161:52:161:54 | [finally: exception(ArgumentNullException), exception: NullReferenceException] "1" | semmle.label | successor | -| Finally.cs:161:39:161:47 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] access to property Message | Finally.cs:161:52:161:54 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] "1" | semmle.label | successor | | Finally.cs:161:39:161:47 | [finally: exception(Exception), exception: Exception] access to property Message | Finally.cs:161:52:161:54 | [finally: exception(Exception), exception: Exception] "1" | semmle.label | successor | | Finally.cs:161:39:161:47 | [finally: exception(Exception), exception: NullReferenceException] access to property Message | Finally.cs:161:52:161:54 | [finally: exception(Exception), exception: NullReferenceException] "1" | semmle.label | successor | -| Finally.cs:161:39:161:47 | [finally: exception(Exception), exception: OutOfMemoryException] access to property Message | Finally.cs:161:52:161:54 | [finally: exception(Exception), exception: OutOfMemoryException] "1" | semmle.label | successor | | Finally.cs:161:39:161:54 | [exception: Exception] ... == ... | Finally.cs:162:13:164:13 | {...} | semmle.label | true | | Finally.cs:161:39:161:54 | [exception: Exception] ... == ... | Finally.cs:165:13:168:13 | catch {...} | semmle.label | false | | Finally.cs:161:39:161:54 | [exception: NullReferenceException] ... == ... | Finally.cs:162:13:164:13 | {...} | semmle.label | true | | Finally.cs:161:39:161:54 | [exception: NullReferenceException] ... == ... | Finally.cs:165:13:168:13 | catch {...} | semmle.label | false | -| Finally.cs:161:39:161:54 | [exception: OutOfMemoryException] ... == ... | Finally.cs:162:13:164:13 | {...} | semmle.label | true | -| Finally.cs:161:39:161:54 | [exception: OutOfMemoryException] ... == ... | Finally.cs:165:13:168:13 | catch {...} | semmle.label | false | | Finally.cs:161:39:161:54 | [finally: exception(ArgumentNullException), exception: Exception] ... == ... | Finally.cs:162:13:164:13 | [finally: exception(ArgumentNullException)] {...} | semmle.label | true | | Finally.cs:161:39:161:54 | [finally: exception(ArgumentNullException), exception: Exception] ... == ... | Finally.cs:165:13:168:13 | [finally: exception(ArgumentNullException)] catch {...} | semmle.label | false | | Finally.cs:161:39:161:54 | [finally: exception(ArgumentNullException), exception: NullReferenceException] ... == ... | Finally.cs:162:13:164:13 | [finally: exception(ArgumentNullException)] {...} | semmle.label | true | | Finally.cs:161:39:161:54 | [finally: exception(ArgumentNullException), exception: NullReferenceException] ... == ... | Finally.cs:165:13:168:13 | [finally: exception(ArgumentNullException)] catch {...} | semmle.label | false | -| Finally.cs:161:39:161:54 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] ... == ... | Finally.cs:162:13:164:13 | [finally: exception(ArgumentNullException)] {...} | semmle.label | true | -| Finally.cs:161:39:161:54 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] ... == ... | Finally.cs:165:13:168:13 | [finally: exception(ArgumentNullException)] catch {...} | semmle.label | false | | Finally.cs:161:39:161:54 | [finally: exception(Exception), exception: Exception] ... == ... | Finally.cs:162:13:164:13 | [finally: exception(Exception)] {...} | semmle.label | true | | Finally.cs:161:39:161:54 | [finally: exception(Exception), exception: Exception] ... == ... | Finally.cs:165:13:168:13 | [finally: exception(Exception)] catch {...} | semmle.label | false | | Finally.cs:161:39:161:54 | [finally: exception(Exception), exception: NullReferenceException] ... == ... | Finally.cs:162:13:164:13 | [finally: exception(Exception)] {...} | semmle.label | true | | Finally.cs:161:39:161:54 | [finally: exception(Exception), exception: NullReferenceException] ... == ... | Finally.cs:165:13:168:13 | [finally: exception(Exception)] catch {...} | semmle.label | false | -| Finally.cs:161:39:161:54 | [finally: exception(Exception), exception: OutOfMemoryException] ... == ... | Finally.cs:162:13:164:13 | [finally: exception(Exception)] {...} | semmle.label | true | -| Finally.cs:161:39:161:54 | [finally: exception(Exception), exception: OutOfMemoryException] ... == ... | Finally.cs:165:13:168:13 | [finally: exception(Exception)] catch {...} | semmle.label | false | | Finally.cs:161:52:161:54 | [exception: Exception] "1" | Finally.cs:161:39:161:54 | [exception: Exception] ... == ... | semmle.label | successor | | Finally.cs:161:52:161:54 | [exception: NullReferenceException] "1" | Finally.cs:161:39:161:54 | [exception: NullReferenceException] ... == ... | semmle.label | successor | -| Finally.cs:161:52:161:54 | [exception: OutOfMemoryException] "1" | Finally.cs:161:39:161:54 | [exception: OutOfMemoryException] ... == ... | semmle.label | successor | | Finally.cs:161:52:161:54 | [finally: exception(ArgumentNullException), exception: Exception] "1" | Finally.cs:161:39:161:54 | [finally: exception(ArgumentNullException), exception: Exception] ... == ... | semmle.label | successor | | Finally.cs:161:52:161:54 | [finally: exception(ArgumentNullException), exception: NullReferenceException] "1" | Finally.cs:161:39:161:54 | [finally: exception(ArgumentNullException), exception: NullReferenceException] ... == ... | semmle.label | successor | -| Finally.cs:161:52:161:54 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] "1" | Finally.cs:161:39:161:54 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] ... == ... | semmle.label | successor | | Finally.cs:161:52:161:54 | [finally: exception(Exception), exception: Exception] "1" | Finally.cs:161:39:161:54 | [finally: exception(Exception), exception: Exception] ... == ... | semmle.label | successor | | Finally.cs:161:52:161:54 | [finally: exception(Exception), exception: NullReferenceException] "1" | Finally.cs:161:39:161:54 | [finally: exception(Exception), exception: NullReferenceException] ... == ... | semmle.label | successor | -| Finally.cs:161:52:161:54 | [finally: exception(Exception), exception: OutOfMemoryException] "1" | Finally.cs:161:39:161:54 | [finally: exception(Exception), exception: OutOfMemoryException] ... == ... | semmle.label | successor | | Finally.cs:162:13:164:13 | [finally: exception(ArgumentNullException)] {...} | Finally.cs:163:17:163:43 | [finally: exception(ArgumentNullException)] ...; | semmle.label | successor | | Finally.cs:162:13:164:13 | [finally: exception(Exception)] {...} | Finally.cs:163:17:163:43 | [finally: exception(Exception)] ...; | semmle.label | successor | | Finally.cs:162:13:164:13 | {...} | Finally.cs:163:17:163:43 | ...; | semmle.label | successor | @@ -2613,7 +2562,6 @@ | Finally.cs:220:13:220:36 | call to method WriteLine | Finally.cs:227:9:229:9 | {...} | semmle.label | successor | | Finally.cs:220:13:220:37 | ...; | Finally.cs:220:31:220:35 | "Try" | semmle.label | successor | | Finally.cs:220:31:220:35 | "Try" | Finally.cs:220:13:220:36 | call to method WriteLine | semmle.label | successor | -| Finally.cs:220:31:220:35 | "Try" | Finally.cs:222:9:225:9 | catch {...} | semmle.label | exception(OutOfMemoryException) | | Finally.cs:222:9:225:9 | catch {...} | Finally.cs:223:9:225:9 | {...} | semmle.label | successor | | Finally.cs:223:9:225:9 | {...} | Finally.cs:224:13:224:39 | ...; | semmle.label | successor | | Finally.cs:224:13:224:38 | call to method WriteLine | Finally.cs:227:9:229:9 | {...} | semmle.label | successor | @@ -2707,23 +2655,18 @@ | Finally.cs:254:13:254:44 | call to method WriteLine | Finally.cs:257:9:259:9 | {...} | semmle.label | successor | | Finally.cs:254:13:254:45 | ...; | Finally.cs:254:31:254:43 | "Mid finally" | semmle.label | successor | | Finally.cs:254:31:254:43 | "Mid finally" | Finally.cs:254:13:254:44 | call to method WriteLine | semmle.label | successor | -| Finally.cs:254:31:254:43 | "Mid finally" | Finally.cs:257:9:259:9 | [finally: exception(OutOfMemoryException)] {...} | semmle.label | exception(OutOfMemoryException) | | Finally.cs:257:9:259:9 | [finally: exception(Exception)] {...} | Finally.cs:258:13:258:47 | [finally: exception(Exception)] ...; | semmle.label | successor | | Finally.cs:257:9:259:9 | [finally: exception(ExceptionA)] {...} | Finally.cs:258:13:258:47 | [finally: exception(ExceptionA)] ...; | semmle.label | successor | -| Finally.cs:257:9:259:9 | [finally: exception(OutOfMemoryException)] {...} | Finally.cs:258:13:258:47 | [finally: exception(OutOfMemoryException)] ...; | semmle.label | successor | | Finally.cs:257:9:259:9 | {...} | Finally.cs:258:13:258:47 | ...; | semmle.label | successor | | Finally.cs:258:13:258:46 | [finally: exception(Exception)] call to method WriteLine | Finally.cs:233:10:233:12 | exit M12 (abnormal) | semmle.label | exception(Exception) | | Finally.cs:258:13:258:46 | [finally: exception(ExceptionA)] call to method WriteLine | Finally.cs:233:10:233:12 | exit M12 (abnormal) | semmle.label | exception(ExceptionA) | -| Finally.cs:258:13:258:46 | [finally: exception(OutOfMemoryException)] call to method WriteLine | Finally.cs:233:10:233:12 | exit M12 (abnormal) | semmle.label | exception(OutOfMemoryException) | | Finally.cs:258:13:258:46 | call to method WriteLine | Finally.cs:260:9:260:34 | ...; | semmle.label | successor | | Finally.cs:258:13:258:47 | ...; | Finally.cs:258:31:258:45 | "Outer finally" | semmle.label | successor | | Finally.cs:258:13:258:47 | [finally: exception(Exception)] ...; | Finally.cs:258:31:258:45 | [finally: exception(Exception)] "Outer finally" | semmle.label | successor | | Finally.cs:258:13:258:47 | [finally: exception(ExceptionA)] ...; | Finally.cs:258:31:258:45 | [finally: exception(ExceptionA)] "Outer finally" | semmle.label | successor | -| Finally.cs:258:13:258:47 | [finally: exception(OutOfMemoryException)] ...; | Finally.cs:258:31:258:45 | [finally: exception(OutOfMemoryException)] "Outer finally" | semmle.label | successor | | Finally.cs:258:31:258:45 | "Outer finally" | Finally.cs:258:13:258:46 | call to method WriteLine | semmle.label | successor | | Finally.cs:258:31:258:45 | [finally: exception(Exception)] "Outer finally" | Finally.cs:258:13:258:46 | [finally: exception(Exception)] call to method WriteLine | semmle.label | successor | | Finally.cs:258:31:258:45 | [finally: exception(ExceptionA)] "Outer finally" | Finally.cs:258:13:258:46 | [finally: exception(ExceptionA)] call to method WriteLine | semmle.label | successor | -| Finally.cs:258:31:258:45 | [finally: exception(OutOfMemoryException)] "Outer finally" | Finally.cs:258:13:258:46 | [finally: exception(OutOfMemoryException)] call to method WriteLine | semmle.label | successor | | Finally.cs:260:9:260:33 | call to method WriteLine | Finally.cs:233:10:233:12 | exit M12 (normal) | semmle.label | successor | | Finally.cs:260:9:260:34 | ...; | Finally.cs:260:27:260:32 | "Done" | semmle.label | successor | | Finally.cs:260:27:260:32 | "Done" | Finally.cs:260:9:260:33 | call to method WriteLine | semmle.label | successor | diff --git a/csharp/ql/test/library-tests/controlflow/graph/Nodes.expected b/csharp/ql/test/library-tests/controlflow/graph/Nodes.expected index 3823d0b2b45..bac3edcdd3f 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Nodes.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/Nodes.expected @@ -619,13 +619,9 @@ finallyNode | CompileTimeOperators.cs:37:13:37:41 | [finally: goto(End)] ...; | CompileTimeOperators.cs:30:9:38:9 | try {...} ... | | CompileTimeOperators.cs:37:31:37:39 | [finally: goto(End)] "Finally" | CompileTimeOperators.cs:30:9:38:9 | try {...} ... | | Finally.cs:14:9:16:9 | [finally: exception(Exception)] {...} | Finally.cs:9:9:16:9 | try {...} ... | -| Finally.cs:14:9:16:9 | [finally: exception(OutOfMemoryException)] {...} | Finally.cs:9:9:16:9 | try {...} ... | | Finally.cs:15:13:15:40 | [finally: exception(Exception)] call to method WriteLine | Finally.cs:9:9:16:9 | try {...} ... | -| Finally.cs:15:13:15:40 | [finally: exception(OutOfMemoryException)] call to method WriteLine | Finally.cs:9:9:16:9 | try {...} ... | | Finally.cs:15:13:15:41 | [finally: exception(Exception)] ...; | Finally.cs:9:9:16:9 | try {...} ... | -| Finally.cs:15:13:15:41 | [finally: exception(OutOfMemoryException)] ...; | Finally.cs:9:9:16:9 | try {...} ... | | Finally.cs:15:31:15:39 | [finally: exception(Exception)] "Finally" | Finally.cs:9:9:16:9 | try {...} ... | -| Finally.cs:15:31:15:39 | [finally: exception(OutOfMemoryException)] "Finally" | Finally.cs:9:9:16:9 | try {...} ... | | Finally.cs:37:13:39:13 | [finally: exception(ArgumentException)] {...} | Finally.cs:32:13:39:13 | try {...} ... | | Finally.cs:38:17:38:44 | [finally: exception(ArgumentException)] throw ...; | Finally.cs:32:13:39:13 | try {...} ... | | Finally.cs:38:23:38:43 | [finally: exception(ArgumentException)] object creation of type Exception | Finally.cs:32:13:39:13 | try {...} ... | @@ -644,19 +640,15 @@ finallyNode | Finally.cs:50:31:50:39 | [finally: return] "Finally" | Finally.cs:21:9:51:9 | try {...} ... | | Finally.cs:69:9:71:9 | [finally: exception(Exception)] {...} | Finally.cs:56:9:71:9 | try {...} ... | | Finally.cs:69:9:71:9 | [finally: exception(IOException)] {...} | Finally.cs:56:9:71:9 | try {...} ... | -| Finally.cs:69:9:71:9 | [finally: exception(OutOfMemoryException)] {...} | Finally.cs:56:9:71:9 | try {...} ... | | Finally.cs:69:9:71:9 | [finally: return] {...} | Finally.cs:56:9:71:9 | try {...} ... | | Finally.cs:70:13:70:40 | [finally: exception(Exception)] call to method WriteLine | Finally.cs:56:9:71:9 | try {...} ... | | Finally.cs:70:13:70:40 | [finally: exception(IOException)] call to method WriteLine | Finally.cs:56:9:71:9 | try {...} ... | -| Finally.cs:70:13:70:40 | [finally: exception(OutOfMemoryException)] call to method WriteLine | Finally.cs:56:9:71:9 | try {...} ... | | Finally.cs:70:13:70:40 | [finally: return] call to method WriteLine | Finally.cs:56:9:71:9 | try {...} ... | | Finally.cs:70:13:70:41 | [finally: exception(Exception)] ...; | Finally.cs:56:9:71:9 | try {...} ... | | Finally.cs:70:13:70:41 | [finally: exception(IOException)] ...; | Finally.cs:56:9:71:9 | try {...} ... | -| Finally.cs:70:13:70:41 | [finally: exception(OutOfMemoryException)] ...; | Finally.cs:56:9:71:9 | try {...} ... | | Finally.cs:70:13:70:41 | [finally: return] ...; | Finally.cs:56:9:71:9 | try {...} ... | | Finally.cs:70:31:70:39 | [finally: exception(Exception)] "Finally" | Finally.cs:56:9:71:9 | try {...} ... | | Finally.cs:70:31:70:39 | [finally: exception(IOException)] "Finally" | Finally.cs:56:9:71:9 | try {...} ... | -| Finally.cs:70:31:70:39 | [finally: exception(OutOfMemoryException)] "Finally" | Finally.cs:56:9:71:9 | try {...} ... | | Finally.cs:70:31:70:39 | [finally: return] "Finally" | Finally.cs:56:9:71:9 | try {...} ... | | Finally.cs:89:13:99:13 | [finally: break] {...} | Finally.cs:79:13:99:13 | try {...} ... | | Finally.cs:89:13:99:13 | [finally: continue] {...} | Finally.cs:79:13:99:13 | try {...} ... | @@ -802,13 +794,9 @@ finallyNode | Finally.cs:117:35:117:35 | [finally: exception(OutOfMemoryException)] 1 | Finally.cs:105:9:118:9 | try {...} ... | | Finally.cs:117:35:117:35 | [finally: return] 1 | Finally.cs:105:9:118:9 | try {...} ... | | Finally.cs:140:9:143:9 | [finally: exception(Exception)] {...} | Finally.cs:135:9:143:9 | try {...} ... | -| Finally.cs:140:9:143:9 | [finally: exception(OutOfMemoryException)] {...} | Finally.cs:135:9:143:9 | try {...} ... | | Finally.cs:141:13:141:44 | [finally: exception(Exception)] throw ...; | Finally.cs:135:9:143:9 | try {...} ... | -| Finally.cs:141:13:141:44 | [finally: exception(OutOfMemoryException)] throw ...; | Finally.cs:135:9:143:9 | try {...} ... | | Finally.cs:141:19:141:43 | [finally: exception(Exception)] object creation of type ArgumentException | Finally.cs:135:9:143:9 | try {...} ... | -| Finally.cs:141:19:141:43 | [finally: exception(OutOfMemoryException)] object creation of type ArgumentException | Finally.cs:135:9:143:9 | try {...} ... | | Finally.cs:141:41:141:42 | [finally: exception(Exception)] "" | Finally.cs:135:9:143:9 | try {...} ... | -| Finally.cs:141:41:141:42 | [finally: exception(OutOfMemoryException)] "" | Finally.cs:135:9:143:9 | try {...} ... | | Finally.cs:155:9:169:9 | [finally: exception(ArgumentNullException)] {...} | Finally.cs:149:9:169:9 | try {...} ... | | Finally.cs:155:9:169:9 | [finally: exception(Exception)] {...} | Finally.cs:149:9:169:9 | try {...} ... | | Finally.cs:156:13:168:13 | [finally: exception(ArgumentNullException)] try {...} ... | Finally.cs:149:9:169:9 | try {...} ... | @@ -833,40 +821,28 @@ finallyNode | Finally.cs:159:41:159:43 | [finally: exception(Exception)] "1" | Finally.cs:149:9:169:9 | try {...} ... | | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: Exception] catch (...) {...} | Finally.cs:149:9:169:9 | try {...} ... | | Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: NullReferenceException] catch (...) {...} | Finally.cs:149:9:169:9 | try {...} ... | -| Finally.cs:161:13:164:13 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] catch (...) {...} | Finally.cs:149:9:169:9 | try {...} ... | | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: Exception] catch (...) {...} | Finally.cs:149:9:169:9 | try {...} ... | | Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: NullReferenceException] catch (...) {...} | Finally.cs:149:9:169:9 | try {...} ... | -| Finally.cs:161:13:164:13 | [finally: exception(Exception), exception: OutOfMemoryException] catch (...) {...} | Finally.cs:149:9:169:9 | try {...} ... | | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: Exception] Exception e | Finally.cs:149:9:169:9 | try {...} ... | | Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: NullReferenceException] Exception e | Finally.cs:149:9:169:9 | try {...} ... | -| Finally.cs:161:30:161:30 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] Exception e | Finally.cs:149:9:169:9 | try {...} ... | | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: Exception] Exception e | Finally.cs:149:9:169:9 | try {...} ... | | Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: NullReferenceException] Exception e | Finally.cs:149:9:169:9 | try {...} ... | -| Finally.cs:161:30:161:30 | [finally: exception(Exception), exception: OutOfMemoryException] Exception e | Finally.cs:149:9:169:9 | try {...} ... | | Finally.cs:161:39:161:39 | [finally: exception(ArgumentNullException), exception: Exception] access to local variable e | Finally.cs:149:9:169:9 | try {...} ... | | Finally.cs:161:39:161:39 | [finally: exception(ArgumentNullException), exception: NullReferenceException] access to local variable e | Finally.cs:149:9:169:9 | try {...} ... | -| Finally.cs:161:39:161:39 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] access to local variable e | Finally.cs:149:9:169:9 | try {...} ... | | Finally.cs:161:39:161:39 | [finally: exception(Exception), exception: Exception] access to local variable e | Finally.cs:149:9:169:9 | try {...} ... | | Finally.cs:161:39:161:39 | [finally: exception(Exception), exception: NullReferenceException] access to local variable e | Finally.cs:149:9:169:9 | try {...} ... | -| Finally.cs:161:39:161:39 | [finally: exception(Exception), exception: OutOfMemoryException] access to local variable e | Finally.cs:149:9:169:9 | try {...} ... | | Finally.cs:161:39:161:47 | [finally: exception(ArgumentNullException), exception: Exception] access to property Message | Finally.cs:149:9:169:9 | try {...} ... | | Finally.cs:161:39:161:47 | [finally: exception(ArgumentNullException), exception: NullReferenceException] access to property Message | Finally.cs:149:9:169:9 | try {...} ... | -| Finally.cs:161:39:161:47 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] access to property Message | Finally.cs:149:9:169:9 | try {...} ... | | Finally.cs:161:39:161:47 | [finally: exception(Exception), exception: Exception] access to property Message | Finally.cs:149:9:169:9 | try {...} ... | | Finally.cs:161:39:161:47 | [finally: exception(Exception), exception: NullReferenceException] access to property Message | Finally.cs:149:9:169:9 | try {...} ... | -| Finally.cs:161:39:161:47 | [finally: exception(Exception), exception: OutOfMemoryException] access to property Message | Finally.cs:149:9:169:9 | try {...} ... | | Finally.cs:161:39:161:54 | [finally: exception(ArgumentNullException), exception: Exception] ... == ... | Finally.cs:149:9:169:9 | try {...} ... | | Finally.cs:161:39:161:54 | [finally: exception(ArgumentNullException), exception: NullReferenceException] ... == ... | Finally.cs:149:9:169:9 | try {...} ... | -| Finally.cs:161:39:161:54 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] ... == ... | Finally.cs:149:9:169:9 | try {...} ... | | Finally.cs:161:39:161:54 | [finally: exception(Exception), exception: Exception] ... == ... | Finally.cs:149:9:169:9 | try {...} ... | | Finally.cs:161:39:161:54 | [finally: exception(Exception), exception: NullReferenceException] ... == ... | Finally.cs:149:9:169:9 | try {...} ... | -| Finally.cs:161:39:161:54 | [finally: exception(Exception), exception: OutOfMemoryException] ... == ... | Finally.cs:149:9:169:9 | try {...} ... | | Finally.cs:161:52:161:54 | [finally: exception(ArgumentNullException), exception: Exception] "1" | Finally.cs:149:9:169:9 | try {...} ... | | Finally.cs:161:52:161:54 | [finally: exception(ArgumentNullException), exception: NullReferenceException] "1" | Finally.cs:149:9:169:9 | try {...} ... | -| Finally.cs:161:52:161:54 | [finally: exception(ArgumentNullException), exception: OutOfMemoryException] "1" | Finally.cs:149:9:169:9 | try {...} ... | | Finally.cs:161:52:161:54 | [finally: exception(Exception), exception: Exception] "1" | Finally.cs:149:9:169:9 | try {...} ... | | Finally.cs:161:52:161:54 | [finally: exception(Exception), exception: NullReferenceException] "1" | Finally.cs:149:9:169:9 | try {...} ... | -| Finally.cs:161:52:161:54 | [finally: exception(Exception), exception: OutOfMemoryException] "1" | Finally.cs:149:9:169:9 | try {...} ... | | Finally.cs:162:13:164:13 | [finally: exception(ArgumentNullException)] {...} | Finally.cs:149:9:169:9 | try {...} ... | | Finally.cs:162:13:164:13 | [finally: exception(Exception)] {...} | Finally.cs:149:9:169:9 | try {...} ... | | Finally.cs:163:17:163:42 | [finally: exception(ArgumentNullException)] call to method WriteLine | Finally.cs:149:9:169:9 | try {...} ... | @@ -1031,16 +1007,12 @@ finallyNode | Finally.cs:251:39:251:53 | [finally: exception(ExceptionA)] "Inner finally" | Finally.cs:244:17:252:17 | try {...} ... | | Finally.cs:257:9:259:9 | [finally: exception(Exception)] {...} | Finally.cs:235:9:259:9 | try {...} ... | | Finally.cs:257:9:259:9 | [finally: exception(ExceptionA)] {...} | Finally.cs:235:9:259:9 | try {...} ... | -| Finally.cs:257:9:259:9 | [finally: exception(OutOfMemoryException)] {...} | Finally.cs:235:9:259:9 | try {...} ... | | Finally.cs:258:13:258:46 | [finally: exception(Exception)] call to method WriteLine | Finally.cs:235:9:259:9 | try {...} ... | | Finally.cs:258:13:258:46 | [finally: exception(ExceptionA)] call to method WriteLine | Finally.cs:235:9:259:9 | try {...} ... | -| Finally.cs:258:13:258:46 | [finally: exception(OutOfMemoryException)] call to method WriteLine | Finally.cs:235:9:259:9 | try {...} ... | | Finally.cs:258:13:258:47 | [finally: exception(Exception)] ...; | Finally.cs:235:9:259:9 | try {...} ... | | Finally.cs:258:13:258:47 | [finally: exception(ExceptionA)] ...; | Finally.cs:235:9:259:9 | try {...} ... | -| Finally.cs:258:13:258:47 | [finally: exception(OutOfMemoryException)] ...; | Finally.cs:235:9:259:9 | try {...} ... | | Finally.cs:258:31:258:45 | [finally: exception(Exception)] "Outer finally" | Finally.cs:235:9:259:9 | try {...} ... | | Finally.cs:258:31:258:45 | [finally: exception(ExceptionA)] "Outer finally" | Finally.cs:235:9:259:9 | try {...} ... | -| Finally.cs:258:31:258:45 | [finally: exception(OutOfMemoryException)] "Outer finally" | Finally.cs:235:9:259:9 | try {...} ... | | cflow.cs:274:9:276:9 | [finally: return] {...} | cflow.cs:268:9:276:9 | try {...} ... | | cflow.cs:275:13:275:41 | [finally: return] call to method WriteLine | cflow.cs:268:9:276:9 | try {...} ... | | cflow.cs:275:13:275:42 | [finally: return] ...; | cflow.cs:268:9:276:9 | try {...} ... | diff --git a/csharp/ql/test/library-tests/exceptions/Exceptions1.expected b/csharp/ql/test/library-tests/exceptions/Exceptions1.expected index 9c88ed1e60a..f3e813a7395 100644 --- a/csharp/ql/test/library-tests/exceptions/Exceptions1.expected +++ b/csharp/ql/test/library-tests/exceptions/Exceptions1.expected @@ -12,7 +12,6 @@ | exceptions.cs:105:13:105:13 | ; | exceptions.cs:114:13:114:13 | ; | | exceptions.cs:134:13:134:13 | ; | exceptions.cs:143:13:143:13 | ; | | exceptions.cs:163:13:163:13 | ; | exceptions.cs:172:13:172:13 | ; | -| exceptions.cs:192:13:192:13 | ; | exceptions.cs:205:13:205:13 | ; | | exceptions.cs:222:13:222:13 | ; | exceptions.cs:235:13:235:13 | ; | | exceptions.cs:280:13:280:13 | ; | exceptions.cs:297:13:297:13 | ; | | exceptions.cs:309:13:309:13 | ; | exceptions.cs:314:13:314:13 | ; | From a00bd7ae027d17a2cd2e2931a37baa31943d1245 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 8 Jan 2021 19:47:02 +0100 Subject: [PATCH 056/343] C++: Respond to review comments. --- .../ir/dataflow/internal/DataFlowPrivate.qll | 48 ++++--- .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 120 +++++++++--------- .../dataflow/fields/ir-path-flow.expected | 6 +- 3 files changed, 92 insertions(+), 82 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index 39672fe8e58..e19fc9228c2 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll @@ -350,20 +350,25 @@ private class InexactLoadOperand extends LoadOperand { InexactLoadOperand() { this.isDefinitionInexact() } } +/** Get the result type of an `Instruction` i, if it is a `PointerType`. */ +private PointerType getPointerType(Instruction i) { + // We are done if the type is a pointer type that is not a glvalue + i.getResultLanguageType().hasType(result, false) + or + // Some instructions produce a glvalue. Recurse past those to get the actual `PointerType`. + result = getPointerType(i.(PointerOffsetInstruction).getLeft()) +} + private predicate arrayReadStep(Node node1, ArrayContent a, Node node2) { a = TArrayContent() and // Explicit dereferences such as `*p` or `p[i]` where `p` is a pointer or array. - exists(InexactLoadOperand operand, Instruction address | + exists(InexactLoadOperand operand, LoadInstruction load | + load.getSourceValueOperand() = operand and node1.asInstruction() = operand.getAnyDef() and not node1.asInstruction().isResultConflated() and operand = node2.asOperand() and - instructionOperandLocalFlowStep+(instructionNode(address), - operandNode(operand.getAddressOperand())) and - ( - address instanceof LoadInstruction or - address instanceof ArrayToPointerConvertInstruction or - address instanceof PointerOffsetInstruction - ) + // Ensure that the load is actually loading from an array or a pointer. + getPointerType(load.getSourceAddress()).getBaseType() = load.getResultType() ) } @@ -392,19 +397,18 @@ bindingset[result, i] private int unbindInt(int i) { i <= result and i >= result } pragma[noinline] -private predicate getFieldNodeFromLoadOperand(FieldNode fieldNode, LoadOperand loadOperand) { - fieldNode = getFieldNodeForFieldInstruction(loadOperand.getAddressOperand().getDef()) +private FieldNode getFieldNodeFromLoadOperand(LoadOperand loadOperand) { + result = getFieldNodeForFieldInstruction(loadOperand.getAddressOperand().getDef()) } -// Sometimes there's no explicit field dereference. In such cases we use the IR alias analysis to -// determine the offset being, and deduce the field from this information. +/** + * Sometimes there's no explicit field dereference. In such cases we use the IR alias analysis to + * determine the offset being, and deduce the field from this information. + */ private predicate aliasedReadStep(Node node1, FieldContent f, Node node2) { exists(LoadOperand operand, Class c, int startBit, int endBit | // Ensure that we don't already catch this store step using a `FieldNode`. - not exists(FieldNode node | - getFieldNodeFromLoadOperand(node, operand) and - instrToFieldNodeReadStep(node, f, _) - ) and + not instrToFieldNodeReadStep(getFieldNodeFromLoadOperand(operand), f, _) and node1.asInstruction() = operand.getAnyDef() and node2.asOperand() = operand and not node1.asInstruction().isResultConflated() and @@ -414,6 +418,11 @@ private predicate aliasedReadStep(Node node1, FieldContent f, Node node2) { ) } +/** Get the result type of an `Instruction` i, if it is a `ReferenceType`. */ +private ReferenceType getReferenceType(Instruction i) { + i.getResultLanguageType().hasType(result, false) +} + /** * In cases such as: * ```cpp @@ -431,7 +440,7 @@ private predicate aliasedReadStep(Node node1, FieldContent f, Node node2) { */ private predicate innerReadSteap(Node node1, Content a, Node node2) { a = TArrayContent() and - exists(WriteSideEffectInstruction write, CallInstruction call, Expr arg | + exists(WriteSideEffectInstruction write, CallInstruction call, CopyValueInstruction copyValue | write.getPrimaryInstruction() = call and node1.asInstruction() = write and ( @@ -440,8 +449,9 @@ private predicate innerReadSteap(Node node1, Content a, Node node2) { exists(ChiInstruction chi | chi.getPartial() = write and not chi.isResultConflated()) ) and node2.asInstruction() = write and - arg = call.getArgument(write.getIndex()).getUnconvertedResultExpression() and - (arg instanceof AddressOfExpr or arg.getConversion() instanceof ReferenceToExpr) + copyValue = call.getArgument(write.getIndex()) and + [getPointerType(copyValue).getBaseType(), getReferenceType(copyValue).getBaseType()] = + copyValue.getSourceValue().getResultType() ) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 5ab582dc6d8..016bf565021 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -192,7 +192,7 @@ class OperandNode extends Node, TOperandNode { FieldNode getFieldNodeForFieldInstruction(Instruction instr) { result.getFieldInstruction() = any(FieldAddressInstruction fai | - instructionOperandLocalFlowStep*(instructionNode(fai), instructionNode(instr)) + longestRegisterInstructionOperandLocalFlowStep(instructionNode(fai), instructionNode(instr)) ) } @@ -251,13 +251,19 @@ class FieldNode extends Node, TFieldNode { /** * INTERNAL: do not use. A partial definition of a `FieldNode`. */ -class PartialFieldDefinition extends PartialDefinition { - override FieldNode node; - - override FieldNode getPreUpdateNode() { result = node } +class PartialFieldDefinition extends FieldNode, PartialDefinition { + /** + * The pre-update node of a partial definition of a `FieldNode` is the `FieldNode` itself. This ensures + * that the data flow library's reverse read mechanism builds up the correct access path for nested + * fields. + * For instance, in `a.b.c = x` there is a partial definition for `c` (let's call it `post[c]`) and a + * partial definition for `b` (let's call it `post[b]`), and there is a read step from `b` to `c` + * (using `instrToFieldNodeReadStep`), so there is a store step from `post[c]` to `post[b]`. + */ + override FieldNode getPreUpdateNode() { result = this } override Expr getDefinedExpr() { - result = node.getFieldInstruction().getObjectAddress().getUnconvertedResultExpression() + result = this.getFieldInstruction().getObjectAddress().getUnconvertedResultExpression() } } @@ -411,39 +417,13 @@ abstract class PostUpdateNode extends Node { override Location getLocation() { result = getPreUpdateNode().getLocation() } } -/** - * A partial definition of a node. A partial definition that targets arrays or pointers is attached to - * an `InstructionNode` (specifially, to the `ChiInstruction` that follows the `StoreInstruction`), and - * a partial definition that targets a `FieldNode` is attached to the `FieldNode`. - * - * The pre-update node of a partial definition of a `FieldNode` is the `FieldNode` itself. This ensures - * that the data flow library's reverse read mechanism builds up the correct access path for nested - * fields. - * For instance, in `a.b.c = x` there is a partial definition for `c` (let's call it `post[c]`) and a - * partial definition for `b` (let's call it `post[b]`), and there is a read step from `b` to `c` - * (using `instrToFieldNodeReadStep`), so there is a store step from `post[c]` to `post[b]`. - */ -private newtype TPartialDefinition = - MkPartialDefinition(Node node) { - isPointerStoreNode(node, _, _) or - isArrayStoreNode(node, _, _) or - node instanceof FieldNode - } - /** INTERNAL: do not use. A partial definition of a node. */ -abstract class PartialDefinition extends TPartialDefinition { - Node node; - - PartialDefinition() { this = MkPartialDefinition(node) } - +abstract class PartialDefinition extends Node { /** Gets the node before the state update. */ abstract Node getPreUpdateNode(); /** Gets the expression that is partially defined by this node. */ abstract Expr getDefinedExpr(); - - /** Gets a string representation of this partial definition. */ - string toString() { result = node.toString() + " [partial definition]" } } /** @@ -475,52 +455,44 @@ class PartialDefinitionNode extends PostUpdateNode, TPartialDefinitionNode { override string toString() { result = getPreUpdateNode().toString() + " [post update]" } } -private predicate isArrayStoreNode( - InstructionNode node, ChiInstruction chi, PointerAddInstruction add -) { - chi = node.getInstruction() and - not chi.isResultConflated() and - exists(StoreInstruction store | - chi.getPartial() = store and - add = store.getDestinationAddress() - ) -} - /** * The `PostUpdateNode` that is the target of a `arrayStoreStepChi` store step. The overriden * `ChiInstruction` corresponds to the instruction represented by `node2` in `arrayStoreStepChi`. */ -private class ArrayStoreNode extends PartialDefinition { - override InstructionNode node; +private class ArrayStoreNode extends InstructionNode, PartialDefinition { ChiInstruction chi; PointerAddInstruction add; - ArrayStoreNode() { isArrayStoreNode(node, chi, add) } + ArrayStoreNode() { + chi = this.getInstruction() and + not chi.isResultConflated() and + exists(StoreInstruction store | + chi.getPartial() = store and + add = store.getDestinationAddress() + ) + } override Node getPreUpdateNode() { result.asOperand() = chi.getTotalOperand() } override Expr getDefinedExpr() { result = add.getLeft().getUnconvertedResultExpression() } } -private predicate isPointerStoreNode(InstructionNode node, ChiInstruction chi, LoadInstruction load) { - chi = node.getInstruction() and - not chi.isResultConflated() and - exists(StoreInstruction store | - chi.getPartial() = store and - load = store.getDestinationAddress().(CopyValueInstruction).getUnary() - ) -} - /** * The `PostUpdateNode` that is the target of a `arrayStoreStepChi` store step. The overriden * `ChiInstruction` corresponds to the instruction represented by `node2` in `arrayStoreStepChi`. */ -private class PointerStoreNode extends PartialDefinition { - override InstructionNode node; +private class PointerStoreNode extends InstructionNode, PartialDefinition { ChiInstruction chi; LoadInstruction load; - PointerStoreNode() { isPointerStoreNode(node, chi, load) } + PointerStoreNode() { + chi = this.getInstruction() and + not chi.isResultConflated() and + exists(StoreInstruction store | + chi.getPartial() = store and + load = store.getDestinationAddress().(CopyValueInstruction).getUnary() + ) + } override Node getPreUpdateNode() { result.asOperand() = chi.getTotalOperand() } @@ -734,12 +706,40 @@ private predicate flowIntoReadNode(Node nodeFrom, FieldNode nodeTo) { ) } +/** Holds if `node` holds an `Instruction` or `Operand` that has a register result. */ +private predicate hasRegisterResult(Node node) { + node.asOperand() instanceof RegisterOperand + or + exists(Instruction i | i = node.asInstruction() and not i.hasMemoryResult()) +} + +/** + * Holds if there is a `Instruction` or `Operand` flow step from `nodeFrom` to `nodeTo` and both + * `nodeFrom` and `nodeTo` wraps register results. + */ +private predicate registerInstructionOperandLocalFlowStep(Node nodeFrom, Node nodeTo) { + hasRegisterResult(nodeFrom) and + hasRegisterResult(nodeTo) and + instructionOperandLocalFlowStep(nodeFrom, nodeTo) +} + +/** + * INTERNAL: do not use. + * Holds if `nodeFrom` has no incoming local `Operand` or `Instruction` register flow and `nodeFrom` can + * reach `nodeTo` using only local `Instruction` or `Operand` register flow steps. + */ +bindingset[nodeTo] +private predicate longestRegisterInstructionOperandLocalFlowStep(Node nodeFrom, Node nodeTo) { + registerInstructionOperandLocalFlowStep*(nodeFrom, nodeTo) and + not registerInstructionOperandLocalFlowStep(_, nodeFrom) +} + /** * INTERNAL: do not use. * Holds if `nodeFrom` is an operand and `nodeTo` is an instruction node that uses this operand, or * if `nodeFrom` is an instruction and `nodeTo` is an operand that refers to this instruction. */ -predicate instructionOperandLocalFlowStep(Node nodeFrom, Node nodeTo) { +private predicate instructionOperandLocalFlowStep(Node nodeFrom, Node nodeTo) { // Operand -> Instruction flow simpleInstructionLocalFlowStep(nodeFrom.asOperand(), nodeTo.asInstruction()) or diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected index ee43cd98302..e787b9a5f0e 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected @@ -58,9 +58,9 @@ edges | aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | | aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | -| aliasing.cpp:98:5:98:6 | m1 [post update] [m1] | aliasing.cpp:101:21:101:22 | m1 [m1] | +| aliasing.cpp:98:5:98:6 | m1 [post update] [m1] | aliasing.cpp:100:14:100:14 | Store [m1] | | aliasing.cpp:98:10:98:19 | call to user_input | aliasing.cpp:98:5:98:6 | m1 [post update] [m1] | -| aliasing.cpp:101:21:101:22 | m1 [m1] | aliasing.cpp:102:8:102:10 | * ... | +| aliasing.cpp:100:14:100:14 | Store [m1] | aliasing.cpp:102:8:102:10 | * ... | | aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:121:15:121:16 | taint_a_ptr output argument [array content] | | aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:126:15:126:20 | taint_a_ptr output argument [array content] | | aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:131:15:131:16 | taint_a_ptr output argument [array content] | @@ -373,7 +373,7 @@ nodes | aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 | | aliasing.cpp:98:5:98:6 | m1 [post update] [m1] | semmle.label | m1 [post update] [m1] | | aliasing.cpp:98:10:98:19 | call to user_input | semmle.label | call to user_input | -| aliasing.cpp:101:21:101:22 | m1 [m1] | semmle.label | m1 [m1] | +| aliasing.cpp:100:14:100:14 | Store [m1] | semmle.label | Store [m1] | | aliasing.cpp:102:8:102:10 | * ... | semmle.label | * ... | | aliasing.cpp:106:3:106:20 | Chi [array content] | semmle.label | Chi [array content] | | aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | semmle.label | ChiTotal [post update] [array content] | From 46393c33ef45534a7e12560f5fba346c6f1b6dc1 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Mon, 11 Jan 2021 09:19:58 +0100 Subject: [PATCH 057/343] C++: Fix bad join orders introduced in previous commit. --- .../ir/dataflow/internal/DataFlowPrivate.qll | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index e19fc9228c2..a5a30dc756e 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll @@ -350,7 +350,7 @@ private class InexactLoadOperand extends LoadOperand { InexactLoadOperand() { this.isDefinitionInexact() } } -/** Get the result type of an `Instruction` i, if it is a `PointerType`. */ +/** Get the result type of `i`, if it is a `PointerType`. */ private PointerType getPointerType(Instruction i) { // We are done if the type is a pointer type that is not a glvalue i.getResultLanguageType().hasType(result, false) @@ -359,16 +359,24 @@ private PointerType getPointerType(Instruction i) { result = getPointerType(i.(PointerOffsetInstruction).getLeft()) } +pragma[noinline] +private predicate deconstructLoad( + LoadInstruction load, InexactLoadOperand loadOperand, Instruction addressInstr +) { + load.getSourceAddress() = addressInstr and + load.getSourceValueOperand() = loadOperand +} + private predicate arrayReadStep(Node node1, ArrayContent a, Node node2) { a = TArrayContent() and // Explicit dereferences such as `*p` or `p[i]` where `p` is a pointer or array. - exists(InexactLoadOperand operand, LoadInstruction load | - load.getSourceValueOperand() = operand and - node1.asInstruction() = operand.getAnyDef() and + exists(InexactLoadOperand loadOperand, LoadInstruction load, Instruction address | + deconstructLoad(load, loadOperand, address) and + node1.asInstruction() = loadOperand.getAnyDef() and not node1.asInstruction().isResultConflated() and - operand = node2.asOperand() and + loadOperand = node2.asOperand() and // Ensure that the load is actually loading from an array or a pointer. - getPointerType(load.getSourceAddress()).getBaseType() = load.getResultType() + getPointerType(address).getBaseType() = load.getResultType() ) } @@ -423,6 +431,11 @@ private ReferenceType getReferenceType(Instruction i) { i.getResultLanguageType().hasType(result, false) } +pragma[noinline] +Type getResultTypeOfSourceValue(CopyValueInstruction copy) { + result = copy.getSourceValue().getResultType() +} + /** * In cases such as: * ```cpp @@ -451,7 +464,7 @@ private predicate innerReadSteap(Node node1, Content a, Node node2) { node2.asInstruction() = write and copyValue = call.getArgument(write.getIndex()) and [getPointerType(copyValue).getBaseType(), getReferenceType(copyValue).getBaseType()] = - copyValue.getSourceValue().getResultType() + getResultTypeOfSourceValue(copyValue) ) } From 141b9adc4d38eda5ea3cd9a5b19688979a303c8f Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 11 Jan 2021 11:18:59 +0100 Subject: [PATCH 058/343] Python: Minor refactoring Co-authored-by: yoff --- python/ql/src/semmle/python/Concepts.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/Concepts.qll b/python/ql/src/semmle/python/Concepts.qll index 9a30ebf4871..a90df346b2f 100644 --- a/python/ql/src/semmle/python/Concepts.qll +++ b/python/ql/src/semmle/python/Concepts.qll @@ -404,7 +404,7 @@ module HTTP { /** A parameter that will receive parts of the url when handling an incoming request. */ private class RoutedParameter extends RemoteFlowSource::Range, DataFlow::ParameterNode { - RoutedParameter() { this.getParameter() = any(RequestHandler setup).getARoutedParameter() } + RoutedParameter() { this.getParameter() = any(RequestHandler handler).getARoutedParameter() } override string getSourceType() { result = "RoutedParameter" } } From 580a24e982db8f8412d3aac6d079e4cb7d4ecaa3 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Fri, 19 Jun 2020 11:50:39 +0200 Subject: [PATCH 059/343] JS: rewrite js/incomplete-multi-character-sanitization --- ...incomplete-multi-character-sanitization.md | 2 + .../IncompleteMultiCharacterSanitization.ql | 194 +++++++++++++----- ...ompleteMultiCharacterSanitization.expected | 66 +++--- .../tst-multi-character-sanitization.js | 37 +++- 4 files changed, 204 insertions(+), 95 deletions(-) create mode 100644 javascript/change-notes/2021-01-08-js-incomplete-multi-character-sanitization.md diff --git a/javascript/change-notes/2021-01-08-js-incomplete-multi-character-sanitization.md b/javascript/change-notes/2021-01-08-js-incomplete-multi-character-sanitization.md new file mode 100644 index 00000000000..653ba2a8994 --- /dev/null +++ b/javascript/change-notes/2021-01-08-js-incomplete-multi-character-sanitization.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* The query "Incomplete multi-character sanitization" (`js/incomplete-multi-character-sanitization`) has been improved to produce additional true positives and fewer false positives. diff --git a/javascript/ql/src/Security/CWE-116/IncompleteMultiCharacterSanitization.ql b/javascript/ql/src/Security/CWE-116/IncompleteMultiCharacterSanitization.ql index dbff9d98bc5..cef10d3cbe7 100644 --- a/javascript/ql/src/Security/CWE-116/IncompleteMultiCharacterSanitization.ql +++ b/javascript/ql/src/Security/CWE-116/IncompleteMultiCharacterSanitization.ql @@ -12,69 +12,153 @@ */ import javascript -import semmle.javascript.security.IncompleteBlacklistSanitizer -predicate isDangerous(RegExpTerm t) { - // path traversals - t.getAMatchedString() = ["..", "/..", "../"] - or - exists(RegExpTerm start | - start = t.(RegExpSequence).getAChild() and - start.getConstantValue() = "." and - start.getSuccessor().getConstantValue() = "." and - not [start.getPredecessor(), start.getSuccessor().getSuccessor()].getConstantValue() = "." - ) - or - // HTML comments - t.getAMatchedString() = "/gm, ""); // NOT OK - x = x.replace(/\sng-[a-z-]+/, ""); // OK (single ng-attribute, should be flagged by some other query!) + x = x.replace(/\sng-[a-z-]+/, ""); // NOT OK x = x.replace(/\sng-[a-z-]+/g, ""); // NOT OK (ng-attributes) x = x.replace(/()/g, "\n"); // OK: not a sanitizer - x = x.replace(//g, ""); // OK, but still flagged [INCONSISTENCY] - x = x.replace(/