From dc58f6fa8748fe947f6a039d5dc332e4cc48cadf Mon Sep 17 00:00:00 2001 From: dilanbhalla Date: Thu, 25 Jun 2020 11:39:09 -0700 Subject: [PATCH 001/725] function/class synatax --- .../Classes/NamingConventionsClasses.qhelp | 30 +++++++++++++++++++ .../src/Classes/NamingConventionsClasses.ql | 17 +++++++++++ .../NamingConventionsFunctions.qhelp | 30 +++++++++++++++++++ .../Functions/NamingConventionsFunctions.ql | 17 +++++++++++ .../Naming/NamingConventionsClasses.expected | 1 + .../Naming/NamingConventionsClasses.py | 11 +++++++ .../Naming/NamingConventionsClasses.qlref | 1 + .../NamingConventionsFunctions.expected | 1 + .../general/NamingConventionsFunctions.py | 9 ++++++ .../general/NamingConventionsFunctions.qlref | 1 + 10 files changed, 118 insertions(+) create mode 100644 python/ql/src/Classes/NamingConventionsClasses.qhelp create mode 100644 python/ql/src/Classes/NamingConventionsClasses.ql create mode 100644 python/ql/src/Functions/NamingConventionsFunctions.qhelp create mode 100644 python/ql/src/Functions/NamingConventionsFunctions.ql create mode 100644 python/ql/test/query-tests/Classes/Naming/NamingConventionsClasses.expected create mode 100644 python/ql/test/query-tests/Classes/Naming/NamingConventionsClasses.py create mode 100644 python/ql/test/query-tests/Classes/Naming/NamingConventionsClasses.qlref create mode 100644 python/ql/test/query-tests/Functions/general/NamingConventionsFunctions.expected create mode 100644 python/ql/test/query-tests/Functions/general/NamingConventionsFunctions.py create mode 100644 python/ql/test/query-tests/Functions/general/NamingConventionsFunctions.qlref diff --git a/python/ql/src/Classes/NamingConventionsClasses.qhelp b/python/ql/src/Classes/NamingConventionsClasses.qhelp new file mode 100644 index 00000000000..7a6c0ca13dd --- /dev/null +++ b/python/ql/src/Classes/NamingConventionsClasses.qhelp @@ -0,0 +1,30 @@ + + + + + +

A class name that begins with a lowercase letter does not follow standard +naming conventions. This decreases code readability. For example, class background. +

+ +
+ + +

+Write the class name beginning with an uppercase letter. For example, class Background. +

+ +
+ + + +
  • + Guido van Rossum, Barry Warsaw, Nick Coghlan PEP 8 -- Style Guide for Python Code + +
  • + +
    + +
    diff --git a/python/ql/src/Classes/NamingConventionsClasses.ql b/python/ql/src/Classes/NamingConventionsClasses.ql new file mode 100644 index 00000000000..a1744f5d3e6 --- /dev/null +++ b/python/ql/src/Classes/NamingConventionsClasses.ql @@ -0,0 +1,17 @@ +/** + * @name Misnamed class + * @description A class name that begins with a lowercase letter decreases readability. + * @kind problem + * @problem.severity recommendation + * @precision medium + * @id python/misnamed-type + * @tags maintainability + */ + +import python + +from Class c +where + c.inSource() and + not c.getName().substring(0, 1).toUpperCase() = c.getName().substring(0, 1) +select c, "Class names should start in uppercase." diff --git a/python/ql/src/Functions/NamingConventionsFunctions.qhelp b/python/ql/src/Functions/NamingConventionsFunctions.qhelp new file mode 100644 index 00000000000..15014045542 --- /dev/null +++ b/python/ql/src/Functions/NamingConventionsFunctions.qhelp @@ -0,0 +1,30 @@ + + + + + +

    A function name that begins with an uppercase letter does not follow standard +naming conventions. This decreases code readability. For example, Jump. +

    + +
    + + +

    +Write the function name beginning with an lowercase letter. For example, jump. +

    + +
    + + + +
  • + Guido van Rossum, Barry Warsaw, Nick Coghlan PEP 8 -- Style Guide for Python Code + +
  • + + + + diff --git a/python/ql/src/Functions/NamingConventionsFunctions.ql b/python/ql/src/Functions/NamingConventionsFunctions.ql new file mode 100644 index 00000000000..3ed619bc084 --- /dev/null +++ b/python/ql/src/Functions/NamingConventionsFunctions.ql @@ -0,0 +1,17 @@ +/** + * @name Misnamed function + * @description A function name that begins with an uppercase letter decreases readability. + * @kind problem + * @problem.severity recommendation + * @precision medium + * @id python/misnamed-function + * @tags maintainability + */ + +import python + +from Function f +where + f.inSource() and + not f.getName().substring(0, 1).toLowerCase() = f.getName().substring(0, 1) +select f, "Function names should start in lowercase." diff --git a/python/ql/test/query-tests/Classes/Naming/NamingConventionsClasses.expected b/python/ql/test/query-tests/Classes/Naming/NamingConventionsClasses.expected new file mode 100644 index 00000000000..8e6dea7fce4 --- /dev/null +++ b/python/ql/test/query-tests/Classes/Naming/NamingConventionsClasses.expected @@ -0,0 +1 @@ +| NamingConventionsClasses.py:2:1:2:14 | Class badName | Class names should start in uppercase. | diff --git a/python/ql/test/query-tests/Classes/Naming/NamingConventionsClasses.py b/python/ql/test/query-tests/Classes/Naming/NamingConventionsClasses.py new file mode 100644 index 00000000000..c07bdb57234 --- /dev/null +++ b/python/ql/test/query-tests/Classes/Naming/NamingConventionsClasses.py @@ -0,0 +1,11 @@ +# BAD, do not start class or interface name with lowercase letter +class badName: + + def hello(self): + print("hello") + +# Good, class name starts with capital letter +class GoodName: + + def hello(self): + print("hello") \ No newline at end of file diff --git a/python/ql/test/query-tests/Classes/Naming/NamingConventionsClasses.qlref b/python/ql/test/query-tests/Classes/Naming/NamingConventionsClasses.qlref new file mode 100644 index 00000000000..01ad29859da --- /dev/null +++ b/python/ql/test/query-tests/Classes/Naming/NamingConventionsClasses.qlref @@ -0,0 +1 @@ +Classes/NamingConventionsClasses.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Functions/general/NamingConventionsFunctions.expected b/python/ql/test/query-tests/Functions/general/NamingConventionsFunctions.expected new file mode 100644 index 00000000000..d87fe6c16f3 --- /dev/null +++ b/python/ql/test/query-tests/Functions/general/NamingConventionsFunctions.expected @@ -0,0 +1 @@ +| NamingConventionsFunctions.py:4:5:4:25 | Function HelloWorld | Function names should start in lowercase. | diff --git a/python/ql/test/query-tests/Functions/general/NamingConventionsFunctions.py b/python/ql/test/query-tests/Functions/general/NamingConventionsFunctions.py new file mode 100644 index 00000000000..fb3e89ab8e9 --- /dev/null +++ b/python/ql/test/query-tests/Functions/general/NamingConventionsFunctions.py @@ -0,0 +1,9 @@ +class Test: + + # BAD, do not start function name with uppercase letter + def HelloWorld(self): + print("hello world") + + # GOOD, function name starts with lowercase letter + def hello_world(self): + print("hello world") \ No newline at end of file diff --git a/python/ql/test/query-tests/Functions/general/NamingConventionsFunctions.qlref b/python/ql/test/query-tests/Functions/general/NamingConventionsFunctions.qlref new file mode 100644 index 00000000000..da4780ecbe9 --- /dev/null +++ b/python/ql/test/query-tests/Functions/general/NamingConventionsFunctions.qlref @@ -0,0 +1 @@ +Functions/NamingConventionsFunctions.ql \ No newline at end of file From dc73fcc4e856cbfc3ea5967013dcf858679563f8 Mon Sep 17 00:00:00 2001 From: dilanbhalla Date: Wed, 1 Jul 2020 09:54:58 -0700 Subject: [PATCH 002/725] moved to experimental --- .../{ => experimental}/Classes/NamingConventionsClasses.qhelp | 0 .../src/{ => experimental}/Classes/NamingConventionsClasses.ql | 0 .../Functions/NamingConventionsFunctions.qhelp | 0 .../{ => experimental}/Functions/NamingConventionsFunctions.ql | 0 .../query-tests/Classes/Naming/NamingConventionsClasses.expected | 0 .../query-tests/Classes/Naming/NamingConventionsClasses.py | 0 .../query-tests/Classes/Naming/NamingConventionsClasses.qlref | 1 + .../Functions/general/NamingConventionsFunctions.expected | 0 .../query-tests/Functions/general/NamingConventionsFunctions.py | 0 .../Functions/general/NamingConventionsFunctions.qlref | 1 + .../query-tests/Classes/Naming/NamingConventionsClasses.qlref | 1 - .../Functions/general/NamingConventionsFunctions.qlref | 1 - 12 files changed, 2 insertions(+), 2 deletions(-) rename python/ql/src/{ => experimental}/Classes/NamingConventionsClasses.qhelp (100%) rename python/ql/src/{ => experimental}/Classes/NamingConventionsClasses.ql (100%) rename python/ql/src/{ => experimental}/Functions/NamingConventionsFunctions.qhelp (100%) rename python/ql/src/{ => experimental}/Functions/NamingConventionsFunctions.ql (100%) rename python/ql/test/{ => experimental}/query-tests/Classes/Naming/NamingConventionsClasses.expected (100%) rename python/ql/test/{ => experimental}/query-tests/Classes/Naming/NamingConventionsClasses.py (100%) create mode 100644 python/ql/test/experimental/query-tests/Classes/Naming/NamingConventionsClasses.qlref rename python/ql/test/{ => experimental}/query-tests/Functions/general/NamingConventionsFunctions.expected (100%) rename python/ql/test/{ => experimental}/query-tests/Functions/general/NamingConventionsFunctions.py (100%) create mode 100644 python/ql/test/experimental/query-tests/Functions/general/NamingConventionsFunctions.qlref delete mode 100644 python/ql/test/query-tests/Classes/Naming/NamingConventionsClasses.qlref delete mode 100644 python/ql/test/query-tests/Functions/general/NamingConventionsFunctions.qlref diff --git a/python/ql/src/Classes/NamingConventionsClasses.qhelp b/python/ql/src/experimental/Classes/NamingConventionsClasses.qhelp similarity index 100% rename from python/ql/src/Classes/NamingConventionsClasses.qhelp rename to python/ql/src/experimental/Classes/NamingConventionsClasses.qhelp diff --git a/python/ql/src/Classes/NamingConventionsClasses.ql b/python/ql/src/experimental/Classes/NamingConventionsClasses.ql similarity index 100% rename from python/ql/src/Classes/NamingConventionsClasses.ql rename to python/ql/src/experimental/Classes/NamingConventionsClasses.ql diff --git a/python/ql/src/Functions/NamingConventionsFunctions.qhelp b/python/ql/src/experimental/Functions/NamingConventionsFunctions.qhelp similarity index 100% rename from python/ql/src/Functions/NamingConventionsFunctions.qhelp rename to python/ql/src/experimental/Functions/NamingConventionsFunctions.qhelp diff --git a/python/ql/src/Functions/NamingConventionsFunctions.ql b/python/ql/src/experimental/Functions/NamingConventionsFunctions.ql similarity index 100% rename from python/ql/src/Functions/NamingConventionsFunctions.ql rename to python/ql/src/experimental/Functions/NamingConventionsFunctions.ql diff --git a/python/ql/test/query-tests/Classes/Naming/NamingConventionsClasses.expected b/python/ql/test/experimental/query-tests/Classes/Naming/NamingConventionsClasses.expected similarity index 100% rename from python/ql/test/query-tests/Classes/Naming/NamingConventionsClasses.expected rename to python/ql/test/experimental/query-tests/Classes/Naming/NamingConventionsClasses.expected diff --git a/python/ql/test/query-tests/Classes/Naming/NamingConventionsClasses.py b/python/ql/test/experimental/query-tests/Classes/Naming/NamingConventionsClasses.py similarity index 100% rename from python/ql/test/query-tests/Classes/Naming/NamingConventionsClasses.py rename to python/ql/test/experimental/query-tests/Classes/Naming/NamingConventionsClasses.py diff --git a/python/ql/test/experimental/query-tests/Classes/Naming/NamingConventionsClasses.qlref b/python/ql/test/experimental/query-tests/Classes/Naming/NamingConventionsClasses.qlref new file mode 100644 index 00000000000..7ed945d782c --- /dev/null +++ b/python/ql/test/experimental/query-tests/Classes/Naming/NamingConventionsClasses.qlref @@ -0,0 +1 @@ +experimental/Classes/NamingConventionsClasses.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Functions/general/NamingConventionsFunctions.expected b/python/ql/test/experimental/query-tests/Functions/general/NamingConventionsFunctions.expected similarity index 100% rename from python/ql/test/query-tests/Functions/general/NamingConventionsFunctions.expected rename to python/ql/test/experimental/query-tests/Functions/general/NamingConventionsFunctions.expected diff --git a/python/ql/test/query-tests/Functions/general/NamingConventionsFunctions.py b/python/ql/test/experimental/query-tests/Functions/general/NamingConventionsFunctions.py similarity index 100% rename from python/ql/test/query-tests/Functions/general/NamingConventionsFunctions.py rename to python/ql/test/experimental/query-tests/Functions/general/NamingConventionsFunctions.py diff --git a/python/ql/test/experimental/query-tests/Functions/general/NamingConventionsFunctions.qlref b/python/ql/test/experimental/query-tests/Functions/general/NamingConventionsFunctions.qlref new file mode 100644 index 00000000000..0204694de0a --- /dev/null +++ b/python/ql/test/experimental/query-tests/Functions/general/NamingConventionsFunctions.qlref @@ -0,0 +1 @@ +experimental/Functions/NamingConventionsFunctions.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Classes/Naming/NamingConventionsClasses.qlref b/python/ql/test/query-tests/Classes/Naming/NamingConventionsClasses.qlref deleted file mode 100644 index 01ad29859da..00000000000 --- a/python/ql/test/query-tests/Classes/Naming/NamingConventionsClasses.qlref +++ /dev/null @@ -1 +0,0 @@ -Classes/NamingConventionsClasses.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Functions/general/NamingConventionsFunctions.qlref b/python/ql/test/query-tests/Functions/general/NamingConventionsFunctions.qlref deleted file mode 100644 index da4780ecbe9..00000000000 --- a/python/ql/test/query-tests/Functions/general/NamingConventionsFunctions.qlref +++ /dev/null @@ -1 +0,0 @@ -Functions/NamingConventionsFunctions.ql \ No newline at end of file From 26b030f8ccaf1b1922623a035e15cef239ec7314 Mon Sep 17 00:00:00 2001 From: dilanbhalla Date: Tue, 7 Jul 2020 10:52:26 -0700 Subject: [PATCH 003/725] fixed pr suggestions --- .../Classes/NamingConventionsClasses.qhelp | 2 +- .../Classes/NamingConventionsClasses.ql | 14 ++++++++++---- .../Functions/NamingConventionsFunctions.qhelp | 2 +- .../Functions/NamingConventionsFunctions.ql | 14 ++++++++++---- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/python/ql/src/experimental/Classes/NamingConventionsClasses.qhelp b/python/ql/src/experimental/Classes/NamingConventionsClasses.qhelp index 7a6c0ca13dd..1a7f4bc45a4 100644 --- a/python/ql/src/experimental/Classes/NamingConventionsClasses.qhelp +++ b/python/ql/src/experimental/Classes/NamingConventionsClasses.qhelp @@ -22,7 +22,7 @@ Write the class name beginning with an uppercase letter. For example, clas
  • Guido van Rossum, Barry Warsaw, Nick Coghlan PEP 8 -- Style Guide for Python Code - + Python Class Names
  • diff --git a/python/ql/src/experimental/Classes/NamingConventionsClasses.ql b/python/ql/src/experimental/Classes/NamingConventionsClasses.ql index a1744f5d3e6..d4919c3ece8 100644 --- a/python/ql/src/experimental/Classes/NamingConventionsClasses.ql +++ b/python/ql/src/experimental/Classes/NamingConventionsClasses.ql @@ -3,15 +3,21 @@ * @description A class name that begins with a lowercase letter decreases readability. * @kind problem * @problem.severity recommendation - * @precision medium - * @id python/misnamed-type + * @id py/misnamed-class * @tags maintainability */ import python -from Class c +from Class c, string first_char where c.inSource() and - not c.getName().substring(0, 1).toUpperCase() = c.getName().substring(0, 1) + first_char = c.getName().prefix(1) and + not first_char = first_char.toUpperCase() and + not exists(Class c1, string first_char1 | + c1 != c and + c1.getLocation().getFile() = c.getLocation().getFile() and + first_char1 = c1.getName().prefix(1) and + not first_char1 = first_char1.toUpperCase() + ) select c, "Class names should start in uppercase." diff --git a/python/ql/src/experimental/Functions/NamingConventionsFunctions.qhelp b/python/ql/src/experimental/Functions/NamingConventionsFunctions.qhelp index 15014045542..46d948592ff 100644 --- a/python/ql/src/experimental/Functions/NamingConventionsFunctions.qhelp +++ b/python/ql/src/experimental/Functions/NamingConventionsFunctions.qhelp @@ -22,7 +22,7 @@ Write the function name beginning with an lowercase letter. For example, j
  • Guido van Rossum, Barry Warsaw, Nick Coghlan PEP 8 -- Style Guide for Python Code - + Python Function and Variable Names
  • diff --git a/python/ql/src/experimental/Functions/NamingConventionsFunctions.ql b/python/ql/src/experimental/Functions/NamingConventionsFunctions.ql index 3ed619bc084..80dc0e99cd8 100644 --- a/python/ql/src/experimental/Functions/NamingConventionsFunctions.ql +++ b/python/ql/src/experimental/Functions/NamingConventionsFunctions.ql @@ -3,15 +3,21 @@ * @description A function name that begins with an uppercase letter decreases readability. * @kind problem * @problem.severity recommendation - * @precision medium - * @id python/misnamed-function + * @id py/misnamed-function * @tags maintainability */ import python -from Function f +from Function f, string first_char where f.inSource() and - not f.getName().substring(0, 1).toLowerCase() = f.getName().substring(0, 1) + first_char = f.getName().prefix(1) and + not first_char = first_char.toLowerCase() and + not exists(Function f1, string first_char1 | + f1 != f and + f1.getLocation().getFile() = f.getLocation().getFile() and + first_char1 = f1.getName().prefix(1) and + not first_char1 = first_char1.toLowerCase() + ) select f, "Function names should start in lowercase." From 7d79be71d1fbac90c30482142a33b48388da9eff Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Mon, 27 Apr 2020 13:57:30 -0700 Subject: [PATCH 004/725] C++: taint tracking conf in DefaultTaintTracking Switch from using additional flow steps with a DataFlow::Configuration in DefaultTaintTracking to using a TaintTracking::Configuration. This makes future improvements to TaintTracking::Configuration reflected in DefaultTaintTracking without further effort. It also removes the predictability constraint in DefaultTaintTracking, which increases the number of results, with both new true positives and new false positives. Those may need to be addressed on a per-query basis. There are some additional regressions from losing pointer/object conflation for arguments. Those can be worked around by adding that conflation to TaintTracking::Configuration until precise indirect parameter flow is ready. --- .../cpp/ir/dataflow/DefaultTaintTracking.qll | 29 ++-- .../CWE-022/semmle/tests/TaintedPath.expected | 10 -- .../UncontrolledProcessOperation.expected | 48 ------ .../CWE-134/semmle/argv/argvLocal.expected | 156 ------------------ .../CWE-134/semmle/funcs/funcsLocal.expected | 52 ------ ...olledFormatStringThroughGlobalVar.expected | 3 - .../ArithmeticUncontrolled.expected | 17 ++ .../CWE/CWE-190/semmle/uncontrolled/test.cpp | 2 +- .../TaintedCondition.expected | 26 ++- 9 files changed, 42 insertions(+), 301 deletions(-) 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 5129078545c..ae2066398a1 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll @@ -9,6 +9,7 @@ private import semmle.code.cpp.ir.dataflow.internal.DataFlowDispatch as Dispatch private import semmle.code.cpp.controlflow.IRGuards private import semmle.code.cpp.models.interfaces.Taint private import semmle.code.cpp.models.interfaces.DataFlow +private import semmle.code.cpp.ir.dataflow.TaintTracking2 /** * A predictable instruction is one where an external user can predict @@ -113,7 +114,7 @@ private class ToGlobalVarTaintTrackingCfg extends DataFlow::Configuration { override predicate isBarrierIn(DataFlow::Node node) { nodeIsBarrierIn(node) } } -private class FromGlobalVarTaintTrackingCfg extends DataFlow2::Configuration { +private class FromGlobalVarTaintTrackingCfg extends DataFlow3::Configuration { FromGlobalVarTaintTrackingCfg() { this = "FromGlobalVarTaintTrackingCfg" } override predicate isSource(DataFlow::Node source) { @@ -560,7 +561,7 @@ module TaintedWithPath { string toString() { result = "TaintTrackingConfiguration" } } - private class AdjustedConfiguration extends DataFlow3::Configuration { + private class AdjustedConfiguration extends TaintTracking2::Configuration { AdjustedConfiguration() { this = "AdjustedConfiguration" } override predicate isSource(DataFlow::Node source) { source = getNodeForSource(_) } @@ -569,9 +570,7 @@ module TaintedWithPath { exists(TaintTrackingConfiguration cfg | cfg.isSink(adjustedSink(sink))) } - override predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) { - commonTaintStep(n1, n2) - or + override predicate isAdditionalTaintStep(DataFlow::Node n1, DataFlow::Node n2) { exists(TaintTrackingConfiguration cfg | cfg.taintThroughGlobals() | writesVariable(n1.asInstruction(), n2.asVariable().(GlobalOrNamespaceVariable)) or @@ -579,9 +578,9 @@ module TaintedWithPath { ) } - override predicate isBarrier(DataFlow::Node node) { nodeIsBarrier(node) } + override predicate isSanitizer(DataFlow::Node node) { nodeIsBarrier(node) } - override predicate isBarrierIn(DataFlow::Node node) { nodeIsBarrierIn(node) } + override predicate isSanitizerIn(DataFlow::Node node) { nodeIsBarrierIn(node) } } /* @@ -599,11 +598,11 @@ module TaintedWithPath { */ private newtype TPathNode = - TWrapPathNode(DataFlow3::PathNode n) or + TWrapPathNode(DataFlow2::PathNode n) or // There's a single newtype constructor for both sources and sinks since // that makes it easiest to deal with the case where source = sink. TEndpointPathNode(Element e) { - exists(AdjustedConfiguration cfg, DataFlow3::Node sourceNode, DataFlow3::Node sinkNode | + exists(AdjustedConfiguration cfg, DataFlow2::Node sourceNode, DataFlow2::Node sinkNode | cfg.hasFlow(sourceNode, sinkNode) | sourceNode = getNodeForSource(e) @@ -633,7 +632,7 @@ module TaintedWithPath { } private class WrapPathNode extends PathNode, TWrapPathNode { - DataFlow3::PathNode inner() { this = TWrapPathNode(result) } + DataFlow2::PathNode inner() { this = TWrapPathNode(result) } override string toString() { result = this.inner().toString() } @@ -671,25 +670,25 @@ module TaintedWithPath { /** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */ query predicate edges(PathNode a, PathNode b) { - DataFlow3::PathGraph::edges(a.(WrapPathNode).inner(), b.(WrapPathNode).inner()) + DataFlow2::PathGraph::edges(a.(WrapPathNode).inner(), b.(WrapPathNode).inner()) or // To avoid showing trivial-looking steps, we _replace_ the last node instead // of adding an edge out of it. exists(WrapPathNode sinkNode | - DataFlow3::PathGraph::edges(a.(WrapPathNode).inner(), sinkNode.inner()) and + DataFlow2::PathGraph::edges(a.(WrapPathNode).inner(), sinkNode.inner()) and b.(FinalPathNode).inner() = adjustedSink(sinkNode.inner().getNode()) ) or // Same for the first node exists(WrapPathNode sourceNode | - DataFlow3::PathGraph::edges(sourceNode.inner(), b.(WrapPathNode).inner()) and + DataFlow2::PathGraph::edges(sourceNode.inner(), b.(WrapPathNode).inner()) and sourceNode.inner().getNode() = getNodeForSource(a.(InitialPathNode).inner()) ) or // Finally, handle the case where the path goes directly from a source to a // sink, meaning that they both need to be translated. exists(WrapPathNode sinkNode, WrapPathNode sourceNode | - DataFlow3::PathGraph::edges(sourceNode.inner(), sinkNode.inner()) and + DataFlow2::PathGraph::edges(sourceNode.inner(), sinkNode.inner()) and sourceNode.inner().getNode() = getNodeForSource(a.(InitialPathNode).inner()) and b.(FinalPathNode).inner() = adjustedSink(sinkNode.inner().getNode()) ) @@ -711,7 +710,7 @@ module TaintedWithPath { * the computation. */ predicate taintedWithPath(Expr source, Element tainted, PathNode sourceNode, PathNode sinkNode) { - exists(AdjustedConfiguration cfg, DataFlow3::Node flowSource, DataFlow3::Node flowSink | + exists(AdjustedConfiguration cfg, DataFlow2::Node flowSource, DataFlow2::Node flowSink | source = sourceNode.(InitialPathNode).inner() and flowSource = getNodeForSource(source) and cfg.hasFlow(flowSource, flowSink) and diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-022/semmle/tests/TaintedPath.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-022/semmle/tests/TaintedPath.expected index d7db531fbde..58e3dda0964 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-022/semmle/tests/TaintedPath.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-022/semmle/tests/TaintedPath.expected @@ -1,13 +1,3 @@ edges -| test.c:9:23:9:26 | argv | test.c:17:11:17:18 | (const char *)... | -| test.c:9:23:9:26 | argv | test.c:17:11:17:18 | (const char *)... | -| test.c:9:23:9:26 | argv | test.c:17:11:17:18 | fileName | -| test.c:9:23:9:26 | argv | test.c:17:11:17:18 | fileName | nodes -| test.c:9:23:9:26 | argv | semmle.label | argv | -| test.c:9:23:9:26 | argv | semmle.label | argv | -| test.c:17:11:17:18 | (const char *)... | semmle.label | (const char *)... | -| test.c:17:11:17:18 | (const char *)... | semmle.label | (const char *)... | -| test.c:17:11:17:18 | fileName | semmle.label | fileName | #select -| test.c:17:11:17:18 | fileName | test.c:9:23:9:26 | argv | test.c:17:11:17:18 | fileName | This argument to a file access function is derived from $@ and then passed to fopen(filename) | test.c:9:23:9:26 | argv | user input (argv) | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/UncontrolledProcessOperation.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/UncontrolledProcessOperation.expected index 0c2778abaf4..c53e4f5be87 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/UncontrolledProcessOperation.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/UncontrolledProcessOperation.expected @@ -1,43 +1,17 @@ edges -| test.cpp:24:30:24:36 | *command | test.cpp:26:10:26:16 | command | -| test.cpp:24:30:24:36 | *command | test.cpp:26:10:26:16 | command | | test.cpp:24:30:24:36 | command | test.cpp:26:10:26:16 | command | | test.cpp:24:30:24:36 | command | test.cpp:26:10:26:16 | command | -| test.cpp:29:30:29:36 | *command | test.cpp:31:10:31:16 | command | -| test.cpp:29:30:29:36 | *command | test.cpp:31:10:31:16 | command | | test.cpp:29:30:29:36 | command | test.cpp:31:10:31:16 | command | | test.cpp:29:30:29:36 | command | test.cpp:31:10:31:16 | command | -| test.cpp:42:18:42:23 | call to getenv | test.cpp:24:30:24:36 | *command | | test.cpp:42:18:42:23 | call to getenv | test.cpp:24:30:24:36 | command | -| test.cpp:42:18:42:34 | (const char *)... | test.cpp:24:30:24:36 | *command | | test.cpp:42:18:42:34 | (const char *)... | test.cpp:24:30:24:36 | command | -| test.cpp:43:18:43:23 | call to getenv | test.cpp:29:30:29:36 | *command | | test.cpp:43:18:43:23 | call to getenv | test.cpp:29:30:29:36 | command | -| test.cpp:43:18:43:34 | (const char *)... | test.cpp:29:30:29:36 | *command | | test.cpp:43:18:43:34 | (const char *)... | test.cpp:29:30:29:36 | command | -| test.cpp:56:12:56:17 | buffer | test.cpp:62:10:62:15 | (const char *)... | -| test.cpp:56:12:56:17 | buffer | test.cpp:62:10:62:15 | buffer | -| test.cpp:56:12:56:17 | buffer | test.cpp:63:10:63:13 | (const char *)... | -| test.cpp:56:12:56:17 | buffer | test.cpp:63:10:63:13 | data | -| test.cpp:56:12:56:17 | fgets output argument | test.cpp:62:10:62:15 | (const char *)... | -| test.cpp:56:12:56:17 | fgets output argument | test.cpp:62:10:62:15 | buffer | -| test.cpp:56:12:56:17 | fgets output argument | test.cpp:63:10:63:13 | (const char *)... | -| test.cpp:56:12:56:17 | fgets output argument | test.cpp:63:10:63:13 | data | -| test.cpp:76:12:76:17 | buffer | test.cpp:78:10:78:15 | (const char *)... | -| test.cpp:76:12:76:17 | buffer | test.cpp:78:10:78:15 | buffer | -| test.cpp:76:12:76:17 | buffer | test.cpp:79:10:79:13 | (const char *)... | -| test.cpp:76:12:76:17 | buffer | test.cpp:79:10:79:13 | data | -| test.cpp:76:12:76:17 | fgets output argument | test.cpp:78:10:78:15 | (const char *)... | -| test.cpp:76:12:76:17 | fgets output argument | test.cpp:78:10:78:15 | buffer | -| test.cpp:76:12:76:17 | fgets output argument | test.cpp:79:10:79:13 | (const char *)... | -| test.cpp:76:12:76:17 | fgets output argument | test.cpp:79:10:79:13 | data | nodes -| test.cpp:24:30:24:36 | *command | semmle.label | *command | | test.cpp:24:30:24:36 | command | semmle.label | command | | test.cpp:26:10:26:16 | command | semmle.label | command | | test.cpp:26:10:26:16 | command | semmle.label | command | | test.cpp:26:10:26:16 | command | semmle.label | command | -| test.cpp:29:30:29:36 | *command | semmle.label | *command | | test.cpp:29:30:29:36 | command | semmle.label | command | | test.cpp:31:10:31:16 | command | semmle.label | command | | test.cpp:31:10:31:16 | command | semmle.label | command | @@ -45,31 +19,9 @@ nodes | test.cpp:42:7:42:16 | Argument 0 | semmle.label | Argument 0 | | test.cpp:42:18:42:23 | call to getenv | semmle.label | call to getenv | | test.cpp:42:18:42:34 | (const char *)... | semmle.label | (const char *)... | -| test.cpp:42:18:42:34 | Argument 0 indirection | semmle.label | Argument 0 indirection | | test.cpp:43:7:43:16 | Argument 0 | semmle.label | Argument 0 | | test.cpp:43:18:43:23 | call to getenv | semmle.label | call to getenv | | test.cpp:43:18:43:34 | (const char *)... | semmle.label | (const char *)... | -| test.cpp:43:18:43:34 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| test.cpp:56:12:56:17 | buffer | semmle.label | buffer | -| test.cpp:56:12:56:17 | fgets output argument | semmle.label | fgets output argument | -| test.cpp:62:10:62:15 | (const char *)... | semmle.label | (const char *)... | -| test.cpp:62:10:62:15 | (const char *)... | semmle.label | (const char *)... | -| test.cpp:62:10:62:15 | buffer | semmle.label | buffer | -| test.cpp:63:10:63:13 | (const char *)... | semmle.label | (const char *)... | -| test.cpp:63:10:63:13 | (const char *)... | semmle.label | (const char *)... | -| test.cpp:63:10:63:13 | data | semmle.label | data | -| test.cpp:76:12:76:17 | buffer | semmle.label | buffer | -| test.cpp:76:12:76:17 | fgets output argument | semmle.label | fgets output argument | -| test.cpp:78:10:78:15 | (const char *)... | semmle.label | (const char *)... | -| test.cpp:78:10:78:15 | (const char *)... | semmle.label | (const char *)... | -| test.cpp:78:10:78:15 | buffer | semmle.label | buffer | -| test.cpp:79:10:79:13 | (const char *)... | semmle.label | (const char *)... | -| test.cpp:79:10:79:13 | (const char *)... | semmle.label | (const char *)... | -| test.cpp:79:10:79:13 | data | semmle.label | data | #select | test.cpp:26:10:26:16 | command | test.cpp:42:18:42:23 | call to getenv | test.cpp:26:10:26:16 | command | The value of this argument may come from $@ and is being passed to system | test.cpp:42:18:42:23 | call to getenv | call to getenv | | test.cpp:31:10:31:16 | command | test.cpp:43:18:43:23 | call to getenv | test.cpp:31:10:31:16 | command | The value of this argument may come from $@ and is being passed to system | test.cpp:43:18:43:23 | call to getenv | call to getenv | -| test.cpp:62:10:62:15 | buffer | test.cpp:56:12:56:17 | buffer | test.cpp:62:10:62:15 | buffer | The value of this argument may come from $@ and is being passed to system | test.cpp:56:12:56:17 | buffer | buffer | -| test.cpp:63:10:63:13 | data | test.cpp:56:12:56:17 | buffer | test.cpp:63:10:63:13 | data | The value of this argument may come from $@ and is being passed to system | test.cpp:56:12:56:17 | buffer | buffer | -| test.cpp:78:10:78:15 | buffer | test.cpp:76:12:76:17 | buffer | test.cpp:78:10:78:15 | buffer | The value of this argument may come from $@ and is being passed to system | test.cpp:76:12:76:17 | buffer | buffer | -| test.cpp:79:10:79:13 | data | test.cpp:76:12:76:17 | buffer | test.cpp:79:10:79:13 | data | The value of this argument may come from $@ and is being passed to system | test.cpp:76:12:76:17 | buffer | buffer | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.expected index ac52436676c..72d1df8a59b 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.expected @@ -61,69 +61,6 @@ edges | argvLocal.c:106:9:106:13 | access to array | argvLocal.c:106:9:106:13 | access to array | | argvLocal.c:110:9:110:11 | * ... | argvLocal.c:110:9:110:11 | (const char *)... | | argvLocal.c:110:9:110:11 | * ... | argvLocal.c:110:9:110:11 | * ... | -| argvLocal.c:115:13:115:16 | argv | argvLocal.c:116:9:116:10 | (const char *)... | -| argvLocal.c:115:13:115:16 | argv | argvLocal.c:116:9:116:10 | (const char *)... | -| argvLocal.c:115:13:115:16 | argv | argvLocal.c:116:9:116:10 | i3 | -| argvLocal.c:115:13:115:16 | argv | argvLocal.c:116:9:116:10 | i3 | -| argvLocal.c:115:13:115:16 | argv | argvLocal.c:117:15:117:16 | array to pointer conversion | -| argvLocal.c:115:13:115:16 | argv | argvLocal.c:117:15:117:16 | array to pointer conversion | -| argvLocal.c:115:13:115:16 | argv | argvLocal.c:117:15:117:16 | i3 | -| argvLocal.c:115:13:115:16 | argv | argvLocal.c:117:15:117:16 | i3 | -| argvLocal.c:115:13:115:16 | argv | argvLocal.c:117:15:117:16 | printWrapper output argument | -| argvLocal.c:115:13:115:16 | argv | argvLocal.c:117:15:117:16 | printWrapper output argument | -| argvLocal.c:115:13:115:16 | argv | argvLocal.c:121:9:121:10 | (const char *)... | -| argvLocal.c:115:13:115:16 | argv | argvLocal.c:121:9:121:10 | (const char *)... | -| argvLocal.c:115:13:115:16 | argv | argvLocal.c:121:9:121:10 | i4 | -| argvLocal.c:115:13:115:16 | argv | argvLocal.c:121:9:121:10 | i4 | -| argvLocal.c:115:13:115:16 | argv | argvLocal.c:122:15:122:16 | i4 | -| argvLocal.c:115:13:115:16 | argv | argvLocal.c:122:15:122:16 | i4 | -| argvLocal.c:115:13:115:16 | argv | argvLocal.c:122:15:122:16 | i4 | -| argvLocal.c:115:13:115:16 | argv | argvLocal.c:122:15:122:16 | i4 | -| argvLocal.c:115:13:115:16 | argv | argvLocal.c:122:15:122:16 | printWrapper output argument | -| argvLocal.c:115:13:115:16 | argv | argvLocal.c:122:15:122:16 | printWrapper output argument | -| argvLocal.c:115:13:115:16 | argv | argvLocal.c:135:9:135:12 | (const char *)... | -| argvLocal.c:115:13:115:16 | argv | argvLocal.c:135:9:135:12 | (const char *)... | -| argvLocal.c:115:13:115:16 | argv | argvLocal.c:135:9:135:12 | ... ++ | -| argvLocal.c:115:13:115:16 | argv | argvLocal.c:135:9:135:12 | ... ++ | -| argvLocal.c:115:13:115:16 | argv | argvLocal.c:136:15:136:18 | -- ... | -| argvLocal.c:115:13:115:16 | argv | argvLocal.c:136:15:136:18 | -- ... | -| argvLocal.c:115:13:115:16 | argv | argvLocal.c:136:15:136:18 | -- ... | -| argvLocal.c:115:13:115:16 | argv | argvLocal.c:136:15:136:18 | -- ... | -| argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:121:9:121:10 | (const char *)... | -| argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:121:9:121:10 | i4 | -| argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:122:15:122:16 | i4 | -| argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:122:15:122:16 | i4 | -| argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:122:15:122:16 | printWrapper output argument | -| argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:135:9:135:12 | (const char *)... | -| argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:135:9:135:12 | ... ++ | -| argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:136:15:136:18 | -- ... | -| argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:136:15:136:18 | -- ... | -| argvLocal.c:122:15:122:16 | printWrapper output argument | argvLocal.c:135:9:135:12 | (const char *)... | -| argvLocal.c:122:15:122:16 | printWrapper output argument | argvLocal.c:135:9:135:12 | ... ++ | -| argvLocal.c:122:15:122:16 | printWrapper output argument | argvLocal.c:136:15:136:18 | -- ... | -| argvLocal.c:122:15:122:16 | printWrapper output argument | argvLocal.c:136:15:136:18 | -- ... | -| argvLocal.c:126:10:126:13 | argv | argvLocal.c:127:9:127:10 | (const char *)... | -| argvLocal.c:126:10:126:13 | argv | argvLocal.c:127:9:127:10 | (const char *)... | -| argvLocal.c:126:10:126:13 | argv | argvLocal.c:127:9:127:10 | i5 | -| argvLocal.c:126:10:126:13 | argv | argvLocal.c:127:9:127:10 | i5 | -| argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | array to pointer conversion | -| argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | array to pointer conversion | -| argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | i5 | -| argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | i5 | -| argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | printWrapper output argument | -| argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | printWrapper output argument | -| argvLocal.c:126:10:126:13 | argv | argvLocal.c:131:9:131:14 | (const char *)... | -| argvLocal.c:126:10:126:13 | argv | argvLocal.c:131:9:131:14 | (const char *)... | -| argvLocal.c:126:10:126:13 | argv | argvLocal.c:131:9:131:14 | ... + ... | -| argvLocal.c:126:10:126:13 | argv | argvLocal.c:131:9:131:14 | ... + ... | -| argvLocal.c:126:10:126:13 | argv | argvLocal.c:132:15:132:20 | ... + ... | -| argvLocal.c:126:10:126:13 | argv | argvLocal.c:132:15:132:20 | ... + ... | -| argvLocal.c:126:10:126:13 | argv | argvLocal.c:132:15:132:20 | ... + ... | -| argvLocal.c:126:10:126:13 | argv | argvLocal.c:132:15:132:20 | ... + ... | -| argvLocal.c:128:15:128:16 | printWrapper output argument | argvLocal.c:131:9:131:14 | (const char *)... | -| argvLocal.c:128:15:128:16 | printWrapper output argument | argvLocal.c:131:9:131:14 | ... + ... | -| argvLocal.c:128:15:128:16 | printWrapper output argument | argvLocal.c:132:15:132:20 | ... + ... | -| argvLocal.c:128:15:128:16 | printWrapper output argument | argvLocal.c:132:15:132:20 | ... + ... | | argvLocal.c:149:11:149:14 | argv | argvLocal.c:150:9:150:10 | (const char *)... | | argvLocal.c:149:11:149:14 | argv | argvLocal.c:150:9:150:10 | (const char *)... | | argvLocal.c:149:11:149:14 | argv | argvLocal.c:150:9:150:10 | i8 | @@ -134,22 +71,6 @@ edges | argvLocal.c:149:11:149:14 | argv | argvLocal.c:151:15:151:16 | i8 | | argvLocal.c:149:11:149:14 | argv | argvLocal.c:151:15:151:16 | i8 | | argvLocal.c:149:11:149:14 | argv | argvLocal.c:151:15:151:16 | i8 | -| argvLocal.c:156:23:156:26 | argv | argvLocal.c:157:9:157:10 | (const char *)... | -| argvLocal.c:156:23:156:26 | argv | argvLocal.c:157:9:157:10 | (const char *)... | -| argvLocal.c:156:23:156:26 | argv | argvLocal.c:157:9:157:10 | i9 | -| argvLocal.c:156:23:156:26 | argv | argvLocal.c:157:9:157:10 | i9 | -| argvLocal.c:156:23:156:26 | argv | argvLocal.c:158:15:158:16 | i9 | -| argvLocal.c:156:23:156:26 | argv | argvLocal.c:158:15:158:16 | i9 | -| argvLocal.c:156:23:156:26 | argv | argvLocal.c:158:15:158:16 | i9 | -| argvLocal.c:156:23:156:26 | argv | argvLocal.c:158:15:158:16 | i9 | -| argvLocal.c:163:22:163:25 | argv | argvLocal.c:164:9:164:11 | (const char *)... | -| argvLocal.c:163:22:163:25 | argv | argvLocal.c:164:9:164:11 | (const char *)... | -| argvLocal.c:163:22:163:25 | argv | argvLocal.c:164:9:164:11 | i91 | -| argvLocal.c:163:22:163:25 | argv | argvLocal.c:164:9:164:11 | i91 | -| argvLocal.c:163:22:163:25 | argv | argvLocal.c:165:15:165:17 | i91 | -| argvLocal.c:163:22:163:25 | argv | argvLocal.c:165:15:165:17 | i91 | -| argvLocal.c:163:22:163:25 | argv | argvLocal.c:165:15:165:17 | i91 | -| argvLocal.c:163:22:163:25 | argv | argvLocal.c:165:15:165:17 | i91 | | argvLocal.c:168:18:168:21 | argv | argvLocal.c:169:9:169:20 | (char *)... | | argvLocal.c:168:18:168:21 | argv | argvLocal.c:169:9:169:20 | (char *)... | | argvLocal.c:168:18:168:21 | argv | argvLocal.c:169:9:169:20 | (const char *)... | @@ -165,10 +86,6 @@ edges | argvLocal.c:168:18:168:21 | argv | argvLocal.c:170:24:170:26 | i10 | | argvLocal.c:168:18:168:21 | argv | argvLocal.c:170:24:170:26 | i10 | nodes -| argvLocal.c:9:25:9:31 | *correct | semmle.label | *correct | -| argvLocal.c:9:25:9:31 | correct | semmle.label | correct | -| argvLocal.c:10:9:10:15 | Chi | semmle.label | Chi | -| argvLocal.c:10:9:10:15 | Chi | semmle.label | Chi | | argvLocal.c:95:9:95:12 | argv | semmle.label | argv | | argvLocal.c:95:9:95:12 | argv | semmle.label | argv | | argvLocal.c:95:9:95:15 | (const char *)... | semmle.label | (const char *)... | @@ -209,49 +126,6 @@ nodes | argvLocal.c:111:15:111:17 | * ... | semmle.label | * ... | | argvLocal.c:111:15:111:17 | * ... | semmle.label | * ... | | argvLocal.c:111:15:111:17 | * ... | semmle.label | * ... | -| argvLocal.c:115:13:115:16 | argv | semmle.label | argv | -| argvLocal.c:115:13:115:16 | argv | semmle.label | argv | -| argvLocal.c:116:9:116:10 | (const char *)... | semmle.label | (const char *)... | -| argvLocal.c:116:9:116:10 | (const char *)... | semmle.label | (const char *)... | -| argvLocal.c:116:9:116:10 | i3 | semmle.label | i3 | -| argvLocal.c:117:2:117:13 | Argument 0 | semmle.label | Argument 0 | -| argvLocal.c:117:15:117:16 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| argvLocal.c:117:15:117:16 | array to pointer conversion | semmle.label | array to pointer conversion | -| argvLocal.c:117:15:117:16 | array to pointer conversion | semmle.label | array to pointer conversion | -| argvLocal.c:117:15:117:16 | i3 | semmle.label | i3 | -| argvLocal.c:117:15:117:16 | printWrapper output argument | semmle.label | printWrapper output argument | -| argvLocal.c:121:9:121:10 | (const char *)... | semmle.label | (const char *)... | -| argvLocal.c:121:9:121:10 | (const char *)... | semmle.label | (const char *)... | -| argvLocal.c:121:9:121:10 | i4 | semmle.label | i4 | -| argvLocal.c:122:2:122:13 | Argument 0 | semmle.label | Argument 0 | -| argvLocal.c:122:15:122:16 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| argvLocal.c:122:15:122:16 | i4 | semmle.label | i4 | -| argvLocal.c:122:15:122:16 | i4 | semmle.label | i4 | -| argvLocal.c:122:15:122:16 | i4 | semmle.label | i4 | -| argvLocal.c:122:15:122:16 | printWrapper output argument | semmle.label | printWrapper output argument | -| argvLocal.c:126:10:126:13 | argv | semmle.label | argv | -| argvLocal.c:126:10:126:13 | argv | semmle.label | argv | -| argvLocal.c:127:9:127:10 | (const char *)... | semmle.label | (const char *)... | -| argvLocal.c:127:9:127:10 | (const char *)... | semmle.label | (const char *)... | -| argvLocal.c:127:9:127:10 | i5 | semmle.label | i5 | -| argvLocal.c:128:2:128:13 | Argument 0 | semmle.label | Argument 0 | -| argvLocal.c:128:15:128:16 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| argvLocal.c:128:15:128:16 | array to pointer conversion | semmle.label | array to pointer conversion | -| argvLocal.c:128:15:128:16 | array to pointer conversion | semmle.label | array to pointer conversion | -| argvLocal.c:128:15:128:16 | i5 | semmle.label | i5 | -| argvLocal.c:128:15:128:16 | printWrapper output argument | semmle.label | printWrapper output argument | -| argvLocal.c:131:9:131:14 | (const char *)... | semmle.label | (const char *)... | -| argvLocal.c:131:9:131:14 | (const char *)... | semmle.label | (const char *)... | -| argvLocal.c:131:9:131:14 | ... + ... | semmle.label | ... + ... | -| argvLocal.c:132:15:132:20 | ... + ... | semmle.label | ... + ... | -| argvLocal.c:132:15:132:20 | ... + ... | semmle.label | ... + ... | -| argvLocal.c:132:15:132:20 | ... + ... | semmle.label | ... + ... | -| argvLocal.c:135:9:135:12 | (const char *)... | semmle.label | (const char *)... | -| argvLocal.c:135:9:135:12 | (const char *)... | semmle.label | (const char *)... | -| argvLocal.c:135:9:135:12 | ... ++ | semmle.label | ... ++ | -| argvLocal.c:136:15:136:18 | -- ... | semmle.label | -- ... | -| argvLocal.c:136:15:136:18 | -- ... | semmle.label | -- ... | -| argvLocal.c:136:15:136:18 | -- ... | semmle.label | -- ... | | argvLocal.c:144:9:144:10 | (const char *)... | semmle.label | (const char *)... | | argvLocal.c:144:9:144:10 | (const char *)... | semmle.label | (const char *)... | | argvLocal.c:144:9:144:10 | i7 | semmle.label | i7 | @@ -270,22 +144,6 @@ nodes | argvLocal.c:151:15:151:16 | i8 | semmle.label | i8 | | argvLocal.c:151:15:151:16 | i8 | semmle.label | i8 | | argvLocal.c:151:15:151:16 | i8 | semmle.label | i8 | -| argvLocal.c:156:23:156:26 | argv | semmle.label | argv | -| argvLocal.c:156:23:156:26 | argv | semmle.label | argv | -| argvLocal.c:157:9:157:10 | (const char *)... | semmle.label | (const char *)... | -| argvLocal.c:157:9:157:10 | (const char *)... | semmle.label | (const char *)... | -| argvLocal.c:157:9:157:10 | i9 | semmle.label | i9 | -| argvLocal.c:158:15:158:16 | i9 | semmle.label | i9 | -| argvLocal.c:158:15:158:16 | i9 | semmle.label | i9 | -| argvLocal.c:158:15:158:16 | i9 | semmle.label | i9 | -| argvLocal.c:163:22:163:25 | argv | semmle.label | argv | -| argvLocal.c:163:22:163:25 | argv | semmle.label | argv | -| argvLocal.c:164:9:164:11 | (const char *)... | semmle.label | (const char *)... | -| argvLocal.c:164:9:164:11 | (const char *)... | semmle.label | (const char *)... | -| argvLocal.c:164:9:164:11 | i91 | semmle.label | i91 | -| argvLocal.c:165:15:165:17 | i91 | semmle.label | i91 | -| argvLocal.c:165:15:165:17 | i91 | semmle.label | i91 | -| argvLocal.c:165:15:165:17 | i91 | semmle.label | i91 | | argvLocal.c:168:18:168:21 | argv | semmle.label | argv | | argvLocal.c:168:18:168:21 | argv | semmle.label | argv | | argvLocal.c:169:9:169:20 | (char *)... | semmle.label | (char *)... | @@ -309,23 +167,9 @@ nodes | argvLocal.c:107:15:107:19 | access to array | argvLocal.c:105:14:105:17 | argv | argvLocal.c:107:15:107:19 | access to array | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:105:14:105:17 | argv | argv | | argvLocal.c:110:9:110:11 | * ... | argvLocal.c:105:14:105:17 | argv | argvLocal.c:110:9:110:11 | * ... | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:105:14:105:17 | argv | argv | | argvLocal.c:111:15:111:17 | * ... | argvLocal.c:105:14:105:17 | argv | argvLocal.c:111:15:111:17 | * ... | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:105:14:105:17 | argv | argv | -| argvLocal.c:116:9:116:10 | i3 | argvLocal.c:115:13:115:16 | argv | argvLocal.c:116:9:116:10 | i3 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:115:13:115:16 | argv | argv | -| argvLocal.c:117:15:117:16 | i3 | argvLocal.c:115:13:115:16 | argv | argvLocal.c:117:15:117:16 | i3 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:115:13:115:16 | argv | argv | -| argvLocal.c:121:9:121:10 | i4 | argvLocal.c:115:13:115:16 | argv | argvLocal.c:121:9:121:10 | i4 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:115:13:115:16 | argv | argv | -| argvLocal.c:122:15:122:16 | i4 | argvLocal.c:115:13:115:16 | argv | argvLocal.c:122:15:122:16 | i4 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:115:13:115:16 | argv | argv | -| argvLocal.c:127:9:127:10 | i5 | argvLocal.c:126:10:126:13 | argv | argvLocal.c:127:9:127:10 | i5 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:126:10:126:13 | argv | argv | -| argvLocal.c:128:15:128:16 | i5 | argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | i5 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:126:10:126:13 | argv | argv | -| argvLocal.c:131:9:131:14 | ... + ... | argvLocal.c:126:10:126:13 | argv | argvLocal.c:131:9:131:14 | ... + ... | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:126:10:126:13 | argv | argv | -| argvLocal.c:132:15:132:20 | ... + ... | argvLocal.c:126:10:126:13 | argv | argvLocal.c:132:15:132:20 | ... + ... | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:126:10:126:13 | argv | argv | -| argvLocal.c:135:9:135:12 | ... ++ | argvLocal.c:115:13:115:16 | argv | argvLocal.c:135:9:135:12 | ... ++ | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:115:13:115:16 | argv | argv | -| argvLocal.c:136:15:136:18 | -- ... | argvLocal.c:115:13:115:16 | argv | argvLocal.c:136:15:136:18 | -- ... | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:115:13:115:16 | argv | argv | | argvLocal.c:144:9:144:10 | i7 | argvLocal.c:100:7:100:10 | argv | argvLocal.c:144:9:144:10 | i7 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:100:7:100:10 | argv | argv | | argvLocal.c:145:15:145:16 | i7 | argvLocal.c:100:7:100:10 | argv | argvLocal.c:145:15:145:16 | i7 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:100:7:100:10 | argv | argv | | argvLocal.c:150:9:150:10 | i8 | argvLocal.c:149:11:149:14 | argv | argvLocal.c:150:9:150:10 | i8 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:149:11:149:14 | argv | argv | | argvLocal.c:151:15:151:16 | i8 | argvLocal.c:149:11:149:14 | argv | argvLocal.c:151:15:151:16 | i8 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:149:11:149:14 | argv | argv | -| argvLocal.c:157:9:157:10 | i9 | argvLocal.c:156:23:156:26 | argv | argvLocal.c:157:9:157:10 | i9 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:156:23:156:26 | argv | argv | -| argvLocal.c:158:15:158:16 | i9 | argvLocal.c:156:23:156:26 | argv | argvLocal.c:158:15:158:16 | i9 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:156:23:156:26 | argv | argv | -| argvLocal.c:164:9:164:11 | i91 | argvLocal.c:163:22:163:25 | argv | argvLocal.c:164:9:164:11 | i91 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:163:22:163:25 | argv | argv | -| argvLocal.c:165:15:165:17 | i91 | argvLocal.c:163:22:163:25 | argv | argvLocal.c:165:15:165:17 | i91 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:163:22:163:25 | argv | argv | | argvLocal.c:169:18:169:20 | i10 | argvLocal.c:168:18:168:21 | argv | argvLocal.c:169:18:169:20 | i10 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:168:18:168:21 | argv | argv | | argvLocal.c:170:24:170:26 | i10 | argvLocal.c:168:18:168:21 | argv | argvLocal.c:170:24:170:26 | i10 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:168:18:168:21 | argv | argv | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/funcs/funcsLocal.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/funcs/funcsLocal.expected index a05e392ecf2..1beb428a832 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/funcs/funcsLocal.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/funcs/funcsLocal.expected @@ -1,83 +1,31 @@ edges -| funcsLocal.c:16:8:16:9 | fread output argument | funcsLocal.c:17:9:17:10 | (const char *)... | -| funcsLocal.c:16:8:16:9 | fread output argument | funcsLocal.c:17:9:17:10 | i1 | -| funcsLocal.c:16:8:16:9 | fread output argument | funcsLocal.c:58:9:58:10 | (const char *)... | -| funcsLocal.c:16:8:16:9 | fread output argument | funcsLocal.c:58:9:58:10 | e1 | -| funcsLocal.c:16:8:16:9 | i1 | funcsLocal.c:17:9:17:10 | (const char *)... | -| funcsLocal.c:16:8:16:9 | i1 | funcsLocal.c:17:9:17:10 | i1 | -| funcsLocal.c:16:8:16:9 | i1 | funcsLocal.c:58:9:58:10 | (const char *)... | -| funcsLocal.c:16:8:16:9 | i1 | funcsLocal.c:58:9:58:10 | e1 | -| funcsLocal.c:26:8:26:9 | fgets output argument | funcsLocal.c:27:9:27:10 | (const char *)... | -| funcsLocal.c:26:8:26:9 | fgets output argument | funcsLocal.c:27:9:27:10 | i3 | -| funcsLocal.c:26:8:26:9 | i3 | funcsLocal.c:27:9:27:10 | (const char *)... | -| funcsLocal.c:26:8:26:9 | i3 | funcsLocal.c:27:9:27:10 | i3 | | funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | (const char *)... | | funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | (const char *)... | | funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | i4 | | funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | i4 | | funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | i4 | | funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | i4 | -| funcsLocal.c:31:19:31:21 | fgets output argument | funcsLocal.c:32:9:32:10 | (const char *)... | -| funcsLocal.c:31:19:31:21 | fgets output argument | funcsLocal.c:32:9:32:10 | i4 | -| funcsLocal.c:31:19:31:21 | i41 | funcsLocal.c:32:9:32:10 | (const char *)... | -| funcsLocal.c:31:19:31:21 | i41 | funcsLocal.c:32:9:32:10 | i4 | -| funcsLocal.c:36:7:36:8 | gets output argument | funcsLocal.c:37:9:37:10 | (const char *)... | -| funcsLocal.c:36:7:36:8 | gets output argument | funcsLocal.c:37:9:37:10 | i5 | -| funcsLocal.c:36:7:36:8 | i5 | funcsLocal.c:37:9:37:10 | (const char *)... | -| funcsLocal.c:36:7:36:8 | i5 | funcsLocal.c:37:9:37:10 | i5 | | funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | (const char *)... | | funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | (const char *)... | | funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | i6 | | funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | i6 | | funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | i6 | | funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | i6 | -| funcsLocal.c:41:18:41:20 | gets output argument | funcsLocal.c:42:9:42:10 | (const char *)... | -| funcsLocal.c:41:18:41:20 | gets output argument | funcsLocal.c:42:9:42:10 | i6 | -| funcsLocal.c:41:18:41:20 | i61 | funcsLocal.c:42:9:42:10 | (const char *)... | -| funcsLocal.c:41:18:41:20 | i61 | funcsLocal.c:42:9:42:10 | i6 | nodes -| funcsLocal.c:16:8:16:9 | fread output argument | semmle.label | fread output argument | -| funcsLocal.c:16:8:16:9 | i1 | semmle.label | i1 | -| funcsLocal.c:17:9:17:10 | (const char *)... | semmle.label | (const char *)... | -| funcsLocal.c:17:9:17:10 | (const char *)... | semmle.label | (const char *)... | -| funcsLocal.c:17:9:17:10 | i1 | semmle.label | i1 | -| funcsLocal.c:26:8:26:9 | fgets output argument | semmle.label | fgets output argument | -| funcsLocal.c:26:8:26:9 | i3 | semmle.label | i3 | -| funcsLocal.c:27:9:27:10 | (const char *)... | semmle.label | (const char *)... | -| funcsLocal.c:27:9:27:10 | (const char *)... | semmle.label | (const char *)... | -| funcsLocal.c:27:9:27:10 | i3 | semmle.label | i3 | | funcsLocal.c:31:13:31:17 | call to fgets | semmle.label | call to fgets | | funcsLocal.c:31:13:31:17 | call to fgets | semmle.label | call to fgets | -| funcsLocal.c:31:19:31:21 | fgets output argument | semmle.label | fgets output argument | -| funcsLocal.c:31:19:31:21 | i41 | semmle.label | i41 | | funcsLocal.c:32:9:32:10 | (const char *)... | semmle.label | (const char *)... | | funcsLocal.c:32:9:32:10 | (const char *)... | semmle.label | (const char *)... | | funcsLocal.c:32:9:32:10 | i4 | semmle.label | i4 | | funcsLocal.c:32:9:32:10 | i4 | semmle.label | i4 | | funcsLocal.c:32:9:32:10 | i4 | semmle.label | i4 | -| funcsLocal.c:36:7:36:8 | gets output argument | semmle.label | gets output argument | -| funcsLocal.c:36:7:36:8 | i5 | semmle.label | i5 | -| funcsLocal.c:37:9:37:10 | (const char *)... | semmle.label | (const char *)... | -| funcsLocal.c:37:9:37:10 | (const char *)... | semmle.label | (const char *)... | -| funcsLocal.c:37:9:37:10 | i5 | semmle.label | i5 | | funcsLocal.c:41:13:41:16 | call to gets | semmle.label | call to gets | | funcsLocal.c:41:13:41:16 | call to gets | semmle.label | call to gets | -| funcsLocal.c:41:18:41:20 | gets output argument | semmle.label | gets output argument | -| funcsLocal.c:41:18:41:20 | i61 | semmle.label | i61 | | funcsLocal.c:42:9:42:10 | (const char *)... | semmle.label | (const char *)... | | funcsLocal.c:42:9:42:10 | (const char *)... | semmle.label | (const char *)... | | funcsLocal.c:42:9:42:10 | i6 | semmle.label | i6 | | funcsLocal.c:42:9:42:10 | i6 | semmle.label | i6 | | funcsLocal.c:42:9:42:10 | i6 | semmle.label | i6 | -| funcsLocal.c:58:9:58:10 | (const char *)... | semmle.label | (const char *)... | -| funcsLocal.c:58:9:58:10 | (const char *)... | semmle.label | (const char *)... | -| funcsLocal.c:58:9:58:10 | e1 | semmle.label | e1 | #select -| funcsLocal.c:17:9:17:10 | i1 | funcsLocal.c:16:8:16:9 | i1 | funcsLocal.c:17:9:17:10 | i1 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:16:8:16:9 | i1 | fread | -| funcsLocal.c:27:9:27:10 | i3 | funcsLocal.c:26:8:26:9 | i3 | funcsLocal.c:27:9:27:10 | i3 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:26:8:26:9 | i3 | fgets | | funcsLocal.c:32:9:32:10 | i4 | funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | i4 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:31:13:31:17 | call to fgets | fgets | -| funcsLocal.c:32:9:32:10 | i4 | funcsLocal.c:31:19:31:21 | i41 | funcsLocal.c:32:9:32:10 | i4 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:31:19:31:21 | i41 | fgets | -| funcsLocal.c:37:9:37:10 | i5 | funcsLocal.c:36:7:36:8 | i5 | funcsLocal.c:37:9:37:10 | i5 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:36:7:36:8 | i5 | gets | | funcsLocal.c:42:9:42:10 | i6 | funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | i6 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:41:13:41:16 | call to gets | gets | -| funcsLocal.c:42:9:42:10 | i6 | funcsLocal.c:41:18:41:20 | i61 | funcsLocal.c:42:9:42:10 | i6 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:41:18:41:20 | i61 | gets | -| funcsLocal.c:58:9:58:10 | e1 | funcsLocal.c:16:8:16:9 | i1 | funcsLocal.c:58:9:58:10 | e1 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:16:8:16:9 | i1 | fread | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatStringThroughGlobalVar.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatStringThroughGlobalVar.expected index 826a659755d..598d7df193c 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatStringThroughGlobalVar.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatStringThroughGlobalVar.expected @@ -13,8 +13,6 @@ edges | globalVars.c:9:7:9:11 | copy2 | globalVars.c:50:9:50:13 | copy2 | | globalVars.c:9:7:9:11 | copy2 | globalVars.c:50:9:50:13 | copy2 | | globalVars.c:9:7:9:11 | copy2 | globalVars.c:50:9:50:13 | copy2 | -| globalVars.c:11:22:11:25 | *argv | globalVars.c:12:2:12:15 | Store | -| globalVars.c:11:22:11:25 | argv | globalVars.c:11:22:11:25 | *argv | | globalVars.c:11:22:11:25 | argv | globalVars.c:12:2:12:15 | Store | | globalVars.c:12:2:12:15 | Store | globalVars.c:8:7:8:10 | copy | | globalVars.c:15:21:15:23 | val | globalVars.c:16:2:16:12 | Store | @@ -33,7 +31,6 @@ edges nodes | globalVars.c:8:7:8:10 | copy | semmle.label | copy | | globalVars.c:9:7:9:11 | copy2 | semmle.label | copy2 | -| globalVars.c:11:22:11:25 | *argv | semmle.label | *argv | | globalVars.c:11:22:11:25 | argv | semmle.label | argv | | globalVars.c:12:2:12:15 | Store | semmle.label | Store | | globalVars.c:15:21:15:23 | val | semmle.label | val | 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 6a897653265..0ae5dc31fae 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 @@ -35,6 +35,14 @@ edges | test.c:75:13:75:19 | ... ^ ... | test.c:77:9:77:9 | r | | test.c:75:13:75:19 | ... ^ ... | test.c:77:9:77:9 | r | | test.c:75:13:75:19 | ... ^ ... | test.c:77:9:77:9 | r | +| test.c:81:14:81:17 | call to rand | test.c:83:9:83:9 | r | +| test.c:81:14:81:17 | call to rand | test.c:83:9:83:9 | r | +| test.c:81:14:81:17 | call to rand | test.c:83:9:83:9 | r | +| test.c:81:14:81:17 | call to rand | test.c:83:9:83:9 | r | +| test.c:81:23:81:26 | call to rand | test.c:83:9:83:9 | r | +| test.c:81:23:81:26 | call to rand | test.c:83:9:83:9 | r | +| test.c:81:23:81:26 | call to rand | test.c:83:9:83:9 | r | +| test.c:81:23:81:26 | call to rand | test.c:83:9:83:9 | r | | test.c:99:14:99:19 | call to rand | test.c:100:5:100:5 | r | | test.c:99:14:99:19 | call to rand | test.c:100:5:100:5 | r | | test.c:99:14:99:19 | call to rand | test.c:100:5:100:5 | r | @@ -102,6 +110,13 @@ nodes | test.c:77:9:77:9 | r | semmle.label | r | | test.c:77:9:77:9 | r | semmle.label | r | | test.c:77:9:77:9 | r | semmle.label | r | +| test.c:81:14:81:17 | call to rand | semmle.label | call to rand | +| test.c:81:14:81:17 | call to rand | semmle.label | call to rand | +| test.c:81:23:81:26 | call to rand | semmle.label | call to rand | +| test.c:81:23:81:26 | call to rand | semmle.label | call to rand | +| test.c:83:9:83:9 | r | semmle.label | r | +| test.c:83:9:83:9 | r | semmle.label | r | +| test.c:83:9:83:9 | r | semmle.label | r | | test.c:99:14:99:19 | call to rand | semmle.label | call to rand | | test.c:99:14:99:19 | call to rand | semmle.label | call to rand | | test.c:100:5:100:5 | r | semmle.label | r | @@ -140,6 +155,8 @@ nodes | test.c:56:5:56:5 | r | test.c:54:13:54:16 | call to rand | test.c:56:5:56:5 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:54:13:54:16 | call to rand | Uncontrolled value | | test.c:67:5:67:5 | r | test.c:66:13:66:16 | call to rand | test.c:67:5:67:5 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:66:13:66:16 | call to rand | Uncontrolled value | | test.c:77:9:77:9 | r | test.c:75:13:75:19 | ... ^ ... | test.c:77:9:77:9 | r | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:75:13:75:19 | ... ^ ... | Uncontrolled value | +| test.c:83:9:83:9 | r | test.c:81:14:81:17 | call to rand | test.c:83:9:83:9 | r | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:81:14:81:17 | call to rand | Uncontrolled value | +| test.c:83:9:83:9 | r | test.c:81:23:81:26 | call to rand | test.c:83:9:83:9 | r | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:81:23:81:26 | call to rand | Uncontrolled value | | test.c:100:5:100:5 | r | test.c:99:14:99:19 | call to rand | test.c:100:5:100:5 | r | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:99:14:99:19 | call to rand | Uncontrolled value | | test.cpp:25:7:25:7 | r | test.cpp:8:9:8:12 | call to rand | test.cpp:25:7:25:7 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:8:9:8:12 | call to rand | Uncontrolled value | | test.cpp:31:7:31:7 | r | test.cpp:13:10:13:13 | call to rand | test.cpp:31:7:31:7 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:13:10:13:13 | call to rand | Uncontrolled value | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/uncontrolled/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/uncontrolled/test.cpp index 5d4d7e8c5c3..d3dc3352a29 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/uncontrolled/test.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/uncontrolled/test.cpp @@ -28,7 +28,7 @@ void randomTester2() { int r; get_rand2(&r); - r = r + 100; // BAD [NOT DETECTED] + r = r + 100; // BAD } { diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-807/semmle/TaintedCondition/TaintedCondition.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-807/semmle/TaintedCondition/TaintedCondition.expected index cc5004047cf..71cd8ce2361 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-807/semmle/TaintedCondition/TaintedCondition.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-807/semmle/TaintedCondition/TaintedCondition.expected @@ -1,37 +1,31 @@ edges | test.cpp:20:29:20:34 | call to getenv | test.cpp:24:10:24:35 | ! ... | | test.cpp:20:29:20:34 | call to getenv | test.cpp:24:11:24:16 | call to strcmp | -| test.cpp:20:29:20:34 | call to getenv | test.cpp:24:11:24:16 | call to strcmp | -| test.cpp:20:29:20:34 | call to getenv | test.cpp:24:11:24:35 | (bool)... | | test.cpp:20:29:20:34 | call to getenv | test.cpp:41:10:41:38 | ! ... | | test.cpp:20:29:20:34 | call to getenv | test.cpp:41:11:41:16 | call to strcmp | -| test.cpp:20:29:20:34 | call to getenv | test.cpp:41:11:41:16 | call to strcmp | -| test.cpp:20:29:20:34 | call to getenv | test.cpp:41:11:41:38 | (bool)... | | test.cpp:20:29:20:47 | (const char *)... | test.cpp:24:10:24:35 | ! ... | | test.cpp:20:29:20:47 | (const char *)... | test.cpp:24:11:24:16 | call to strcmp | -| test.cpp:20:29:20:47 | (const char *)... | test.cpp:24:11:24:16 | call to strcmp | -| test.cpp:20:29:20:47 | (const char *)... | test.cpp:24:11:24:35 | (bool)... | | test.cpp:20:29:20:47 | (const char *)... | test.cpp:41:10:41:38 | ! ... | | test.cpp:20:29:20:47 | (const char *)... | test.cpp:41:11:41:16 | call to strcmp | -| test.cpp:20:29:20:47 | (const char *)... | test.cpp:41:11:41:16 | call to strcmp | -| test.cpp:20:29:20:47 | (const char *)... | test.cpp:41:11:41:38 | (bool)... | -| test.cpp:24:11:24:16 | call to strcmp | test.cpp:24:10:24:35 | ! ... | -| test.cpp:24:11:24:16 | call to strcmp | test.cpp:24:11:24:35 | (bool)... | -| test.cpp:41:11:41:16 | call to strcmp | test.cpp:41:10:41:38 | ! ... | -| test.cpp:41:11:41:16 | call to strcmp | test.cpp:41:11:41:38 | (bool)... | +| test.cpp:29:27:29:32 | call to getenv | test.cpp:30:10:30:37 | ! ... | +| test.cpp:29:27:29:32 | call to getenv | test.cpp:30:11:30:16 | call to strcmp | +| test.cpp:29:27:29:42 | (const char *)... | test.cpp:30:10:30:37 | ! ... | +| test.cpp:29:27:29:42 | (const char *)... | test.cpp:30:11:30:16 | call to strcmp | nodes | test.cpp:20:29:20:34 | call to getenv | semmle.label | call to getenv | | test.cpp:20:29:20:47 | (const char *)... | semmle.label | (const char *)... | | test.cpp:24:10:24:35 | ! ... | semmle.label | ! ... | | test.cpp:24:11:24:16 | call to strcmp | semmle.label | call to strcmp | | test.cpp:24:11:24:16 | call to strcmp | semmle.label | call to strcmp | -| test.cpp:24:11:24:35 | (bool)... | semmle.label | (bool)... | -| test.cpp:24:11:24:35 | (bool)... | semmle.label | (bool)... | +| test.cpp:29:27:29:32 | call to getenv | semmle.label | call to getenv | +| test.cpp:29:27:29:42 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:30:10:30:37 | ! ... | semmle.label | ! ... | +| test.cpp:30:11:30:16 | call to strcmp | semmle.label | call to strcmp | +| test.cpp:30:11:30:16 | call to strcmp | semmle.label | call to strcmp | | test.cpp:41:10:41:38 | ! ... | semmle.label | ! ... | | test.cpp:41:11:41:16 | call to strcmp | semmle.label | call to strcmp | | test.cpp:41:11:41:16 | call to strcmp | semmle.label | call to strcmp | -| test.cpp:41:11:41:38 | (bool)... | semmle.label | (bool)... | -| test.cpp:41:11:41:38 | (bool)... | semmle.label | (bool)... | #select | test.cpp:24:10:24:35 | ! ... | test.cpp:20:29:20:34 | call to getenv | test.cpp:24:10:24:35 | ! ... | Reliance on untrusted input $@ to raise privilege at $@ | test.cpp:20:29:20:34 | call to getenv | call to getenv | test.cpp:25:9:25:27 | ... = ... | ... = ... | +| test.cpp:30:10:30:37 | ! ... | test.cpp:29:27:29:32 | call to getenv | test.cpp:30:10:30:37 | ! ... | Reliance on untrusted input $@ to raise privilege at $@ | test.cpp:29:27:29:32 | call to getenv | call to getenv | test.cpp:31:9:31:27 | ... = ... | ... = ... | | test.cpp:41:10:41:38 | ! ... | test.cpp:20:29:20:34 | call to getenv | test.cpp:41:10:41:38 | ! ... | Reliance on untrusted input $@ to raise privilege at $@ | test.cpp:20:29:20:34 | call to getenv | call to getenv | test.cpp:42:8:42:26 | ... = ... | ... = ... | From fbe857d1fa8a3b577e043a74155b804214522373 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Thu, 30 Apr 2020 14:25:17 -0700 Subject: [PATCH 005/725] C++: require that other operands be predictable This brings back a constraint that was lost when switching DefaultTaintTracking to use a TaintTracking::Configuration --- .../cpp/ir/dataflow/DefaultTaintTracking.qll | 19 +++++++++++++++++++ .../ArithmeticUncontrolled.expected | 17 ----------------- .../TaintedCondition.expected | 10 ---------- 3 files changed, 19 insertions(+), 27 deletions(-) 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 ae2066398a1..0ab6248a6bd 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll @@ -213,6 +213,25 @@ private predicate nodeIsBarrierIn(DataFlow::Node node) { // `getNodeForSource`. node = DataFlow::definitionByReferenceNodeFromArgument(source) ) + or + // don't use dataflow into binary instructions if both operands are unpredictable + exists(BinaryInstruction iTo | + iTo = node.asInstruction() and + not predictableInstruction(iTo.getLeft()) and + not predictableInstruction(iTo.getRight()) + ) + or + // don't use dataflow through calls to pure functions if two or more operands + // are unpredictable + exists(Instruction iFrom1, Instruction iFrom2, CallInstruction iTo | + iTo = node.asInstruction() and + isPureFunction(iTo.getStaticCallTarget().getName()) and + iFrom1 = iTo.getAnArgument() and + iFrom2 = iTo.getAnArgument() and + not predictableInstruction(iFrom1) and + not predictableInstruction(iFrom2) and + iFrom1 != iFrom2 + ) } cached 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 0ae5dc31fae..6a897653265 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 @@ -35,14 +35,6 @@ edges | test.c:75:13:75:19 | ... ^ ... | test.c:77:9:77:9 | r | | test.c:75:13:75:19 | ... ^ ... | test.c:77:9:77:9 | r | | test.c:75:13:75:19 | ... ^ ... | test.c:77:9:77:9 | r | -| test.c:81:14:81:17 | call to rand | test.c:83:9:83:9 | r | -| test.c:81:14:81:17 | call to rand | test.c:83:9:83:9 | r | -| test.c:81:14:81:17 | call to rand | test.c:83:9:83:9 | r | -| test.c:81:14:81:17 | call to rand | test.c:83:9:83:9 | r | -| test.c:81:23:81:26 | call to rand | test.c:83:9:83:9 | r | -| test.c:81:23:81:26 | call to rand | test.c:83:9:83:9 | r | -| test.c:81:23:81:26 | call to rand | test.c:83:9:83:9 | r | -| test.c:81:23:81:26 | call to rand | test.c:83:9:83:9 | r | | test.c:99:14:99:19 | call to rand | test.c:100:5:100:5 | r | | test.c:99:14:99:19 | call to rand | test.c:100:5:100:5 | r | | test.c:99:14:99:19 | call to rand | test.c:100:5:100:5 | r | @@ -110,13 +102,6 @@ nodes | test.c:77:9:77:9 | r | semmle.label | r | | test.c:77:9:77:9 | r | semmle.label | r | | test.c:77:9:77:9 | r | semmle.label | r | -| test.c:81:14:81:17 | call to rand | semmle.label | call to rand | -| test.c:81:14:81:17 | call to rand | semmle.label | call to rand | -| test.c:81:23:81:26 | call to rand | semmle.label | call to rand | -| test.c:81:23:81:26 | call to rand | semmle.label | call to rand | -| test.c:83:9:83:9 | r | semmle.label | r | -| test.c:83:9:83:9 | r | semmle.label | r | -| test.c:83:9:83:9 | r | semmle.label | r | | test.c:99:14:99:19 | call to rand | semmle.label | call to rand | | test.c:99:14:99:19 | call to rand | semmle.label | call to rand | | test.c:100:5:100:5 | r | semmle.label | r | @@ -155,8 +140,6 @@ nodes | test.c:56:5:56:5 | r | test.c:54:13:54:16 | call to rand | test.c:56:5:56:5 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:54:13:54:16 | call to rand | Uncontrolled value | | test.c:67:5:67:5 | r | test.c:66:13:66:16 | call to rand | test.c:67:5:67:5 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:66:13:66:16 | call to rand | Uncontrolled value | | test.c:77:9:77:9 | r | test.c:75:13:75:19 | ... ^ ... | test.c:77:9:77:9 | r | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:75:13:75:19 | ... ^ ... | Uncontrolled value | -| test.c:83:9:83:9 | r | test.c:81:14:81:17 | call to rand | test.c:83:9:83:9 | r | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:81:14:81:17 | call to rand | Uncontrolled value | -| test.c:83:9:83:9 | r | test.c:81:23:81:26 | call to rand | test.c:83:9:83:9 | r | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:81:23:81:26 | call to rand | Uncontrolled value | | test.c:100:5:100:5 | r | test.c:99:14:99:19 | call to rand | test.c:100:5:100:5 | r | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:99:14:99:19 | call to rand | Uncontrolled value | | test.cpp:25:7:25:7 | r | test.cpp:8:9:8:12 | call to rand | test.cpp:25:7:25:7 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:8:9:8:12 | call to rand | Uncontrolled value | | test.cpp:31:7:31:7 | r | test.cpp:13:10:13:13 | call to rand | test.cpp:31:7:31:7 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:13:10:13:13 | call to rand | Uncontrolled value | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-807/semmle/TaintedCondition/TaintedCondition.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-807/semmle/TaintedCondition/TaintedCondition.expected index 71cd8ce2361..e04a20830d0 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-807/semmle/TaintedCondition/TaintedCondition.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-807/semmle/TaintedCondition/TaintedCondition.expected @@ -7,25 +7,15 @@ edges | test.cpp:20:29:20:47 | (const char *)... | test.cpp:24:11:24:16 | call to strcmp | | test.cpp:20:29:20:47 | (const char *)... | test.cpp:41:10:41:38 | ! ... | | test.cpp:20:29:20:47 | (const char *)... | test.cpp:41:11:41:16 | call to strcmp | -| test.cpp:29:27:29:32 | call to getenv | test.cpp:30:10:30:37 | ! ... | -| test.cpp:29:27:29:32 | call to getenv | test.cpp:30:11:30:16 | call to strcmp | -| test.cpp:29:27:29:42 | (const char *)... | test.cpp:30:10:30:37 | ! ... | -| test.cpp:29:27:29:42 | (const char *)... | test.cpp:30:11:30:16 | call to strcmp | nodes | test.cpp:20:29:20:34 | call to getenv | semmle.label | call to getenv | | test.cpp:20:29:20:47 | (const char *)... | semmle.label | (const char *)... | | test.cpp:24:10:24:35 | ! ... | semmle.label | ! ... | | test.cpp:24:11:24:16 | call to strcmp | semmle.label | call to strcmp | | test.cpp:24:11:24:16 | call to strcmp | semmle.label | call to strcmp | -| test.cpp:29:27:29:32 | call to getenv | semmle.label | call to getenv | -| test.cpp:29:27:29:42 | (const char *)... | semmle.label | (const char *)... | -| test.cpp:30:10:30:37 | ! ... | semmle.label | ! ... | -| test.cpp:30:11:30:16 | call to strcmp | semmle.label | call to strcmp | -| test.cpp:30:11:30:16 | call to strcmp | semmle.label | call to strcmp | | test.cpp:41:10:41:38 | ! ... | semmle.label | ! ... | | test.cpp:41:11:41:16 | call to strcmp | semmle.label | call to strcmp | | test.cpp:41:11:41:16 | call to strcmp | semmle.label | call to strcmp | #select | test.cpp:24:10:24:35 | ! ... | test.cpp:20:29:20:34 | call to getenv | test.cpp:24:10:24:35 | ! ... | Reliance on untrusted input $@ to raise privilege at $@ | test.cpp:20:29:20:34 | call to getenv | call to getenv | test.cpp:25:9:25:27 | ... = ... | ... = ... | -| test.cpp:30:10:30:37 | ! ... | test.cpp:29:27:29:32 | call to getenv | test.cpp:30:10:30:37 | ! ... | Reliance on untrusted input $@ to raise privilege at $@ | test.cpp:29:27:29:32 | call to getenv | call to getenv | test.cpp:31:9:31:27 | ... = ... | ... = ... | | test.cpp:41:10:41:38 | ! ... | test.cpp:20:29:20:34 | call to getenv | test.cpp:41:10:41:38 | ! ... | Reliance on untrusted input $@ to raise privilege at $@ | test.cpp:20:29:20:34 | call to getenv | call to getenv | test.cpp:42:8:42:26 | ... = ... | ... = ... | From 95ed5465de9b0db3b98db81b9b0cd2f995361949 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Tue, 5 May 2020 13:30:45 -0700 Subject: [PATCH 006/725] C++: improve handling of function arguments in DTT --- .../cpp/ir/dataflow/DefaultTaintTracking.qll | 23 +++++++- .../defaulttainttracking.cpp | 2 +- .../dataflow/DefaultTaintTracking/tainted.ql | 8 ++- .../DefaultTaintTracking/test_diff.ql | 25 ++++++--- .../dataflow/security-taint/tainted_diff.ql | 10 +++- .../dataflow/security-taint/tainted_ir.ql | 12 +++- .../CWE-022/semmle/tests/TaintedPath.expected | 12 ++++ .../UncontrolledProcessOperation.expected | 36 ++++++++++++ .../CWE-134/semmle/argv/argvLocal.expected | 43 ++++++++++++++ .../CWE-134/semmle/funcs/funcsLocal.expected | 56 +++++++++++++++++++ 10 files changed, 211 insertions(+), 16 deletions(-) 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 0ab6248a6bd..62e7f7b9738 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll @@ -10,6 +10,7 @@ private import semmle.code.cpp.controlflow.IRGuards private import semmle.code.cpp.models.interfaces.Taint private import semmle.code.cpp.models.interfaces.DataFlow private import semmle.code.cpp.ir.dataflow.TaintTracking2 +private import semmle.code.cpp.ir.dataflow.internal.ModelUtil /** * A predictable instruction is one where an external user can predict @@ -218,7 +219,10 @@ private predicate nodeIsBarrierIn(DataFlow::Node node) { exists(BinaryInstruction iTo | iTo = node.asInstruction() and not predictableInstruction(iTo.getLeft()) and - not predictableInstruction(iTo.getRight()) + not predictableInstruction(iTo.getRight()) and + // propagate taint from either the pointer or the offset, regardless of predictability + not iTo instanceof PointerArithmeticInstruction + ) or // don't use dataflow through calls to pure functions if two or more operands @@ -468,6 +472,8 @@ private Element adjustedSink(DataFlow::Node sink) { or // Taint `e1 += e2`, `e &= e2` and friends when `e1` or `e2` is tainted. result.(AssignOperation).getAnOperand() = sink.asExpr() + or + result = sink.asOperand().(SideEffectOperand).getUse().(ReadSideEffectInstruction).getArgumentDef().getUnconvertedResultExpression() } /** @@ -590,11 +596,26 @@ module TaintedWithPath { } override predicate isAdditionalTaintStep(DataFlow::Node n1, DataFlow::Node n2) { + // Steps into and out of global variables exists(TaintTrackingConfiguration cfg | cfg.taintThroughGlobals() | writesVariable(n1.asInstruction(), n2.asVariable().(GlobalOrNamespaceVariable)) or readsVariable(n2.asInstruction(), n1.asVariable().(GlobalOrNamespaceVariable)) ) + or + // Step to return value of a modeled function when an input taints the + // dereference of the return value + exists(CallInstruction call, Function func, FunctionInput modelIn, FunctionOutput modelOut | + n1 = callInput(call, modelIn) and + ( + func.(TaintFunction).hasTaintFlow(modelIn, modelOut) + or + func.(DataFlowFunction).hasDataFlow(modelIn, modelOut) + ) and + call.getStaticCallTarget() = func and + modelOut.isReturnValueDeref() and + call = n2.asInstruction() + ) } override predicate isSanitizer(DataFlow::Node node) { nodeIsBarrier(node) } diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp index 0ca85d29bab..8540b20708d 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp @@ -9,7 +9,7 @@ -int main() { +int test() { diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.ql b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.ql index bbd94cab403..3382775b6d9 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.ql +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.ql @@ -1,5 +1,11 @@ import semmle.code.cpp.ir.dataflow.DefaultTaintTracking +class SourceConfiguration extends TaintedWithPath::TaintTrackingConfiguration { + override predicate isSink(Element e) { + any() + } +} + from Expr source, Element tainted -where tainted(source, tainted) +where TaintedWithPath::taintedWithPath(source, tainted, _, _) select source, tainted diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.ql b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.ql index b31147fd423..40bed5680c0 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.ql +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.ql @@ -3,17 +3,26 @@ import semmle.code.cpp.security.Security import semmle.code.cpp.security.TaintTrackingImpl as ASTTaintTracking import semmle.code.cpp.ir.dataflow.DefaultTaintTracking as IRDefaultTaintTracking +class SourceConfiguration extends IRDefaultTaintTracking::TaintedWithPath::TaintTrackingConfiguration { + override predicate isSink(Element e) { any() } +} + predicate astFlow(Expr source, Element sink) { ASTTaintTracking::tainted(source, sink) } -predicate irFlow(Expr source, Element sink) { IRDefaultTaintTracking::tainted(source, sink) } +predicate irFlow(Expr source, Element sink) { + IRDefaultTaintTracking::TaintedWithPath::taintedWithPath(source, sink, _, _) +} from Expr source, Element sink, string note where - astFlow(source, sink) and - not irFlow(source, sink) and - note = "AST only" - or - irFlow(source, sink) and - not astFlow(source, sink) and - note = "IR only" + not sink instanceof Parameter and + ( + astFlow(source, sink) and + not irFlow(source, sink) and + note = "AST only" + or + irFlow(source, sink) and + not astFlow(source, sink) and + note = "IR only" + ) select source, sink, note diff --git a/cpp/ql/test/library-tests/dataflow/security-taint/tainted_diff.ql b/cpp/ql/test/library-tests/dataflow/security-taint/tainted_diff.ql index 13a1b7b6f3f..f3ed14d16b1 100644 --- a/cpp/ql/test/library-tests/dataflow/security-taint/tainted_diff.ql +++ b/cpp/ql/test/library-tests/dataflow/security-taint/tainted_diff.ql @@ -2,14 +2,20 @@ import semmle.code.cpp.security.TaintTrackingImpl as AST import semmle.code.cpp.ir.dataflow.DefaultTaintTracking as IR import cpp +class SourceConfiguration extends IR::TaintedWithPath::TaintTrackingConfiguration { + override predicate isSink(Element e) { + any() + } +} + from Expr source, Element tainted, string side where AST::taintedIncludingGlobalVars(source, tainted, _) and - not IR::taintedIncludingGlobalVars(source, tainted, _) and + not IR::TaintedWithPath::taintedWithPath(source, tainted, _, _) and not tainted.getLocation().getFile().getExtension() = "h" and side = "AST only" or - IR::taintedIncludingGlobalVars(source, tainted, _) and + IR::TaintedWithPath::taintedWithPath(source, tainted, _, _) and not AST::taintedIncludingGlobalVars(source, tainted, _) and not tainted.getLocation().getFile().getExtension() = "h" and side = "IR only" diff --git a/cpp/ql/test/library-tests/dataflow/security-taint/tainted_ir.ql b/cpp/ql/test/library-tests/dataflow/security-taint/tainted_ir.ql index 6d8effe7ffe..77f04d301f0 100644 --- a/cpp/ql/test/library-tests/dataflow/security-taint/tainted_ir.ql +++ b/cpp/ql/test/library-tests/dataflow/security-taint/tainted_ir.ql @@ -1,7 +1,13 @@ import semmle.code.cpp.ir.dataflow.DefaultTaintTracking -from Expr source, Element tainted, string globalVar +class SourceConfiguration extends TaintedWithPath::TaintTrackingConfiguration { + override predicate isSink(Element e) { + any() + } +} + +from Expr source, Element tainted where - taintedIncludingGlobalVars(source, tainted, globalVar) and + TaintedWithPath::taintedWithPath(source, tainted, _, _) and not tainted.getLocation().getFile().getExtension() = "h" -select source, tainted, globalVar +select source, tainted \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-022/semmle/tests/TaintedPath.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-022/semmle/tests/TaintedPath.expected index 58e3dda0964..03d1bfd25b3 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-022/semmle/tests/TaintedPath.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-022/semmle/tests/TaintedPath.expected @@ -1,3 +1,15 @@ +WARNING: Unused predicate sinkInstructionNodes (C:/semmle/code/ql/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql:64,13-33) +WARNING: Unused predicate sinkOperand (C:/semmle/code/ql/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql:70,13-24) edges +| test.c:9:23:9:26 | argv | test.c:17:11:17:18 | Argument 0 indirection | +| test.c:9:23:9:26 | argv | test.c:17:11:17:18 | Argument 0 indirection | +| test.c:9:23:9:26 | argv | test.c:17:11:17:18 | fileName | +| test.c:9:23:9:26 | argv | test.c:17:11:17:18 | fileName | nodes +| test.c:9:23:9:26 | argv | semmle.label | argv | +| test.c:9:23:9:26 | argv | semmle.label | argv | +| test.c:17:11:17:18 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| test.c:17:11:17:18 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| test.c:17:11:17:18 | fileName | semmle.label | fileName | #select +| test.c:17:11:17:18 | fileName | test.c:9:23:9:26 | argv | test.c:17:11:17:18 | fileName | This argument to a file access function is derived from $@ and then passed to fopen(filename) | test.c:9:23:9:26 | argv | user input (argv) | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/UncontrolledProcessOperation.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/UncontrolledProcessOperation.expected index c53e4f5be87..06ac4c9e499 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/UncontrolledProcessOperation.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/UncontrolledProcessOperation.expected @@ -7,6 +7,22 @@ edges | test.cpp:42:18:42:34 | (const char *)... | test.cpp:24:30:24:36 | command | | test.cpp:43:18:43:23 | call to getenv | test.cpp:29:30:29:36 | command | | test.cpp:43:18:43:34 | (const char *)... | test.cpp:29:30:29:36 | command | +| test.cpp:56:12:56:17 | buffer | test.cpp:62:10:62:15 | Argument 0 indirection | +| test.cpp:56:12:56:17 | buffer | test.cpp:62:10:62:15 | buffer | +| test.cpp:56:12:56:17 | buffer | test.cpp:63:10:63:13 | Argument 0 indirection | +| test.cpp:56:12:56:17 | buffer | test.cpp:63:10:63:13 | data | +| test.cpp:56:12:56:17 | fgets output argument | test.cpp:62:10:62:15 | Argument 0 indirection | +| test.cpp:56:12:56:17 | fgets output argument | test.cpp:62:10:62:15 | buffer | +| test.cpp:56:12:56:17 | fgets output argument | test.cpp:63:10:63:13 | Argument 0 indirection | +| test.cpp:56:12:56:17 | fgets output argument | test.cpp:63:10:63:13 | data | +| test.cpp:76:12:76:17 | buffer | test.cpp:78:10:78:15 | Argument 0 indirection | +| test.cpp:76:12:76:17 | buffer | test.cpp:78:10:78:15 | buffer | +| test.cpp:76:12:76:17 | buffer | test.cpp:79:10:79:13 | Argument 0 indirection | +| test.cpp:76:12:76:17 | buffer | test.cpp:79:10:79:13 | data | +| test.cpp:76:12:76:17 | fgets output argument | test.cpp:78:10:78:15 | Argument 0 indirection | +| test.cpp:76:12:76:17 | fgets output argument | test.cpp:78:10:78:15 | buffer | +| test.cpp:76:12:76:17 | fgets output argument | test.cpp:79:10:79:13 | Argument 0 indirection | +| test.cpp:76:12:76:17 | fgets output argument | test.cpp:79:10:79:13 | data | nodes | test.cpp:24:30:24:36 | command | semmle.label | command | | test.cpp:26:10:26:16 | command | semmle.label | command | @@ -22,6 +38,26 @@ nodes | test.cpp:43:7:43:16 | Argument 0 | semmle.label | Argument 0 | | test.cpp:43:18:43:23 | call to getenv | semmle.label | call to getenv | | test.cpp:43:18:43:34 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:56:12:56:17 | buffer | semmle.label | buffer | +| test.cpp:56:12:56:17 | fgets output argument | semmle.label | fgets output argument | +| test.cpp:62:10:62:15 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| test.cpp:62:10:62:15 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| test.cpp:62:10:62:15 | buffer | semmle.label | buffer | +| test.cpp:63:10:63:13 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| test.cpp:63:10:63:13 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| test.cpp:63:10:63:13 | data | semmle.label | data | +| test.cpp:76:12:76:17 | buffer | semmle.label | buffer | +| test.cpp:76:12:76:17 | fgets output argument | semmle.label | fgets output argument | +| test.cpp:78:10:78:15 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| test.cpp:78:10:78:15 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| test.cpp:78:10:78:15 | buffer | semmle.label | buffer | +| test.cpp:79:10:79:13 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| test.cpp:79:10:79:13 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| test.cpp:79:10:79:13 | data | semmle.label | data | #select | test.cpp:26:10:26:16 | command | test.cpp:42:18:42:23 | call to getenv | test.cpp:26:10:26:16 | command | The value of this argument may come from $@ and is being passed to system | test.cpp:42:18:42:23 | call to getenv | call to getenv | | test.cpp:31:10:31:16 | command | test.cpp:43:18:43:23 | call to getenv | test.cpp:31:10:31:16 | command | The value of this argument may come from $@ and is being passed to system | test.cpp:43:18:43:23 | call to getenv | call to getenv | +| test.cpp:62:10:62:15 | buffer | test.cpp:56:12:56:17 | buffer | test.cpp:62:10:62:15 | buffer | The value of this argument may come from $@ and is being passed to system | test.cpp:56:12:56:17 | buffer | buffer | +| test.cpp:63:10:63:13 | data | test.cpp:56:12:56:17 | buffer | test.cpp:63:10:63:13 | data | The value of this argument may come from $@ and is being passed to system | test.cpp:56:12:56:17 | buffer | buffer | +| test.cpp:78:10:78:15 | buffer | test.cpp:76:12:76:17 | buffer | test.cpp:78:10:78:15 | buffer | The value of this argument may come from $@ and is being passed to system | test.cpp:76:12:76:17 | buffer | buffer | +| test.cpp:79:10:79:13 | data | test.cpp:76:12:76:17 | buffer | test.cpp:79:10:79:13 | data | The value of this argument may come from $@ and is being passed to system | test.cpp:76:12:76:17 | buffer | buffer | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.expected index 72d1df8a59b..35008e71818 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.expected @@ -61,6 +61,28 @@ edges | argvLocal.c:106:9:106:13 | access to array | argvLocal.c:106:9:106:13 | access to array | | argvLocal.c:110:9:110:11 | * ... | argvLocal.c:110:9:110:11 | (const char *)... | | argvLocal.c:110:9:110:11 | * ... | argvLocal.c:110:9:110:11 | * ... | +| argvLocal.c:126:10:126:13 | argv | argvLocal.c:127:9:127:10 | Argument 0 indirection | +| argvLocal.c:126:10:126:13 | argv | argvLocal.c:127:9:127:10 | Argument 0 indirection | +| argvLocal.c:126:10:126:13 | argv | argvLocal.c:127:9:127:10 | i5 | +| argvLocal.c:126:10:126:13 | argv | argvLocal.c:127:9:127:10 | i5 | +| argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | Argument 0 indirection | +| argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | Argument 0 indirection | +| argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | i5 | +| argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | i5 | +| argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | printWrapper output argument | +| argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | printWrapper output argument | +| argvLocal.c:126:10:126:13 | argv | argvLocal.c:131:9:131:14 | ... + ... | +| argvLocal.c:126:10:126:13 | argv | argvLocal.c:131:9:131:14 | ... + ... | +| argvLocal.c:126:10:126:13 | argv | argvLocal.c:131:9:131:14 | Argument 0 indirection | +| argvLocal.c:126:10:126:13 | argv | argvLocal.c:131:9:131:14 | Argument 0 indirection | +| argvLocal.c:126:10:126:13 | argv | argvLocal.c:132:15:132:20 | ... + ... | +| argvLocal.c:126:10:126:13 | argv | argvLocal.c:132:15:132:20 | ... + ... | +| argvLocal.c:126:10:126:13 | argv | argvLocal.c:132:15:132:20 | Argument 0 indirection | +| argvLocal.c:126:10:126:13 | argv | argvLocal.c:132:15:132:20 | Argument 0 indirection | +| argvLocal.c:128:15:128:16 | printWrapper output argument | argvLocal.c:131:9:131:14 | ... + ... | +| argvLocal.c:128:15:128:16 | printWrapper output argument | argvLocal.c:131:9:131:14 | Argument 0 indirection | +| argvLocal.c:128:15:128:16 | printWrapper output argument | argvLocal.c:132:15:132:20 | ... + ... | +| argvLocal.c:128:15:128:16 | printWrapper output argument | argvLocal.c:132:15:132:20 | Argument 0 indirection | | argvLocal.c:149:11:149:14 | argv | argvLocal.c:150:9:150:10 | (const char *)... | | argvLocal.c:149:11:149:14 | argv | argvLocal.c:150:9:150:10 | (const char *)... | | argvLocal.c:149:11:149:14 | argv | argvLocal.c:150:9:150:10 | i8 | @@ -86,6 +108,8 @@ edges | argvLocal.c:168:18:168:21 | argv | argvLocal.c:170:24:170:26 | i10 | | argvLocal.c:168:18:168:21 | argv | argvLocal.c:170:24:170:26 | i10 | nodes +| argvLocal.c:9:25:9:31 | *correct | semmle.label | *correct | +| argvLocal.c:10:9:10:15 | Chi | semmle.label | Chi | | argvLocal.c:95:9:95:12 | argv | semmle.label | argv | | argvLocal.c:95:9:95:12 | argv | semmle.label | argv | | argvLocal.c:95:9:95:15 | (const char *)... | semmle.label | (const char *)... | @@ -126,6 +150,21 @@ nodes | argvLocal.c:111:15:111:17 | * ... | semmle.label | * ... | | argvLocal.c:111:15:111:17 | * ... | semmle.label | * ... | | argvLocal.c:111:15:111:17 | * ... | semmle.label | * ... | +| argvLocal.c:126:10:126:13 | argv | semmle.label | argv | +| argvLocal.c:126:10:126:13 | argv | semmle.label | argv | +| argvLocal.c:127:9:127:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| argvLocal.c:127:9:127:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| argvLocal.c:127:9:127:10 | i5 | semmle.label | i5 | +| argvLocal.c:128:15:128:16 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| argvLocal.c:128:15:128:16 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| argvLocal.c:128:15:128:16 | i5 | semmle.label | i5 | +| argvLocal.c:128:15:128:16 | printWrapper output argument | semmle.label | printWrapper output argument | +| argvLocal.c:131:9:131:14 | ... + ... | semmle.label | ... + ... | +| argvLocal.c:131:9:131:14 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| argvLocal.c:131:9:131:14 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| argvLocal.c:132:15:132:20 | ... + ... | semmle.label | ... + ... | +| argvLocal.c:132:15:132:20 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| argvLocal.c:132:15:132:20 | Argument 0 indirection | semmle.label | Argument 0 indirection | | argvLocal.c:144:9:144:10 | (const char *)... | semmle.label | (const char *)... | | argvLocal.c:144:9:144:10 | (const char *)... | semmle.label | (const char *)... | | argvLocal.c:144:9:144:10 | i7 | semmle.label | i7 | @@ -167,6 +206,10 @@ nodes | argvLocal.c:107:15:107:19 | access to array | argvLocal.c:105:14:105:17 | argv | argvLocal.c:107:15:107:19 | access to array | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:105:14:105:17 | argv | argv | | argvLocal.c:110:9:110:11 | * ... | argvLocal.c:105:14:105:17 | argv | argvLocal.c:110:9:110:11 | * ... | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:105:14:105:17 | argv | argv | | argvLocal.c:111:15:111:17 | * ... | argvLocal.c:105:14:105:17 | argv | argvLocal.c:111:15:111:17 | * ... | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:105:14:105:17 | argv | argv | +| argvLocal.c:127:9:127:10 | i5 | argvLocal.c:126:10:126:13 | argv | argvLocal.c:127:9:127:10 | i5 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:126:10:126:13 | argv | argv | +| argvLocal.c:128:15:128:16 | i5 | argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | i5 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:126:10:126:13 | argv | argv | +| argvLocal.c:131:9:131:14 | ... + ... | argvLocal.c:126:10:126:13 | argv | argvLocal.c:131:9:131:14 | ... + ... | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:126:10:126:13 | argv | argv | +| argvLocal.c:132:15:132:20 | ... + ... | argvLocal.c:126:10:126:13 | argv | argvLocal.c:132:15:132:20 | ... + ... | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:126:10:126:13 | argv | argv | | argvLocal.c:144:9:144:10 | i7 | argvLocal.c:100:7:100:10 | argv | argvLocal.c:144:9:144:10 | i7 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:100:7:100:10 | argv | argv | | argvLocal.c:145:15:145:16 | i7 | argvLocal.c:100:7:100:10 | argv | argvLocal.c:145:15:145:16 | i7 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:100:7:100:10 | argv | argv | | argvLocal.c:150:9:150:10 | i8 | argvLocal.c:149:11:149:14 | argv | argvLocal.c:150:9:150:10 | i8 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:149:11:149:14 | argv | argv | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/funcs/funcsLocal.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/funcs/funcsLocal.expected index 1beb428a832..5d04ac6149d 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/funcs/funcsLocal.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/funcs/funcsLocal.expected @@ -1,31 +1,87 @@ edges +| funcsLocal.c:16:8:16:9 | fread output argument | funcsLocal.c:17:9:17:10 | Argument 0 indirection | +| funcsLocal.c:16:8:16:9 | fread output argument | funcsLocal.c:17:9:17:10 | i1 | +| funcsLocal.c:16:8:16:9 | fread output argument | funcsLocal.c:58:9:58:10 | Argument 0 indirection | +| funcsLocal.c:16:8:16:9 | fread output argument | funcsLocal.c:58:9:58:10 | e1 | +| funcsLocal.c:16:8:16:9 | i1 | funcsLocal.c:17:9:17:10 | Argument 0 indirection | +| funcsLocal.c:16:8:16:9 | i1 | funcsLocal.c:17:9:17:10 | i1 | +| funcsLocal.c:16:8:16:9 | i1 | funcsLocal.c:58:9:58:10 | Argument 0 indirection | +| funcsLocal.c:16:8:16:9 | i1 | funcsLocal.c:58:9:58:10 | e1 | +| funcsLocal.c:26:8:26:9 | fgets output argument | funcsLocal.c:27:9:27:10 | Argument 0 indirection | +| funcsLocal.c:26:8:26:9 | fgets output argument | funcsLocal.c:27:9:27:10 | i3 | +| funcsLocal.c:26:8:26:9 | i3 | funcsLocal.c:27:9:27:10 | Argument 0 indirection | +| funcsLocal.c:26:8:26:9 | i3 | funcsLocal.c:27:9:27:10 | i3 | | funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | (const char *)... | | funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | (const char *)... | | funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | i4 | | funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | i4 | | funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | i4 | | funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | i4 | +| funcsLocal.c:31:19:31:21 | fgets output argument | funcsLocal.c:32:9:32:10 | Argument 0 indirection | +| funcsLocal.c:31:19:31:21 | fgets output argument | funcsLocal.c:32:9:32:10 | i4 | +| funcsLocal.c:31:19:31:21 | i41 | funcsLocal.c:32:9:32:10 | Argument 0 indirection | +| funcsLocal.c:31:19:31:21 | i41 | funcsLocal.c:32:9:32:10 | i4 | +| funcsLocal.c:36:7:36:8 | gets output argument | funcsLocal.c:37:9:37:10 | Argument 0 indirection | +| funcsLocal.c:36:7:36:8 | gets output argument | funcsLocal.c:37:9:37:10 | i5 | +| funcsLocal.c:36:7:36:8 | i5 | funcsLocal.c:37:9:37:10 | Argument 0 indirection | +| funcsLocal.c:36:7:36:8 | i5 | funcsLocal.c:37:9:37:10 | i5 | | funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | (const char *)... | | funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | (const char *)... | | funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | i6 | | funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | i6 | | funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | i6 | | funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | i6 | +| funcsLocal.c:41:18:41:20 | gets output argument | funcsLocal.c:42:9:42:10 | Argument 0 indirection | +| funcsLocal.c:41:18:41:20 | gets output argument | funcsLocal.c:42:9:42:10 | i6 | +| funcsLocal.c:41:18:41:20 | i61 | funcsLocal.c:42:9:42:10 | Argument 0 indirection | +| funcsLocal.c:41:18:41:20 | i61 | funcsLocal.c:42:9:42:10 | i6 | nodes +| funcsLocal.c:16:8:16:9 | fread output argument | semmle.label | fread output argument | +| funcsLocal.c:16:8:16:9 | i1 | semmle.label | i1 | +| funcsLocal.c:17:9:17:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| funcsLocal.c:17:9:17:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| funcsLocal.c:17:9:17:10 | i1 | semmle.label | i1 | +| funcsLocal.c:26:8:26:9 | fgets output argument | semmle.label | fgets output argument | +| funcsLocal.c:26:8:26:9 | i3 | semmle.label | i3 | +| funcsLocal.c:27:9:27:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| funcsLocal.c:27:9:27:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| funcsLocal.c:27:9:27:10 | i3 | semmle.label | i3 | | funcsLocal.c:31:13:31:17 | call to fgets | semmle.label | call to fgets | | funcsLocal.c:31:13:31:17 | call to fgets | semmle.label | call to fgets | +| funcsLocal.c:31:19:31:21 | fgets output argument | semmle.label | fgets output argument | +| funcsLocal.c:31:19:31:21 | i41 | semmle.label | i41 | | funcsLocal.c:32:9:32:10 | (const char *)... | semmle.label | (const char *)... | | funcsLocal.c:32:9:32:10 | (const char *)... | semmle.label | (const char *)... | +| funcsLocal.c:32:9:32:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| funcsLocal.c:32:9:32:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | | funcsLocal.c:32:9:32:10 | i4 | semmle.label | i4 | | funcsLocal.c:32:9:32:10 | i4 | semmle.label | i4 | | funcsLocal.c:32:9:32:10 | i4 | semmle.label | i4 | +| funcsLocal.c:36:7:36:8 | gets output argument | semmle.label | gets output argument | +| funcsLocal.c:36:7:36:8 | i5 | semmle.label | i5 | +| funcsLocal.c:37:9:37:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| funcsLocal.c:37:9:37:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| funcsLocal.c:37:9:37:10 | i5 | semmle.label | i5 | | funcsLocal.c:41:13:41:16 | call to gets | semmle.label | call to gets | | funcsLocal.c:41:13:41:16 | call to gets | semmle.label | call to gets | +| funcsLocal.c:41:18:41:20 | gets output argument | semmle.label | gets output argument | +| funcsLocal.c:41:18:41:20 | i61 | semmle.label | i61 | | funcsLocal.c:42:9:42:10 | (const char *)... | semmle.label | (const char *)... | | funcsLocal.c:42:9:42:10 | (const char *)... | semmle.label | (const char *)... | +| funcsLocal.c:42:9:42:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| funcsLocal.c:42:9:42:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | | funcsLocal.c:42:9:42:10 | i6 | semmle.label | i6 | | funcsLocal.c:42:9:42:10 | i6 | semmle.label | i6 | | funcsLocal.c:42:9:42:10 | i6 | semmle.label | i6 | +| funcsLocal.c:58:9:58:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| funcsLocal.c:58:9:58:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| funcsLocal.c:58:9:58:10 | e1 | semmle.label | e1 | #select +| funcsLocal.c:17:9:17:10 | i1 | funcsLocal.c:16:8:16:9 | i1 | funcsLocal.c:17:9:17:10 | i1 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:16:8:16:9 | i1 | fread | +| funcsLocal.c:27:9:27:10 | i3 | funcsLocal.c:26:8:26:9 | i3 | funcsLocal.c:27:9:27:10 | i3 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:26:8:26:9 | i3 | fgets | | funcsLocal.c:32:9:32:10 | i4 | funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | i4 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:31:13:31:17 | call to fgets | fgets | +| funcsLocal.c:32:9:32:10 | i4 | funcsLocal.c:31:19:31:21 | i41 | funcsLocal.c:32:9:32:10 | i4 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:31:19:31:21 | i41 | fgets | +| funcsLocal.c:37:9:37:10 | i5 | funcsLocal.c:36:7:36:8 | i5 | funcsLocal.c:37:9:37:10 | i5 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:36:7:36:8 | i5 | gets | | funcsLocal.c:42:9:42:10 | i6 | funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | i6 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:41:13:41:16 | call to gets | gets | +| funcsLocal.c:42:9:42:10 | i6 | funcsLocal.c:41:18:41:20 | i61 | funcsLocal.c:42:9:42:10 | i6 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:41:18:41:20 | i61 | gets | +| funcsLocal.c:58:9:58:10 | e1 | funcsLocal.c:16:8:16:9 | i1 | funcsLocal.c:58:9:58:10 | e1 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:16:8:16:9 | i1 | fread | From afbeca0d54e4beb06ce200a5b7128ceb0916d6c7 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Mon, 9 Nov 2020 13:24:31 -0800 Subject: [PATCH 007/725] C++: Accept test outputs --- .../CWE-022/semmle/tests/TaintedPath.expected | 2 - .../CWE/CWE-079/semmle/CgiXss/CgiXss.expected | 12 ------ .../semmle/tests/UnboundedWrite.expected | 40 +++++++++++++++++++ ...olledFormatStringThroughGlobalVar.expected | 3 -- 4 files changed, 40 insertions(+), 17 deletions(-) diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-022/semmle/tests/TaintedPath.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-022/semmle/tests/TaintedPath.expected index 03d1bfd25b3..7383fbbd215 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-022/semmle/tests/TaintedPath.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-022/semmle/tests/TaintedPath.expected @@ -1,5 +1,3 @@ -WARNING: Unused predicate sinkInstructionNodes (C:/semmle/code/ql/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql:64,13-33) -WARNING: Unused predicate sinkOperand (C:/semmle/code/ql/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql:70,13-24) edges | test.c:9:23:9:26 | argv | test.c:17:11:17:18 | Argument 0 indirection | | test.c:9:23:9:26 | argv | test.c:17:11:17:18 | Argument 0 indirection | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/CgiXss.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/CgiXss.expected index 6f08104489e..20bb97a9f66 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/CgiXss.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/CgiXss.expected @@ -1,30 +1,20 @@ edges -| search.c:14:24:14:28 | *query | search.c:17:8:17:12 | (const char *)... | -| search.c:14:24:14:28 | *query | search.c:17:8:17:12 | query | | search.c:14:24:14:28 | query | search.c:17:8:17:12 | (const char *)... | | search.c:14:24:14:28 | query | search.c:17:8:17:12 | query | | search.c:14:24:14:28 | query | search.c:17:8:17:12 | query | -| search.c:22:24:22:28 | *query | search.c:23:39:23:43 | query | -| search.c:22:24:22:28 | *query | search.c:23:39:23:43 | query | | search.c:22:24:22:28 | query | search.c:23:39:23:43 | query | | search.c:22:24:22:28 | query | search.c:23:39:23:43 | query | -| search.c:41:21:41:26 | call to getenv | search.c:14:24:14:28 | *query | -| search.c:41:21:41:26 | call to getenv | search.c:14:24:14:28 | *query | | search.c:41:21:41:26 | call to getenv | search.c:14:24:14:28 | query | | search.c:41:21:41:26 | call to getenv | search.c:14:24:14:28 | query | -| search.c:41:21:41:26 | call to getenv | search.c:22:24:22:28 | *query | -| search.c:41:21:41:26 | call to getenv | search.c:22:24:22:28 | *query | | search.c:41:21:41:26 | call to getenv | search.c:22:24:22:28 | query | | search.c:41:21:41:26 | call to getenv | search.c:22:24:22:28 | query | nodes -| search.c:14:24:14:28 | *query | semmle.label | *query | | search.c:14:24:14:28 | query | semmle.label | query | | search.c:17:8:17:12 | (const char *)... | semmle.label | (const char *)... | | search.c:17:8:17:12 | (const char *)... | semmle.label | (const char *)... | | search.c:17:8:17:12 | query | semmle.label | query | | search.c:17:8:17:12 | query | semmle.label | query | | search.c:17:8:17:12 | query | semmle.label | query | -| search.c:22:24:22:28 | *query | semmle.label | *query | | search.c:22:24:22:28 | query | semmle.label | query | | search.c:23:39:23:43 | query | semmle.label | query | | search.c:23:39:23:43 | query | semmle.label | query | @@ -32,9 +22,7 @@ nodes | search.c:41:21:41:26 | call to getenv | semmle.label | call to getenv | | search.c:41:21:41:26 | call to getenv | semmle.label | call to getenv | | search.c:45:5:45:15 | Argument 0 | semmle.label | Argument 0 | -| search.c:45:17:45:25 | Argument 0 indirection | semmle.label | Argument 0 indirection | | search.c:47:5:47:15 | Argument 0 | semmle.label | Argument 0 | -| search.c:47:17:47:25 | Argument 0 indirection | semmle.label | Argument 0 indirection | #select | search.c:17:8:17:12 | query | search.c:41:21:41:26 | call to getenv | search.c:17:8:17:12 | query | Cross-site scripting vulnerability due to $@. | search.c:41:21:41:26 | call to getenv | this query data | | search.c:23:39:23:43 | query | search.c:41:21:41:26 | call to getenv | search.c:23:39:23:43 | query | Cross-site scripting vulnerability due to $@. | search.c:41:21:41:26 | call to getenv | this query data | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-120/semmle/tests/UnboundedWrite.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-120/semmle/tests/UnboundedWrite.expected index 365f9ed0aa9..7aed6f01dc3 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-120/semmle/tests/UnboundedWrite.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-120/semmle/tests/UnboundedWrite.expected @@ -7,12 +7,42 @@ edges | tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array | | tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array | | tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array | +| tests.c:28:22:28:25 | argv | tests.c:31:15:31:23 | Argument 1 indirection | +| tests.c:28:22:28:25 | argv | tests.c:31:15:31:23 | Argument 1 indirection | +| tests.c:28:22:28:25 | argv | tests.c:31:15:31:23 | buffer100 | +| tests.c:28:22:28:25 | argv | tests.c:31:15:31:23 | buffer100 | +| tests.c:28:22:28:25 | argv | tests.c:33:21:33:29 | Argument 2 indirection | +| tests.c:28:22:28:25 | argv | tests.c:33:21:33:29 | Argument 2 indirection | +| tests.c:28:22:28:25 | argv | tests.c:33:21:33:29 | buffer100 | +| tests.c:28:22:28:25 | argv | tests.c:33:21:33:29 | buffer100 | | tests.c:28:22:28:28 | access to array | tests.c:28:22:28:28 | (const char *)... | | tests.c:28:22:28:28 | access to array | tests.c:28:22:28:28 | access to array | +| tests.c:28:22:28:28 | access to array | tests.c:31:15:31:23 | Argument 1 indirection | +| tests.c:28:22:28:28 | access to array | tests.c:31:15:31:23 | buffer100 | +| tests.c:28:22:28:28 | access to array | tests.c:33:21:33:29 | Argument 2 indirection | +| tests.c:28:22:28:28 | access to array | tests.c:33:21:33:29 | buffer100 | | tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | access to array | | tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | access to array | | tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | access to array | | tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | access to array | +| tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | access to array | +| tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | access to array | +| tests.c:29:28:29:31 | argv | tests.c:31:15:31:23 | Argument 1 indirection | +| tests.c:29:28:29:31 | argv | tests.c:31:15:31:23 | Argument 1 indirection | +| tests.c:29:28:29:31 | argv | tests.c:31:15:31:23 | buffer100 | +| tests.c:29:28:29:31 | argv | tests.c:31:15:31:23 | buffer100 | +| tests.c:29:28:29:31 | argv | tests.c:33:21:33:29 | Argument 2 indirection | +| tests.c:29:28:29:31 | argv | tests.c:33:21:33:29 | Argument 2 indirection | +| tests.c:29:28:29:31 | argv | tests.c:33:21:33:29 | buffer100 | +| tests.c:29:28:29:31 | argv | tests.c:33:21:33:29 | buffer100 | +| tests.c:29:28:29:34 | access to array | tests.c:31:15:31:23 | Argument 1 indirection | +| tests.c:29:28:29:34 | access to array | tests.c:31:15:31:23 | buffer100 | +| tests.c:29:28:29:34 | access to array | tests.c:33:21:33:29 | Argument 2 indirection | +| tests.c:29:28:29:34 | access to array | tests.c:33:21:33:29 | buffer100 | +| tests.c:31:15:31:23 | buffer100 | tests.c:33:21:33:29 | Argument 2 indirection | +| tests.c:31:15:31:23 | buffer100 | tests.c:33:21:33:29 | buffer100 | +| tests.c:31:15:31:23 | scanf output argument | tests.c:33:21:33:29 | Argument 2 indirection | +| tests.c:31:15:31:23 | scanf output argument | tests.c:33:21:33:29 | buffer100 | | tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | (const char *)... | | tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | (const char *)... | | tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | access to array | @@ -36,11 +66,16 @@ nodes | tests.c:29:28:29:34 | access to array | semmle.label | access to array | | tests.c:29:28:29:34 | access to array | semmle.label | access to array | | tests.c:29:28:29:34 | access to array | semmle.label | access to array | +| tests.c:31:15:31:23 | Argument 1 indirection | semmle.label | Argument 1 indirection | +| tests.c:31:15:31:23 | Argument 1 indirection | semmle.label | Argument 1 indirection | | tests.c:31:15:31:23 | array to pointer conversion | semmle.label | array to pointer conversion | | tests.c:31:15:31:23 | array to pointer conversion | semmle.label | array to pointer conversion | | tests.c:31:15:31:23 | buffer100 | semmle.label | buffer100 | | tests.c:31:15:31:23 | buffer100 | semmle.label | buffer100 | | tests.c:31:15:31:23 | buffer100 | semmle.label | buffer100 | +| tests.c:31:15:31:23 | scanf output argument | semmle.label | scanf output argument | +| tests.c:33:21:33:29 | Argument 2 indirection | semmle.label | Argument 2 indirection | +| tests.c:33:21:33:29 | Argument 2 indirection | semmle.label | Argument 2 indirection | | tests.c:33:21:33:29 | array to pointer conversion | semmle.label | array to pointer conversion | | tests.c:33:21:33:29 | array to pointer conversion | semmle.label | array to pointer conversion | | tests.c:33:21:33:29 | buffer100 | semmle.label | buffer100 | @@ -56,6 +91,11 @@ nodes #select | tests.c:28:3:28:9 | call to sprintf | tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array | This 'call to sprintf' with input from $@ may overflow the destination. | tests.c:28:22:28:25 | argv | argv | | tests.c:29:3:29:9 | call to sprintf | tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | access to array | This 'call to sprintf' with input from $@ may overflow the destination. | tests.c:29:28:29:31 | argv | argv | +| tests.c:31:15:31:23 | buffer100 | tests.c:28:22:28:25 | argv | tests.c:31:15:31:23 | buffer100 | This 'scanf string argument' with input from $@ may overflow the destination. | tests.c:28:22:28:25 | argv | argv | +| tests.c:31:15:31:23 | buffer100 | tests.c:29:28:29:31 | argv | tests.c:31:15:31:23 | buffer100 | This 'scanf string argument' with input from $@ may overflow the destination. | tests.c:29:28:29:31 | argv | argv | | tests.c:31:15:31:23 | buffer100 | tests.c:31:15:31:23 | buffer100 | tests.c:31:15:31:23 | buffer100 | This 'scanf string argument' with input from $@ may overflow the destination. | tests.c:31:15:31:23 | buffer100 | buffer100 | +| tests.c:33:21:33:29 | buffer100 | tests.c:28:22:28:25 | argv | tests.c:33:21:33:29 | buffer100 | This 'scanf string argument' with input from $@ may overflow the destination. | tests.c:28:22:28:25 | argv | argv | +| tests.c:33:21:33:29 | buffer100 | tests.c:29:28:29:31 | argv | tests.c:33:21:33:29 | buffer100 | This 'scanf string argument' with input from $@ may overflow the destination. | tests.c:29:28:29:31 | argv | argv | +| tests.c:33:21:33:29 | buffer100 | tests.c:31:15:31:23 | buffer100 | tests.c:33:21:33:29 | buffer100 | This 'scanf string argument' with input from $@ may overflow the destination. | tests.c:31:15:31:23 | buffer100 | buffer100 | | tests.c:33:21:33:29 | buffer100 | tests.c:33:21:33:29 | buffer100 | tests.c:33:21:33:29 | buffer100 | This 'scanf string argument' with input from $@ may overflow the destination. | tests.c:33:21:33:29 | buffer100 | buffer100 | | tests.c:34:25:34:33 | buffer100 | tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | access to array | This 'sscanf string argument' with input from $@ may overflow the destination. | tests.c:34:10:34:13 | argv | argv | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatStringThroughGlobalVar.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatStringThroughGlobalVar.expected index 598d7df193c..14593adce48 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatStringThroughGlobalVar.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatStringThroughGlobalVar.expected @@ -17,8 +17,6 @@ edges | globalVars.c:12:2:12:15 | Store | globalVars.c:8:7:8:10 | copy | | globalVars.c:15:21:15:23 | val | globalVars.c:16:2:16:12 | Store | | globalVars.c:16:2:16:12 | Store | globalVars.c:9:7:9:11 | copy2 | -| globalVars.c:24:11:24:14 | argv | globalVars.c:11:22:11:25 | *argv | -| globalVars.c:24:11:24:14 | argv | globalVars.c:11:22:11:25 | *argv | | globalVars.c:24:11:24:14 | argv | globalVars.c:11:22:11:25 | argv | | globalVars.c:24:11:24:14 | argv | globalVars.c:11:22:11:25 | argv | | globalVars.c:27:9:27:12 | copy | globalVars.c:27:9:27:12 | (const char *)... | @@ -36,7 +34,6 @@ nodes | globalVars.c:15:21:15:23 | val | semmle.label | val | | globalVars.c:16:2:16:12 | Store | semmle.label | Store | | globalVars.c:24:2:24:9 | Argument 0 | semmle.label | Argument 0 | -| globalVars.c:24:11:24:14 | Argument 0 indirection | semmle.label | Argument 0 indirection | | globalVars.c:24:11:24:14 | argv | semmle.label | argv | | globalVars.c:24:11:24:14 | argv | semmle.label | argv | | globalVars.c:27:9:27:12 | (const char *)... | semmle.label | (const char *)... | From 04ad94d1cc1b027b9ccbc06ae2afb9b9d6c7f29e Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Wed, 1 Jul 2020 14:48:19 -0700 Subject: [PATCH 008/725] C++: model taint from pointers to aliased buffers --- .../dataflow/internal/TaintTrackingUtil.qll | 18 +++ .../CWE-134/semmle/argv/argvLocal.expected | 105 ++++++++++++++++++ 2 files changed, 123 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll index 202d3f1c14e..1cbddcd70ae 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll @@ -142,4 +142,22 @@ predicate modeledTaintStep(DataFlow::Node nodeIn, DataFlow::Node nodeOut) { modelMidOut.isParameterDeref(indexMid) and modelMidIn.isParameter(indexMid) ) + or + // Taint flow from a pointer argument to an output, when the model specifies flow from the deref + // to that output, but the deref is not modeled in the IR for the caller. + exists( + CallInstruction call, ReadSideEffectInstruction read, Function func, + FunctionInput modelIn, FunctionOutput modelOut + | + read.getSideEffectOperand() = callInput(call, modelIn).asOperand() and + read.getArgumentDef() = nodeIn.asInstruction() and + not read.getSideEffect().isResultModeled() and + call.getStaticCallTarget() = func and + ( + func.(DataFlowFunction).hasDataFlow(modelIn, modelOut) + or + func.(TaintFunction).hasTaintFlow(modelIn, modelOut) + ) and + nodeOut.asInstruction() = callOutput(call, modelOut) + ) } diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.expected index 35008e71818..bd5653e97fa 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.expected @@ -61,6 +61,47 @@ edges | argvLocal.c:106:9:106:13 | access to array | argvLocal.c:106:9:106:13 | access to array | | argvLocal.c:110:9:110:11 | * ... | argvLocal.c:110:9:110:11 | (const char *)... | | argvLocal.c:110:9:110:11 | * ... | argvLocal.c:110:9:110:11 | * ... | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:116:9:116:10 | Argument 0 indirection | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:116:9:116:10 | Argument 0 indirection | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:116:9:116:10 | i3 | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:116:9:116:10 | i3 | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:117:15:117:16 | Argument 0 indirection | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:117:15:117:16 | Argument 0 indirection | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:117:15:117:16 | i3 | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:117:15:117:16 | i3 | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:117:15:117:16 | printWrapper output argument | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:117:15:117:16 | printWrapper output argument | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:121:9:121:10 | Argument 0 indirection | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:121:9:121:10 | Argument 0 indirection | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:121:9:121:10 | i4 | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:121:9:121:10 | i4 | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:122:15:122:16 | Argument 0 indirection | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:122:15:122:16 | Argument 0 indirection | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:122:15:122:16 | i4 | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:122:15:122:16 | i4 | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:122:15:122:16 | printWrapper output argument | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:122:15:122:16 | printWrapper output argument | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:135:9:135:12 | ... ++ | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:135:9:135:12 | ... ++ | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:135:9:135:12 | Argument 0 indirection | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:135:9:135:12 | Argument 0 indirection | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:136:15:136:18 | -- ... | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:136:15:136:18 | -- ... | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:136:15:136:18 | Argument 0 indirection | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:136:15:136:18 | Argument 0 indirection | +| argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:121:9:121:10 | Argument 0 indirection | +| argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:121:9:121:10 | i4 | +| argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:122:15:122:16 | Argument 0 indirection | +| argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:122:15:122:16 | i4 | +| argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:122:15:122:16 | printWrapper output argument | +| argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:135:9:135:12 | ... ++ | +| argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:135:9:135:12 | Argument 0 indirection | +| argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:136:15:136:18 | -- ... | +| argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:136:15:136:18 | Argument 0 indirection | +| argvLocal.c:122:15:122:16 | printWrapper output argument | argvLocal.c:135:9:135:12 | ... ++ | +| argvLocal.c:122:15:122:16 | printWrapper output argument | argvLocal.c:135:9:135:12 | Argument 0 indirection | +| argvLocal.c:122:15:122:16 | printWrapper output argument | argvLocal.c:136:15:136:18 | -- ... | +| argvLocal.c:122:15:122:16 | printWrapper output argument | argvLocal.c:136:15:136:18 | Argument 0 indirection | | argvLocal.c:126:10:126:13 | argv | argvLocal.c:127:9:127:10 | Argument 0 indirection | | argvLocal.c:126:10:126:13 | argv | argvLocal.c:127:9:127:10 | Argument 0 indirection | | argvLocal.c:126:10:126:13 | argv | argvLocal.c:127:9:127:10 | i5 | @@ -93,6 +134,22 @@ edges | argvLocal.c:149:11:149:14 | argv | argvLocal.c:151:15:151:16 | i8 | | argvLocal.c:149:11:149:14 | argv | argvLocal.c:151:15:151:16 | i8 | | argvLocal.c:149:11:149:14 | argv | argvLocal.c:151:15:151:16 | i8 | +| argvLocal.c:156:23:156:26 | argv | argvLocal.c:157:9:157:10 | Argument 0 indirection | +| argvLocal.c:156:23:156:26 | argv | argvLocal.c:157:9:157:10 | Argument 0 indirection | +| argvLocal.c:156:23:156:26 | argv | argvLocal.c:157:9:157:10 | i9 | +| argvLocal.c:156:23:156:26 | argv | argvLocal.c:157:9:157:10 | i9 | +| argvLocal.c:156:23:156:26 | argv | argvLocal.c:158:15:158:16 | Argument 0 indirection | +| argvLocal.c:156:23:156:26 | argv | argvLocal.c:158:15:158:16 | Argument 0 indirection | +| argvLocal.c:156:23:156:26 | argv | argvLocal.c:158:15:158:16 | i9 | +| argvLocal.c:156:23:156:26 | argv | argvLocal.c:158:15:158:16 | i9 | +| argvLocal.c:163:22:163:25 | argv | argvLocal.c:164:9:164:11 | Argument 0 indirection | +| argvLocal.c:163:22:163:25 | argv | argvLocal.c:164:9:164:11 | Argument 0 indirection | +| argvLocal.c:163:22:163:25 | argv | argvLocal.c:164:9:164:11 | i91 | +| argvLocal.c:163:22:163:25 | argv | argvLocal.c:164:9:164:11 | i91 | +| argvLocal.c:163:22:163:25 | argv | argvLocal.c:165:15:165:17 | Argument 0 indirection | +| argvLocal.c:163:22:163:25 | argv | argvLocal.c:165:15:165:17 | Argument 0 indirection | +| argvLocal.c:163:22:163:25 | argv | argvLocal.c:165:15:165:17 | i91 | +| argvLocal.c:163:22:163:25 | argv | argvLocal.c:165:15:165:17 | i91 | | argvLocal.c:168:18:168:21 | argv | argvLocal.c:169:9:169:20 | (char *)... | | argvLocal.c:168:18:168:21 | argv | argvLocal.c:169:9:169:20 | (char *)... | | argvLocal.c:168:18:168:21 | argv | argvLocal.c:169:9:169:20 | (const char *)... | @@ -150,6 +207,22 @@ nodes | argvLocal.c:111:15:111:17 | * ... | semmle.label | * ... | | argvLocal.c:111:15:111:17 | * ... | semmle.label | * ... | | argvLocal.c:111:15:111:17 | * ... | semmle.label | * ... | +| argvLocal.c:115:13:115:16 | argv | semmle.label | argv | +| argvLocal.c:115:13:115:16 | argv | semmle.label | argv | +| argvLocal.c:116:9:116:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| argvLocal.c:116:9:116:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| argvLocal.c:116:9:116:10 | i3 | semmle.label | i3 | +| argvLocal.c:117:15:117:16 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| argvLocal.c:117:15:117:16 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| argvLocal.c:117:15:117:16 | i3 | semmle.label | i3 | +| argvLocal.c:117:15:117:16 | printWrapper output argument | semmle.label | printWrapper output argument | +| argvLocal.c:121:9:121:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| argvLocal.c:121:9:121:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| argvLocal.c:121:9:121:10 | i4 | semmle.label | i4 | +| argvLocal.c:122:15:122:16 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| argvLocal.c:122:15:122:16 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| argvLocal.c:122:15:122:16 | i4 | semmle.label | i4 | +| argvLocal.c:122:15:122:16 | printWrapper output argument | semmle.label | printWrapper output argument | | argvLocal.c:126:10:126:13 | argv | semmle.label | argv | | argvLocal.c:126:10:126:13 | argv | semmle.label | argv | | argvLocal.c:127:9:127:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | @@ -165,6 +238,12 @@ nodes | argvLocal.c:132:15:132:20 | ... + ... | semmle.label | ... + ... | | argvLocal.c:132:15:132:20 | Argument 0 indirection | semmle.label | Argument 0 indirection | | argvLocal.c:132:15:132:20 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| argvLocal.c:135:9:135:12 | ... ++ | semmle.label | ... ++ | +| argvLocal.c:135:9:135:12 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| argvLocal.c:135:9:135:12 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| argvLocal.c:136:15:136:18 | -- ... | semmle.label | -- ... | +| argvLocal.c:136:15:136:18 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| argvLocal.c:136:15:136:18 | Argument 0 indirection | semmle.label | Argument 0 indirection | | argvLocal.c:144:9:144:10 | (const char *)... | semmle.label | (const char *)... | | argvLocal.c:144:9:144:10 | (const char *)... | semmle.label | (const char *)... | | argvLocal.c:144:9:144:10 | i7 | semmle.label | i7 | @@ -183,6 +262,22 @@ nodes | argvLocal.c:151:15:151:16 | i8 | semmle.label | i8 | | argvLocal.c:151:15:151:16 | i8 | semmle.label | i8 | | argvLocal.c:151:15:151:16 | i8 | semmle.label | i8 | +| argvLocal.c:156:23:156:26 | argv | semmle.label | argv | +| argvLocal.c:156:23:156:26 | argv | semmle.label | argv | +| argvLocal.c:157:9:157:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| argvLocal.c:157:9:157:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| argvLocal.c:157:9:157:10 | i9 | semmle.label | i9 | +| argvLocal.c:158:15:158:16 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| argvLocal.c:158:15:158:16 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| argvLocal.c:158:15:158:16 | i9 | semmle.label | i9 | +| argvLocal.c:163:22:163:25 | argv | semmle.label | argv | +| argvLocal.c:163:22:163:25 | argv | semmle.label | argv | +| argvLocal.c:164:9:164:11 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| argvLocal.c:164:9:164:11 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| argvLocal.c:164:9:164:11 | i91 | semmle.label | i91 | +| argvLocal.c:165:15:165:17 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| argvLocal.c:165:15:165:17 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| argvLocal.c:165:15:165:17 | i91 | semmle.label | i91 | | argvLocal.c:168:18:168:21 | argv | semmle.label | argv | | argvLocal.c:168:18:168:21 | argv | semmle.label | argv | | argvLocal.c:169:9:169:20 | (char *)... | semmle.label | (char *)... | @@ -206,13 +301,23 @@ nodes | argvLocal.c:107:15:107:19 | access to array | argvLocal.c:105:14:105:17 | argv | argvLocal.c:107:15:107:19 | access to array | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:105:14:105:17 | argv | argv | | argvLocal.c:110:9:110:11 | * ... | argvLocal.c:105:14:105:17 | argv | argvLocal.c:110:9:110:11 | * ... | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:105:14:105:17 | argv | argv | | argvLocal.c:111:15:111:17 | * ... | argvLocal.c:105:14:105:17 | argv | argvLocal.c:111:15:111:17 | * ... | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:105:14:105:17 | argv | argv | +| argvLocal.c:116:9:116:10 | i3 | argvLocal.c:115:13:115:16 | argv | argvLocal.c:116:9:116:10 | i3 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:115:13:115:16 | argv | argv | +| argvLocal.c:117:15:117:16 | i3 | argvLocal.c:115:13:115:16 | argv | argvLocal.c:117:15:117:16 | i3 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:115:13:115:16 | argv | argv | +| argvLocal.c:121:9:121:10 | i4 | argvLocal.c:115:13:115:16 | argv | argvLocal.c:121:9:121:10 | i4 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:115:13:115:16 | argv | argv | +| argvLocal.c:122:15:122:16 | i4 | argvLocal.c:115:13:115:16 | argv | argvLocal.c:122:15:122:16 | i4 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:115:13:115:16 | argv | argv | | argvLocal.c:127:9:127:10 | i5 | argvLocal.c:126:10:126:13 | argv | argvLocal.c:127:9:127:10 | i5 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:126:10:126:13 | argv | argv | | argvLocal.c:128:15:128:16 | i5 | argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | i5 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:126:10:126:13 | argv | argv | | argvLocal.c:131:9:131:14 | ... + ... | argvLocal.c:126:10:126:13 | argv | argvLocal.c:131:9:131:14 | ... + ... | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:126:10:126:13 | argv | argv | | argvLocal.c:132:15:132:20 | ... + ... | argvLocal.c:126:10:126:13 | argv | argvLocal.c:132:15:132:20 | ... + ... | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:126:10:126:13 | argv | argv | +| argvLocal.c:135:9:135:12 | ... ++ | argvLocal.c:115:13:115:16 | argv | argvLocal.c:135:9:135:12 | ... ++ | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:115:13:115:16 | argv | argv | +| argvLocal.c:136:15:136:18 | -- ... | argvLocal.c:115:13:115:16 | argv | argvLocal.c:136:15:136:18 | -- ... | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:115:13:115:16 | argv | argv | | argvLocal.c:144:9:144:10 | i7 | argvLocal.c:100:7:100:10 | argv | argvLocal.c:144:9:144:10 | i7 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:100:7:100:10 | argv | argv | | argvLocal.c:145:15:145:16 | i7 | argvLocal.c:100:7:100:10 | argv | argvLocal.c:145:15:145:16 | i7 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:100:7:100:10 | argv | argv | | argvLocal.c:150:9:150:10 | i8 | argvLocal.c:149:11:149:14 | argv | argvLocal.c:150:9:150:10 | i8 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:149:11:149:14 | argv | argv | | argvLocal.c:151:15:151:16 | i8 | argvLocal.c:149:11:149:14 | argv | argvLocal.c:151:15:151:16 | i8 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:149:11:149:14 | argv | argv | +| argvLocal.c:157:9:157:10 | i9 | argvLocal.c:156:23:156:26 | argv | argvLocal.c:157:9:157:10 | i9 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:156:23:156:26 | argv | argv | +| argvLocal.c:158:15:158:16 | i9 | argvLocal.c:156:23:156:26 | argv | argvLocal.c:158:15:158:16 | i9 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:156:23:156:26 | argv | argv | +| argvLocal.c:164:9:164:11 | i91 | argvLocal.c:163:22:163:25 | argv | argvLocal.c:164:9:164:11 | i91 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:163:22:163:25 | argv | argv | +| argvLocal.c:165:15:165:17 | i91 | argvLocal.c:163:22:163:25 | argv | argvLocal.c:165:15:165:17 | i91 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:163:22:163:25 | argv | argv | | argvLocal.c:169:18:169:20 | i10 | argvLocal.c:168:18:168:21 | argv | argvLocal.c:169:18:169:20 | i10 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:168:18:168:21 | argv | argv | | argvLocal.c:170:24:170:26 | i10 | argvLocal.c:168:18:168:21 | argv | argvLocal.c:170:24:170:26 | i10 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:168:18:168:21 | argv | argv | From 2a6ba40a93972f345a821805e8cd245b27d650a4 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Tue, 10 Nov 2020 13:59:35 -0800 Subject: [PATCH 009/725] C++: Accept more test changes --- .../security-taint/tainted_diff.expected | 25 ++++ .../security-taint/tainted_ir.expected | 117 +++++++----------- .../dataflow/taint-tests/test_diff.expected | 1 - .../dataflow/taint-tests/test_ir.expected | 1 + 4 files changed, 72 insertions(+), 72 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/security-taint/tainted_diff.expected b/cpp/ql/test/library-tests/dataflow/security-taint/tainted_diff.expected index 26441b08ba4..9050ad322f8 100644 --- a/cpp/ql/test/library-tests/dataflow/security-taint/tainted_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/security-taint/tainted_diff.expected @@ -1,19 +1,44 @@ +| test.cpp:23:23:23:28 | call to getenv | test.cpp:8:24:8:25 | s1 | AST only | +| test.cpp:23:23:23:28 | call to getenv | test.cpp:23:14:23:19 | envStr | AST only | +| test.cpp:38:23:38:28 | call to getenv | test.cpp:8:24:8:25 | s1 | AST only | +| test.cpp:38:23:38:28 | call to getenv | test.cpp:38:14:38:19 | envStr | AST only | +| test.cpp:49:23:49:28 | call to getenv | test.cpp:8:24:8:25 | s1 | AST only | +| test.cpp:49:23:49:28 | call to getenv | test.cpp:45:13:45:24 | envStrGlobal | AST only | +| test.cpp:49:23:49:28 | call to getenv | test.cpp:49:14:49:19 | envStr | AST only | | test.cpp:49:23:49:28 | call to getenv | test.cpp:50:15:50:24 | envStr_ptr | AST only | | test.cpp:49:23:49:28 | call to getenv | test.cpp:50:28:50:40 | & ... | AST only | | test.cpp:49:23:49:28 | call to getenv | test.cpp:50:29:50:40 | envStrGlobal | AST only | | test.cpp:49:23:49:28 | call to getenv | test.cpp:52:2:52:12 | * ... | AST only | | test.cpp:49:23:49:28 | call to getenv | test.cpp:52:3:52:12 | envStr_ptr | AST only | +| test.cpp:60:29:60:34 | call to getenv | test.cpp:10:27:10:27 | s | AST only | +| test.cpp:60:29:60:34 | call to getenv | test.cpp:60:18:60:25 | userName | AST only | | test.cpp:68:28:68:33 | call to getenv | test.cpp:11:20:11:21 | s1 | AST only | +| test.cpp:68:28:68:33 | call to getenv | test.cpp:11:36:11:37 | s2 | AST only | | test.cpp:68:28:68:33 | call to getenv | test.cpp:67:7:67:13 | copying | AST only | +| test.cpp:68:28:68:33 | call to getenv | test.cpp:68:17:68:24 | userName | AST only | | test.cpp:68:28:68:33 | call to getenv | test.cpp:69:10:69:13 | copy | AST only | +| test.cpp:68:28:68:33 | call to getenv | test.cpp:70:5:70:10 | call to strcpy | AST only | | test.cpp:68:28:68:33 | call to getenv | test.cpp:70:12:70:15 | copy | AST only | | test.cpp:68:28:68:33 | call to getenv | test.cpp:71:12:71:15 | copy | AST only | +| test.cpp:75:20:75:25 | call to getenv | test.cpp:15:22:15:25 | nptr | AST only | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:8:24:8:25 | s1 | AST only | | test.cpp:83:28:83:33 | call to getenv | test.cpp:11:20:11:21 | s1 | AST only | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:11:36:11:37 | s2 | AST only | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:83:17:83:24 | userName | AST only | | test.cpp:83:28:83:33 | call to getenv | test.cpp:85:8:85:11 | copy | AST only | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:86:2:86:7 | call to strcpy | AST only | | test.cpp:83:28:83:33 | call to getenv | test.cpp:86:9:86:12 | copy | AST only | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:88:14:88:17 | (const char *)... | AST only | +| test.cpp:100:12:100:15 | call to gets | test.cpp:98:8:98:14 | pointer | AST only | | test.cpp:100:12:100:15 | call to gets | test.cpp:100:2:100:8 | pointer | AST only | +| test.cpp:100:17:100:22 | buffer | test.cpp:93:18:93:18 | s | AST only | | test.cpp:100:17:100:22 | buffer | test.cpp:97:7:97:12 | buffer | AST only | | test.cpp:100:17:100:22 | buffer | test.cpp:100:17:100:22 | array to pointer conversion | IR only | +| test.cpp:106:28:106:33 | call to getenv | test.cpp:8:24:8:25 | s1 | AST only | | test.cpp:106:28:106:33 | call to getenv | test.cpp:11:20:11:21 | s1 | AST only | +| test.cpp:106:28:106:33 | call to getenv | test.cpp:11:36:11:37 | s2 | AST only | +| test.cpp:106:28:106:33 | call to getenv | test.cpp:106:17:106:24 | userName | AST only | | test.cpp:106:28:106:33 | call to getenv | test.cpp:108:8:108:11 | copy | AST only | +| test.cpp:106:28:106:33 | call to getenv | test.cpp:109:2:109:7 | call to strcpy | AST only | | test.cpp:106:28:106:33 | call to getenv | test.cpp:109:9:109:12 | copy | AST only | +| test.cpp:106:28:106:33 | call to getenv | test.cpp:111:14:111:17 | (const char *)... | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/security-taint/tainted_ir.expected b/cpp/ql/test/library-tests/dataflow/security-taint/tainted_ir.expected index 50c90bccb2b..7f3044e6715 100644 --- a/cpp/ql/test/library-tests/dataflow/security-taint/tainted_ir.expected +++ b/cpp/ql/test/library-tests/dataflow/security-taint/tainted_ir.expected @@ -1,71 +1,46 @@ -| test.cpp:23:23:23:28 | call to getenv | test.cpp:8:24:8:25 | s1 | | -| test.cpp:23:23:23:28 | call to getenv | test.cpp:23:14:23:19 | envStr | | -| test.cpp:23:23:23:28 | call to getenv | test.cpp:23:23:23:28 | call to getenv | | -| test.cpp:23:23:23:28 | call to getenv | test.cpp:23:23:23:40 | (const char *)... | | -| test.cpp:23:23:23:28 | call to getenv | test.cpp:25:6:25:29 | ! ... | | -| test.cpp:23:23:23:28 | call to getenv | test.cpp:25:7:25:12 | call to strcmp | | -| test.cpp:23:23:23:28 | call to getenv | test.cpp:25:7:25:29 | (bool)... | | -| test.cpp:23:23:23:28 | call to getenv | test.cpp:25:14:25:19 | envStr | | -| test.cpp:23:23:23:28 | call to getenv | test.cpp:29:6:29:28 | ! ... | | -| test.cpp:23:23:23:28 | call to getenv | test.cpp:29:7:29:12 | call to strcmp | | -| test.cpp:23:23:23:28 | call to getenv | test.cpp:29:7:29:28 | (bool)... | | -| test.cpp:23:23:23:28 | call to getenv | test.cpp:29:14:29:19 | envStr | | -| test.cpp:38:23:38:28 | call to getenv | test.cpp:8:24:8:25 | s1 | | -| test.cpp:38:23:38:28 | call to getenv | test.cpp:38:14:38:19 | envStr | | -| test.cpp:38:23:38:28 | call to getenv | test.cpp:38:23:38:28 | call to getenv | | -| test.cpp:38:23:38:28 | call to getenv | test.cpp:38:23:38:40 | (const char *)... | | -| test.cpp:38:23:38:28 | call to getenv | test.cpp:40:14:40:19 | envStr | | -| test.cpp:49:23:49:28 | call to getenv | test.cpp:8:24:8:25 | s1 | | -| test.cpp:49:23:49:28 | call to getenv | test.cpp:45:13:45:24 | envStrGlobal | | -| test.cpp:49:23:49:28 | call to getenv | test.cpp:49:14:49:19 | envStr | | -| test.cpp:49:23:49:28 | call to getenv | test.cpp:49:23:49:28 | call to getenv | | -| test.cpp:49:23:49:28 | call to getenv | test.cpp:49:23:49:40 | (const char *)... | | -| test.cpp:49:23:49:28 | call to getenv | test.cpp:52:16:52:21 | envStr | | -| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:6:54:35 | ! ... | | -| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:7:54:12 | call to strcmp | | -| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:7:54:35 | (bool)... | | -| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:14:54:25 | envStrGlobal | | -| test.cpp:60:29:60:34 | call to getenv | test.cpp:10:27:10:27 | s | | -| test.cpp:60:29:60:34 | call to getenv | test.cpp:60:18:60:25 | userName | | -| test.cpp:60:29:60:34 | call to getenv | test.cpp:60:29:60:34 | call to getenv | | -| test.cpp:60:29:60:34 | call to getenv | test.cpp:60:29:60:47 | (const char *)... | | -| test.cpp:60:29:60:34 | call to getenv | test.cpp:64:25:64:32 | userName | | -| test.cpp:68:28:68:33 | call to getenv | test.cpp:11:36:11:37 | s2 | | -| test.cpp:68:28:68:33 | call to getenv | test.cpp:68:17:68:24 | userName | | -| test.cpp:68:28:68:33 | call to getenv | test.cpp:68:28:68:33 | call to getenv | | -| test.cpp:68:28:68:33 | call to getenv | test.cpp:68:28:68:46 | (const char *)... | | -| test.cpp:68:28:68:33 | call to getenv | test.cpp:70:5:70:10 | call to strcpy | | -| test.cpp:68:28:68:33 | call to getenv | test.cpp:70:18:70:25 | userName | | -| test.cpp:75:20:75:25 | call to getenv | test.cpp:15:22:15:25 | nptr | | -| test.cpp:75:20:75:25 | call to getenv | test.cpp:75:15:75:18 | call to atoi | | -| test.cpp:75:20:75:25 | call to getenv | test.cpp:75:20:75:25 | call to getenv | | -| test.cpp:75:20:75:25 | call to getenv | test.cpp:75:20:75:45 | (const char *)... | | -| test.cpp:83:28:83:33 | call to getenv | test.cpp:8:24:8:25 | s1 | | -| test.cpp:83:28:83:33 | call to getenv | test.cpp:11:36:11:37 | s2 | | -| test.cpp:83:28:83:33 | call to getenv | test.cpp:83:17:83:24 | userName | | -| test.cpp:83:28:83:33 | call to getenv | test.cpp:83:28:83:33 | call to getenv | | -| test.cpp:83:28:83:33 | call to getenv | test.cpp:83:28:83:46 | (const char *)... | | -| test.cpp:83:28:83:33 | call to getenv | test.cpp:86:2:86:7 | call to strcpy | | -| test.cpp:83:28:83:33 | call to getenv | test.cpp:86:15:86:22 | userName | | -| test.cpp:83:28:83:33 | call to getenv | test.cpp:88:6:88:27 | ! ... | | -| test.cpp:83:28:83:33 | call to getenv | test.cpp:88:7:88:12 | call to strcmp | | -| test.cpp:83:28:83:33 | call to getenv | test.cpp:88:7:88:27 | (bool)... | | -| test.cpp:83:28:83:33 | call to getenv | test.cpp:88:14:88:17 | (const char *)... | | -| test.cpp:83:28:83:33 | call to getenv | test.cpp:88:14:88:17 | copy | | -| test.cpp:100:12:100:15 | call to gets | test.cpp:98:8:98:14 | pointer | | -| test.cpp:100:12:100:15 | call to gets | test.cpp:100:12:100:15 | call to gets | | -| test.cpp:100:17:100:22 | buffer | test.cpp:93:18:93:18 | s | | -| test.cpp:100:17:100:22 | buffer | test.cpp:100:17:100:22 | array to pointer conversion | | -| test.cpp:100:17:100:22 | buffer | test.cpp:100:17:100:22 | buffer | | -| test.cpp:106:28:106:33 | call to getenv | test.cpp:8:24:8:25 | s1 | | -| test.cpp:106:28:106:33 | call to getenv | test.cpp:11:36:11:37 | s2 | | -| test.cpp:106:28:106:33 | call to getenv | test.cpp:106:17:106:24 | userName | | -| test.cpp:106:28:106:33 | call to getenv | test.cpp:106:28:106:33 | call to getenv | | -| test.cpp:106:28:106:33 | call to getenv | test.cpp:106:28:106:46 | (const char *)... | | -| test.cpp:106:28:106:33 | call to getenv | test.cpp:109:2:109:7 | call to strcpy | | -| test.cpp:106:28:106:33 | call to getenv | test.cpp:109:15:109:22 | userName | | -| test.cpp:106:28:106:33 | call to getenv | test.cpp:111:6:111:27 | ! ... | | -| test.cpp:106:28:106:33 | call to getenv | test.cpp:111:7:111:12 | call to strcmp | | -| test.cpp:106:28:106:33 | call to getenv | test.cpp:111:7:111:27 | (bool)... | | -| test.cpp:106:28:106:33 | call to getenv | test.cpp:111:14:111:17 | (const char *)... | | -| test.cpp:106:28:106:33 | call to getenv | test.cpp:111:14:111:17 | copy | | +| test.cpp:23:23:23:28 | call to getenv | test.cpp:23:23:23:28 | call to getenv | +| test.cpp:23:23:23:28 | call to getenv | test.cpp:23:23:23:40 | (const char *)... | +| test.cpp:23:23:23:28 | call to getenv | test.cpp:25:6:25:29 | ! ... | +| test.cpp:23:23:23:28 | call to getenv | test.cpp:25:7:25:12 | call to strcmp | +| test.cpp:23:23:23:28 | call to getenv | test.cpp:25:7:25:29 | (bool)... | +| test.cpp:23:23:23:28 | call to getenv | test.cpp:25:14:25:19 | envStr | +| test.cpp:23:23:23:28 | call to getenv | test.cpp:29:6:29:28 | ! ... | +| test.cpp:23:23:23:28 | call to getenv | test.cpp:29:7:29:12 | call to strcmp | +| test.cpp:23:23:23:28 | call to getenv | test.cpp:29:7:29:28 | (bool)... | +| test.cpp:23:23:23:28 | call to getenv | test.cpp:29:14:29:19 | envStr | +| test.cpp:38:23:38:28 | call to getenv | test.cpp:38:23:38:28 | call to getenv | +| test.cpp:38:23:38:28 | call to getenv | test.cpp:38:23:38:40 | (const char *)... | +| test.cpp:38:23:38:28 | call to getenv | test.cpp:40:14:40:19 | envStr | +| test.cpp:49:23:49:28 | call to getenv | test.cpp:49:23:49:28 | call to getenv | +| test.cpp:49:23:49:28 | call to getenv | test.cpp:49:23:49:40 | (const char *)... | +| test.cpp:49:23:49:28 | call to getenv | test.cpp:52:16:52:21 | envStr | +| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:6:54:35 | ! ... | +| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:7:54:12 | call to strcmp | +| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:7:54:35 | (bool)... | +| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:14:54:25 | envStrGlobal | +| test.cpp:60:29:60:34 | call to getenv | test.cpp:60:29:60:34 | call to getenv | +| test.cpp:60:29:60:34 | call to getenv | test.cpp:60:29:60:47 | (const char *)... | +| test.cpp:60:29:60:34 | call to getenv | test.cpp:64:25:64:32 | userName | +| test.cpp:68:28:68:33 | call to getenv | test.cpp:68:28:68:33 | call to getenv | +| test.cpp:68:28:68:33 | call to getenv | test.cpp:68:28:68:46 | (const char *)... | +| test.cpp:68:28:68:33 | call to getenv | test.cpp:70:18:70:25 | userName | +| test.cpp:75:20:75:25 | call to getenv | test.cpp:75:15:75:18 | call to atoi | +| test.cpp:75:20:75:25 | call to getenv | test.cpp:75:20:75:25 | call to getenv | +| test.cpp:75:20:75:25 | call to getenv | test.cpp:75:20:75:45 | (const char *)... | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:83:28:83:33 | call to getenv | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:83:28:83:46 | (const char *)... | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:86:15:86:22 | userName | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:88:6:88:27 | ! ... | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:88:7:88:12 | call to strcmp | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:88:7:88:27 | (bool)... | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:88:14:88:17 | copy | +| test.cpp:100:12:100:15 | call to gets | test.cpp:100:12:100:15 | call to gets | +| test.cpp:100:17:100:22 | buffer | test.cpp:100:17:100:22 | array to pointer conversion | +| test.cpp:100:17:100:22 | buffer | test.cpp:100:17:100:22 | buffer | +| test.cpp:106:28:106:33 | call to getenv | test.cpp:106:28:106:33 | call to getenv | +| test.cpp:106:28:106:33 | call to getenv | test.cpp:106:28:106:46 | (const char *)... | +| test.cpp:106:28:106:33 | call to getenv | test.cpp:109:15:109:22 | userName | +| test.cpp:106:28:106:33 | call to getenv | test.cpp:111:6:111:27 | ! ... | +| test.cpp:106:28:106:33 | call to getenv | test.cpp:111:7:111:12 | call to strcmp | +| test.cpp:106:28:106:33 | call to getenv | test.cpp:111:7:111:27 | (bool)... | +| test.cpp:106:28:106:33 | call to getenv | test.cpp:111:14:111:17 | copy | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected index a9eaa898a11..88f79183d2a 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected @@ -200,7 +200,6 @@ | taint.cpp:42:7:42:13 | taint.cpp:35:12:35:17 | AST only | | taint.cpp:43:7:43:13 | taint.cpp:37:22:37:27 | AST only | | taint.cpp:137:7:137:9 | taint.cpp:120:11:120:16 | AST only | -| taint.cpp:195:7:195:7 | taint.cpp:192:23:192:28 | AST only | | taint.cpp:195:7:195:7 | taint.cpp:193:6:193:6 | AST only | | taint.cpp:236:3:236:6 | taint.cpp:223:10:223:15 | AST only | | taint.cpp:372:7:372:7 | taint.cpp:365:24:365:29 | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected index 5ba1707dd76..e84ce0d4c2e 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected @@ -513,6 +513,7 @@ | taint.cpp:168:8:168:14 | tainted | taint.cpp:164:19:164:24 | call to source | | taint.cpp:173:8:173:13 | Argument 0 indirection | taint.cpp:164:19:164:24 | call to source | | taint.cpp:181:8:181:9 | * ... | taint.cpp:185:11:185:16 | call to source | +| taint.cpp:195:7:195:7 | x | taint.cpp:192:23:192:28 | source | | taint.cpp:210:7:210:7 | x | taint.cpp:207:6:207:11 | call to source | | taint.cpp:215:7:215:7 | x | taint.cpp:207:6:207:11 | call to source | | taint.cpp:216:7:216:7 | y | taint.cpp:207:6:207:11 | call to source | From 68040b717e55045593ab63d7687059aefa74f7cc Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Thu, 12 Nov 2020 14:32:19 -0800 Subject: [PATCH 010/725] C++: autoformat --- .../library-tests/dataflow/security-taint/tainted_ir.ql | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/security-taint/tainted_ir.ql b/cpp/ql/test/library-tests/dataflow/security-taint/tainted_ir.ql index 77f04d301f0..2a07e444cf9 100644 --- a/cpp/ql/test/library-tests/dataflow/security-taint/tainted_ir.ql +++ b/cpp/ql/test/library-tests/dataflow/security-taint/tainted_ir.ql @@ -1,13 +1,11 @@ import semmle.code.cpp.ir.dataflow.DefaultTaintTracking class SourceConfiguration extends TaintedWithPath::TaintTrackingConfiguration { - override predicate isSink(Element e) { - any() - } + override predicate isSink(Element e) { any() } } from Expr source, Element tainted where TaintedWithPath::taintedWithPath(source, tainted, _, _) and not tainted.getLocation().getFile().getExtension() = "h" -select source, tainted \ No newline at end of file +select source, tainted From bd00988c372ba09d0c88f3aa2eafc93bd4aae54f Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Thu, 12 Nov 2020 14:38:53 -0800 Subject: [PATCH 011/725] C++: accept test output for DefaultTaintTracking --- .../DefaultTaintTracking/tainted.expected | 162 ++---------------- .../DefaultTaintTracking/test_diff.expected | 91 ++++------ 2 files changed, 48 insertions(+), 205 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected index ea756d0efc5..9f8ed0d28d3 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected @@ -1,105 +1,55 @@ -| defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:16:8:16:14 | call to _strdup | -| defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:16:8:16:29 | (const char *)... | | defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:16:16:16:21 | call to getenv | | defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:16:16:16:28 | (const char *)... | -| defaulttainttracking.cpp:16:16:16:21 | call to getenv | shared.h:5:23:5:31 | sinkparam | -| defaulttainttracking.cpp:16:16:16:21 | call to getenv | shared.h:13:27:13:32 | string | -| defaulttainttracking.cpp:17:15:17:20 | call to getenv | defaulttainttracking.cpp:17:8:17:13 | call to strdup | -| defaulttainttracking.cpp:17:15:17:20 | call to getenv | defaulttainttracking.cpp:17:8:17:28 | (const char *)... | | defaulttainttracking.cpp:17:15:17:20 | call to getenv | defaulttainttracking.cpp:17:15:17:20 | call to getenv | | defaulttainttracking.cpp:17:15:17:20 | call to getenv | defaulttainttracking.cpp:17:15:17:27 | (const char *)... | -| defaulttainttracking.cpp:17:15:17:20 | call to getenv | shared.h:5:23:5:31 | sinkparam | -| defaulttainttracking.cpp:17:15:17:20 | call to getenv | shared.h:12:26:12:31 | string | | defaulttainttracking.cpp:18:27:18:32 | call to getenv | defaulttainttracking.cpp:18:27:18:32 | call to getenv | | defaulttainttracking.cpp:18:27:18:32 | call to getenv | defaulttainttracking.cpp:18:27:18:39 | (const char *)... | -| defaulttainttracking.cpp:18:27:18:32 | call to getenv | shared.h:14:38:14:49 | const_string | -| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:22:8:22:13 | call to strcat | -| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:22:8:22:33 | (const char *)... | | defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:22:20:22:25 | call to getenv | | defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:22:20:22:32 | (const char *)... | -| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:24:8:24:10 | (const char *)... | -| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:24:8:24:10 | array to pointer conversion | | defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:24:8:24:10 | buf | -| defaulttainttracking.cpp:22:20:22:25 | call to getenv | shared.h:5:23:5:31 | sinkparam | -| defaulttainttracking.cpp:22:20:22:25 | call to getenv | shared.h:10:38:10:39 | s2 | -| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:31:40:31:53 | dotted_address | -| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:32:11:32:26 | (unnamed parameter 0) | -| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:38:11:38:21 | env_pointer | | defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:38:25:38:30 | call to getenv | | defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:38:25:38:37 | (void *)... | -| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:39:22:39:22 | a | | defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:39:26:39:34 | call to inet_addr | -| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:39:36:39:61 | (const char *)... | | defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:39:50:39:61 | & ... | | defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:40:10:40:10 | a | -| defaulttainttracking.cpp:64:10:64:15 | call to getenv | defaulttainttracking.cpp:45:20:45:29 | (unnamed parameter 0) | -| defaulttainttracking.cpp:64:10:64:15 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p | -| defaulttainttracking.cpp:64:10:64:15 | call to getenv | defaulttainttracking.cpp:57:24:57:24 | p | | defaulttainttracking.cpp:64:10:64:15 | call to getenv | defaulttainttracking.cpp:58:14:58:14 | p | | defaulttainttracking.cpp:64:10:64:15 | call to getenv | defaulttainttracking.cpp:64:10:64:15 | call to getenv | | defaulttainttracking.cpp:64:10:64:15 | call to getenv | defaulttainttracking.cpp:64:10:64:22 | (const char *)... | -| defaulttainttracking.cpp:64:10:64:15 | call to getenv | shared.h:5:23:5:31 | sinkparam | -| defaulttainttracking.cpp:66:17:66:22 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p | -| defaulttainttracking.cpp:66:17:66:22 | call to getenv | defaulttainttracking.cpp:57:24:57:24 | p | | defaulttainttracking.cpp:66:17:66:22 | call to getenv | defaulttainttracking.cpp:58:14:58:14 | p | | defaulttainttracking.cpp:66:17:66:22 | call to getenv | defaulttainttracking.cpp:66:17:66:22 | call to getenv | | defaulttainttracking.cpp:66:17:66:22 | call to getenv | defaulttainttracking.cpp:66:17:66:29 | (const char *)... | -| defaulttainttracking.cpp:66:17:66:22 | call to getenv | shared.h:5:23:5:31 | sinkparam | -| defaulttainttracking.cpp:67:28:67:33 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p | -| defaulttainttracking.cpp:67:28:67:33 | call to getenv | defaulttainttracking.cpp:57:24:57:24 | p | | defaulttainttracking.cpp:67:28:67:33 | call to getenv | defaulttainttracking.cpp:58:14:58:14 | p | | defaulttainttracking.cpp:67:28:67:33 | call to getenv | defaulttainttracking.cpp:67:28:67:33 | call to getenv | | defaulttainttracking.cpp:67:28:67:33 | call to getenv | defaulttainttracking.cpp:67:28:67:40 | (const char *)... | -| defaulttainttracking.cpp:67:28:67:33 | call to getenv | shared.h:5:23:5:31 | sinkparam | -| defaulttainttracking.cpp:68:29:68:34 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p | -| defaulttainttracking.cpp:68:29:68:34 | call to getenv | defaulttainttracking.cpp:57:24:57:24 | p | | defaulttainttracking.cpp:68:29:68:34 | call to getenv | defaulttainttracking.cpp:58:14:58:14 | p | | defaulttainttracking.cpp:68:29:68:34 | call to getenv | defaulttainttracking.cpp:68:29:68:34 | call to getenv | | defaulttainttracking.cpp:68:29:68:34 | call to getenv | defaulttainttracking.cpp:68:29:68:41 | (const char *)... | -| defaulttainttracking.cpp:68:29:68:34 | call to getenv | shared.h:5:23:5:31 | sinkparam | -| defaulttainttracking.cpp:69:33:69:38 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p | -| defaulttainttracking.cpp:69:33:69:38 | call to getenv | defaulttainttracking.cpp:57:24:57:24 | p | | defaulttainttracking.cpp:69:33:69:38 | call to getenv | defaulttainttracking.cpp:58:14:58:14 | p | | defaulttainttracking.cpp:69:33:69:38 | call to getenv | defaulttainttracking.cpp:69:33:69:38 | call to getenv | | defaulttainttracking.cpp:69:33:69:38 | call to getenv | defaulttainttracking.cpp:69:33:69:45 | (const char *)... | -| defaulttainttracking.cpp:69:33:69:38 | call to getenv | shared.h:5:23:5:31 | sinkparam | -| defaulttainttracking.cpp:72:11:72:16 | call to getenv | defaulttainttracking.cpp:45:20:45:29 | (unnamed parameter 0) | -| defaulttainttracking.cpp:72:11:72:16 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p | | defaulttainttracking.cpp:72:11:72:16 | call to getenv | defaulttainttracking.cpp:72:11:72:16 | call to getenv | | defaulttainttracking.cpp:72:11:72:16 | call to getenv | defaulttainttracking.cpp:72:11:72:23 | (const char *)... | -| defaulttainttracking.cpp:74:18:74:23 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p | | defaulttainttracking.cpp:74:18:74:23 | call to getenv | defaulttainttracking.cpp:74:18:74:23 | call to getenv | | defaulttainttracking.cpp:74:18:74:23 | call to getenv | defaulttainttracking.cpp:74:18:74:30 | (const char *)... | -| defaulttainttracking.cpp:75:29:75:34 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p | | defaulttainttracking.cpp:75:29:75:34 | call to getenv | defaulttainttracking.cpp:75:29:75:34 | call to getenv | | defaulttainttracking.cpp:75:29:75:34 | call to getenv | defaulttainttracking.cpp:75:29:75:41 | (const char *)... | -| defaulttainttracking.cpp:76:30:76:35 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p | | defaulttainttracking.cpp:76:30:76:35 | call to getenv | defaulttainttracking.cpp:76:30:76:35 | call to getenv | | defaulttainttracking.cpp:76:30:76:35 | call to getenv | defaulttainttracking.cpp:76:30:76:42 | (const char *)... | -| defaulttainttracking.cpp:77:34:77:39 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p | | defaulttainttracking.cpp:77:34:77:39 | call to getenv | defaulttainttracking.cpp:77:34:77:39 | call to getenv | | defaulttainttracking.cpp:77:34:77:39 | call to getenv | defaulttainttracking.cpp:77:34:77:46 | (const char *)... | -| defaulttainttracking.cpp:79:30:79:35 | call to getenv | defaulttainttracking.cpp:57:24:57:24 | p | | defaulttainttracking.cpp:79:30:79:35 | call to getenv | defaulttainttracking.cpp:58:14:58:14 | p | | defaulttainttracking.cpp:79:30:79:35 | call to getenv | defaulttainttracking.cpp:79:30:79:35 | call to getenv | | defaulttainttracking.cpp:79:30:79:35 | call to getenv | defaulttainttracking.cpp:79:30:79:42 | (const char *)... | -| defaulttainttracking.cpp:79:30:79:35 | call to getenv | shared.h:5:23:5:31 | sinkparam | -| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:84:17:84:17 | t | | defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:8:88:16 | call to move | | defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:8:88:32 | (const char *)... | | defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:8:88:32 | (reference dereference) | | defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:18:88:23 | call to getenv | | defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:18:88:30 | (reference to) | | defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:18:88:30 | temporary object | -| defaulttainttracking.cpp:88:18:88:23 | call to getenv | shared.h:5:23:5:31 | sinkparam | -| defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:91:42:91:44 | arg | | defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:92:12:92:14 | arg | -| defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:96:11:96:12 | p2 | | defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:97:27:97:32 | call to getenv | | defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:98:10:98:11 | (const char *)... | | defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:98:10:98:11 | p2 | -| defaulttainttracking.cpp:97:27:97:32 | call to getenv | shared.h:5:23:5:31 | sinkparam | -| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:110:7:110:13 | tainted | | defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:110:17:110:22 | call to getenv | | defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:110:17:110:32 | (int)... | | defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:110:17:110:32 | access to array | @@ -109,17 +59,14 @@ | defaulttainttracking.cpp:133:9:133:14 | call to getenv | defaulttainttracking.cpp:133:9:133:24 | (int)... | | defaulttainttracking.cpp:133:9:133:14 | call to getenv | defaulttainttracking.cpp:133:9:133:24 | access to array | | defaulttainttracking.cpp:133:9:133:14 | call to getenv | defaulttainttracking.cpp:134:10:134:10 | x | -| defaulttainttracking.cpp:133:9:133:14 | call to getenv | shared.h:6:15:6:23 | sinkparam | | defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:140:11:140:16 | call to getenv | | defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:140:11:140:26 | (int)... | | defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:140:11:140:26 | access to array | | defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:166:10:166:10 | x | -| defaulttainttracking.cpp:140:11:140:16 | call to getenv | shared.h:6:15:6:23 | sinkparam | | defaulttainttracking.cpp:157:9:157:14 | call to getenv | defaulttainttracking.cpp:157:9:157:14 | call to getenv | | defaulttainttracking.cpp:157:9:157:14 | call to getenv | defaulttainttracking.cpp:157:9:157:24 | (int)... | | defaulttainttracking.cpp:157:9:157:14 | call to getenv | defaulttainttracking.cpp:157:9:157:24 | access to array | | defaulttainttracking.cpp:157:9:157:14 | call to getenv | defaulttainttracking.cpp:159:10:159:10 | x | -| defaulttainttracking.cpp:157:9:157:14 | call to getenv | shared.h:6:15:6:23 | sinkparam | | defaulttainttracking.cpp:170:11:170:16 | call to getenv | defaulttainttracking.cpp:170:11:170:16 | call to getenv | | defaulttainttracking.cpp:170:11:170:16 | call to getenv | defaulttainttracking.cpp:170:11:170:26 | (int)... | | defaulttainttracking.cpp:170:11:170:16 | call to getenv | defaulttainttracking.cpp:170:11:170:26 | access to array | @@ -135,84 +82,48 @@ | defaulttainttracking.cpp:208:27:208:32 | call to getenv | defaulttainttracking.cpp:208:27:208:32 | call to getenv | | defaulttainttracking.cpp:208:27:208:32 | call to getenv | defaulttainttracking.cpp:208:27:208:42 | (int)... | | defaulttainttracking.cpp:208:27:208:32 | call to getenv | defaulttainttracking.cpp:208:27:208:42 | access to array | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:218:8:218:8 | s | | defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:218:12:218:17 | call to getenv | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:224:2:224:7 | call to memcpy | | defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:224:17:224:17 | (const void *)... | | defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:224:17:224:17 | s | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:228:7:228:12 | (const char *)... | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:228:7:228:12 | array to pointer conversion | | defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:228:7:228:12 | buffer | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:229:7:229:10 | (const char *)... | | defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:229:7:229:10 | ptr1 | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:232:7:232:10 | (const char *)... | | defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:232:7:232:10 | ptr3 | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | shared.h:5:23:5:31 | sinkparam | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | shared.h:17:36:17:37 | s2 | -| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:240:8:240:8 | s | | defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:240:12:240:17 | call to getenv | -| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:246:2:246:7 | call to memcpy | | defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:246:16:246:16 | (const void *)... | | defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:246:16:246:16 | s | -| defaulttainttracking.cpp:240:12:240:17 | call to getenv | shared.h:17:36:17:37 | s2 | | dispatch.cpp:28:29:28:34 | call to getenv | dispatch.cpp:28:24:28:27 | call to atoi | | dispatch.cpp:28:29:28:34 | call to getenv | dispatch.cpp:28:29:28:34 | call to getenv | | dispatch.cpp:28:29:28:34 | call to getenv | dispatch.cpp:28:29:28:45 | (const char *)... | -| dispatch.cpp:28:29:28:34 | call to getenv | shared.h:8:22:8:25 | nptr | | dispatch.cpp:29:32:29:37 | call to getenv | dispatch.cpp:29:27:29:30 | call to atoi | | dispatch.cpp:29:32:29:37 | call to getenv | dispatch.cpp:29:32:29:37 | call to getenv | | dispatch.cpp:29:32:29:37 | call to getenv | dispatch.cpp:29:32:29:48 | (const char *)... | -| dispatch.cpp:29:32:29:37 | call to getenv | shared.h:8:22:8:25 | nptr | -| dispatch.cpp:31:28:31:33 | call to getenv | dispatch.cpp:7:20:7:28 | sinkParam | | dispatch.cpp:31:28:31:33 | call to getenv | dispatch.cpp:8:8:8:16 | sinkParam | | dispatch.cpp:31:28:31:33 | call to getenv | dispatch.cpp:31:23:31:26 | call to atoi | | dispatch.cpp:31:28:31:33 | call to getenv | dispatch.cpp:31:28:31:33 | call to getenv | | dispatch.cpp:31:28:31:33 | call to getenv | dispatch.cpp:31:28:31:44 | (const char *)... | -| dispatch.cpp:31:28:31:33 | call to getenv | shared.h:6:15:6:23 | sinkparam | -| dispatch.cpp:31:28:31:33 | call to getenv | shared.h:8:22:8:25 | nptr | -| dispatch.cpp:32:31:32:36 | call to getenv | dispatch.cpp:7:20:7:28 | sinkParam | | dispatch.cpp:32:31:32:36 | call to getenv | dispatch.cpp:8:8:8:16 | sinkParam | | dispatch.cpp:32:31:32:36 | call to getenv | dispatch.cpp:32:26:32:29 | call to atoi | | dispatch.cpp:32:31:32:36 | call to getenv | dispatch.cpp:32:31:32:36 | call to getenv | | dispatch.cpp:32:31:32:36 | call to getenv | dispatch.cpp:32:31:32:47 | (const char *)... | -| dispatch.cpp:32:31:32:36 | call to getenv | shared.h:6:15:6:23 | sinkparam | -| dispatch.cpp:32:31:32:36 | call to getenv | shared.h:8:22:8:25 | nptr | -| dispatch.cpp:34:22:34:27 | call to getenv | dispatch.cpp:7:20:7:28 | sinkParam | | dispatch.cpp:34:22:34:27 | call to getenv | dispatch.cpp:8:8:8:16 | sinkParam | | dispatch.cpp:34:22:34:27 | call to getenv | dispatch.cpp:34:17:34:20 | call to atoi | | dispatch.cpp:34:22:34:27 | call to getenv | dispatch.cpp:34:22:34:27 | call to getenv | | dispatch.cpp:34:22:34:27 | call to getenv | dispatch.cpp:34:22:34:38 | (const char *)... | -| dispatch.cpp:34:22:34:27 | call to getenv | shared.h:6:15:6:23 | sinkparam | -| dispatch.cpp:34:22:34:27 | call to getenv | shared.h:8:22:8:25 | nptr | -| globals.cpp:5:20:5:25 | call to getenv | globals.cpp:5:12:5:16 | local | | globals.cpp:5:20:5:25 | call to getenv | globals.cpp:5:20:5:25 | call to getenv | | globals.cpp:5:20:5:25 | call to getenv | globals.cpp:6:10:6:14 | (const char *)... | | globals.cpp:5:20:5:25 | call to getenv | globals.cpp:6:10:6:14 | local | -| globals.cpp:5:20:5:25 | call to getenv | shared.h:5:23:5:31 | sinkparam | -| globals.cpp:13:15:13:20 | call to getenv | globals.cpp:9:8:9:14 | global1 | | globals.cpp:13:15:13:20 | call to getenv | globals.cpp:13:15:13:20 | call to getenv | -| globals.cpp:23:15:23:20 | call to getenv | globals.cpp:16:15:16:21 | global2 | | globals.cpp:23:15:23:20 | call to getenv | globals.cpp:23:15:23:20 | call to getenv | -| stl.cpp:62:25:62:30 | call to getenv | shared.h:5:23:5:31 | sinkparam | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:21:29:21:29 | s | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:43:78:43:104 | (unnamed parameter 0) | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:43:114:43:118 | (unnamed parameter 1) | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:44:176:44:178 | str | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:62:25:62:30 | call to getenv | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:63:30:63:30 | s | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:64:36:64:36 | s | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:68:8:68:8 | a | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:68:12:68:17 | call to source | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:70:16:70:21 | call to source | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:70:16:70:23 | (const char *)... | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:70:16:70:24 | call to basic_string | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:72:7:72:7 | (const char *)... | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:72:7:72:7 | a | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:74:7:74:7 | (const string)... | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:74:7:74:7 | (reference to) | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:74:7:74:7 | c | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:76:7:76:7 | (const basic_string, allocator>)... | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:76:7:76:7 | c | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:76:9:76:13 | call to c_str | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:82:16:82:21 | call to source | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:82:16:82:23 | (const char *)... | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:82:16:82:24 | call to basic_string | @@ -231,80 +142,60 @@ | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:9:87:16 | (const char *)... | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:18:87:18 | call to operator<< | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:18:87:26 | (reference dereference) | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:88:6:88:6 | call to operator<< | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:88:6:88:10 | (reference dereference) | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:88:9:88:9 | (const basic_string, allocator>)... | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:88:9:88:9 | (reference to) | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:88:9:88:9 | t | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:91:7:91:9 | (const stringstream)... | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:91:7:91:9 | (reference to) | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:91:7:91:9 | ss2 | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:93:7:93:9 | (const stringstream)... | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:93:7:93:9 | (reference to) | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:93:7:93:9 | ss4 | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:94:7:94:9 | (const stringstream)... | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:94:7:94:9 | (reference to) | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:94:7:94:9 | ss5 | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:96:7:96:9 | (const basic_stringstream, allocator>)... | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:96:7:96:9 | ss2 | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:98:7:98:9 | (const basic_stringstream, allocator>)... | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:96:7:96:15 | (const string)... | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:96:7:96:15 | (reference to) | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:96:7:96:15 | temporary object | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:96:11:96:13 | call to str | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:98:7:98:9 | ss4 | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:99:7:99:9 | (const basic_stringstream, allocator>)... | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:99:7:99:9 | ss5 | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:98:7:98:15 | (const string)... | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:98:7:98:15 | (reference to) | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:98:7:98:15 | temporary object | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:98:11:98:13 | call to str | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:118:10:118:15 | call to source | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:125:16:125:28 | call to basic_string | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:125:17:125:26 | call to user_input | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:125:17:125:28 | (const char *)... | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:126:7:126:11 | (const basic_string, allocator>)... | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:126:7:126:11 | path1 | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:128:9:128:13 | path2 | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:126:13:126:17 | call to c_str | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:129:10:129:19 | call to user_input | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:129:10:129:21 | (const char *)... | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:129:10:129:21 | call to basic_string | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:129:10:129:21 | temporary object | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:130:7:130:11 | (const basic_string, allocator>)... | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:130:7:130:11 | path2 | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:130:13:130:17 | call to c_str | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:132:15:132:24 | call to user_input | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:132:15:132:26 | (const char *)... | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:132:15:132:27 | call to basic_string | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:133:7:133:11 | (const basic_string, allocator>)... | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:133:7:133:11 | path3 | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:138:14:138:15 | cs | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:133:13:133:17 | call to c_str | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:138:19:138:24 | call to source | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:138:19:138:26 | (const char *)... | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:141:17:141:18 | cs | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:141:17:141:19 | call to basic_string | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:143:7:143:8 | cs | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:144:7:144:8 | (const string)... | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:144:7:144:8 | (reference to) | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:144:7:144:8 | ss | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:149:14:149:15 | cs | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:149:19:149:24 | call to source | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:149:19:149:26 | (const char *)... | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:152:17:152:18 | cs | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:152:17:152:19 | call to basic_string | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:155:7:155:8 | (const basic_string, allocator>)... | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:155:7:155:8 | ss | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:158:7:158:8 | (const string)... | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:158:7:158:8 | (reference to) | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:155:10:155:14 | call to c_str | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:157:7:157:8 | cs | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:158:7:158:8 | ss | -| test_diff.cpp:92:10:92:13 | argv | shared.h:5:23:5:31 | sinkparam | | test_diff.cpp:92:10:92:13 | argv | test_diff.cpp:92:10:92:13 | argv | | test_diff.cpp:92:10:92:13 | argv | test_diff.cpp:92:10:92:16 | (const char *)... | | test_diff.cpp:92:10:92:13 | argv | test_diff.cpp:92:10:92:16 | access to array | -| test_diff.cpp:94:32:94:35 | argv | shared.h:6:15:6:23 | sinkparam | | test_diff.cpp:94:32:94:35 | argv | test_diff.cpp:94:10:94:36 | reinterpret_cast... | | test_diff.cpp:94:32:94:35 | argv | test_diff.cpp:94:32:94:35 | argv | -| test_diff.cpp:96:26:96:29 | argv | shared.h:5:23:5:31 | sinkparam | -| test_diff.cpp:96:26:96:29 | argv | test_diff.cpp:16:39:16:39 | a | | test_diff.cpp:96:26:96:29 | argv | test_diff.cpp:17:10:17:10 | a | | test_diff.cpp:96:26:96:29 | argv | test_diff.cpp:96:26:96:29 | argv | | test_diff.cpp:96:26:96:29 | argv | test_diff.cpp:96:26:96:32 | (const char *)... | | test_diff.cpp:96:26:96:29 | argv | test_diff.cpp:96:26:96:32 | access to array | -| test_diff.cpp:98:18:98:21 | argv | shared.h:5:23:5:31 | sinkparam | -| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:16:39:16:39 | a | | test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:17:10:17:10 | a | -| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:98:13:98:13 | p | | test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:98:17:98:21 | & ... | | test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:98:18:98:21 | argv | | test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:100:10:100:14 | (const char *)... | @@ -315,65 +206,40 @@ | test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:102:26:102:30 | * ... | | test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:102:27:102:27 | p | | test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:102:27:102:30 | access to array | -| test_diff.cpp:104:12:104:15 | argv | shared.h:5:23:5:31 | sinkparam | | test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:10:104:20 | (const char *)... | | test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:10:104:20 | * ... | | test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:11:104:20 | (...) | | test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:12:104:15 | argv | | test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:12:104:19 | ... + ... | -| test_diff.cpp:108:10:108:13 | argv | shared.h:5:23:5:31 | sinkparam | -| test_diff.cpp:108:10:108:13 | argv | test_diff.cpp:24:20:24:29 | (unnamed parameter 0) | -| test_diff.cpp:108:10:108:13 | argv | test_diff.cpp:29:24:29:24 | p | | test_diff.cpp:108:10:108:13 | argv | test_diff.cpp:30:14:30:14 | p | | test_diff.cpp:108:10:108:13 | argv | test_diff.cpp:108:10:108:13 | argv | | test_diff.cpp:108:10:108:13 | argv | test_diff.cpp:108:10:108:16 | (const char *)... | | test_diff.cpp:108:10:108:13 | argv | test_diff.cpp:108:10:108:16 | access to array | -| test_diff.cpp:111:10:111:13 | argv | test_diff.cpp:24:20:24:29 | (unnamed parameter 0) | -| test_diff.cpp:111:10:111:13 | argv | test_diff.cpp:36:24:36:24 | p | | test_diff.cpp:111:10:111:13 | argv | test_diff.cpp:111:10:111:13 | argv | | test_diff.cpp:111:10:111:13 | argv | test_diff.cpp:111:10:111:16 | (const char *)... | | test_diff.cpp:111:10:111:13 | argv | test_diff.cpp:111:10:111:16 | access to array | -| test_diff.cpp:115:11:115:14 | argv | shared.h:5:23:5:31 | sinkparam | -| test_diff.cpp:115:11:115:14 | argv | test_diff.cpp:24:20:24:29 | (unnamed parameter 0) | -| test_diff.cpp:115:11:115:14 | argv | test_diff.cpp:41:24:41:24 | p | | test_diff.cpp:115:11:115:14 | argv | test_diff.cpp:42:14:42:14 | p | -| test_diff.cpp:115:11:115:14 | argv | test_diff.cpp:52:24:52:24 | p | | test_diff.cpp:115:11:115:14 | argv | test_diff.cpp:53:37:53:37 | p | | test_diff.cpp:115:11:115:14 | argv | test_diff.cpp:115:11:115:14 | argv | | test_diff.cpp:115:11:115:14 | argv | test_diff.cpp:115:11:115:17 | (const char *)... | | test_diff.cpp:115:11:115:14 | argv | test_diff.cpp:115:11:115:17 | access to array | -| test_diff.cpp:118:26:118:29 | argv | test_diff.cpp:60:24:60:24 | p | | test_diff.cpp:118:26:118:29 | argv | test_diff.cpp:61:34:61:34 | p | -| test_diff.cpp:118:26:118:29 | argv | test_diff.cpp:88:24:88:24 | p | | test_diff.cpp:118:26:118:29 | argv | test_diff.cpp:118:26:118:29 | argv | | test_diff.cpp:118:26:118:29 | argv | test_diff.cpp:118:26:118:32 | (const char *)... | | test_diff.cpp:118:26:118:29 | argv | test_diff.cpp:118:26:118:32 | access to array | -| test_diff.cpp:121:23:121:26 | argv | shared.h:5:23:5:31 | sinkparam | -| test_diff.cpp:121:23:121:26 | argv | test_diff.cpp:60:24:60:24 | p | | test_diff.cpp:121:23:121:26 | argv | test_diff.cpp:61:34:61:34 | p | -| test_diff.cpp:121:23:121:26 | argv | test_diff.cpp:67:24:67:24 | p | | test_diff.cpp:121:23:121:26 | argv | test_diff.cpp:68:14:68:14 | p | | test_diff.cpp:121:23:121:26 | argv | test_diff.cpp:121:23:121:26 | argv | | test_diff.cpp:121:23:121:26 | argv | test_diff.cpp:121:23:121:29 | (const char *)... | | test_diff.cpp:121:23:121:26 | argv | test_diff.cpp:121:23:121:29 | access to array | -| test_diff.cpp:124:19:124:22 | argv | shared.h:5:23:5:31 | sinkparam | -| test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:24:20:24:29 | (unnamed parameter 0) | -| test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:76:24:76:24 | p | -| test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:81:24:81:24 | p | | test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:82:14:82:14 | p | | test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:124:19:124:22 | argv | | test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:124:19:124:25 | (const char *)... | | test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:124:19:124:25 | access to array | -| test_diff.cpp:126:43:126:46 | argv | shared.h:5:23:5:31 | sinkparam | -| test_diff.cpp:126:43:126:46 | argv | test_diff.cpp:76:24:76:24 | p | -| test_diff.cpp:126:43:126:46 | argv | test_diff.cpp:81:24:81:24 | p | | test_diff.cpp:126:43:126:46 | argv | test_diff.cpp:82:14:82:14 | p | | test_diff.cpp:126:43:126:46 | argv | test_diff.cpp:126:43:126:46 | argv | | test_diff.cpp:126:43:126:46 | argv | test_diff.cpp:126:43:126:49 | (const char *)... | | test_diff.cpp:126:43:126:46 | argv | test_diff.cpp:126:43:126:49 | access to array | -| test_diff.cpp:128:44:128:47 | argv | shared.h:5:23:5:31 | sinkparam | -| test_diff.cpp:128:44:128:47 | argv | test_diff.cpp:76:24:76:24 | p | -| test_diff.cpp:128:44:128:47 | argv | test_diff.cpp:81:24:81:24 | p | | test_diff.cpp:128:44:128:47 | argv | test_diff.cpp:82:14:82:14 | p | | test_diff.cpp:128:44:128:47 | argv | test_diff.cpp:128:44:128:47 | argv | | test_diff.cpp:128:44:128:47 | argv | test_diff.cpp:128:44:128:50 | (const char *)... | diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected index 8d7963b2156..ffc640c15f3 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected @@ -1,44 +1,38 @@ -| defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:16:8:16:14 | call to _strdup | IR only | -| defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:16:8:16:29 | (const char *)... | IR only | -| defaulttainttracking.cpp:16:16:16:21 | call to getenv | shared.h:5:23:5:31 | sinkparam | IR only | +| defaulttainttracking.cpp:17:15:17:20 | call to getenv | defaulttainttracking.cpp:17:8:17:13 | call to strdup | AST only | +| defaulttainttracking.cpp:17:15:17:20 | call to getenv | defaulttainttracking.cpp:17:8:17:28 | (const char *)... | AST only | | defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:21:8:21:10 | buf | AST only | +| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:22:8:22:13 | call to strcat | AST only | +| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:22:8:22:33 | (const char *)... | AST only | | defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:22:15:22:17 | buf | AST only | -| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:24:8:24:10 | (const char *)... | IR only | -| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:24:8:24:10 | array to pointer conversion | IR only | -| defaulttainttracking.cpp:22:20:22:25 | call to getenv | shared.h:10:21:10:22 | s1 | AST only | +| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:38:11:38:21 | env_pointer | AST only | +| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:39:22:39:22 | a | AST only | +| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:39:36:39:61 | (const char *)... | AST only | | defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:39:51:39:61 | env_pointer | AST only | -| defaulttainttracking.cpp:64:10:64:15 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p | IR only | | defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:8:88:16 | call to move | IR only | | defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:8:88:32 | (const char *)... | IR only | | defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:8:88:32 | (reference dereference) | IR only | | defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:18:88:30 | (reference to) | IR only | | defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:18:88:30 | temporary object | IR only | -| defaulttainttracking.cpp:88:18:88:23 | call to getenv | shared.h:5:23:5:31 | sinkparam | IR only | -| defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:91:31:91:33 | ret | AST only | | defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:92:5:92:8 | * ... | AST only | | defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:92:6:92:8 | ret | AST only | -| defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:96:11:96:12 | p2 | IR only | | defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:98:10:98:11 | (const char *)... | IR only | | defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:98:10:98:11 | p2 | IR only | -| defaulttainttracking.cpp:97:27:97:32 | call to getenv | shared.h:5:23:5:31 | sinkparam | IR only | +| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:110:7:110:13 | tainted | AST only | | defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:111:8:111:8 | y | AST only | | defaulttainttracking.cpp:133:9:133:14 | call to getenv | defaulttainttracking.cpp:126:16:126:16 | x | IR only | | defaulttainttracking.cpp:133:9:133:14 | call to getenv | defaulttainttracking.cpp:133:5:133:5 | x | AST only | | defaulttainttracking.cpp:133:9:133:14 | call to getenv | defaulttainttracking.cpp:134:10:134:10 | x | IR only | -| defaulttainttracking.cpp:133:9:133:14 | call to getenv | shared.h:6:15:6:23 | sinkparam | IR only | | defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:140:7:140:7 | x | AST only | | defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:166:10:166:10 | x | IR only | -| defaulttainttracking.cpp:140:11:140:16 | call to getenv | shared.h:6:15:6:23 | sinkparam | IR only | | defaulttainttracking.cpp:157:9:157:14 | call to getenv | defaulttainttracking.cpp:157:5:157:5 | x | AST only | | defaulttainttracking.cpp:157:9:157:14 | call to getenv | defaulttainttracking.cpp:159:10:159:10 | x | IR only | -| defaulttainttracking.cpp:157:9:157:14 | call to getenv | shared.h:6:15:6:23 | sinkparam | IR only | | defaulttainttracking.cpp:170:11:170:16 | call to getenv | defaulttainttracking.cpp:170:7:170:7 | x | AST only | | defaulttainttracking.cpp:181:11:181:16 | call to getenv | defaulttainttracking.cpp:181:7:181:7 | x | AST only | | defaulttainttracking.cpp:195:11:195:16 | call to getenv | defaulttainttracking.cpp:195:7:195:7 | x | AST only | | defaulttainttracking.cpp:201:13:201:18 | call to getenv | defaulttainttracking.cpp:201:9:201:9 | x | AST only | | defaulttainttracking.cpp:208:27:208:32 | call to getenv | defaulttainttracking.cpp:208:23:208:23 | x | AST only | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:213:11:213:14 | (unnamed parameter 0) | AST only | | defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:217:7:217:12 | buffer | AST only | +| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:218:8:218:8 | s | AST only | | defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:219:8:219:11 | ptr1 | AST only | | defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:219:16:219:19 | ptr2 | AST only | | defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:220:8:220:11 | ptr3 | AST only | @@ -48,29 +42,30 @@ | defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:223:2:223:5 | ptr2 | AST only | | defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:223:9:223:13 | & ... | AST only | | defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:223:10:223:13 | ptr1 | AST only | +| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:224:2:224:7 | call to memcpy | AST only | | defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:224:9:224:14 | buffer | AST only | | defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:225:2:225:5 | ptr3 | AST only | | defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:225:9:225:14 | buffer | AST only | | defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:226:2:226:5 | ptr4 | AST only | | defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:226:9:226:13 | & ... | AST only | | defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:226:10:226:13 | ptr3 | AST only | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:228:7:228:12 | (const char *)... | IR only | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:228:7:228:12 | array to pointer conversion | IR only | +| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:229:7:229:10 | (const char *)... | AST only | | defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:230:7:230:10 | ptr2 | AST only | | defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:231:7:231:11 | (const char *)... | AST only | | defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:231:7:231:11 | * ... | AST only | | defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:231:8:231:11 | ptr2 | AST only | +| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:232:7:232:10 | (const char *)... | AST only | | defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:233:7:233:10 | ptr4 | AST only | | defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:234:7:234:11 | (const char *)... | AST only | | defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:234:7:234:11 | * ... | AST only | | defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:234:8:234:11 | ptr4 | AST only | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | shared.h:17:20:17:21 | s1 | AST only | -| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:213:11:213:14 | (unnamed parameter 0) | AST only | +| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:240:8:240:8 | s | AST only | | defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:241:8:241:11 | ptr1 | AST only | | defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:241:16:241:19 | ptr2 | AST only | | defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:245:2:245:5 | ptr2 | AST only | | defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:245:9:245:13 | & ... | AST only | | defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:245:10:245:13 | ptr1 | AST only | +| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:246:2:246:7 | call to memcpy | AST only | | defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:246:9:246:13 | * ... | AST only | | defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:246:10:246:13 | ptr2 | AST only | | defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:251:7:251:10 | (const char *)... | AST only | @@ -79,21 +74,17 @@ | defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:253:7:253:11 | (const char *)... | AST only | | defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:253:7:253:11 | * ... | AST only | | defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:253:8:253:11 | ptr2 | AST only | -| defaulttainttracking.cpp:240:12:240:17 | call to getenv | shared.h:5:23:5:31 | sinkparam | AST only | -| defaulttainttracking.cpp:240:12:240:17 | call to getenv | shared.h:17:20:17:21 | s1 | AST only | +| globals.cpp:5:20:5:25 | call to getenv | globals.cpp:5:12:5:16 | local | AST only | +| globals.cpp:13:15:13:20 | call to getenv | globals.cpp:9:8:9:14 | global1 | AST only | | globals.cpp:13:15:13:20 | call to getenv | globals.cpp:13:5:13:11 | global1 | AST only | +| globals.cpp:23:15:23:20 | call to getenv | globals.cpp:16:15:16:21 | global2 | AST only | | globals.cpp:23:15:23:20 | call to getenv | globals.cpp:23:5:23:11 | global2 | AST only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:43:78:43:104 | (unnamed parameter 0) | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:44:176:44:178 | str | IR only | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:62:7:62:12 | source | AST only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:63:30:63:30 | s | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:64:36:64:36 | s | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:68:8:68:8 | a | AST only | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:70:16:70:24 | call to basic_string | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:74:7:74:7 | (const string)... | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:74:7:74:7 | (reference to) | IR only | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:74:7:74:7 | c | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:76:7:76:7 | (const basic_string, allocator>)... | IR only | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:76:7:76:7 | c | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:76:9:76:13 | call to c_str | IR only | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:82:16:82:24 | call to basic_string | IR only | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:85:6:85:6 | call to operator<< | IR only | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:85:6:85:17 | (reference dereference) | IR only | @@ -105,52 +96,38 @@ | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:9:87:16 | (const char *)... | IR only | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:18:87:18 | call to operator<< | IR only | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:18:87:26 | (reference dereference) | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:88:6:88:6 | call to operator<< | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:88:6:88:10 | (reference dereference) | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:88:9:88:9 | (const basic_string, allocator>)... | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:88:9:88:9 | (reference to) | IR only | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:88:9:88:9 | t | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:91:7:91:9 | (const stringstream)... | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:91:7:91:9 | (reference to) | IR only | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:91:7:91:9 | ss2 | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:93:7:93:9 | (const stringstream)... | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:93:7:93:9 | (reference to) | IR only | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:93:7:93:9 | ss4 | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:94:7:94:9 | (const stringstream)... | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:94:7:94:9 | (reference to) | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:94:7:94:9 | ss5 | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:96:7:96:9 | (const basic_stringstream, allocator>)... | IR only | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:96:7:96:9 | ss2 | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:98:7:98:9 | (const basic_stringstream, allocator>)... | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:96:7:96:15 | (const string)... | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:96:7:96:15 | (reference to) | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:96:7:96:15 | temporary object | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:96:11:96:13 | call to str | IR only | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:98:7:98:9 | ss4 | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:99:7:99:9 | (const basic_stringstream, allocator>)... | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:99:7:99:9 | ss5 | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:98:7:98:15 | (const string)... | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:98:7:98:15 | (reference to) | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:98:7:98:15 | temporary object | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:98:11:98:13 | call to str | IR only | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:117:7:117:16 | user_input | AST only | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:125:16:125:28 | call to basic_string | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:126:7:126:11 | (const basic_string, allocator>)... | IR only | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:126:7:126:11 | path1 | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:128:9:128:13 | path2 | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:126:13:126:17 | call to c_str | IR only | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:129:10:129:21 | call to basic_string | IR only | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:129:10:129:21 | temporary object | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:130:7:130:11 | (const basic_string, allocator>)... | IR only | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:130:7:130:11 | path2 | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:130:13:130:17 | call to c_str | IR only | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:132:15:132:27 | call to basic_string | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:133:7:133:11 | (const basic_string, allocator>)... | IR only | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:133:7:133:11 | path3 | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:133:13:133:17 | call to c_str | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:138:14:138:15 | cs | AST only | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:141:17:141:19 | call to basic_string | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:144:7:144:8 | (const string)... | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:144:7:144:8 | (reference to) | IR only | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:144:7:144:8 | ss | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:149:14:149:15 | cs | AST only | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:152:17:152:19 | call to basic_string | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:155:7:155:8 | (const basic_string, allocator>)... | IR only | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:155:7:155:8 | ss | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:157:7:157:8 | cs | AST only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:158:7:158:8 | (const string)... | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:158:7:158:8 | (reference to) | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:155:10:155:14 | call to c_str | IR only | | stl.cpp:62:25:62:30 | call to getenv | stl.cpp:158:7:158:8 | ss | IR only | +| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:98:13:98:13 | p | AST only | | test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:11:104:20 | (...) | IR only | -| test_diff.cpp:108:10:108:13 | argv | test_diff.cpp:36:24:36:24 | p | AST only | -| test_diff.cpp:111:10:111:13 | argv | shared.h:5:23:5:31 | sinkparam | AST only | -| test_diff.cpp:111:10:111:13 | argv | test_diff.cpp:29:24:29:24 | p | AST only | | test_diff.cpp:111:10:111:13 | argv | test_diff.cpp:30:14:30:14 | p | AST only | -| test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:76:24:76:24 | p | IR only | From 525aeb65510ff406c52495722ad3492be36ee5e3 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Fri, 13 Nov 2020 16:14:07 -0800 Subject: [PATCH 012/725] C++: autoformat --- .../code/cpp/ir/dataflow/DefaultTaintTracking.qll | 10 ++++++++-- .../dataflow/DefaultTaintTracking/tainted.ql | 4 +--- 2 files changed, 9 insertions(+), 5 deletions(-) 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 62e7f7b9738..38acc20f44f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll @@ -222,7 +222,6 @@ private predicate nodeIsBarrierIn(DataFlow::Node node) { not predictableInstruction(iTo.getRight()) and // propagate taint from either the pointer or the offset, regardless of predictability not iTo instanceof PointerArithmeticInstruction - ) or // don't use dataflow through calls to pure functions if two or more operands @@ -473,7 +472,14 @@ private Element adjustedSink(DataFlow::Node sink) { // Taint `e1 += e2`, `e &= e2` and friends when `e1` or `e2` is tainted. result.(AssignOperation).getAnOperand() = sink.asExpr() or - result = sink.asOperand().(SideEffectOperand).getUse().(ReadSideEffectInstruction).getArgumentDef().getUnconvertedResultExpression() + result = + sink + .asOperand() + .(SideEffectOperand) + .getUse() + .(ReadSideEffectInstruction) + .getArgumentDef() + .getUnconvertedResultExpression() } /** diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.ql b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.ql index 3382775b6d9..240418f9bf4 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.ql +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.ql @@ -1,9 +1,7 @@ import semmle.code.cpp.ir.dataflow.DefaultTaintTracking class SourceConfiguration extends TaintedWithPath::TaintTrackingConfiguration { - override predicate isSink(Element e) { - any() - } + override predicate isSink(Element e) { any() } } from Expr source, Element tainted From c2e44fa180954ac5aa64eda2e020562282a9b6de Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Tue, 17 Nov 2020 09:28:39 -0800 Subject: [PATCH 013/725] C++: autoformat --- .../library-tests/dataflow/security-taint/tainted_diff.ql | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/security-taint/tainted_diff.ql b/cpp/ql/test/library-tests/dataflow/security-taint/tainted_diff.ql index f3ed14d16b1..37bd9f5437d 100644 --- a/cpp/ql/test/library-tests/dataflow/security-taint/tainted_diff.ql +++ b/cpp/ql/test/library-tests/dataflow/security-taint/tainted_diff.ql @@ -3,9 +3,7 @@ import semmle.code.cpp.ir.dataflow.DefaultTaintTracking as IR import cpp class SourceConfiguration extends IR::TaintedWithPath::TaintTrackingConfiguration { - override predicate isSink(Element e) { - any() - } + override predicate isSink(Element e) { any() } } from Expr source, Element tainted, string side From 5aed82a210f2e4e23ead18c41990e061696214ed Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Tue, 17 Nov 2020 13:44:20 -0800 Subject: [PATCH 014/725] C++: Autoformat more --- .../code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll index 1cbddcd70ae..0ea24dc7862 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll @@ -146,8 +146,8 @@ predicate modeledTaintStep(DataFlow::Node nodeIn, DataFlow::Node nodeOut) { // Taint flow from a pointer argument to an output, when the model specifies flow from the deref // to that output, but the deref is not modeled in the IR for the caller. exists( - CallInstruction call, ReadSideEffectInstruction read, Function func, - FunctionInput modelIn, FunctionOutput modelOut + CallInstruction call, ReadSideEffectInstruction read, Function func, FunctionInput modelIn, + FunctionOutput modelOut | read.getSideEffectOperand() = callInput(call, modelIn).asOperand() and read.getArgumentDef() = nodeIn.asInstruction() and From ce2db21f15d68ff69835e11367a02e3a1832d13d Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Wed, 6 Jan 2021 17:26:53 +0000 Subject: [PATCH 015/725] Query to detect hash without salt --- .../Security/CWE/CWE-759/HashWithoutSalt.java | 14 +++ .../CWE/CWE-759/HashWithoutSalt.qhelp | 29 ++++++ .../Security/CWE/CWE-759/HashWithoutSalt.ql | 93 +++++++++++++++++++ .../security/CWE-759/HashWithoutSalt.expected | 11 +++ .../security/CWE-759/HashWithoutSalt.java | 40 ++++++++ .../security/CWE-759/HashWithoutSalt.qlref | 1 + 6 files changed, 188 insertions(+) create mode 100644 java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.java create mode 100644 java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql create mode 100644 java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.java create mode 100644 java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.qlref diff --git a/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.java b/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.java new file mode 100644 index 00000000000..91d39eb5798 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.java @@ -0,0 +1,14 @@ +public class HashWithoutSalt { + // BAD - Hash without a salt. + public void getSHA256Hash(String password) throws NoSuchAlgorithmException { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + byte[] messageDigest = md.digest(password.getBytes()); + } + + // GOOD - Hash with a salt. + public void getSHA256Hash(String password, byte[] salt) throws NoSuchAlgorithmException { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + md.update(salt); + byte[] messageDigest = md.digest(password.getBytes()); + } +} \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.qhelp b/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.qhelp new file mode 100644 index 00000000000..a3875c35c37 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.qhelp @@ -0,0 +1,29 @@ + + + + +

    In cryptography, "salt" is random data that are used as an additional input to a one-way function that hashes a password or pass-phrase. It makes dictionary attacks more difficult.

    + +

    Without a salt, it is much easier for attackers to pre-compute the hash value using dictionary attack techniques such as rainbow tables to crack passwords.

    +
    + + +

    Use a long random salt of at least 32 bytes then use the combination of password and salt to hash a password or password phrase.

    +
    + + +

    The following example shows two ways of hashing. In the 'BAD' case, no salt is provided. In the 'GOOD' case, a salt is provided.

    + +
    + + +
  • + DZone: + A Look at Java Cryptography +
  • +
  • + CWE: + CWE-759: Use of a One-Way Hash without a Salt +
  • +
    +
    diff --git a/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql b/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql new file mode 100644 index 00000000000..5e308838072 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql @@ -0,0 +1,93 @@ +/** + * @id java/hash-without-salt + * @name Use of a One-Way Hash without a Salt + * @description Hashed passwords without a salt are vulnerable to dictionary attacks. + * @kind path-problem + * @tags security + * external/cwe-759 + */ + +import java +import semmle.code.java.dataflow.TaintTracking +import DataFlow::PathGraph + +/** The Java class `java.security.MessageDigest` */ +class MessageDigest extends RefType { + MessageDigest() { this.hasQualifiedName("java.security", "MessageDigest") } +} + +/** The method `digest()` declared in `java.security.MessageDigest`. */ +class MDDigestMethod extends Method { + MDDigestMethod() { + getDeclaringType() instanceof MessageDigest and + hasName("digest") + } +} + +/** The method `update()` declared in `java.security.MessageDigest`. */ +class MDUpdateMethod extends Method { + MDUpdateMethod() { + getDeclaringType() instanceof MessageDigest and + hasName("update") + } +} + +/** + * Gets a regular expression for matching common names of variables that indicate the value being held is a password. + */ +string getPasswordRegex() { result = "(?i).*pass(wd|word|code|phrase).*" } + +/** Finds variables that hold password information judging by their names. */ +class PasswordVarExpr extends Expr { + PasswordVarExpr() { + exists(Variable v | this = v.getAnAccess() | v.getName().regexpMatch(getPasswordRegex())) + } +} + +/** Taint configuration tracking flow from an expression whose name suggests it holds password data to a method call that generates a hash without a salt. */ +class HashWithoutSaltConfiguration extends TaintTracking::Configuration { + HashWithoutSaltConfiguration() { this = "HashWithoutSaltConfiguration" } + + override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof PasswordVarExpr } + + override predicate isSink(DataFlow::Node sink) { + exists( + MethodAccess mda, MethodAccess mua // invoke `md.digest()` with only one call of `md.update(password)`, that is, without the call of `md.update(digest)` + | + sink.asExpr() = mda.getQualifier() and + mda.getMethod() instanceof MDDigestMethod and + mda.getNumArgument() = 0 and // md.digest() + mua.getMethod() instanceof MDUpdateMethod and // md.update(password) + mua.getQualifier() = mda.getQualifier().(VarAccess).getVariable().getAnAccess() and + not exists(MethodAccess mua2 | + mua2.getMethod() instanceof MDUpdateMethod and // md.update(salt) + mua2.getQualifier() = mua.getQualifier().(VarAccess).getVariable().getAnAccess() and + mua2 != mua + ) + ) + or + // invoke `md.digest(password)` without another call of `md.update(salt)` + exists(MethodAccess mda | + sink.asExpr() = mda and + mda.getMethod() instanceof MDDigestMethod and // md.digest(password) + mda.getNumArgument() = 1 and + not exists(MethodAccess mua | + mua.getMethod() instanceof MDUpdateMethod and // md.update(salt) + mua.getQualifier() = mda.getQualifier().(VarAccess).getVariable().getAnAccess() + ) + ) + } + + /** Holds for additional steps such as `passwordStr.getBytes()` */ + override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { + exists(MethodAccess ma | + pred.asExpr() = ma.getAnArgument() and + (succ.asExpr() = ma or succ.asExpr() = ma.getQualifier()) + ) + } +} + +from DataFlow::PathNode source, DataFlow::PathNode sink, HashWithoutSaltConfiguration c +where c.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "$@ is hashed without a salt.", source.getNode(), + "The password" diff --git a/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.expected b/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.expected new file mode 100644 index 00000000000..4983391a231 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.expected @@ -0,0 +1,11 @@ +edges +| HashWithoutSalt.java:9:36:9:43 | password : String | HashWithoutSalt.java:9:26:9:55 | digest(...) | +| HashWithoutSalt.java:15:13:15:20 | password : String | HashWithoutSalt.java:16:26:16:27 | md | +nodes +| HashWithoutSalt.java:9:26:9:55 | digest(...) | semmle.label | digest(...) | +| HashWithoutSalt.java:9:36:9:43 | password : String | semmle.label | password : String | +| HashWithoutSalt.java:15:13:15:20 | password : String | semmle.label | password : String | +| HashWithoutSalt.java:16:26:16:27 | md | semmle.label | md | +#select +| HashWithoutSalt.java:9:26:9:55 | digest(...) | HashWithoutSalt.java:9:36:9:43 | password : String | HashWithoutSalt.java:9:26:9:55 | digest(...) | $@ is hashed without a salt. | HashWithoutSalt.java:9:36:9:43 | password | The password | +| HashWithoutSalt.java:16:26:16:27 | md | HashWithoutSalt.java:15:13:15:20 | password : String | HashWithoutSalt.java:16:26:16:27 | md | $@ is hashed without a salt. | HashWithoutSalt.java:15:13:15:20 | password | The password | diff --git a/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.java b/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.java new file mode 100644 index 00000000000..809f923d2c3 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.java @@ -0,0 +1,40 @@ +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; + +public class HashWithoutSalt { + // BAD - Hash without a salt. + public void getSHA256Hash(String password) throws NoSuchAlgorithmException { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + byte[] messageDigest = md.digest(password.getBytes()); + } + + // BAD - Hash without a salt. + public void getSHA256Hash2(String password) throws NoSuchAlgorithmException { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + md.update(password.getBytes()); + byte[] messageDigest = md.digest(); + } + + // GOOD - Hash with a salt. + public void getSHA256Hash(String password, byte[] salt) throws NoSuchAlgorithmException { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + md.update(salt); + byte[] messageDigest = md.digest(password.getBytes()); + } + + // GOOD - Hash with a salt. + public void getSHA256Hash2(String password, byte[] salt) throws NoSuchAlgorithmException { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + md.update(salt); + md.update(password.getBytes()); + byte[] messageDigest = md.digest(); + } + + public static byte[] getSalt() throws NoSuchAlgorithmException { + SecureRandom sr = SecureRandom.getInstance("SHA1PRNG"); + byte[] salt = new byte[16]; + sr.nextBytes(salt); + return salt; + } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.qlref b/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.qlref new file mode 100644 index 00000000000..a8233ca37d2 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-759/HashWithoutSalt.ql From 19ff00bad421034aabac6cc6d5891a9b2441aa72 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Thu, 7 Jan 2021 13:15:30 +0000 Subject: [PATCH 016/725] Enhance the additional step flow and update qldoc --- .../CWE/CWE-759/HashWithoutSalt.qhelp | 2 +- .../Security/CWE/CWE-759/HashWithoutSalt.ql | 22 +++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.qhelp b/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.qhelp index a3875c35c37..3418645bc97 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.qhelp +++ b/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.qhelp @@ -2,7 +2,7 @@ -

    In cryptography, "salt" is random data that are used as an additional input to a one-way function that hashes a password or pass-phrase. It makes dictionary attacks more difficult.

    +

    In cryptography, a salt is some random data used as an additional input to a one-way function that hashes a password or pass-phrase. It makes dictionary attacks more difficult.

    Without a salt, it is much easier for attackers to pre-compute the hash value using dictionary attack techniques such as rainbow tables to crack passwords.

    diff --git a/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql b/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql index 5e308838072..6cc7de4f847 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql @@ -1,8 +1,8 @@ /** - * @id java/hash-without-salt - * @name Use of a One-Way Hash without a Salt + * @name Use of a hash function without a salt * @description Hashed passwords without a salt are vulnerable to dictionary attacks. * @kind path-problem + * @id java/hash-without-salt * @tags security * external/cwe-759 */ @@ -11,7 +11,7 @@ import java import semmle.code.java.dataflow.TaintTracking import DataFlow::PathGraph -/** The Java class `java.security.MessageDigest` */ +/** The Java class `java.security.MessageDigest`. */ class MessageDigest extends RefType { MessageDigest() { this.hasQualifiedName("java.security", "MessageDigest") } } @@ -19,22 +19,20 @@ class MessageDigest extends RefType { /** The method `digest()` declared in `java.security.MessageDigest`. */ class MDDigestMethod extends Method { MDDigestMethod() { - getDeclaringType() instanceof MessageDigest and - hasName("digest") + this.getDeclaringType() instanceof MessageDigest and + this.hasName("digest") } } /** The method `update()` declared in `java.security.MessageDigest`. */ class MDUpdateMethod extends Method { MDUpdateMethod() { - getDeclaringType() instanceof MessageDigest and - hasName("update") + this.getDeclaringType() instanceof MessageDigest and + this.hasName("update") } } -/** - * Gets a regular expression for matching common names of variables that indicate the value being held is a password. - */ +/** Gets a regular expression for matching common names of variables that indicate the value being held is a password. */ string getPasswordRegex() { result = "(?i).*pass(wd|word|code|phrase).*" } /** Finds variables that hold password information judging by their names. */ @@ -78,9 +76,11 @@ class HashWithoutSaltConfiguration extends TaintTracking::Configuration { ) } - /** Holds for additional steps such as `passwordStr.getBytes()` */ + /** Holds for additional steps that flow to a method call of `update` or `digest` declared in `java.security.MessageDigest`. */ override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { exists(MethodAccess ma | + ma.getMethod().getDeclaringType() instanceof MessageDigest and + ma.getMethod().hasName(["digest", "update"]) and pred.asExpr() = ma.getAnArgument() and (succ.asExpr() = ma or succ.asExpr() = ma.getQualifier()) ) From b56fe2b25f644866e4ae0d6a9474843c95c1eeba Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Thu, 7 Jan 2021 16:31:21 +0000 Subject: [PATCH 017/725] Remove specific method name in additional taint step --- .../src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql b/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql index 6cc7de4f847..eae6c0ed149 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql @@ -76,11 +76,10 @@ class HashWithoutSaltConfiguration extends TaintTracking::Configuration { ) } - /** Holds for additional steps that flow to a method call of `update` or `digest` declared in `java.security.MessageDigest`. */ + /** Holds for additional steps that flow to additional method calls of the type `java.security.MessageDigest`. */ override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { exists(MethodAccess ma | ma.getMethod().getDeclaringType() instanceof MessageDigest and - ma.getMethod().hasName(["digest", "update"]) and pred.asExpr() = ma.getAnArgument() and (succ.asExpr() = ma or succ.asExpr() = ma.getQualifier()) ) From 39103af71833732617518f68af71dbba5d743cc9 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Fri, 8 Jan 2021 13:02:57 +0000 Subject: [PATCH 018/725] Remove additional taint step --- .../Security/CWE/CWE-759/HashWithoutSalt.ql | 19 +++++-------------- .../security/CWE-759/HashWithoutSalt.expected | 12 ++++++------ 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql b/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql index eae6c0ed149..bb74f24f347 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql @@ -50,13 +50,13 @@ class HashWithoutSaltConfiguration extends TaintTracking::Configuration { override predicate isSink(DataFlow::Node sink) { exists( - MethodAccess mda, MethodAccess mua // invoke `md.digest()` with only one call of `md.update(password)`, that is, without the call of `md.update(digest)` + MethodAccess mua, MethodAccess mda // invoke `md.digest()` with only one call of `md.update(password)`, that is, without the call of `md.update(digest)` | - sink.asExpr() = mda.getQualifier() and + sink.asExpr() = mua.getArgument(0) and + mua.getMethod() instanceof MDUpdateMethod and // md.update(password) mda.getMethod() instanceof MDDigestMethod and mda.getNumArgument() = 0 and // md.digest() - mua.getMethod() instanceof MDUpdateMethod and // md.update(password) - mua.getQualifier() = mda.getQualifier().(VarAccess).getVariable().getAnAccess() and + mda.getQualifier() = mua.getQualifier().(VarAccess).getVariable().getAnAccess() and not exists(MethodAccess mua2 | mua2.getMethod() instanceof MDUpdateMethod and // md.update(salt) mua2.getQualifier() = mua.getQualifier().(VarAccess).getVariable().getAnAccess() and @@ -66,7 +66,7 @@ class HashWithoutSaltConfiguration extends TaintTracking::Configuration { or // invoke `md.digest(password)` without another call of `md.update(salt)` exists(MethodAccess mda | - sink.asExpr() = mda and + sink.asExpr() = mda.getArgument(0) and mda.getMethod() instanceof MDDigestMethod and // md.digest(password) mda.getNumArgument() = 1 and not exists(MethodAccess mua | @@ -75,15 +75,6 @@ class HashWithoutSaltConfiguration extends TaintTracking::Configuration { ) ) } - - /** Holds for additional steps that flow to additional method calls of the type `java.security.MessageDigest`. */ - override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { - exists(MethodAccess ma | - ma.getMethod().getDeclaringType() instanceof MessageDigest and - pred.asExpr() = ma.getAnArgument() and - (succ.asExpr() = ma or succ.asExpr() = ma.getQualifier()) - ) - } } from DataFlow::PathNode source, DataFlow::PathNode sink, HashWithoutSaltConfiguration c diff --git a/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.expected b/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.expected index 4983391a231..d1ed0b00338 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.expected @@ -1,11 +1,11 @@ edges -| HashWithoutSalt.java:9:36:9:43 | password : String | HashWithoutSalt.java:9:26:9:55 | digest(...) | -| HashWithoutSalt.java:15:13:15:20 | password : String | HashWithoutSalt.java:16:26:16:27 | md | +| HashWithoutSalt.java:9:36:9:43 | password : String | HashWithoutSalt.java:9:36:9:54 | getBytes(...) | +| HashWithoutSalt.java:15:13:15:20 | password : String | HashWithoutSalt.java:15:13:15:31 | getBytes(...) | nodes -| HashWithoutSalt.java:9:26:9:55 | digest(...) | semmle.label | digest(...) | | HashWithoutSalt.java:9:36:9:43 | password : String | semmle.label | password : String | +| HashWithoutSalt.java:9:36:9:54 | getBytes(...) | semmle.label | getBytes(...) | | HashWithoutSalt.java:15:13:15:20 | password : String | semmle.label | password : String | -| HashWithoutSalt.java:16:26:16:27 | md | semmle.label | md | +| HashWithoutSalt.java:15:13:15:31 | getBytes(...) | semmle.label | getBytes(...) | #select -| HashWithoutSalt.java:9:26:9:55 | digest(...) | HashWithoutSalt.java:9:36:9:43 | password : String | HashWithoutSalt.java:9:26:9:55 | digest(...) | $@ is hashed without a salt. | HashWithoutSalt.java:9:36:9:43 | password | The password | -| HashWithoutSalt.java:16:26:16:27 | md | HashWithoutSalt.java:15:13:15:20 | password : String | HashWithoutSalt.java:16:26:16:27 | md | $@ is hashed without a salt. | HashWithoutSalt.java:15:13:15:20 | password | The password | +| HashWithoutSalt.java:9:36:9:54 | getBytes(...) | HashWithoutSalt.java:9:36:9:43 | password : String | HashWithoutSalt.java:9:36:9:54 | getBytes(...) | $@ is hashed without a salt. | HashWithoutSalt.java:9:36:9:43 | password | The password | +| HashWithoutSalt.java:15:13:15:31 | getBytes(...) | HashWithoutSalt.java:15:13:15:20 | password : String | HashWithoutSalt.java:15:13:15:31 | getBytes(...) | $@ is hashed without a salt. | HashWithoutSalt.java:15:13:15:20 | password | The password | From 86c04e6971b10569e4209817a1a497dd51a9308e Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Mon, 11 Jan 2021 16:59:57 +0000 Subject: [PATCH 019/725] Detect the scenario of passwords concatenated with a salt to reduce FPs --- .../Security/CWE/CWE-759/HashWithoutSalt.ql | 14 +++++++ .../security/CWE-759/HashWithoutSalt.expected | 16 ++++---- .../security/CWE-759/HashWithoutSalt.java | 39 ++++++++++++++----- 3 files changed, 52 insertions(+), 17 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql b/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql index bb74f24f347..8330d5b9a42 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql @@ -75,6 +75,20 @@ class HashWithoutSaltConfiguration extends TaintTracking::Configuration { ) ) } + + /** + * Holds if a password is concatenated with a salt then hashed together through the call `System.arraycopy(password.getBytes(), ...)`. For example, + * `System.arraycopy(password.getBytes(), 0, allBytes, 0, password.getBytes().length);` + * `System.arraycopy(salt, 0, allBytes, password.getBytes().length, salt.length);` + * `byte[] messageDigest = md.digest(allBytes);` + */ + override predicate isSanitizer(DataFlow::Node node) { + exists(MethodAccess ma | + ma.getMethod().getDeclaringType().hasQualifiedName("java.lang", "System") and + ma.getMethod().hasName("arraycopy") and + ma.getArgument(0) = node.asExpr() + ) + } } from DataFlow::PathNode source, DataFlow::PathNode sink, HashWithoutSaltConfiguration c diff --git a/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.expected b/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.expected index d1ed0b00338..2077f2d6266 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.expected @@ -1,11 +1,11 @@ edges -| HashWithoutSalt.java:9:36:9:43 | password : String | HashWithoutSalt.java:9:36:9:54 | getBytes(...) | -| HashWithoutSalt.java:15:13:15:20 | password : String | HashWithoutSalt.java:15:13:15:31 | getBytes(...) | +| HashWithoutSalt.java:10:36:10:43 | password : String | HashWithoutSalt.java:10:36:10:54 | getBytes(...) | +| HashWithoutSalt.java:17:13:17:20 | password : String | HashWithoutSalt.java:17:13:17:31 | getBytes(...) | nodes -| HashWithoutSalt.java:9:36:9:43 | password : String | semmle.label | password : String | -| HashWithoutSalt.java:9:36:9:54 | getBytes(...) | semmle.label | getBytes(...) | -| HashWithoutSalt.java:15:13:15:20 | password : String | semmle.label | password : String | -| HashWithoutSalt.java:15:13:15:31 | getBytes(...) | semmle.label | getBytes(...) | +| HashWithoutSalt.java:10:36:10:43 | password : String | semmle.label | password : String | +| HashWithoutSalt.java:10:36:10:54 | getBytes(...) | semmle.label | getBytes(...) | +| HashWithoutSalt.java:17:13:17:20 | password : String | semmle.label | password : String | +| HashWithoutSalt.java:17:13:17:31 | getBytes(...) | semmle.label | getBytes(...) | #select -| HashWithoutSalt.java:9:36:9:54 | getBytes(...) | HashWithoutSalt.java:9:36:9:43 | password : String | HashWithoutSalt.java:9:36:9:54 | getBytes(...) | $@ is hashed without a salt. | HashWithoutSalt.java:9:36:9:43 | password | The password | -| HashWithoutSalt.java:15:13:15:31 | getBytes(...) | HashWithoutSalt.java:15:13:15:20 | password : String | HashWithoutSalt.java:15:13:15:31 | getBytes(...) | $@ is hashed without a salt. | HashWithoutSalt.java:15:13:15:20 | password | The password | +| HashWithoutSalt.java:10:36:10:54 | getBytes(...) | HashWithoutSalt.java:10:36:10:43 | password : String | HashWithoutSalt.java:10:36:10:54 | getBytes(...) | $@ is hashed without a salt. | HashWithoutSalt.java:10:36:10:43 | password | The password | +| HashWithoutSalt.java:17:13:17:31 | getBytes(...) | HashWithoutSalt.java:17:13:17:20 | password : String | HashWithoutSalt.java:17:13:17:31 | getBytes(...) | $@ is hashed without a salt. | HashWithoutSalt.java:17:13:17:20 | password | The password | diff --git a/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.java b/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.java index 809f923d2c3..53d406a4fca 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.java +++ b/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.java @@ -1,40 +1,61 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; +import java.util.Base64; public class HashWithoutSalt { // BAD - Hash without a salt. - public void getSHA256Hash(String password) throws NoSuchAlgorithmException { + public String getSHA256Hash(String password) throws NoSuchAlgorithmException { MessageDigest md = MessageDigest.getInstance("SHA-256"); byte[] messageDigest = md.digest(password.getBytes()); + return Base64.getEncoder().encodeToString(messageDigest); } // BAD - Hash without a salt. - public void getSHA256Hash2(String password) throws NoSuchAlgorithmException { + public String getSHA256Hash2(String password) throws NoSuchAlgorithmException { MessageDigest md = MessageDigest.getInstance("SHA-256"); md.update(password.getBytes()); byte[] messageDigest = md.digest(); + return Base64.getEncoder().encodeToString(messageDigest); } // GOOD - Hash with a salt. - public void getSHA256Hash(String password, byte[] salt) throws NoSuchAlgorithmException { + public String getSHA256Hash(String password, byte[] salt) throws NoSuchAlgorithmException { MessageDigest md = MessageDigest.getInstance("SHA-256"); md.update(salt); byte[] messageDigest = md.digest(password.getBytes()); + return Base64.getEncoder().encodeToString(messageDigest); } // GOOD - Hash with a salt. - public void getSHA256Hash2(String password, byte[] salt) throws NoSuchAlgorithmException { + public String getSHA256Hash2(String password, byte[] salt) throws NoSuchAlgorithmException { MessageDigest md = MessageDigest.getInstance("SHA-256"); md.update(salt); md.update(password.getBytes()); byte[] messageDigest = md.digest(); + return Base64.getEncoder().encodeToString(messageDigest); + } + + // GOOD - Hash with a salt concatenated with the password. + public String getSHA256Hash3(String password, byte[] salt) throws NoSuchAlgorithmException { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + + byte[] passBytes = password.getBytes(); + byte[] allBytes = new byte[passBytes.length + salt.length]; + System.arraycopy(passBytes, 0, allBytes, 0, passBytes.length); + System.arraycopy(salt, 0, allBytes, passBytes.length, salt.length); + byte[] messageDigest = md.digest(allBytes); + + byte[] cipherBytes = new byte[32 + salt.length]; // SHA-256 is 32 bytes long + System.arraycopy(messageDigest, 0, cipherBytes, 0, 32); + System.arraycopy(salt, 0, cipherBytes, 32, salt.length); + return Base64.getEncoder().encodeToString(cipherBytes); } public static byte[] getSalt() throws NoSuchAlgorithmException { - SecureRandom sr = SecureRandom.getInstance("SHA1PRNG"); - byte[] salt = new byte[16]; - sr.nextBytes(salt); - return salt; - } + SecureRandom sr = SecureRandom.getInstance("SHA1PRNG"); + byte[] salt = new byte[16]; + sr.nextBytes(salt); + return salt; + } } From 3af8773dd6c6639578fa309bba819dbbf5d308f6 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Fri, 15 Jan 2021 16:20:31 +0000 Subject: [PATCH 020/725] Add more cases --- .../Security/CWE/CWE-759/HashWithoutSalt.ql | 14 ++++++++++--- .../security/CWE-759/HashWithoutSalt.java | 17 ++++++++++++++++ .../query-tests/security/CWE-759/SHA256.java | 20 +++++++++++++++++++ 3 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 java/ql/test/experimental/query-tests/security/CWE-759/SHA256.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql b/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql index 8330d5b9a42..4f4f4180159 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql @@ -38,7 +38,12 @@ string getPasswordRegex() { result = "(?i).*pass(wd|word|code|phrase).*" } /** Finds variables that hold password information judging by their names. */ class PasswordVarExpr extends Expr { PasswordVarExpr() { - exists(Variable v | this = v.getAnAccess() | v.getName().regexpMatch(getPasswordRegex())) + exists(Variable v | this = v.getAnAccess() | + ( + v.getName().toLowerCase().regexpMatch(getPasswordRegex()) and + not v.getName().toLowerCase().matches("%hash%") // Exclude variable names such as `passwordHash` since their values were already hashed + ) + ) } } @@ -77,17 +82,20 @@ class HashWithoutSaltConfiguration extends TaintTracking::Configuration { } /** - * Holds if a password is concatenated with a salt then hashed together through the call `System.arraycopy(password.getBytes(), ...)`. For example, + * Holds if a password is concatenated with a salt then hashed together through the call `System.arraycopy(password.getBytes(), ...)`, for example, * `System.arraycopy(password.getBytes(), 0, allBytes, 0, password.getBytes().length);` * `System.arraycopy(salt, 0, allBytes, password.getBytes().length, salt.length);` * `byte[] messageDigest = md.digest(allBytes);` + * Or the password is concatenated with a salt as a string. */ override predicate isSanitizer(DataFlow::Node node) { exists(MethodAccess ma | ma.getMethod().getDeclaringType().hasQualifiedName("java.lang", "System") and ma.getMethod().hasName("arraycopy") and ma.getArgument(0) = node.asExpr() - ) + ) // System.arraycopy(password.getBytes(), ...) + or + exists(AddExpr e | node.asExpr() = e.getAnOperand()) // password+salt } } diff --git a/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.java b/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.java index 53d406a4fca..44004f3a8c9 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.java +++ b/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.java @@ -52,6 +52,23 @@ public class HashWithoutSalt { return Base64.getEncoder().encodeToString(cipherBytes); } + // GOOD - Hash with a given salt stored somewhere else. + public String getSHA256Hash(String password, String salt) throws NoSuchAlgorithmException { + return hash(password+salt); + } + + // GOOD - Hash with a salt for a variable named passwordHash, whose value is a hash used as an input for a hashing function. + public String getSHA256Hash3(String passwordHash) throws NoSuchAlgorithmException { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + byte[] messageDigest = md.digest(passwordHash.getBytes()); + return Base64.getEncoder().encodeToString(messageDigest); + } + + private String hash(String payload) { + MessageDigest alg = MessageDigest.getInstance("SHA-256"); + return Base64.getEncoder().encodeToString(alg.digest(payload.getBytes(java.nio.charset.StandardCharsets.UTF_8))); + } + public static byte[] getSalt() throws NoSuchAlgorithmException { SecureRandom sr = SecureRandom.getInstance("SHA1PRNG"); byte[] salt = new byte[16]; diff --git a/java/ql/test/experimental/query-tests/security/CWE-759/SHA256.java b/java/ql/test/experimental/query-tests/security/CWE-759/SHA256.java new file mode 100644 index 00000000000..0d46f71d193 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-759/SHA256.java @@ -0,0 +1,20 @@ +import java.security.MessageDigest; + +public class SHA256 { + MessageDigest md; + public int getBlockSize() {return 32;} + public void init() throws Exception { + try { md = MessageDigest.getInstance("SHA-256"); } + catch (Exception e){ + System.err.println(e); + } + } + + public void update(byte[] foo, int start, int len) throws Exception { + md.update(foo, start, len); + } + + public byte[] digest() throws Exception { + return md.digest(); + } +} \ No newline at end of file From 048167d39adef862a6a3191d5ed56ccc5d953d92 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Mon, 18 Jan 2021 04:23:30 +0000 Subject: [PATCH 021/725] Revamp the query to reduce FPs introduced by wrapper calls --- .../Security/CWE/CWE-759/HashWithoutSalt.ql | 46 +++++++++++++------ .../security/CWE-759/HashWithoutSalt.java | 38 ++++++++++++++- .../query-tests/security/CWE-759/SHA256.java | 7 +-- 3 files changed, 72 insertions(+), 19 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql b/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql index 4f4f4180159..15361071610 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql @@ -55,29 +55,17 @@ class HashWithoutSaltConfiguration extends TaintTracking::Configuration { override predicate isSink(DataFlow::Node sink) { exists( - MethodAccess mua, MethodAccess mda // invoke `md.digest()` with only one call of `md.update(password)`, that is, without the call of `md.update(digest)` + MethodAccess mua // invoke `md.update(password)` without the call of `md.update(digest)` | sink.asExpr() = mua.getArgument(0) and - mua.getMethod() instanceof MDUpdateMethod and // md.update(password) - mda.getMethod() instanceof MDDigestMethod and - mda.getNumArgument() = 0 and // md.digest() - mda.getQualifier() = mua.getQualifier().(VarAccess).getVariable().getAnAccess() and - not exists(MethodAccess mua2 | - mua2.getMethod() instanceof MDUpdateMethod and // md.update(salt) - mua2.getQualifier() = mua.getQualifier().(VarAccess).getVariable().getAnAccess() and - mua2 != mua - ) + mua.getMethod() instanceof MDUpdateMethod // md.update(password) ) or // invoke `md.digest(password)` without another call of `md.update(salt)` exists(MethodAccess mda | sink.asExpr() = mda.getArgument(0) and mda.getMethod() instanceof MDDigestMethod and // md.digest(password) - mda.getNumArgument() = 1 and - not exists(MethodAccess mua | - mua.getMethod() instanceof MDUpdateMethod and // md.update(salt) - mua.getQualifier() = mda.getQualifier().(VarAccess).getVariable().getAnAccess() - ) + mda.getNumArgument() = 1 ) } @@ -96,9 +84,37 @@ class HashWithoutSaltConfiguration extends TaintTracking::Configuration { ) // System.arraycopy(password.getBytes(), ...) or exists(AddExpr e | node.asExpr() = e.getAnOperand()) // password+salt + or + exists(MethodAccess mua, MethodAccess ma | + ma.getArgument(0) = node.asExpr() and // Detect wrapper methods that invoke `md.update(salt)` + ma != mua and + ( + mua.getQualifier().(VarAccess).getVariable().getAnAccess() = ma.getQualifier() + or + mua.getAnArgument().(VarAccess).getVariable().getAnAccess() = ma.getQualifier() + or + mua.getQualifier().(VarAccess).getVariable().getAnAccess() = ma.getAnArgument() + or + mua.getAnArgument().(VarAccess).getVariable().getAnAccess() = ma.getAnArgument() + ) and + isMDUpdateCall(mua.getMethod()) + ) } } +/** Holds if a method invokes `md.update(salt)`. */ +predicate isMDUpdateCall(Callable caller) { + caller instanceof MDUpdateMethod + or + exists(Callable callee | + caller.polyCalls(callee) and + ( + callee instanceof MDUpdateMethod or + isMDUpdateCall(callee) + ) + ) +} + from DataFlow::PathNode source, DataFlow::PathNode sink, HashWithoutSaltConfiguration c where c.hasFlowPath(source, sink) select sink.getNode(), source, sink, "$@ is hashed without a salt.", source.getNode(), diff --git a/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.java b/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.java index 44004f3a8c9..852898f5481 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.java +++ b/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.java @@ -64,7 +64,43 @@ public class HashWithoutSalt { return Base64.getEncoder().encodeToString(messageDigest); } - private String hash(String payload) { + public void update(SHA256 sha256, byte[] foo, int start, int len) throws NoSuchAlgorithmException { + sha256.update(foo, start, len); + } + + public void update2(SHA256 sha256, byte[] foo, int start, int len) throws NoSuchAlgorithmException { + sha256.update(foo, start, len); + } + + // GOOD - Invoke a wrapper implementation with a salt. + public String getSHA256Hash4(String password) throws NoSuchAlgorithmException { + SHA256 sha256 = new SHA256(); + byte[] salt = getSalt(); + byte[] passBytes = password.getBytes(); + sha256.update(passBytes, 0, passBytes.length); + sha256.update(salt, 0, salt.length); + return Base64.getEncoder().encodeToString(sha256.digest()); + } + + // GOOD - Invoke a wrapper implementation with a salt. + public String getSHA256Hash5(String password) throws NoSuchAlgorithmException { + SHA256 sha256 = new SHA256(); + byte[] salt = getSalt(); + byte[] passBytes = password.getBytes(); + sha256.update(passBytes, 0, passBytes.length); + update(sha256, salt, 0, salt.length); + return Base64.getEncoder().encodeToString(sha256.digest()); + } + + // BAD - Invoke a wrapper implementation without a salt. + public String getSHA256Hash6(String password) throws NoSuchAlgorithmException { + SHA256 sha256 = new SHA256(); + byte[] passBytes = password.getBytes(); + sha256.update(passBytes, 0, passBytes.length); + return Base64.getEncoder().encodeToString(sha256.digest()); + } + + private String hash(String payload) throws NoSuchAlgorithmException { MessageDigest alg = MessageDigest.getInstance("SHA-256"); return Base64.getEncoder().encodeToString(alg.digest(payload.getBytes(java.nio.charset.StandardCharsets.UTF_8))); } diff --git a/java/ql/test/experimental/query-tests/security/CWE-759/SHA256.java b/java/ql/test/experimental/query-tests/security/CWE-759/SHA256.java index 0d46f71d193..a0657af7112 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-759/SHA256.java +++ b/java/ql/test/experimental/query-tests/security/CWE-759/SHA256.java @@ -1,20 +1,21 @@ import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; public class SHA256 { MessageDigest md; public int getBlockSize() {return 32;} - public void init() throws Exception { + public void init() throws NoSuchAlgorithmException { try { md = MessageDigest.getInstance("SHA-256"); } catch (Exception e){ System.err.println(e); } } - public void update(byte[] foo, int start, int len) throws Exception { + public void update(byte[] foo, int start, int len) throws NoSuchAlgorithmException { md.update(foo, start, len); } - public byte[] digest() throws Exception { + public byte[] digest() throws NoSuchAlgorithmException { return md.digest(); } } \ No newline at end of file From b9809b071e5bc0f758770b1ccdeb0d945296ccaf Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Mon, 18 Jan 2021 19:22:34 +0000 Subject: [PATCH 022/725] Update the query to work with wrapper classes --- .../Security/CWE/CWE-759/HashWithoutSalt.ql | 4 +++- .../query-tests/security/CWE-759/HASH.java | 11 +++++++++++ .../security/CWE-759/HashWithoutSalt.expected | 8 ++++++++ .../security/CWE-759/HashWithoutSalt.java | 16 ++++++++++++++++ .../query-tests/security/CWE-759/SHA256.java | 2 +- 5 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 java/ql/test/experimental/query-tests/security/CWE-759/HASH.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql b/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql index 15361071610..b7c353de77a 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql @@ -89,13 +89,15 @@ class HashWithoutSaltConfiguration extends TaintTracking::Configuration { ma.getArgument(0) = node.asExpr() and // Detect wrapper methods that invoke `md.update(salt)` ma != mua and ( + ma.getQualifier().getType() instanceof Interface + or mua.getQualifier().(VarAccess).getVariable().getAnAccess() = ma.getQualifier() or mua.getAnArgument().(VarAccess).getVariable().getAnAccess() = ma.getQualifier() or mua.getQualifier().(VarAccess).getVariable().getAnAccess() = ma.getAnArgument() or - mua.getAnArgument().(VarAccess).getVariable().getAnAccess() = ma.getAnArgument() + mua.getArgument(0).(VarAccess).getVariable().getAnAccess() = ma.getAnArgument() ) and isMDUpdateCall(mua.getMethod()) ) diff --git a/java/ql/test/experimental/query-tests/security/CWE-759/HASH.java b/java/ql/test/experimental/query-tests/security/CWE-759/HASH.java new file mode 100644 index 00000000000..ed4da313244 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-759/HASH.java @@ -0,0 +1,11 @@ +import java.security.NoSuchAlgorithmException; + +public interface HASH { + void init() throws NoSuchAlgorithmException; + + int getBlockSize(); + + void update(byte[] foo, int start, int len) throws NoSuchAlgorithmException; + + byte[] digest() throws NoSuchAlgorithmException; +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.expected b/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.expected index 2077f2d6266..7fc5fe115e4 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.expected @@ -1,11 +1,19 @@ edges | HashWithoutSalt.java:10:36:10:43 | password : String | HashWithoutSalt.java:10:36:10:54 | getBytes(...) | | HashWithoutSalt.java:17:13:17:20 | password : String | HashWithoutSalt.java:17:13:17:31 | getBytes(...) | +| HashWithoutSalt.java:98:22:98:29 | password : String | HashWithoutSalt.java:99:17:99:25 | passBytes : byte[] | +| HashWithoutSalt.java:99:17:99:25 | passBytes : byte[] | SHA256.java:14:22:14:31 | foo : byte[] | +| SHA256.java:14:22:14:31 | foo : byte[] | SHA256.java:15:15:15:17 | foo | nodes | HashWithoutSalt.java:10:36:10:43 | password : String | semmle.label | password : String | | HashWithoutSalt.java:10:36:10:54 | getBytes(...) | semmle.label | getBytes(...) | | HashWithoutSalt.java:17:13:17:20 | password : String | semmle.label | password : String | | HashWithoutSalt.java:17:13:17:31 | getBytes(...) | semmle.label | getBytes(...) | +| HashWithoutSalt.java:98:22:98:29 | password : String | semmle.label | password : String | +| HashWithoutSalt.java:99:17:99:25 | passBytes : byte[] | semmle.label | passBytes : byte[] | +| SHA256.java:14:22:14:31 | foo : byte[] | semmle.label | foo : byte[] | +| SHA256.java:15:15:15:17 | foo | semmle.label | foo | #select | HashWithoutSalt.java:10:36:10:54 | getBytes(...) | HashWithoutSalt.java:10:36:10:43 | password : String | HashWithoutSalt.java:10:36:10:54 | getBytes(...) | $@ is hashed without a salt. | HashWithoutSalt.java:10:36:10:43 | password | The password | | HashWithoutSalt.java:17:13:17:31 | getBytes(...) | HashWithoutSalt.java:17:13:17:20 | password : String | HashWithoutSalt.java:17:13:17:31 | getBytes(...) | $@ is hashed without a salt. | HashWithoutSalt.java:17:13:17:20 | password | The password | +| SHA256.java:15:15:15:17 | foo | HashWithoutSalt.java:98:22:98:29 | password : String | SHA256.java:15:15:15:17 | foo | $@ is hashed without a salt. | HashWithoutSalt.java:98:22:98:29 | password | The password | diff --git a/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.java b/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.java index 852898f5481..9535e4d01e5 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.java +++ b/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.java @@ -100,6 +100,22 @@ public class HashWithoutSalt { return Base64.getEncoder().encodeToString(sha256.digest()); } + // GOOD - Invoke a wrapper implementation with a salt, which is only detectable when a class type is declared (not interface). + public String getSHA256Hash7(byte[] passphrase) throws NoSuchAlgorithmException, ClassNotFoundException, IllegalAccessException, InstantiationException { + Class c = Class.forName("SHA256"); + HASH sha256 = (HASH) (c.newInstance()); + byte[] tmp = new byte[4]; + byte[] key = new byte[32 * 2]; + for (int i = 0; i < 2; i++) { + sha256.init(); + tmp[3] = (byte) i; + sha256.update(tmp, 0, tmp.length); + sha256.update(passphrase, 0, passphrase.length); + System.arraycopy(sha256.digest(), 0, key, i * 32, 32); + } + return Base64.getEncoder().encodeToString(key); + } + private String hash(String payload) throws NoSuchAlgorithmException { MessageDigest alg = MessageDigest.getInstance("SHA-256"); return Base64.getEncoder().encodeToString(alg.digest(payload.getBytes(java.nio.charset.StandardCharsets.UTF_8))); diff --git a/java/ql/test/experimental/query-tests/security/CWE-759/SHA256.java b/java/ql/test/experimental/query-tests/security/CWE-759/SHA256.java index a0657af7112..53532c66f8c 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-759/SHA256.java +++ b/java/ql/test/experimental/query-tests/security/CWE-759/SHA256.java @@ -1,7 +1,7 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -public class SHA256 { +public class SHA256 implements HASH { MessageDigest md; public int getBlockSize() {return 32;} public void init() throws NoSuchAlgorithmException { From a56dd60baa3e882d5e85a3479fecae8cc4c6ac19 Mon Sep 17 00:00:00 2001 From: haby0 Date: Thu, 21 Jan 2021 19:18:10 +0800 Subject: [PATCH 023/725] *)add CWE-652 XQueryInjection detection --- .../Security/CWE/CWE-652/XQueryInjection.java | 35 +++++++++++++++++++ .../CWE/CWE-652/XQueryInjection.qhelp | 34 ++++++++++++++++++ .../Security/CWE/CWE-652/XQueryInjection.ql | 21 +++++++++++ .../CWE/CWE-652/XQueryInjectionLib.qll | 35 +++++++++++++++++++ 4 files changed, 125 insertions(+) create mode 100644 java/ql/src/Security/CWE/CWE-652/XQueryInjection.java create mode 100644 java/ql/src/Security/CWE/CWE-652/XQueryInjection.qhelp create mode 100644 java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql create mode 100644 java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll diff --git a/java/ql/src/Security/CWE/CWE-652/XQueryInjection.java b/java/ql/src/Security/CWE/CWE-652/XQueryInjection.java new file mode 100644 index 00000000000..a60adb37db2 --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-652/XQueryInjection.java @@ -0,0 +1,35 @@ +import javax.servlet.http.HttpServletRequest; +import javax.xml.namespace.QName; +import javax.xml.xquery.XQConnection; +import javax.xml.xquery.XQDataSource; +import javax.xml.xquery.XQException; +import javax.xml.xquery.XQItemType; +import javax.xml.xquery.XQPreparedExpression; +import javax.xml.xquery.XQResultSequence; +import net.sf.saxon.xqj.SaxonXQDataSource; + +public void bad(HttpServletRequest request) throws XQException { + String name = request.getParameter("name"); + XQDataSource ds = new SaxonXQDataSource(); + XQConnection conn = ds.getConnection(); + String query = "for $user in doc(\"users.xml\")/Users/User[name='" + name + "'] return $user/password"; + XQPreparedExpression xqpe = conn.prepareExpression(query); + XQResultSequence result = xqpe.executeQuery(); + while (result.next()){ + System.out.println(result.getItemAsString(null)); + } +} + +public void good(HttpServletRequest request) throws XQException { + String name = request.getParameter("name"); + XQDataSource ds = new SaxonXQDataSource(); + XQConnection conn = ds.getConnection(); + String query = "declare variable $name as xs:string external;" + + " for $user in doc(\"users.xml\")/Users/User[name=$name] return $user/password"; + XQPreparedExpression xqpe = conn.prepareExpression(query); + xqpe.bindString(new QName("name"), name, conn.createAtomicType(XQItemType.XQBASETYPE_STRING)); + XQResultSequence result = xqpe.executeQuery(); + while (result.next()){ + System.out.println(result.getItemAsString(null)); + } +} \ No newline at end of file diff --git a/java/ql/src/Security/CWE/CWE-652/XQueryInjection.qhelp b/java/ql/src/Security/CWE/CWE-652/XQueryInjection.qhelp new file mode 100644 index 00000000000..e05e24706cf --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-652/XQueryInjection.qhelp @@ -0,0 +1,34 @@ + + + +

    The software uses external input to dynamically construct an XQuery expression used to retrieve data from an XML database, but it does not neutralize or incorrectly neutralizes that input. +This allows an attacker to control the structure of the query.

    + +
    + + +

    Use parameterized queries. This will help ensure separation between data plane and control plane.

    + +
    + + +

    This example is a comparison of unused parameterized query and using parameterized query. +Parameterized query through bindString.

    + + + +
    + + +
  • cwe description: +XQuery Injection.
  • + + + + + +
    +
    diff --git a/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql b/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql new file mode 100644 index 00000000000..01a29e047f5 --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql @@ -0,0 +1,21 @@ +/** + * @name XQuery query built from user-controlled sources + * @description Building an XQuery query from user-controlled sources is vulnerable to insertion of + * malicious XQuery code by the user. + * @kind path-problem + * @problem.severity error + * @precision high + * @id java/XQuery-injection + * @tags security + * external/cwe/cwe-652 + */ + +import java +import semmle.code.java.dataflow.FlowSources +import XQueryInjectionLib +import DataFlow::PathGraph + +from DataFlow::PathNode source, DataFlow::PathNode sink, XQueryInjectionConfig conf +where conf.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "XQuery query might include code from $@.", source.getNode(), + "this user input" diff --git a/java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll b/java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll new file mode 100644 index 00000000000..06d04760986 --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll @@ -0,0 +1,35 @@ +import java +import semmle.code.java.dataflow.FlowSources + +class XQueryInjectionConfig extends TaintTracking::Configuration { + XQueryInjectionConfig() { this = "XQueryInjectionConfig" } + + override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } + + override predicate isSink(DataFlow::Node sink) { sink instanceof XQueryInjectionSink } +} + +/*Find if the executeQuery method is finally called.*/ +predicate executeQuery(MethodAccess ma) { + exists(LocalVariableDeclExpr lvd, MethodAccess ma1, Method m | lvd.getAChildExpr() = ma | + m = ma1.getMethod() and + m.hasName("executeQuery") and + m.getDeclaringType() + .getASourceSupertype*() + .hasQualifiedName("javax.xml.xquery", "XQPreparedExpression") and + ma1.getQualifier() = lvd.getAnAccess() + ) +} + +class XQueryInjectionSink extends DataFlow::ExprNode { + XQueryInjectionSink() { + exists(MethodAccess ma, Method m | m = ma.getMethod() | + m.hasName("prepareExpression") and + m.getDeclaringType() + .getASourceSupertype*() + .hasQualifiedName("javax.xml.xquery", "XQConnection") and + executeQuery(ma) and + asExpr() = ma.getArgument(0) + ) + } +} From ec4c155043198aba71bd42920f6c957cfd82643b Mon Sep 17 00:00:00 2001 From: haby0 Date: Sat, 23 Jan 2021 18:26:15 +0800 Subject: [PATCH 024/725] *)update XQueryInjection.qhelp --- java/ql/src/Security/CWE/CWE-652/XQueryInjection.qhelp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-652/XQueryInjection.qhelp b/java/ql/src/Security/CWE/CWE-652/XQueryInjection.qhelp index e05e24706cf..2b6433d6ef3 100644 --- a/java/ql/src/Security/CWE/CWE-652/XQueryInjection.qhelp +++ b/java/ql/src/Security/CWE/CWE-652/XQueryInjection.qhelp @@ -9,20 +9,19 @@ This allows an attacker to control the structure of the query.

    -

    Use parameterized queries. This will help ensure separation between data plane and control plane.

    +

    Use parameterized queries. This will help ensure the program retains control of the query structure.

    -

    This example is a comparison of unused parameterized query and using parameterized query. -Parameterized query through bindString.

    +

    The following example compares building a query by string concatenation (bad) vs. using bindString to parameterize the query (good).

    -
  • cwe description: +
  • CWE description: XQuery Injection.
  • From 44d99f8cd4a895c180ace4871450233d5609668b Mon Sep 17 00:00:00 2001 From: haby0 Date: Sat, 23 Jan 2021 18:26:58 +0800 Subject: [PATCH 025/725] *)update XQueryInjection.ql --- .../Security/CWE/CWE-652/XQueryInjection.ql | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql b/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql index 01a29e047f5..b4fcac80a43 100644 --- a/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql +++ b/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql @@ -15,6 +15,28 @@ import semmle.code.java.dataflow.FlowSources import XQueryInjectionLib import DataFlow::PathGraph +class XQueryInjectionConfig extends DataFlow::Configuration { + XQueryInjectionConfig() { this = "XQueryInjectionConfig" } + + override predicate isSource(DataFlow::Node source) { source instanceof XQueryInjectionSource } + + override predicate isSink(DataFlow::Node sink) { sink instanceof XQueryInjectionSink } + + override predicate isBarrier(DataFlow::Node node) { + exists(MethodAccess ma, Method m, BindParameterRemoteFlowConf conf, DataFlow::Node node1 | + m = ma.getMethod() + | + node.asExpr() = ma and + m.hasName("bindString") and + m.getDeclaringType() + .getASourceSupertype*() + .hasQualifiedName("javax.xml.xquery", "XQDynamicContext") and + ma.getArgument(1) = node1.asExpr() and + conf.hasFlowTo(node1) + ) + } +} + from DataFlow::PathNode source, DataFlow::PathNode sink, XQueryInjectionConfig conf where conf.hasFlowPath(source, sink) select sink.getNode(), source, sink, "XQuery query might include code from $@.", source.getNode(), From 0b326aae202c05d7b04f0999df0c72eb2034c2e8 Mon Sep 17 00:00:00 2001 From: haby0 Date: Sat, 23 Jan 2021 18:27:38 +0800 Subject: [PATCH 026/725] *)update XQueryInjectionLib.qll --- .../CWE/CWE-652/XQueryInjectionLib.qll | 97 +++++++++++++++---- 1 file changed, 76 insertions(+), 21 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll b/java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll index 06d04760986..808e5a984a5 100644 --- a/java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll +++ b/java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll @@ -1,35 +1,90 @@ import java import semmle.code.java.dataflow.FlowSources +import semmle.code.java.dataflow.TaintTracking2 +import DataFlow::PathGraph -class XQueryInjectionConfig extends TaintTracking::Configuration { - XQueryInjectionConfig() { this = "XQueryInjectionConfig" } - - override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } - - override predicate isSink(DataFlow::Node sink) { sink instanceof XQueryInjectionSink } +/** A call to `XQConnection.prepareExpression`. */ +class XQueryParserCall extends MethodAccess { + XQueryParserCall() { + exists(Method m | + this.getMethod() = m and + m.getDeclaringType() + .getASourceSupertype*() + .hasQualifiedName("javax.xml.xquery", "XQConnection") and + m.hasName("prepareExpression") + ) + } + // return the first parameter of the `bindString` method and use it as a sink + Expr getSink() { result = this.getArgument(0) } } -/*Find if the executeQuery method is finally called.*/ -predicate executeQuery(MethodAccess ma) { - exists(LocalVariableDeclExpr lvd, MethodAccess ma1, Method m | lvd.getAChildExpr() = ma | - m = ma1.getMethod() and - m.hasName("executeQuery") and - m.getDeclaringType() - .getASourceSupertype*() - .hasQualifiedName("javax.xml.xquery", "XQPreparedExpression") and - ma1.getQualifier() = lvd.getAnAccess() - ) +/** A call to `XQDynamicContext.bindString`. */ +class XQueryBindStringCall extends MethodAccess { + XQueryBindStringCall() { + exists(Method m | + this.getMethod() = m and + m.getDeclaringType() + .getASourceSupertype*() + .hasQualifiedName("javax.xml.xquery", "XQDynamicContext") and + m.hasName("bindString") + ) + } + // return the second parameter of the `bindString` method and use it as a sink + Expr getSink() { result = this.getArgument(1) } } -class XQueryInjectionSink extends DataFlow::ExprNode { - XQueryInjectionSink() { - exists(MethodAccess ma, Method m | m = ma.getMethod() | +/** Used to determine whether to call the `prepareExpression` method, and the first parameter value can be remotely controlled. */ +class ParserParameterRemoteFlowConf extends TaintTracking2::Configuration { + ParserParameterRemoteFlowConf() { this = "ParserParameterRemoteFlowConf" } + + override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource } + + override predicate isSink(DataFlow::Node sink) { + exists(XQueryParserCall xqpc | xqpc.getSink() = sink.asExpr()) + } +} + +/** Used to determine whether to call the `bindString` method, and the second parameter value can be controlled remotely. */ +class BindParameterRemoteFlowConf extends TaintTracking2::Configuration { + BindParameterRemoteFlowConf() { this = "BindParameterRemoteFlowConf" } + + override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource } + + override predicate isSink(DataFlow::Node sink) { + exists(XQueryBindStringCall xqbsc | xqbsc.getSink() = sink.asExpr()) + } +} + +/** + * A data flow source for XQuery injection vulnerability. + * 1. `prepareExpression` call as sink. + * 2. Determine whether the `var1` parameter of `prepareExpression` method can be controlled remotely. + */ +class XQueryInjectionSource extends DataFlow::ExprNode { + XQueryInjectionSource() { + exists(MethodAccess ma, Method m, ParserParameterRemoteFlowConf conf, DataFlow::Node node | + m = ma.getMethod() + | m.hasName("prepareExpression") and m.getDeclaringType() .getASourceSupertype*() .hasQualifiedName("javax.xml.xquery", "XQConnection") and - executeQuery(ma) and - asExpr() = ma.getArgument(0) + asExpr() = ma and + node.asExpr() = ma.getArgument(0) and + conf.hasFlowTo(node) + ) + } +} + +/** A data flow sink for XQuery injection vulnerability. */ +class XQueryInjectionSink extends DataFlow::Node { + XQueryInjectionSink() { + exists(MethodAccess ma, Method m | m = ma.getMethod() | + m.hasName("executeQuery") and + m.getDeclaringType() + .getASourceSupertype*() + .hasQualifiedName("javax.xml.xquery", "XQPreparedExpression") and + asExpr() = ma.getQualifier() ) } } From a64fc2b24ee7e084a0a402d11bb6795dabac6049 Mon Sep 17 00:00:00 2001 From: Francis Alexander Date: Sun, 24 Jan 2021 18:58:39 +0530 Subject: [PATCH 027/725] Java: Queries to detect remote source flow to CORS header --- .../Security/CWE/CWE-346/UnvalidatedCors.java | 40 ++++++++++ .../CWE/CWE-346/UnvalidatedCors.qhelp | 75 +++++++++++++++++++ .../Security/CWE/CWE-346/UnvalidatedCors.ql | 55 ++++++++++++++ .../security/CWE-346/UnvalidatedCors.expected | 7 ++ .../security/CWE-346/UnvalidatedCors.java | 52 +++++++++++++ .../security/CWE-346/UnvalidatedCors.qlref | 1 + .../test/query-tests/security/CWE-346/options | 1 + .../org/apache/commons/lang3/StringUtils.java | 7 ++ .../servlet-api-2.4/javax/servlet/Filter.java | 11 +++ .../javax/servlet/FilterChain.java | 7 ++ .../javax/servlet/FilterConfig.java | 10 +++ .../servlet/http/HttpServletResponse.java | 6 ++ 12 files changed, 272 insertions(+) create mode 100644 java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.java create mode 100644 java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.qhelp create mode 100644 java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql create mode 100644 java/ql/test/query-tests/security/CWE-346/UnvalidatedCors.expected create mode 100644 java/ql/test/query-tests/security/CWE-346/UnvalidatedCors.java create mode 100644 java/ql/test/query-tests/security/CWE-346/UnvalidatedCors.qlref create mode 100644 java/ql/test/query-tests/security/CWE-346/options create mode 100644 java/ql/test/stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/StringUtils.java create mode 100644 java/ql/test/stubs/servlet-api-2.4/javax/servlet/Filter.java create mode 100644 java/ql/test/stubs/servlet-api-2.4/javax/servlet/FilterChain.java create mode 100644 java/ql/test/stubs/servlet-api-2.4/javax/servlet/FilterConfig.java diff --git a/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.java b/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.java new file mode 100644 index 00000000000..8f388b13553 --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.java @@ -0,0 +1,40 @@ +import java.io.IOException; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang3.StringUtils; + +public class CorsFilter implements Filter { + public void init(FilterConfig filterConfig) throws ServletException { + // init + } + + public void doFilter(ServletRequest req, ServletResponse res, + FilterChain chain) throws IOException, ServletException { + HttpServletRequest request = (HttpServletRequest) req; + HttpServletResponse response = (HttpServletResponse) res; + String url = request.getHeader("Origin"); + + if (!StringUtils.isEmpty(url)) { + String val = response.getHeader("Access-Control-Allow-Origin"); + + if (StringUtils.isEmpty(val)) { + response.addHeader("Access-Control-Allow-Origin", url); + response.addHeader("Access-Control-Allow-Credentials", "true"); + } + } + + chain.doFilter(req, res); + } + + public void destroy() { + // destroy + } +} diff --git a/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.qhelp b/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.qhelp new file mode 100644 index 00000000000..3293352c0d5 --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.qhelp @@ -0,0 +1,75 @@ + + + + +

    + + A server can send the + "Access-Control-Allow-Credentials" CORS header to control + when a browser may send user credentials in Cross-Origin HTTP + requests. + +

    +

    + + When the Access-Control-Allow-Credentials header + is "true", the Access-Control-Allow-Origin + header must have a value different from "*" in order to + make browsers accept the header. Therefore, to allow multiple origins + for Cross-Origin requests with credentials, the server must + dynamically compute the value of the + "Access-Control-Allow-Origin" header. Computing this + header value from information in the request to the server can + therefore potentially allow an attacker to control the origins that + the browser sends credentials to. + +

    + + + +
    + + +

    + + When the Access-Control-Allow-Credentials header + value is "true", a dynamic computation of the + Access-Control-Allow-Origin header must involve + sanitization if it relies on user-controlled input. + + +

    +

    + + Since the "null" origin is easy to obtain for an + attacker, it is never safe to use "null" as the value of + the Access-Control-Allow-Origin header when the + Access-Control-Allow-Credentials header value is + "true". + +

    +
    + + +

    + + In the example below, the server allows the browser to send + user credentials in a Cross-Origin request. The request header + origins controls the allowed origins for such a + Cross-Origin request. + +

    + + + +
    + + +
  • Mozilla Developer Network: CORS, Access-Control-Allow-Origin.
  • +
  • Mozilla Developer Network: CORS, Access-Control-Allow-Credentials.
  • +
  • PortSwigger: Exploiting CORS Misconfigurations for Bitcoins and Bounties
  • +
  • W3C: CORS for developers, Advice for Resource Owners
  • +
    +
    diff --git a/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql b/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql new file mode 100644 index 00000000000..3685ec2209c --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql @@ -0,0 +1,55 @@ +/** + * @name Cors header being set from remote source + * @description Cors header is being set from remote source, allowing to control the origin. + * @kind path-problem + * @problem.severity error + * @precision high + * @id java/unvalidated-cors-origin-set + * @tags security + * external/cwe/cwe-346 + */ + +import java +import semmle.code.java.dataflow.FlowSources +import semmle.code.java.frameworks.Servlets +import semmle.code.java.dataflow.TaintTracking +import DataFlow::PathGraph + +// Check for Access-Control-Allow-Credentials as well, this ensures fair chances of exploitability. +predicate satisfyAllowCredentials(MethodAccess header, MethodAccess check) { + header.getArgument(0).(CompileTimeConstantExpr).getStringValue().toLowerCase() = + "access-control-allow-credentials" and + header.getArgument(1).(CompileTimeConstantExpr).getStringValue() = "true" and + header.getEnclosingCallable() = check.getEnclosingCallable() +} + +predicate checkAccessControlAllowOriginHeader(Expr expr) { + expr.(CompileTimeConstantExpr).getStringValue().toLowerCase() = "access-control-allow-origin" +} + +class CorsOriginConfig extends TaintTracking::Configuration { + CorsOriginConfig() { this = "CORSOriginConfig" } + + override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } + + override predicate isSink(DataFlow::Node sink) { + exists(ResponseSetHeaderMethod h, MethodAccess m | + m = h.getAReference() and + checkAccessControlAllowOriginHeader(m.getArgument(0)) and + satisfyAllowCredentials(h.getAReference(), m) and + sink.asExpr() = m.getArgument(1) + ) + or + exists(ResponseAddHeaderMethod a, MethodAccess m | + m = a.getAReference() and + checkAccessControlAllowOriginHeader(m.getArgument(0)) and + satisfyAllowCredentials(a.getAReference(), m) and + sink.asExpr() = m.getArgument(1) + ) + } +} + +from DataFlow::PathNode source, DataFlow::PathNode sink, CorsOriginConfig conf +where conf.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "Cors header is being set using user controlled value $@.", + source.getNode(), "user-provided value" diff --git a/java/ql/test/query-tests/security/CWE-346/UnvalidatedCors.expected b/java/ql/test/query-tests/security/CWE-346/UnvalidatedCors.expected new file mode 100644 index 00000000000..8bb9202b582 --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-346/UnvalidatedCors.expected @@ -0,0 +1,7 @@ +edges +| UnvalidatedCors.java:34:22:34:48 | getHeader(...) : String | UnvalidatedCors.java:40:67:40:69 | url | +nodes +| UnvalidatedCors.java:34:22:34:48 | getHeader(...) : String | semmle.label | getHeader(...) : String | +| UnvalidatedCors.java:40:67:40:69 | url | semmle.label | url | +#select +| UnvalidatedCors.java:40:67:40:69 | url | UnvalidatedCors.java:34:22:34:48 | getHeader(...) : String | UnvalidatedCors.java:40:67:40:69 | url | Cors header is being set using user controlled value $@. | UnvalidatedCors.java:34:22:34:48 | getHeader(...) | user-provided value | diff --git a/java/ql/test/query-tests/security/CWE-346/UnvalidatedCors.java b/java/ql/test/query-tests/security/CWE-346/UnvalidatedCors.java new file mode 100644 index 00000000000..b05a88ab432 --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-346/UnvalidatedCors.java @@ -0,0 +1,52 @@ +package com.mossle.core.servlet; + +import java.io.IOException; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang3.StringUtils; + +/** + *
    + * 
    + * 
    + */ +public class UnvalidatedCors implements Filter { + public void init(FilterConfig filterConfig) throws ServletException { + // init + } + + public void doFilter(ServletRequest req, ServletResponse res, + FilterChain chain) throws IOException, ServletException { + HttpServletRequest request = (HttpServletRequest) req; + HttpServletResponse response = (HttpServletResponse) res; + String url = request.getHeader("Origin"); + + if (!StringUtils.isEmpty(url)) { + String val = response.getHeader("Access-Control-Allow-Origin"); + + if (StringUtils.isEmpty(val)) { + response.addHeader("Access-Control-Allow-Origin", url); + response.addHeader("Access-Control-Allow-Credentials", "true"); + } + } + + chain.doFilter(req, res); + } + + public void destroy() { + // destroy + } +} + diff --git a/java/ql/test/query-tests/security/CWE-346/UnvalidatedCors.qlref b/java/ql/test/query-tests/security/CWE-346/UnvalidatedCors.qlref new file mode 100644 index 00000000000..93df7860cb4 --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-346/UnvalidatedCors.qlref @@ -0,0 +1 @@ +Security/CWE/CWE-346/UnvalidatedCors.ql diff --git a/java/ql/test/query-tests/security/CWE-346/options b/java/ql/test/query-tests/security/CWE-346/options new file mode 100644 index 00000000000..4fd2033a3d4 --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-346/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/apache-commons-lang3-3.7 diff --git a/java/ql/test/stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/StringUtils.java b/java/ql/test/stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/StringUtils.java new file mode 100644 index 00000000000..62b13e0e259 --- /dev/null +++ b/java/ql/test/stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/StringUtils.java @@ -0,0 +1,7 @@ +package org.apache.commons.lang3; + +public class StringUtils { + public static boolean isEmpty(final CharSequence cs) { + return cs == null || cs.length() == 0; + } +} diff --git a/java/ql/test/stubs/servlet-api-2.4/javax/servlet/Filter.java b/java/ql/test/stubs/servlet-api-2.4/javax/servlet/Filter.java new file mode 100644 index 00000000000..47fb902a3d6 --- /dev/null +++ b/java/ql/test/stubs/servlet-api-2.4/javax/servlet/Filter.java @@ -0,0 +1,11 @@ +package javax.servlet; + +import java.io.IOException; + +public interface Filter { + default public void init(FilterConfig filterConfig) throws ServletException {} + public void doFilter(ServletRequest request, ServletResponse response, + FilterChain chain) + throws IOException, ServletException; + default public void destroy() {} +} diff --git a/java/ql/test/stubs/servlet-api-2.4/javax/servlet/FilterChain.java b/java/ql/test/stubs/servlet-api-2.4/javax/servlet/FilterChain.java new file mode 100644 index 00000000000..b9f9708be56 --- /dev/null +++ b/java/ql/test/stubs/servlet-api-2.4/javax/servlet/FilterChain.java @@ -0,0 +1,7 @@ +package javax.servlet; + +import java.io.IOException; + +public interface FilterChain { + public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException; +} diff --git a/java/ql/test/stubs/servlet-api-2.4/javax/servlet/FilterConfig.java b/java/ql/test/stubs/servlet-api-2.4/javax/servlet/FilterConfig.java new file mode 100644 index 00000000000..85d172231e9 --- /dev/null +++ b/java/ql/test/stubs/servlet-api-2.4/javax/servlet/FilterConfig.java @@ -0,0 +1,10 @@ +package javax.servlet; + +import java.util.Enumeration; + +public interface FilterConfig { + public String getFilterName(); + public ServletContext getServletContext(); + public String getInitParameter(String name); + public Enumeration getInitParameterNames(); +} diff --git a/java/ql/test/stubs/servlet-api-2.4/javax/servlet/http/HttpServletResponse.java b/java/ql/test/stubs/servlet-api-2.4/javax/servlet/http/HttpServletResponse.java index 2971e023390..162ac0db3cc 100644 --- a/java/ql/test/stubs/servlet-api-2.4/javax/servlet/http/HttpServletResponse.java +++ b/java/ql/test/stubs/servlet-api-2.4/javax/servlet/http/HttpServletResponse.java @@ -24,6 +24,7 @@ package javax.servlet.http; import java.io.IOException; +import java.util.Collection; import javax.servlet.ServletResponse; public interface HttpServletResponse extends ServletResponse { @@ -44,6 +45,11 @@ public interface HttpServletResponse extends ServletResponse { public void addIntHeader(String name, int value); public void setStatus(int sc); public void setStatus(int sc, String sm); + public int getStatus(); + public String getHeader(String name); + public Collection getHeaders(String name); + public Collection getHeaderNames(); + public static final int SC_CONTINUE = 100; public static final int SC_SWITCHING_PROTOCOLS = 101; From 81e372d0782d21d30394e21912db6013c88503b8 Mon Sep 17 00:00:00 2001 From: Francis Alexander Date: Sun, 24 Jan 2021 20:44:21 +0530 Subject: [PATCH 028/725] Formatting changes --- .../Security/CWE/CWE-346/UnvalidatedCors.java | 10 +++------- .../Security/CWE/CWE-346/UnvalidatedCors.ql | 2 +- .../security/CWE-346/UnvalidatedCors.expected | 8 ++++---- .../security/CWE-346/UnvalidatedCors.java | 19 ++----------------- 4 files changed, 10 insertions(+), 29 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.java b/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.java index 8f388b13553..af07cdd1d8d 100644 --- a/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.java +++ b/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.java @@ -12,9 +12,7 @@ import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang3.StringUtils; public class CorsFilter implements Filter { - public void init(FilterConfig filterConfig) throws ServletException { - // init - } + public void init(FilterConfig filterConfig) throws ServletException {} public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { @@ -23,7 +21,7 @@ public class CorsFilter implements Filter { String url = request.getHeader("Origin"); if (!StringUtils.isEmpty(url)) { - String val = response.getHeader("Access-Control-Allow-Origin"); + String val = response.getHeader("Access-Control-Allow-Origin"); // BAD -> User controlled CORS header. if (StringUtils.isEmpty(val)) { response.addHeader("Access-Control-Allow-Origin", url); @@ -34,7 +32,5 @@ public class CorsFilter implements Filter { chain.doFilter(req, res); } - public void destroy() { - // destroy - } + public void destroy() {} } diff --git a/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql b/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql index 3685ec2209c..058bf535b82 100644 --- a/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql +++ b/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql @@ -28,7 +28,7 @@ predicate checkAccessControlAllowOriginHeader(Expr expr) { } class CorsOriginConfig extends TaintTracking::Configuration { - CorsOriginConfig() { this = "CORSOriginConfig" } + CorsOriginConfig() { this = "CorsOriginConfig" } override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } diff --git a/java/ql/test/query-tests/security/CWE-346/UnvalidatedCors.expected b/java/ql/test/query-tests/security/CWE-346/UnvalidatedCors.expected index 8bb9202b582..b7954950deb 100644 --- a/java/ql/test/query-tests/security/CWE-346/UnvalidatedCors.expected +++ b/java/ql/test/query-tests/security/CWE-346/UnvalidatedCors.expected @@ -1,7 +1,7 @@ edges -| UnvalidatedCors.java:34:22:34:48 | getHeader(...) : String | UnvalidatedCors.java:40:67:40:69 | url | +| UnvalidatedCors.java:21:22:21:48 | getHeader(...) : String | UnvalidatedCors.java:27:67:27:69 | url | nodes -| UnvalidatedCors.java:34:22:34:48 | getHeader(...) : String | semmle.label | getHeader(...) : String | -| UnvalidatedCors.java:40:67:40:69 | url | semmle.label | url | +| UnvalidatedCors.java:21:22:21:48 | getHeader(...) : String | semmle.label | getHeader(...) : String | +| UnvalidatedCors.java:27:67:27:69 | url | semmle.label | url | #select -| UnvalidatedCors.java:40:67:40:69 | url | UnvalidatedCors.java:34:22:34:48 | getHeader(...) : String | UnvalidatedCors.java:40:67:40:69 | url | Cors header is being set using user controlled value $@. | UnvalidatedCors.java:34:22:34:48 | getHeader(...) | user-provided value | +| UnvalidatedCors.java:27:67:27:69 | url | UnvalidatedCors.java:21:22:21:48 | getHeader(...) : String | UnvalidatedCors.java:27:67:27:69 | url | Cors header is being set using user controlled value $@. | UnvalidatedCors.java:21:22:21:48 | getHeader(...) | user-provided value | diff --git a/java/ql/test/query-tests/security/CWE-346/UnvalidatedCors.java b/java/ql/test/query-tests/security/CWE-346/UnvalidatedCors.java index b05a88ab432..9ec3c8466be 100644 --- a/java/ql/test/query-tests/security/CWE-346/UnvalidatedCors.java +++ b/java/ql/test/query-tests/security/CWE-346/UnvalidatedCors.java @@ -1,5 +1,3 @@ -package com.mossle.core.servlet; - import java.io.IOException; import javax.servlet.Filter; @@ -13,19 +11,8 @@ import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang3.StringUtils; -/** - *
    - * 
    - * 
    - */ public class UnvalidatedCors implements Filter { - public void init(FilterConfig filterConfig) throws ServletException { - // init - } + public void init(FilterConfig filterConfig) throws ServletException {} public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { @@ -45,8 +32,6 @@ public class UnvalidatedCors implements Filter { chain.doFilter(req, res); } - public void destroy() { - // destroy - } + public void destroy() {} } From 75b79039a1c452de1b78736e8f319537e8fa1d5f Mon Sep 17 00:00:00 2001 From: Francis Alexander Date: Sun, 24 Jan 2021 20:46:37 +0530 Subject: [PATCH 029/725] Example fixes --- java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.java b/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.java index af07cdd1d8d..772a64969ea 100644 --- a/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.java +++ b/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.java @@ -21,10 +21,10 @@ public class CorsFilter implements Filter { String url = request.getHeader("Origin"); if (!StringUtils.isEmpty(url)) { - String val = response.getHeader("Access-Control-Allow-Origin"); // BAD -> User controlled CORS header. + String val = response.getHeader("Access-Control-Allow-Origin"); if (StringUtils.isEmpty(val)) { - response.addHeader("Access-Control-Allow-Origin", url); + response.addHeader("Access-Control-Allow-Origin", url); // BAD -> User controlled CORS header being set here. response.addHeader("Access-Control-Allow-Credentials", "true"); } } From 14a23eed4f09977b3ce217828b7a40581b78374e Mon Sep 17 00:00:00 2001 From: haby0 Date: Mon, 25 Jan 2021 19:15:59 +0800 Subject: [PATCH 030/725] Update java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll Co-authored-by: Chris Smowton --- java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll b/java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll index 808e5a984a5..10235770b2a 100644 --- a/java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll +++ b/java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll @@ -14,8 +14,8 @@ class XQueryParserCall extends MethodAccess { m.hasName("prepareExpression") ) } - // return the first parameter of the `bindString` method and use it as a sink - Expr getSink() { result = this.getArgument(0) } + /** Returns the first parameter of the `bindString` method. */ + Expr getInput() { result = this.getArgument(0) } } /** A call to `XQDynamicContext.bindString`. */ From 16308fe557bafc8079a89ed8435b00e27406d730 Mon Sep 17 00:00:00 2001 From: haby0 Date: Mon, 25 Jan 2021 19:16:18 +0800 Subject: [PATCH 031/725] Update java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll Co-authored-by: Chris Smowton --- java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll b/java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll index 10235770b2a..3d5770b5be6 100644 --- a/java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll +++ b/java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll @@ -29,8 +29,8 @@ class XQueryBindStringCall extends MethodAccess { m.hasName("bindString") ) } - // return the second parameter of the `bindString` method and use it as a sink - Expr getSink() { result = this.getArgument(1) } + /** Returns the second parameter of the `bindString` method. */ + Expr getInput() { result = this.getArgument(1) } } /** Used to determine whether to call the `prepareExpression` method, and the first parameter value can be remotely controlled. */ From d34233b44fd905989191563cd05e303ce3a0eaf6 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Mon, 25 Jan 2021 11:10:00 +0000 Subject: [PATCH 032/725] Rewrite XQuery injection to use an additional taint step instead of multiple configurations. Also remove a needless barrier -- the method in question doesn't conduct taint by default, so excluding particular instances of that call is not necessary. --- .../Security/CWE/CWE-652/XQueryInjection.ql | 26 +++--- .../CWE/CWE-652/XQueryInjectionLib.qll | 87 ++++--------------- 2 files changed, 27 insertions(+), 86 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql b/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql index b4fcac80a43..7163a1fd93d 100644 --- a/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql +++ b/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql @@ -15,25 +15,21 @@ import semmle.code.java.dataflow.FlowSources import XQueryInjectionLib import DataFlow::PathGraph -class XQueryInjectionConfig extends DataFlow::Configuration { +class XQueryInjectionConfig extends TaintTracking::Configuration { XQueryInjectionConfig() { this = "XQueryInjectionConfig" } - override predicate isSource(DataFlow::Node source) { source instanceof XQueryInjectionSource } + override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } - override predicate isSink(DataFlow::Node sink) { sink instanceof XQueryInjectionSink } + override predicate isSink(DataFlow::Node sink) { + sink.asExpr() = any(XQueryExecuteCall execute).getPreparedExpression() + } - override predicate isBarrier(DataFlow::Node node) { - exists(MethodAccess ma, Method m, BindParameterRemoteFlowConf conf, DataFlow::Node node1 | - m = ma.getMethod() - | - node.asExpr() = ma and - m.hasName("bindString") and - m.getDeclaringType() - .getASourceSupertype*() - .hasQualifiedName("javax.xml.xquery", "XQDynamicContext") and - ma.getArgument(1) = node1.asExpr() and - conf.hasFlowTo(node1) - ) + /** + * Conveys taint from the input to a `prepareExpression` call to the returned prepared expression. + */ + override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { + exists(XQueryParserCall parser | + pred.asExpr() = parser.getInput() and succ.asExpr() = parser) } } diff --git a/java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll b/java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll index 3d5770b5be6..cfdbaaa70da 100644 --- a/java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll +++ b/java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll @@ -1,7 +1,4 @@ import java -import semmle.code.java.dataflow.FlowSources -import semmle.code.java.dataflow.TaintTracking2 -import DataFlow::PathGraph /** A call to `XQConnection.prepareExpression`. */ class XQueryParserCall extends MethodAccess { @@ -14,77 +11,25 @@ class XQueryParserCall extends MethodAccess { m.hasName("prepareExpression") ) } - /** Returns the first parameter of the `bindString` method. */ + + /** + * Returns the first parameter of the `prepareExpression` method, which provides + * the string, stream or reader to be compiled into a prepared expression. + */ Expr getInput() { result = this.getArgument(0) } } -/** A call to `XQDynamicContext.bindString`. */ -class XQueryBindStringCall extends MethodAccess { - XQueryBindStringCall() { - exists(Method m | - this.getMethod() = m and - m.getDeclaringType() - .getASourceSupertype*() - .hasQualifiedName("javax.xml.xquery", "XQDynamicContext") and - m.hasName("bindString") - ) - } - /** Returns the second parameter of the `bindString` method. */ - Expr getInput() { result = this.getArgument(1) } -} - -/** Used to determine whether to call the `prepareExpression` method, and the first parameter value can be remotely controlled. */ -class ParserParameterRemoteFlowConf extends TaintTracking2::Configuration { - ParserParameterRemoteFlowConf() { this = "ParserParameterRemoteFlowConf" } - - override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource } - - override predicate isSink(DataFlow::Node sink) { - exists(XQueryParserCall xqpc | xqpc.getSink() = sink.asExpr()) - } -} - -/** Used to determine whether to call the `bindString` method, and the second parameter value can be controlled remotely. */ -class BindParameterRemoteFlowConf extends TaintTracking2::Configuration { - BindParameterRemoteFlowConf() { this = "BindParameterRemoteFlowConf" } - - override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource } - - override predicate isSink(DataFlow::Node sink) { - exists(XQueryBindStringCall xqbsc | xqbsc.getSink() = sink.asExpr()) - } -} - -/** - * A data flow source for XQuery injection vulnerability. - * 1. `prepareExpression` call as sink. - * 2. Determine whether the `var1` parameter of `prepareExpression` method can be controlled remotely. - */ -class XQueryInjectionSource extends DataFlow::ExprNode { - XQueryInjectionSource() { - exists(MethodAccess ma, Method m, ParserParameterRemoteFlowConf conf, DataFlow::Node node | - m = ma.getMethod() - | - m.hasName("prepareExpression") and - m.getDeclaringType() - .getASourceSupertype*() - .hasQualifiedName("javax.xml.xquery", "XQConnection") and - asExpr() = ma and - node.asExpr() = ma.getArgument(0) and - conf.hasFlowTo(node) - ) - } -} - -/** A data flow sink for XQuery injection vulnerability. */ -class XQueryInjectionSink extends DataFlow::Node { - XQueryInjectionSink() { - exists(MethodAccess ma, Method m | m = ma.getMethod() | - m.hasName("executeQuery") and - m.getDeclaringType() - .getASourceSupertype*() - .hasQualifiedName("javax.xml.xquery", "XQPreparedExpression") and - asExpr() = ma.getQualifier() +/** A call to `XQPreparedExpression.executeQuery`. */ +class XQueryExecuteCall extends MethodAccess { + XQueryExecuteCall() { + exists(Method m | this.getMethod() = m and + m.hasName("executeQuery") and + m.getDeclaringType() + .getASourceSupertype*() + .hasQualifiedName("javax.xml.xquery", "XQPreparedExpression") ) } + + /** Return this prepared expression. */ + Expr getPreparedExpression() { result = this.getQualifier() } } From 985d3d469aed73369d809befb847140b455a8010 Mon Sep 17 00:00:00 2001 From: Francis Alexander Date: Mon, 25 Jan 2021 23:26:36 +0530 Subject: [PATCH 033/725] PR feedback integration --- .../CWE/CWE-346/UnvalidatedCors.qhelp | 17 +++++---- .../Security/CWE/CWE-346/UnvalidatedCors.ql | 38 ++++++++++--------- 2 files changed, 29 insertions(+), 26 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.qhelp b/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.qhelp index 3293352c0d5..b10d2a9150a 100644 --- a/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.qhelp +++ b/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.qhelp @@ -7,7 +7,7 @@

    A server can send the - "Access-Control-Allow-Credentials" CORS header to control + Access-Control-Allow-Credentials CORS header to control when a browser may send user credentials in Cross-Origin HTTP requests. @@ -15,12 +15,12 @@

    When the Access-Control-Allow-Credentials header - is "true", the Access-Control-Allow-Origin - header must have a value different from "*" in order to + is true, the Access-Control-Allow-Origin + header must have a value different from * in order to make browsers accept the header. Therefore, to allow multiple origins for Cross-Origin requests with credentials, the server must dynamically compute the value of the - "Access-Control-Allow-Origin" header. Computing this + Access-Control-Allow-Origin header. Computing this header value from information in the request to the server can therefore potentially allow an attacker to control the origins that the browser sends credentials to. @@ -35,7 +35,7 @@

    When the Access-Control-Allow-Credentials header - value is "true", a dynamic computation of the + value is true, a dynamic computation of the Access-Control-Allow-Origin header must involve sanitization if it relies on user-controlled input. @@ -43,11 +43,12 @@

    - Since the "null" origin is easy to obtain for an - attacker, it is never safe to use "null" as the value of + Since the null origin is easy to obtain for an + attacker, it is never safe to use null as the value of the Access-Control-Allow-Origin header when the Access-Control-Allow-Credentials header value is - "true". + true.This can be done using a sandboxed iframe. A more detailed + explanation is available in the portswigger blogpost.

    diff --git a/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql b/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql index 058bf535b82..17e4cddb87e 100644 --- a/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql +++ b/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql @@ -15,16 +15,17 @@ import semmle.code.java.frameworks.Servlets import semmle.code.java.dataflow.TaintTracking import DataFlow::PathGraph -// Check for Access-Control-Allow-Credentials as well, this ensures fair chances of exploitability. -predicate satisfyAllowCredentials(MethodAccess header, MethodAccess check) { +/** + * Holds if `header` sets `Access-Control-Allow-Credentials` to `true`. This ensures fair chances of exploitability. + */ +private predicate setsAllowCredentials(MethodAccess header) { header.getArgument(0).(CompileTimeConstantExpr).getStringValue().toLowerCase() = "access-control-allow-credentials" and - header.getArgument(1).(CompileTimeConstantExpr).getStringValue() = "true" and - header.getEnclosingCallable() = check.getEnclosingCallable() + header.getArgument(1).(CompileTimeConstantExpr).getStringValue() = "true" } -predicate checkAccessControlAllowOriginHeader(Expr expr) { - expr.(CompileTimeConstantExpr).getStringValue().toLowerCase() = "access-control-allow-origin" +private Expr getAccessControlAllowOriginHeaderName() { + result.(CompileTimeConstantExpr).getStringValue().toLowerCase() = "access-control-allow-origin" } class CorsOriginConfig extends TaintTracking::Configuration { @@ -33,18 +34,19 @@ class CorsOriginConfig extends TaintTracking::Configuration { override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } override predicate isSink(DataFlow::Node sink) { - exists(ResponseSetHeaderMethod h, MethodAccess m | - m = h.getAReference() and - checkAccessControlAllowOriginHeader(m.getArgument(0)) and - satisfyAllowCredentials(h.getAReference(), m) and - sink.asExpr() = m.getArgument(1) - ) - or - exists(ResponseAddHeaderMethod a, MethodAccess m | - m = a.getAReference() and - checkAccessControlAllowOriginHeader(m.getArgument(0)) and - satisfyAllowCredentials(a.getAReference(), m) and - sink.asExpr() = m.getArgument(1) + exists(MethodAccess corsheader, MethodAccess allowcredentialsheader | + ( + corsheader.getMethod() instanceof ResponseSetHeaderMethod or + corsheader.getMethod() instanceof ResponseAddHeaderMethod + ) and + ( + allowcredentialsheader.getMethod() instanceof ResponseSetHeaderMethod or + allowcredentialsheader.getMethod() instanceof ResponseAddHeaderMethod + ) and + getAccessControlAllowOriginHeaderName() = corsheader.getArgument(0) and + setsAllowCredentials(allowcredentialsheader) and + corsheader.getEnclosingCallable() = allowcredentialsheader.getEnclosingCallable() and + sink.asExpr() = corsheader.getArgument(1) ) } } From 19872e9aedb7892acf2be3c7f693a085c7cc6de6 Mon Sep 17 00:00:00 2001 From: Francis Alexander Date: Tue, 26 Jan 2021 17:24:17 +0530 Subject: [PATCH 034/725] More Feedback integration --- java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.qhelp | 2 +- java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql | 8 ++++---- .../org/apache/commons/lang3/StringUtils.java | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.qhelp b/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.qhelp index b10d2a9150a..d01c27c23ca 100644 --- a/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.qhelp +++ b/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.qhelp @@ -48,7 +48,7 @@ the Access-Control-Allow-Origin header when the Access-Control-Allow-Credentials header value is true.This can be done using a sandboxed iframe. A more detailed - explanation is available in the portswigger blogpost. + explanation is available in the portswigger blogpost referenced below.

    diff --git a/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql b/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql index 17e4cddb87e..3d98237b104 100644 --- a/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql +++ b/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql @@ -19,6 +19,10 @@ import DataFlow::PathGraph * Holds if `header` sets `Access-Control-Allow-Credentials` to `true`. This ensures fair chances of exploitability. */ private predicate setsAllowCredentials(MethodAccess header) { + ( + header.getMethod() instanceof ResponseSetHeaderMethod or + header.getMethod() instanceof ResponseAddHeaderMethod + ) and header.getArgument(0).(CompileTimeConstantExpr).getStringValue().toLowerCase() = "access-control-allow-credentials" and header.getArgument(1).(CompileTimeConstantExpr).getStringValue() = "true" @@ -39,10 +43,6 @@ class CorsOriginConfig extends TaintTracking::Configuration { corsheader.getMethod() instanceof ResponseSetHeaderMethod or corsheader.getMethod() instanceof ResponseAddHeaderMethod ) and - ( - allowcredentialsheader.getMethod() instanceof ResponseSetHeaderMethod or - allowcredentialsheader.getMethod() instanceof ResponseAddHeaderMethod - ) and getAccessControlAllowOriginHeaderName() = corsheader.getArgument(0) and setsAllowCredentials(allowcredentialsheader) and corsheader.getEnclosingCallable() = allowcredentialsheader.getEnclosingCallable() and diff --git a/java/ql/test/stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/StringUtils.java b/java/ql/test/stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/StringUtils.java index 62b13e0e259..06517fa9615 100644 --- a/java/ql/test/stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/StringUtils.java +++ b/java/ql/test/stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/StringUtils.java @@ -2,6 +2,6 @@ package org.apache.commons.lang3; public class StringUtils { public static boolean isEmpty(final CharSequence cs) { - return cs == null || cs.length() == 0; + return true; } } From b76854a384cb7636e2a396fc399b12213dc2ff69 Mon Sep 17 00:00:00 2001 From: haby0 Date: Wed, 27 Jan 2021 10:14:33 +0800 Subject: [PATCH 035/725] *)add CWE-652 test case --- .../security/CWE-652/XQueryInjection.expected | 19 ++++ .../security/CWE-652/XQueryInjection.java | 87 +++++++++++++++++++ .../security/CWE-652/XQueryInjection.qlref | 1 + .../query-tests/security/CWE-652/options | 1 + .../javax/xml/xquery/XQConnection.java | 19 ++++ .../javax/xml/xquery/XQDataFactory.java | 5 ++ .../javax/xml/xquery/XQDataSource.java | 5 ++ .../javax/xml/xquery/XQDynamicContext.java | 7 ++ .../javax/xml/xquery/XQException.java | 3 + .../javax/xml/xquery/XQItemAccessor.java | 7 ++ .../javax/xml/xquery/XQItemType.java | 68 +++++++++++++++ .../xml/xquery/XQPreparedExpression.java | 5 ++ .../javax/xml/xquery/XQResultSequence.java | 3 + .../javax/xml/xquery/XQSequence.java | 5 ++ .../javax/xml/xquery/XQSequenceType.java | 3 + .../javax/xml/xquery/XQStaticContext.java | 3 + .../net/sf/saxon/Configuration.java | 6 ++ .../net/sf/saxon/SourceResolver.java | 3 + .../net/sf/saxon/xqj/Closable.java | 3 + .../net/sf/saxon/xqj/SaxonXQConnection.java | 41 +++++++++ .../net/sf/saxon/xqj/SaxonXQDataFactory.java | 11 +++ .../net/sf/saxon/xqj/SaxonXQDataSource.java | 12 +++ .../sf/saxon/xqj/SaxonXQStaticContext.java | 5 ++ 23 files changed, 322 insertions(+) create mode 100644 java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.java create mode 100644 java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.qlref create mode 100644 java/ql/test/experimental/query-tests/security/CWE-652/options create mode 100644 java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQConnection.java create mode 100644 java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQDataFactory.java create mode 100644 java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQDataSource.java create mode 100644 java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQDynamicContext.java create mode 100644 java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQException.java create mode 100644 java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQItemAccessor.java create mode 100644 java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQItemType.java create mode 100644 java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQPreparedExpression.java create mode 100644 java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQResultSequence.java create mode 100644 java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQSequence.java create mode 100644 java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQSequenceType.java create mode 100644 java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQStaticContext.java create mode 100644 java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/Configuration.java create mode 100644 java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/SourceResolver.java create mode 100644 java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/xqj/Closable.java create mode 100644 java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/xqj/SaxonXQConnection.java create mode 100644 java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/xqj/SaxonXQDataFactory.java create mode 100644 java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/xqj/SaxonXQDataSource.java create mode 100644 java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/xqj/SaxonXQStaticContext.java diff --git a/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.expected b/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.expected new file mode 100644 index 00000000000..1ac4289a99c --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.expected @@ -0,0 +1,19 @@ +edges +| XQueryInjection.java:26:37:26:65 | prepareExpression(...) : XQPreparedExpression | XQueryInjection.java:27:35:27:38 | xqpe | +| XQueryInjection.java:41:37:41:65 | prepareExpression(...) : XQPreparedExpression | XQueryInjection.java:42:35:42:38 | xqpe | +| XQueryInjection.java:53:37:53:64 | prepareExpression(...) : XQPreparedExpression | XQueryInjection.java:54:35:54:38 | xqpe | +| XQueryInjection.java:66:37:66:62 | prepareExpression(...) : XQPreparedExpression | XQueryInjection.java:67:35:67:38 | xqpe | +nodes +| XQueryInjection.java:26:37:26:65 | prepareExpression(...) : XQPreparedExpression | semmle.label | prepareExpression(...) : XQPreparedExpression | +| XQueryInjection.java:27:35:27:38 | xqpe | semmle.label | xqpe | +| XQueryInjection.java:41:37:41:65 | prepareExpression(...) : XQPreparedExpression | semmle.label | prepareExpression(...) : XQPreparedExpression | +| XQueryInjection.java:42:35:42:38 | xqpe | semmle.label | xqpe | +| XQueryInjection.java:53:37:53:64 | prepareExpression(...) : XQPreparedExpression | semmle.label | prepareExpression(...) : XQPreparedExpression | +| XQueryInjection.java:54:35:54:38 | xqpe | semmle.label | xqpe | +| XQueryInjection.java:66:37:66:62 | prepareExpression(...) : XQPreparedExpression | semmle.label | prepareExpression(...) : XQPreparedExpression | +| XQueryInjection.java:67:35:67:38 | xqpe | semmle.label | xqpe | +#select +| XQueryInjection.java:27:35:27:38 | xqpe | XQueryInjection.java:26:37:26:65 | prepareExpression(...) : XQPreparedExpression | XQueryInjection.java:27:35:27:38 | xqpe | XQuery query might include code from $@. | XQueryInjection.java:26:37:26:65 | prepareExpression(...) | this user input | +| XQueryInjection.java:42:35:42:38 | xqpe | XQueryInjection.java:41:37:41:65 | prepareExpression(...) : XQPreparedExpression | XQueryInjection.java:42:35:42:38 | xqpe | XQuery query might include code from $@. | XQueryInjection.java:41:37:41:65 | prepareExpression(...) | this user input | +| XQueryInjection.java:54:35:54:38 | xqpe | XQueryInjection.java:53:37:53:64 | prepareExpression(...) : XQPreparedExpression | XQueryInjection.java:54:35:54:38 | xqpe | XQuery query might include code from $@. | XQueryInjection.java:53:37:53:64 | prepareExpression(...) | this user input | +| XQueryInjection.java:67:35:67:38 | xqpe | XQueryInjection.java:66:37:66:62 | prepareExpression(...) : XQPreparedExpression | XQueryInjection.java:67:35:67:38 | xqpe | XQuery query might include code from $@. | XQueryInjection.java:66:37:66:62 | prepareExpression(...) | this user input | diff --git a/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.java b/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.java new file mode 100644 index 00000000000..48846ae1bca --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.java @@ -0,0 +1,87 @@ +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import javax.servlet.http.HttpServletRequest; +import javax.xml.namespace.QName; +import javax.xml.xquery.XQConnection; +import javax.xml.xquery.XQDataSource; +import javax.xml.xquery.XQException; +import javax.xml.xquery.XQItemType; +import javax.xml.xquery.XQPreparedExpression; +import javax.xml.xquery.XQResultSequence; +import net.sf.saxon.xqj.SaxonXQDataSource; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +@Controller +public class XQueryInjection { + + @RequestMapping + public void testRequestbad(HttpServletRequest request) throws Exception { + String name = request.getParameter("name"); + XQDataSource ds = new SaxonXQDataSource(); + XQConnection conn = ds.getConnection(); + String query = "for $user in doc(\"users.xml\")/Users/User[name='" + name + "'] return $user/password"; + XQPreparedExpression xqpe = conn.prepareExpression(query); + XQResultSequence result = xqpe.executeQuery(); + while (result.next()){ + System.out.println(result.getItemAsString(null)); + } + + } + + + @RequestMapping + public void testStringtbad(@RequestParam String nameStr) throws XQException { + String name = nameStr; + XQDataSource ds = new SaxonXQDataSource(); + XQConnection conn = ds.getConnection(); + String query = "for $user in doc(\"users.xml\")/Users/User[name='" + name + "'] return $user/password"; + XQPreparedExpression xqpe = conn.prepareExpression(query); + XQResultSequence result = xqpe.executeQuery(); + while (result.next()){ + System.out.println(result.getItemAsString(null)); + } + } + + @RequestMapping + public void testInputStreambad(HttpServletRequest request) throws Exception { + InputStream name = request.getInputStream(); + XQDataSource ds = new SaxonXQDataSource(); + XQConnection conn = ds.getConnection(); + XQPreparedExpression xqpe = conn.prepareExpression(name); + XQResultSequence result = xqpe.executeQuery(); + while (result.next()){ + System.out.println(result.getItemAsString(null)); + } + } + + @RequestMapping + public void testReaderbad(HttpServletRequest request) throws Exception { + InputStream name = request.getInputStream(); + BufferedReader br = new BufferedReader(new InputStreamReader(name)); + XQDataSource ds = new SaxonXQDataSource(); + XQConnection conn = ds.getConnection(); + XQPreparedExpression xqpe = conn.prepareExpression(br); + XQResultSequence result = xqpe.executeQuery(); + while (result.next()){ + System.out.println(result.getItemAsString(null)); + } + } + + @RequestMapping + public void good(HttpServletRequest request) throws XQException { + String name = request.getParameter("name"); + XQDataSource ds = new SaxonXQDataSource(); + XQConnection conn = ds.getConnection(); + String query = "declare variable $name as xs:string external;" + + " for $user in doc(\"users.xml\")/Users/User[name=$name] return $user/password"; + XQPreparedExpression xqpe = conn.prepareExpression(query); + xqpe.bindString(new QName("name"), name, conn.createAtomicType(XQItemType.XQBASETYPE_STRING)); + XQResultSequence result = xqpe.executeQuery(); + while (result.next()){ + System.out.println(result.getItemAsString(null)); + } + } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.qlref b/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.qlref new file mode 100644 index 00000000000..9bdeeeffa0f --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.qlref @@ -0,0 +1 @@ +Security/CWE/CWE-652/XQueryInjection.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-652/options b/java/ql/test/experimental/query-tests/security/CWE-652/options new file mode 100644 index 00000000000..98e36c19267 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-652/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/apache-http-4.4.13/:${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/saxon-xqj-9.x/:${testdir}/../../../../stubs/springframework-5.2.3/ diff --git a/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQConnection.java b/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQConnection.java new file mode 100644 index 00000000000..3cff7592168 --- /dev/null +++ b/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQConnection.java @@ -0,0 +1,19 @@ +package javax.xml.xquery; + +import java.io.InputStream; +import java.io.Reader; + +public interface XQConnection extends XQDataFactory { + + XQPreparedExpression prepareExpression(String var1) throws XQException; + + XQPreparedExpression prepareExpression(String var1, XQStaticContext var2) throws XQException; + + XQPreparedExpression prepareExpression(Reader var1) throws XQException; + + XQPreparedExpression prepareExpression(Reader var1, XQStaticContext var2) throws XQException; + + XQPreparedExpression prepareExpression(InputStream var1) throws XQException; + + XQPreparedExpression prepareExpression(InputStream var1, XQStaticContext var2) throws XQException; +} diff --git a/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQDataFactory.java b/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQDataFactory.java new file mode 100644 index 00000000000..6bc2dbade6d --- /dev/null +++ b/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQDataFactory.java @@ -0,0 +1,5 @@ +package javax.xml.xquery; + +public interface XQDataFactory { + XQItemType createAtomicType(int var1) throws XQException; +} diff --git a/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQDataSource.java b/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQDataSource.java new file mode 100644 index 00000000000..7f981a1ff00 --- /dev/null +++ b/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQDataSource.java @@ -0,0 +1,5 @@ +package javax.xml.xquery; + +public interface XQDataSource { + XQConnection getConnection() throws XQException; +} diff --git a/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQDynamicContext.java b/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQDynamicContext.java new file mode 100644 index 00000000000..c5058a2f866 --- /dev/null +++ b/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQDynamicContext.java @@ -0,0 +1,7 @@ +package javax.xml.xquery; + +import javax.xml.namespace.QName; + +public interface XQDynamicContext { + void bindString(QName var1, String var2, XQItemType var3) throws XQException; +} diff --git a/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQException.java b/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQException.java new file mode 100644 index 00000000000..4d81c322327 --- /dev/null +++ b/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQException.java @@ -0,0 +1,3 @@ +package javax.xml.xquery; + +public class XQException extends Exception {} diff --git a/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQItemAccessor.java b/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQItemAccessor.java new file mode 100644 index 00000000000..b52f5c16461 --- /dev/null +++ b/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQItemAccessor.java @@ -0,0 +1,7 @@ +package javax.xml.xquery; + +import java.util.Properties; + +public interface XQItemAccessor { + String getItemAsString(Properties var1) throws XQException; +} diff --git a/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQItemType.java b/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQItemType.java new file mode 100644 index 00000000000..b6c9cb896b0 --- /dev/null +++ b/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQItemType.java @@ -0,0 +1,68 @@ +package javax.xml.xquery; + +public interface XQItemType extends XQSequenceType { + int XQITEMKIND_ATOMIC = 1; + int XQITEMKIND_ATTRIBUTE = 2; + int XQITEMKIND_COMMENT = 3; + int XQITEMKIND_DOCUMENT = 4; + int XQITEMKIND_DOCUMENT_ELEMENT = 5; + int XQITEMKIND_DOCUMENT_SCHEMA_ELEMENT = 6; + int XQITEMKIND_ELEMENT = 7; + int XQITEMKIND_ITEM = 8; + int XQITEMKIND_NODE = 9; + int XQITEMKIND_PI = 10; + int XQITEMKIND_TEXT = 11; + int XQITEMKIND_SCHEMA_ELEMENT = 12; + int XQITEMKIND_SCHEMA_ATTRIBUTE = 13; + int XQBASETYPE_UNTYPED = 1; + int XQBASETYPE_ANYTYPE = 2; + int XQBASETYPE_ANYSIMPLETYPE = 3; + int XQBASETYPE_ANYATOMICTYPE = 4; + int XQBASETYPE_UNTYPEDATOMIC = 5; + int XQBASETYPE_DAYTIMEDURATION = 6; + int XQBASETYPE_YEARMONTHDURATION = 7; + int XQBASETYPE_ANYURI = 8; + int XQBASETYPE_BASE64BINARY = 9; + int XQBASETYPE_BOOLEAN = 10; + int XQBASETYPE_DATE = 11; + int XQBASETYPE_INT = 12; + int XQBASETYPE_INTEGER = 13; + int XQBASETYPE_SHORT = 14; + int XQBASETYPE_LONG = 15; + int XQBASETYPE_DATETIME = 16; + int XQBASETYPE_DECIMAL = 17; + int XQBASETYPE_DOUBLE = 18; + int XQBASETYPE_DURATION = 19; + int XQBASETYPE_FLOAT = 20; + int XQBASETYPE_GDAY = 21; + int XQBASETYPE_GMONTH = 22; + int XQBASETYPE_GMONTHDAY = 23; + int XQBASETYPE_GYEAR = 24; + int XQBASETYPE_GYEARMONTH = 25; + int XQBASETYPE_HEXBINARY = 26; + int XQBASETYPE_NOTATION = 27; + int XQBASETYPE_QNAME = 28; + int XQBASETYPE_STRING = 29; + int XQBASETYPE_TIME = 30; + int XQBASETYPE_BYTE = 31; + int XQBASETYPE_NONPOSITIVE_INTEGER = 32; + int XQBASETYPE_NONNEGATIVE_INTEGER = 33; + int XQBASETYPE_NEGATIVE_INTEGER = 34; + int XQBASETYPE_POSITIVE_INTEGER = 35; + int XQBASETYPE_UNSIGNED_LONG = 36; + int XQBASETYPE_UNSIGNED_INT = 37; + int XQBASETYPE_UNSIGNED_SHORT = 38; + int XQBASETYPE_UNSIGNED_BYTE = 39; + int XQBASETYPE_NORMALIZED_STRING = 40; + int XQBASETYPE_TOKEN = 41; + int XQBASETYPE_LANGUAGE = 42; + int XQBASETYPE_NAME = 43; + int XQBASETYPE_NCNAME = 44; + int XQBASETYPE_NMTOKEN = 45; + int XQBASETYPE_ID = 46; + int XQBASETYPE_IDREF = 47; + int XQBASETYPE_ENTITY = 48; + int XQBASETYPE_IDREFS = 49; + int XQBASETYPE_ENTITIES = 50; + int XQBASETYPE_NMTOKENS = 51; +} diff --git a/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQPreparedExpression.java b/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQPreparedExpression.java new file mode 100644 index 00000000000..3ab5024c1e6 --- /dev/null +++ b/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQPreparedExpression.java @@ -0,0 +1,5 @@ +package javax.xml.xquery; + +public interface XQPreparedExpression extends XQDynamicContext { + XQResultSequence executeQuery() throws XQException; +} diff --git a/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQResultSequence.java b/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQResultSequence.java new file mode 100644 index 00000000000..c7cd24e8561 --- /dev/null +++ b/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQResultSequence.java @@ -0,0 +1,3 @@ +package javax.xml.xquery; + +public interface XQResultSequence extends XQSequence {} diff --git a/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQSequence.java b/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQSequence.java new file mode 100644 index 00000000000..b872795a759 --- /dev/null +++ b/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQSequence.java @@ -0,0 +1,5 @@ +package javax.xml.xquery; + +public interface XQSequence extends XQItemAccessor { + boolean next() throws XQException; +} diff --git a/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQSequenceType.java b/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQSequenceType.java new file mode 100644 index 00000000000..17d908f9e1c --- /dev/null +++ b/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQSequenceType.java @@ -0,0 +1,3 @@ +package javax.xml.xquery; + +public interface XQSequenceType {} diff --git a/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQStaticContext.java b/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQStaticContext.java new file mode 100644 index 00000000000..60911d4fb72 --- /dev/null +++ b/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQStaticContext.java @@ -0,0 +1,3 @@ +package javax.xml.xquery; + +public interface XQStaticContext {} diff --git a/java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/Configuration.java b/java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/Configuration.java new file mode 100644 index 00000000000..bfd8bf1ff58 --- /dev/null +++ b/java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/Configuration.java @@ -0,0 +1,6 @@ +package net.sf.saxon; + +import java.io.Serializable; + + +public class Configuration implements Serializable, SourceResolver {} diff --git a/java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/SourceResolver.java b/java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/SourceResolver.java new file mode 100644 index 00000000000..aa2e2b2fe4d --- /dev/null +++ b/java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/SourceResolver.java @@ -0,0 +1,3 @@ +package net.sf.saxon; + +public interface SourceResolver {} diff --git a/java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/xqj/Closable.java b/java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/xqj/Closable.java new file mode 100644 index 00000000000..91245a31fc9 --- /dev/null +++ b/java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/xqj/Closable.java @@ -0,0 +1,3 @@ +package net.sf.saxon.xqj; + +public abstract class Closable {} diff --git a/java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/xqj/SaxonXQConnection.java b/java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/xqj/SaxonXQConnection.java new file mode 100644 index 00000000000..85bae6e7540 --- /dev/null +++ b/java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/xqj/SaxonXQConnection.java @@ -0,0 +1,41 @@ +package net.sf.saxon.xqj; + +import java.io.Reader; +import net.sf.saxon.Configuration; +import javax.xml.xquery.XQConnection; +import javax.xml.xquery.XQPreparedExpression; +import javax.xml.xquery.XQException; +import javax.xml.xquery.XQStaticContext; +import java.io.InputStream; + +public class SaxonXQConnection extends SaxonXQDataFactory implements XQConnection { + + private SaxonXQStaticContext staticContext; + + SaxonXQConnection(SaxonXQDataSource dataSource) { + } + + public XQPreparedExpression prepareExpression(InputStream xquery) throws XQException { + return null; + } + + public XQPreparedExpression prepareExpression(InputStream xquery, XQStaticContext properties) throws XQException { + return null; + } + + public XQPreparedExpression prepareExpression(Reader xquery) throws XQException { + return null; + } + + public XQPreparedExpression prepareExpression(Reader xquery, XQStaticContext properties){ + return null; + } + + public XQPreparedExpression prepareExpression(String xquery) throws XQException { + return null; + } + + public XQPreparedExpression prepareExpression(String xquery, XQStaticContext properties) throws XQException { + return null; + } +} diff --git a/java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/xqj/SaxonXQDataFactory.java b/java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/xqj/SaxonXQDataFactory.java new file mode 100644 index 00000000000..2ea1a82541e --- /dev/null +++ b/java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/xqj/SaxonXQDataFactory.java @@ -0,0 +1,11 @@ +package net.sf.saxon.xqj; + +import javax.xml.xquery.XQException; +import javax.xml.xquery.XQDataFactory; +import javax.xml.xquery.XQItemType; + +public abstract class SaxonXQDataFactory extends Closable implements XQDataFactory { + public XQItemType createAtomicType(int baseType) throws XQException { + return null; + } +} diff --git a/java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/xqj/SaxonXQDataSource.java b/java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/xqj/SaxonXQDataSource.java new file mode 100644 index 00000000000..7e2549b6fe8 --- /dev/null +++ b/java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/xqj/SaxonXQDataSource.java @@ -0,0 +1,12 @@ +package net.sf.saxon.xqj; + +import javax.xml.xquery.XQDataSource; +import javax.xml.xquery.XQException; +import javax.xml.xquery.XQConnection; + +public class SaxonXQDataSource implements XQDataSource { + + public XQConnection getConnection() throws XQException { + return new SaxonXQConnection(this); + } +} diff --git a/java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/xqj/SaxonXQStaticContext.java b/java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/xqj/SaxonXQStaticContext.java new file mode 100644 index 00000000000..e5e19b6ae1f --- /dev/null +++ b/java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/xqj/SaxonXQStaticContext.java @@ -0,0 +1,5 @@ +package net.sf.saxon.xqj; + +import javax.xml.xquery.XQStaticContext; + +public class SaxonXQStaticContext implements XQStaticContext {} From b5ae4178515d970dda6ae59931a4ae5b6b2fa2fa Mon Sep 17 00:00:00 2001 From: haby0 Date: Wed, 27 Jan 2021 10:19:04 +0800 Subject: [PATCH 036/725] *)update CWE-652 qhelp references --- java/ql/src/Security/CWE/CWE-652/XQueryInjection.qhelp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-652/XQueryInjection.qhelp b/java/ql/src/Security/CWE/CWE-652/XQueryInjection.qhelp index 2b6433d6ef3..4e70553557c 100644 --- a/java/ql/src/Security/CWE/CWE-652/XQueryInjection.qhelp +++ b/java/ql/src/Security/CWE/CWE-652/XQueryInjection.qhelp @@ -21,8 +21,8 @@ This allows an attacker to control the structure of the query.

    -
  • CWE description: -XQuery Injection.
  • +
  • Introduction to XQuery Injection: +Balisage Paper: XQuery Injection.
  • From ca2e6587fe9d14e1fd5a01970f93c2f630a8b5d2 Mon Sep 17 00:00:00 2001 From: haby0 Date: Wed, 27 Jan 2021 19:46:15 +0800 Subject: [PATCH 037/725] Update java/ql/src/Security/CWE/CWE-652/XQueryInjection.qhelp Co-authored-by: Chris Smowton --- java/ql/src/Security/CWE/CWE-652/XQueryInjection.qhelp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-652/XQueryInjection.qhelp b/java/ql/src/Security/CWE/CWE-652/XQueryInjection.qhelp index 4e70553557c..7dfdc846c44 100644 --- a/java/ql/src/Security/CWE/CWE-652/XQueryInjection.qhelp +++ b/java/ql/src/Security/CWE/CWE-652/XQueryInjection.qhelp @@ -21,8 +21,8 @@ This allows an attacker to control the structure of the query.

    -
  • Introduction to XQuery Injection: -Balisage Paper: XQuery Injection.
  • +
  • Balisage: +XQuery Injection.
  • From 31deca016fd545707e1c269efe96941decc9f0dd Mon Sep 17 00:00:00 2001 From: haby0 Date: Wed, 27 Jan 2021 19:46:45 +0800 Subject: [PATCH 038/725] Update java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql Co-authored-by: Chris Smowton --- java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql b/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql index 7163a1fd93d..bb18e613b94 100644 --- a/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql +++ b/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql @@ -5,7 +5,7 @@ * @kind path-problem * @problem.severity error * @precision high - * @id java/XQuery-injection + * @id java/xquery-injection * @tags security * external/cwe/cwe-652 */ From 81c56b9bed33f2cd0033f8bc1ba8a8d091db2133 Mon Sep 17 00:00:00 2001 From: haby0 Date: Wed, 27 Jan 2021 19:47:12 +0800 Subject: [PATCH 039/725] Update java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql Co-authored-by: Chris Smowton --- java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql | 3 +++ 1 file changed, 3 insertions(+) diff --git a/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql b/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql index bb18e613b94..b1bca496e5c 100644 --- a/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql +++ b/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql @@ -15,6 +15,9 @@ import semmle.code.java.dataflow.FlowSources import XQueryInjectionLib import DataFlow::PathGraph +/** + * Taint-tracking configuration tracing flow from remote sources, through an XQuery parser, to its eventual execution. + */ class XQueryInjectionConfig extends TaintTracking::Configuration { XQueryInjectionConfig() { this = "XQueryInjectionConfig" } From ff1ed3a012e720da3a04779ee0c177dd2ba7b4c0 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Fri, 29 Jan 2021 03:39:02 +0000 Subject: [PATCH 040/725] Revamp the query to use three configurations to detect password hash without salt --- .../Security/CWE/CWE-759/HashWithoutSalt.ql | 110 ++++++++++------- .../code/java/dataflow/TaintTracking3.qll | 7 ++ .../tainttracking3/TaintTrackingImpl.qll | 115 ++++++++++++++++++ .../tainttracking3/TaintTrackingParameter.qll | 5 + 4 files changed, 194 insertions(+), 43 deletions(-) create mode 100644 java/ql/src/semmle/code/java/dataflow/TaintTracking3.qll create mode 100644 java/ql/src/semmle/code/java/dataflow/internal/tainttracking3/TaintTrackingImpl.qll create mode 100644 java/ql/src/semmle/code/java/dataflow/internal/tainttracking3/TaintTrackingParameter.qll diff --git a/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql b/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql index b7c353de77a..d9fcc22c02b 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql @@ -8,7 +8,10 @@ */ import java +import semmle.code.java.dataflow.DataFlow3 import semmle.code.java.dataflow.TaintTracking +import semmle.code.java.dataflow.TaintTracking2 +import semmle.code.java.dataflow.TaintTracking3 import DataFlow::PathGraph /** The Java class `java.security.MessageDigest`. */ @@ -16,6 +19,15 @@ class MessageDigest extends RefType { MessageDigest() { this.hasQualifiedName("java.security", "MessageDigest") } } +class MDConstructor extends StaticMethodAccess { + MDConstructor() { + exists(Method m | m = this.getMethod() | + m.getDeclaringType() instanceof MessageDigest and + m.hasName("getInstance") + ) + } +} + /** The method `digest()` declared in `java.security.MessageDigest`. */ class MDDigestMethod extends Method { MDDigestMethod() { @@ -48,24 +60,20 @@ class PasswordVarExpr extends Expr { } /** Taint configuration tracking flow from an expression whose name suggests it holds password data to a method call that generates a hash without a salt. */ -class HashWithoutSaltConfiguration extends TaintTracking::Configuration { - HashWithoutSaltConfiguration() { this = "HashWithoutSaltConfiguration" } +class PasswordHashConfiguration extends TaintTracking3::Configuration { + PasswordHashConfiguration() { this = "PasswordHashConfiguration" } - override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof PasswordVarExpr } + override predicate isSource(DataFlow3::Node source) { source.asExpr() instanceof PasswordVarExpr } - override predicate isSink(DataFlow::Node sink) { + override predicate isSink(DataFlow3::Node sink) { exists( - MethodAccess mua // invoke `md.update(password)` without the call of `md.update(digest)` + MethodAccess ma // invoke `md.update(password)` without the call of `md.update(digest)` | - sink.asExpr() = mua.getArgument(0) and - mua.getMethod() instanceof MDUpdateMethod // md.update(password) - ) - or - // invoke `md.digest(password)` without another call of `md.update(salt)` - exists(MethodAccess mda | - sink.asExpr() = mda.getArgument(0) and - mda.getMethod() instanceof MDDigestMethod and // md.digest(password) - mda.getNumArgument() = 1 + sink.asExpr() = ma.getArgument(0) and + ( + ma.getMethod() instanceof MDUpdateMethod or // md.update(password) + ma.getMethod() instanceof MDDigestMethod // md.digest(password) + ) ) } @@ -76,7 +84,7 @@ class HashWithoutSaltConfiguration extends TaintTracking::Configuration { * `byte[] messageDigest = md.digest(allBytes);` * Or the password is concatenated with a salt as a string. */ - override predicate isSanitizer(DataFlow::Node node) { + override predicate isSanitizer(DataFlow3::Node node) { exists(MethodAccess ma | ma.getMethod().getDeclaringType().hasQualifiedName("java.lang", "System") and ma.getMethod().hasName("arraycopy") and @@ -84,40 +92,56 @@ class HashWithoutSaltConfiguration extends TaintTracking::Configuration { ) // System.arraycopy(password.getBytes(), ...) or exists(AddExpr e | node.asExpr() = e.getAnOperand()) // password+salt - or - exists(MethodAccess mua, MethodAccess ma | - ma.getArgument(0) = node.asExpr() and // Detect wrapper methods that invoke `md.update(salt)` - ma != mua and + } +} + +class PasswordDigestConfiguration extends TaintTracking2::Configuration { + PasswordDigestConfiguration() { this = "PasswordDigestConfiguration" } + + override predicate isSource(DataFlow2::Node source) { + exists(MDConstructor mc | source.asExpr() = mc) + } + + override predicate isSink(DataFlow2::Node sink) { + exists(MethodAccess ma | ( - ma.getQualifier().getType() instanceof Interface - or - mua.getQualifier().(VarAccess).getVariable().getAnAccess() = ma.getQualifier() - or - mua.getAnArgument().(VarAccess).getVariable().getAnAccess() = ma.getQualifier() - or - mua.getQualifier().(VarAccess).getVariable().getAnAccess() = ma.getAnArgument() - or - mua.getArgument(0).(VarAccess).getVariable().getAnAccess() = ma.getAnArgument() + ma.getMethod() instanceof MDUpdateMethod or + ma.getMethod() instanceof MDDigestMethod ) and - isMDUpdateCall(mua.getMethod()) + exists(PasswordHashConfiguration cc | cc.hasFlowToExpr(ma.getAnArgument())) and + sink.asExpr() = ma.getQualifier() ) } } -/** Holds if a method invokes `md.update(salt)`. */ -predicate isMDUpdateCall(Callable caller) { - caller instanceof MDUpdateMethod - or - exists(Callable callee | - caller.polyCalls(callee) and - ( - callee instanceof MDUpdateMethod or - isMDUpdateCall(callee) +class HashWithoutSaltConfiguration extends TaintTracking::Configuration { + HashWithoutSaltConfiguration() { this = "HashWithoutSaltConfiguration" } + + override predicate isSource(DataFlow::Node source) { + exists(PasswordDigestConfiguration pc | pc.hasFlow(source, _)) + } + + override predicate isSink(DataFlow::Node sink) { + exists(MethodAccess ma | + ma.getMethod() instanceof MDDigestMethod and // md.digest(password) + sink.asExpr() = ma.getQualifier() ) - ) + } + + /** Holds if `md.update` or `md.digest` calls integrate something other than the password, perhaps a salt. */ + override predicate isSanitizer(DataFlow::Node node) { + exists(MethodAccess ma | + ( + ma.getMethod() instanceof MDUpdateMethod + or + ma.getMethod() instanceof MDDigestMethod and ma.getNumArgument() != 0 + ) and + node.asExpr() = ma.getQualifier() and + not exists(PasswordHashConfiguration cc | cc.hasFlowToExpr(ma.getAnArgument())) + ) + } } -from DataFlow::PathNode source, DataFlow::PathNode sink, HashWithoutSaltConfiguration c -where c.hasFlowPath(source, sink) -select sink.getNode(), source, sink, "$@ is hashed without a salt.", source.getNode(), - "The password" +from DataFlow::PathNode source, DataFlow::PathNode sink, HashWithoutSaltConfiguration cc +where cc.hasFlowPath(source, sink) +select sink, source, sink, "$@ is hashed without a salt.", source, "The password" diff --git a/java/ql/src/semmle/code/java/dataflow/TaintTracking3.qll b/java/ql/src/semmle/code/java/dataflow/TaintTracking3.qll new file mode 100644 index 00000000000..49c43ed1418 --- /dev/null +++ b/java/ql/src/semmle/code/java/dataflow/TaintTracking3.qll @@ -0,0 +1,7 @@ +/** + * Provides classes for performing local (intra-procedural) and + * global (inter-procedural) taint-tracking analyses. + */ +module TaintTracking3 { + import semmle.code.java.dataflow.internal.tainttracking3.TaintTrackingImpl +} diff --git a/java/ql/src/semmle/code/java/dataflow/internal/tainttracking3/TaintTrackingImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/tainttracking3/TaintTrackingImpl.qll new file mode 100644 index 00000000000..b509fad9cd2 --- /dev/null +++ b/java/ql/src/semmle/code/java/dataflow/internal/tainttracking3/TaintTrackingImpl.qll @@ -0,0 +1,115 @@ +/** + * Provides an implementation of global (interprocedural) taint tracking. + * This file re-exports the local (intraprocedural) taint-tracking analysis + * from `TaintTrackingParameter::Public` and adds a global analysis, mainly + * exposed through the `Configuration` class. For some languages, this file + * exists in several identical copies, allowing queries to use multiple + * `Configuration` classes that depend on each other without introducing + * mutual recursion among those configurations. + */ + +import TaintTrackingParameter::Public +private import TaintTrackingParameter::Private + +/** + * A configuration of interprocedural taint tracking analysis. This defines + * sources, sinks, and any other configurable aspect of the analysis. Each + * use of the taint tracking library must define its own unique extension of + * this abstract class. + * + * A taint-tracking configuration is a special data flow configuration + * (`DataFlow::Configuration`) that allows for flow through nodes that do not + * necessarily preserve values but are still relevant from a taint tracking + * perspective. (For example, string concatenation, where one of the operands + * is tainted.) + * + * To create a configuration, extend this class with a subclass whose + * characteristic predicate is a unique singleton string. For example, write + * + * ```ql + * class MyAnalysisConfiguration extends TaintTracking::Configuration { + * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } + * // Override `isSource` and `isSink`. + * // Optionally override `isSanitizer`. + * // Optionally override `isSanitizerIn`. + * // Optionally override `isSanitizerOut`. + * // Optionally override `isSanitizerGuard`. + * // Optionally override `isAdditionalTaintStep`. + * } + * ``` + * + * Then, to query whether there is flow between some `source` and `sink`, + * write + * + * ```ql + * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) + * ``` + * + * Multiple configurations can coexist, but it is unsupported to depend on + * another `TaintTracking::Configuration` or a `DataFlow::Configuration` in the + * overridden predicates that define sources, sinks, or additional steps. + * Instead, the dependency should go to a `TaintTracking2::Configuration` or a + * `DataFlow2::Configuration`, `DataFlow3::Configuration`, etc. + */ +abstract class Configuration extends DataFlow::Configuration { + bindingset[this] + Configuration() { any() } + + /** + * Holds if `source` is a relevant taint source. + * + * The smaller this predicate is, the faster `hasFlow()` will converge. + */ + // overridden to provide taint-tracking specific qldoc + abstract override predicate isSource(DataFlow::Node source); + + /** + * Holds if `sink` is a relevant taint sink. + * + * The smaller this predicate is, the faster `hasFlow()` will converge. + */ + // overridden to provide taint-tracking specific qldoc + abstract override predicate isSink(DataFlow::Node sink); + + /** Holds if the node `node` is a taint sanitizer. */ + predicate isSanitizer(DataFlow::Node node) { none() } + + final override predicate isBarrier(DataFlow::Node node) { + isSanitizer(node) or + defaultTaintSanitizer(node) + } + + /** Holds if taint propagation into `node` is prohibited. */ + predicate isSanitizerIn(DataFlow::Node node) { none() } + + final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) } + + /** Holds if taint propagation out of `node` is prohibited. */ + predicate isSanitizerOut(DataFlow::Node node) { none() } + + final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) } + + /** Holds if taint propagation through nodes guarded by `guard` is prohibited. */ + predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() } + + final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) } + + /** + * Holds if the additional taint propagation step from `node1` to `node2` + * must be taken into account in the analysis. + */ + predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() } + + final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { + isAdditionalTaintStep(node1, node2) or + defaultAdditionalTaintStep(node1, node2) + } + + /** + * Holds if taint may flow from `source` to `sink` for this configuration. + */ + // overridden to provide taint-tracking specific qldoc + override predicate hasFlow(DataFlow::Node source, DataFlow::Node sink) { + super.hasFlow(source, sink) + } +} diff --git a/java/ql/src/semmle/code/java/dataflow/internal/tainttracking3/TaintTrackingParameter.qll b/java/ql/src/semmle/code/java/dataflow/internal/tainttracking3/TaintTrackingParameter.qll new file mode 100644 index 00000000000..10fb6b09fa8 --- /dev/null +++ b/java/ql/src/semmle/code/java/dataflow/internal/tainttracking3/TaintTrackingParameter.qll @@ -0,0 +1,5 @@ +import semmle.code.java.dataflow.internal.TaintTrackingUtil as Public + +module Private { + import semmle.code.java.dataflow.DataFlow3::DataFlow3 as DataFlow +} From 97690b4eb7e66dac034d1482e3f7b4da50166357 Mon Sep 17 00:00:00 2001 From: haby0 Date: Mon, 8 Feb 2021 19:15:28 +0800 Subject: [PATCH 041/725] Update java/ql/src/Security/CWE/CWE-652/XQueryInjection.qhelp Co-authored-by: Felicity Chapman --- java/ql/src/Security/CWE/CWE-652/XQueryInjection.qhelp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-652/XQueryInjection.qhelp b/java/ql/src/Security/CWE/CWE-652/XQueryInjection.qhelp index 7dfdc846c44..1ca6e780627 100644 --- a/java/ql/src/Security/CWE/CWE-652/XQueryInjection.qhelp +++ b/java/ql/src/Security/CWE/CWE-652/XQueryInjection.qhelp @@ -3,8 +3,8 @@ "qhelp.dtd"> -

    The software uses external input to dynamically construct an XQuery expression used to retrieve data from an XML database, but it does not neutralize or incorrectly neutralizes that input. -This allows an attacker to control the structure of the query.

    +

    The software uses external input to dynamically construct an XQuery expression which is then used to retrieve data from an XML database. +However, the input is not neutralized, or is incorrectly neutralized, which allows an attacker to control the structure of the query.

    From a6a0fa28c4d8ecddf1c058276c1d448d52722824 Mon Sep 17 00:00:00 2001 From: haby0 Date: Thu, 11 Feb 2021 16:05:48 +0800 Subject: [PATCH 042/725] *)add XQExpression.executeQuery(0) sink --- .../Security/CWE/CWE-652/XQueryInjection.java | 26 ++++++ .../Security/CWE/CWE-652/XQueryInjection.ql | 6 +- .../CWE/CWE-652/XQueryInjectionLib.qll | 31 +++++-- .../security/CWE-652/XQueryInjection.expected | 48 ++++++---- .../security/CWE-652/XQueryInjection.java | 89 ++++++++++++++++++- .../javax/xml/xquery/XQConnection.java | 2 + .../javax/xml/xquery/XQExpression.java | 25 ++++++ .../net/sf/saxon/xqj/SaxonXQConnection.java | 4 + 8 files changed, 202 insertions(+), 29 deletions(-) create mode 100644 java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQExpression.java diff --git a/java/ql/src/Security/CWE/CWE-652/XQueryInjection.java b/java/ql/src/Security/CWE/CWE-652/XQueryInjection.java index a60adb37db2..f00df84968c 100644 --- a/java/ql/src/Security/CWE/CWE-652/XQueryInjection.java +++ b/java/ql/src/Security/CWE/CWE-652/XQueryInjection.java @@ -20,6 +20,18 @@ public void bad(HttpServletRequest request) throws XQException { } } +public void bad1(HttpServletRequest request) throws XQException { + String name = request.getParameter("name"); + XQDataSource xqds = new SaxonXQDataSource(); + String query = "for $user in doc(\"users.xml\")/Users/User[name='" + name + "'] return $user/password"; + XQConnection conn = xqds.getConnection(); + XQExpression expr = conn.createExpression(); + XQResultSequence result = expr.executeQuery(query); + while (result.next()){ + System.out.println(result.getItemAsString(null)); + } +} + public void good(HttpServletRequest request) throws XQException { String name = request.getParameter("name"); XQDataSource ds = new SaxonXQDataSource(); @@ -32,4 +44,18 @@ public void good(HttpServletRequest request) throws XQException { while (result.next()){ System.out.println(result.getItemAsString(null)); } +} + +public void good1(HttpServletRequest request) throws XQException { + String name = request.getParameter("name"); + String query = "declare variable $name as xs:string external;" + + " for $user in doc(\"users.xml\")/Users/User[name=$name] return $user/password"; + XQDataSource xqds = new SaxonXQDataSource(); + XQConnection conn = xqds.getConnection(); + XQExpression expr = conn.createExpression(); + expr.bindString(new QName("name"), name, conn.createAtomicType(XQItemType.XQBASETYPE_STRING)); + XQResultSequence result = expr.executeQuery(query); + while (result.next()){ + System.out.println(result.getItemAsString(null)); + } } \ No newline at end of file diff --git a/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql b/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql index b1bca496e5c..796df6b68da 100644 --- a/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql +++ b/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql @@ -24,15 +24,15 @@ class XQueryInjectionConfig extends TaintTracking::Configuration { override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } override predicate isSink(DataFlow::Node sink) { - sink.asExpr() = any(XQueryExecuteCall execute).getPreparedExpression() + sink.asExpr() = any(XQueryPreparedExecuteCall xpec).getPreparedExpression() or + sink.asExpr() = any(XQueryExecuteCall xec).getExecuteQueryArgument() } /** * Conveys taint from the input to a `prepareExpression` call to the returned prepared expression. */ override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { - exists(XQueryParserCall parser | - pred.asExpr() = parser.getInput() and succ.asExpr() = parser) + exists(XQueryParserCall parser | pred.asExpr() = parser.getInput() and succ.asExpr() = parser) } } diff --git a/java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll b/java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll index cfdbaaa70da..756caf2cd75 100644 --- a/java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll +++ b/java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll @@ -20,16 +20,33 @@ class XQueryParserCall extends MethodAccess { } /** A call to `XQPreparedExpression.executeQuery`. */ -class XQueryExecuteCall extends MethodAccess { - XQueryExecuteCall() { - exists(Method m | this.getMethod() = m and - m.hasName("executeQuery") and - m.getDeclaringType() - .getASourceSupertype*() - .hasQualifiedName("javax.xml.xquery", "XQPreparedExpression") +class XQueryPreparedExecuteCall extends MethodAccess { + XQueryPreparedExecuteCall() { + exists(Method m | + this.getMethod() = m and + m.hasName("executeQuery") and + m.getDeclaringType() + .getASourceSupertype*() + .hasQualifiedName("javax.xml.xquery", "XQPreparedExpression") ) } /** Return this prepared expression. */ Expr getPreparedExpression() { result = this.getQualifier() } } + +/** A call to `XQExpression.executeQuery`. */ +class XQueryExecuteCall extends MethodAccess { + XQueryExecuteCall() { + exists(Method m | + this.getMethod() = m and + m.hasName("executeQuery") and + m.getDeclaringType() + .getASourceSupertype*() + .hasQualifiedName("javax.xml.xquery", "XQExpression") + ) + } + + /** Return this execute query argument. */ + Expr getExecuteQueryArgument() { result = this.getArgument(0) } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.expected b/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.expected index 1ac4289a99c..e2b04e1e020 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.expected @@ -1,19 +1,35 @@ edges -| XQueryInjection.java:26:37:26:65 | prepareExpression(...) : XQPreparedExpression | XQueryInjection.java:27:35:27:38 | xqpe | -| XQueryInjection.java:41:37:41:65 | prepareExpression(...) : XQPreparedExpression | XQueryInjection.java:42:35:42:38 | xqpe | -| XQueryInjection.java:53:37:53:64 | prepareExpression(...) : XQPreparedExpression | XQueryInjection.java:54:35:54:38 | xqpe | -| XQueryInjection.java:66:37:66:62 | prepareExpression(...) : XQPreparedExpression | XQueryInjection.java:67:35:67:38 | xqpe | +| XQueryInjection.java:42:23:42:50 | getParameter(...) : String | XQueryInjection.java:47:35:47:38 | xqpe | +| XQueryInjection.java:55:23:55:50 | getParameter(...) : String | XQueryInjection.java:60:53:60:57 | query | +| XQueryInjection.java:68:32:68:59 | nameStr : String | XQueryInjection.java:73:35:73:38 | xqpe | +| XQueryInjection.java:80:33:80:60 | nameStr : String | XQueryInjection.java:85:53:85:57 | query | +| XQueryInjection.java:93:28:93:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:97:35:97:38 | xqpe | +| XQueryInjection.java:105:28:105:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:109:53:109:56 | name | +| XQueryInjection.java:117:28:117:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:122:35:122:38 | xqpe | +| XQueryInjection.java:130:28:130:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:135:53:135:54 | br | nodes -| XQueryInjection.java:26:37:26:65 | prepareExpression(...) : XQPreparedExpression | semmle.label | prepareExpression(...) : XQPreparedExpression | -| XQueryInjection.java:27:35:27:38 | xqpe | semmle.label | xqpe | -| XQueryInjection.java:41:37:41:65 | prepareExpression(...) : XQPreparedExpression | semmle.label | prepareExpression(...) : XQPreparedExpression | -| XQueryInjection.java:42:35:42:38 | xqpe | semmle.label | xqpe | -| XQueryInjection.java:53:37:53:64 | prepareExpression(...) : XQPreparedExpression | semmle.label | prepareExpression(...) : XQPreparedExpression | -| XQueryInjection.java:54:35:54:38 | xqpe | semmle.label | xqpe | -| XQueryInjection.java:66:37:66:62 | prepareExpression(...) : XQPreparedExpression | semmle.label | prepareExpression(...) : XQPreparedExpression | -| XQueryInjection.java:67:35:67:38 | xqpe | semmle.label | xqpe | +| XQueryInjection.java:42:23:42:50 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| XQueryInjection.java:47:35:47:38 | xqpe | semmle.label | xqpe | +| XQueryInjection.java:55:23:55:50 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| XQueryInjection.java:60:53:60:57 | query | semmle.label | query | +| XQueryInjection.java:68:32:68:59 | nameStr : String | semmle.label | nameStr : String | +| XQueryInjection.java:73:35:73:38 | xqpe | semmle.label | xqpe | +| XQueryInjection.java:80:33:80:60 | nameStr : String | semmle.label | nameStr : String | +| XQueryInjection.java:85:53:85:57 | query | semmle.label | query | +| XQueryInjection.java:93:28:93:51 | getInputStream(...) : ServletInputStream | semmle.label | getInputStream(...) : ServletInputStream | +| XQueryInjection.java:97:35:97:38 | xqpe | semmle.label | xqpe | +| XQueryInjection.java:105:28:105:51 | getInputStream(...) : ServletInputStream | semmle.label | getInputStream(...) : ServletInputStream | +| XQueryInjection.java:109:53:109:56 | name | semmle.label | name | +| XQueryInjection.java:117:28:117:51 | getInputStream(...) : ServletInputStream | semmle.label | getInputStream(...) : ServletInputStream | +| XQueryInjection.java:122:35:122:38 | xqpe | semmle.label | xqpe | +| XQueryInjection.java:130:28:130:51 | getInputStream(...) : ServletInputStream | semmle.label | getInputStream(...) : ServletInputStream | +| XQueryInjection.java:135:53:135:54 | br | semmle.label | br | #select -| XQueryInjection.java:27:35:27:38 | xqpe | XQueryInjection.java:26:37:26:65 | prepareExpression(...) : XQPreparedExpression | XQueryInjection.java:27:35:27:38 | xqpe | XQuery query might include code from $@. | XQueryInjection.java:26:37:26:65 | prepareExpression(...) | this user input | -| XQueryInjection.java:42:35:42:38 | xqpe | XQueryInjection.java:41:37:41:65 | prepareExpression(...) : XQPreparedExpression | XQueryInjection.java:42:35:42:38 | xqpe | XQuery query might include code from $@. | XQueryInjection.java:41:37:41:65 | prepareExpression(...) | this user input | -| XQueryInjection.java:54:35:54:38 | xqpe | XQueryInjection.java:53:37:53:64 | prepareExpression(...) : XQPreparedExpression | XQueryInjection.java:54:35:54:38 | xqpe | XQuery query might include code from $@. | XQueryInjection.java:53:37:53:64 | prepareExpression(...) | this user input | -| XQueryInjection.java:67:35:67:38 | xqpe | XQueryInjection.java:66:37:66:62 | prepareExpression(...) : XQPreparedExpression | XQueryInjection.java:67:35:67:38 | xqpe | XQuery query might include code from $@. | XQueryInjection.java:66:37:66:62 | prepareExpression(...) | this user input | +| XQueryInjection.java:47:35:47:38 | xqpe | XQueryInjection.java:42:23:42:50 | getParameter(...) : String | XQueryInjection.java:47:35:47:38 | xqpe | XQuery query might include code from $@. | XQueryInjection.java:42:23:42:50 | getParameter(...) | this user input | +| XQueryInjection.java:60:53:60:57 | query | XQueryInjection.java:55:23:55:50 | getParameter(...) : String | XQueryInjection.java:60:53:60:57 | query | XQuery query might include code from $@. | XQueryInjection.java:55:23:55:50 | getParameter(...) | this user input | +| XQueryInjection.java:73:35:73:38 | xqpe | XQueryInjection.java:68:32:68:59 | nameStr : String | XQueryInjection.java:73:35:73:38 | xqpe | XQuery query might include code from $@. | XQueryInjection.java:68:32:68:59 | nameStr | this user input | +| XQueryInjection.java:85:53:85:57 | query | XQueryInjection.java:80:33:80:60 | nameStr : String | XQueryInjection.java:85:53:85:57 | query | XQuery query might include code from $@. | XQueryInjection.java:80:33:80:60 | nameStr | this user input | +| XQueryInjection.java:97:35:97:38 | xqpe | XQueryInjection.java:93:28:93:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:97:35:97:38 | xqpe | XQuery query might include code from $@. | XQueryInjection.java:93:28:93:51 | getInputStream(...) | this user input | +| XQueryInjection.java:109:53:109:56 | name | XQueryInjection.java:105:28:105:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:109:53:109:56 | name | XQuery query might include code from $@. | XQueryInjection.java:105:28:105:51 | getInputStream(...) | this user input | +| XQueryInjection.java:122:35:122:38 | xqpe | XQueryInjection.java:117:28:117:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:122:35:122:38 | xqpe | XQuery query might include code from $@. | XQueryInjection.java:117:28:117:51 | getInputStream(...) | this user input | +| XQueryInjection.java:135:53:135:54 | br | XQueryInjection.java:130:28:130:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:135:53:135:54 | br | XQuery query might include code from $@. | XQueryInjection.java:130:28:130:51 | getInputStream(...) | this user input | diff --git a/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.java b/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.java index 48846ae1bca..36f829d81bd 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.java +++ b/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.java @@ -6,6 +6,7 @@ import javax.xml.namespace.QName; import javax.xml.xquery.XQConnection; import javax.xml.xquery.XQDataSource; import javax.xml.xquery.XQException; +import javax.xml.xquery.XQExpression; import javax.xml.xquery.XQItemType; import javax.xml.xquery.XQPreparedExpression; import javax.xml.xquery.XQResultSequence; @@ -17,6 +18,25 @@ import org.springframework.web.bind.annotation.RequestParam; @Controller public class XQueryInjection { + public static void main(String[] args) throws Exception { + XQDataSource xqds = new SaxonXQDataSource(); + XQConnection conn; + try { + String name = "admin"; + String query = "declare variable $name as xs:string external;" + + " for $user in doc(\"users.xml\")/Users/User[name=$name] return $user/password"; + conn = xqds.getConnection(); + XQExpression expr = conn.createExpression(); + expr.bindString(new QName("name"), name, conn.createAtomicType(XQItemType.XQBASETYPE_STRING)); + XQResultSequence result = expr.executeQuery(query); + while (result.next()){ + System.out.println(result.getItemAsString(null)); + } + } catch (XQException e) { + e.printStackTrace(); + } + } + @RequestMapping public void testRequestbad(HttpServletRequest request) throws Exception { String name = request.getParameter("name"); @@ -28,16 +48,27 @@ public class XQueryInjection { while (result.next()){ System.out.println(result.getItemAsString(null)); } + } + @RequestMapping + public void testRequestbad1(HttpServletRequest request) throws Exception { + String name = request.getParameter("name"); + XQDataSource xqds = new SaxonXQDataSource(); + String query = "for $user in doc(\"users.xml\")/Users/User[name='" + name + "'] return $user/password"; + XQConnection conn = xqds.getConnection(); + XQExpression expr = conn.createExpression(); + XQResultSequence result = expr.executeQuery(query); + while (result.next()){ + System.out.println(result.getItemAsString(null)); + } } @RequestMapping public void testStringtbad(@RequestParam String nameStr) throws XQException { - String name = nameStr; XQDataSource ds = new SaxonXQDataSource(); XQConnection conn = ds.getConnection(); - String query = "for $user in doc(\"users.xml\")/Users/User[name='" + name + "'] return $user/password"; + String query = "for $user in doc(\"users.xml\")/Users/User[name='" + nameStr + "'] return $user/password"; XQPreparedExpression xqpe = conn.prepareExpression(query); XQResultSequence result = xqpe.executeQuery(); while (result.next()){ @@ -45,6 +76,18 @@ public class XQueryInjection { } } + @RequestMapping + public void testStringtbad1(@RequestParam String nameStr) throws XQException { + XQDataSource xqds = new SaxonXQDataSource(); + String query = "for $user in doc(\"users.xml\")/Users/User[name='" + nameStr + "'] return $user/password"; + XQConnection conn = xqds.getConnection(); + XQExpression expr = conn.createExpression(); + XQResultSequence result = expr.executeQuery(query); + while (result.next()){ + System.out.println(result.getItemAsString(null)); + } + } + @RequestMapping public void testInputStreambad(HttpServletRequest request) throws Exception { InputStream name = request.getInputStream(); @@ -57,6 +100,18 @@ public class XQueryInjection { } } + @RequestMapping + public void testInputStreambad1(HttpServletRequest request) throws Exception { + InputStream name = request.getInputStream(); + XQDataSource xqds = new SaxonXQDataSource(); + XQConnection conn = xqds.getConnection(); + XQExpression expr = conn.createExpression(); + XQResultSequence result = expr.executeQuery(name); + while (result.next()){ + System.out.println(result.getItemAsString(null)); + } + } + @RequestMapping public void testReaderbad(HttpServletRequest request) throws Exception { InputStream name = request.getInputStream(); @@ -70,6 +125,19 @@ public class XQueryInjection { } } + @RequestMapping + public void testReaderbad1(HttpServletRequest request) throws Exception { + InputStream name = request.getInputStream(); + BufferedReader br = new BufferedReader(new InputStreamReader(name)); + XQDataSource xqds = new SaxonXQDataSource(); + XQConnection conn = xqds.getConnection(); + XQExpression expr = conn.createExpression(); + XQResultSequence result = expr.executeQuery(br); + while (result.next()){ + System.out.println(result.getItemAsString(null)); + } + } + @RequestMapping public void good(HttpServletRequest request) throws XQException { String name = request.getParameter("name"); @@ -84,4 +152,19 @@ public class XQueryInjection { System.out.println(result.getItemAsString(null)); } } -} + + @RequestMapping + public void good1(HttpServletRequest request) throws XQException { + String name = request.getParameter("name"); + String query = "declare variable $name as xs:string external;" + + " for $user in doc(\"users.xml\")/Users/User[name=$name] return $user/password"; + XQDataSource xqds = new SaxonXQDataSource(); + XQConnection conn = xqds.getConnection(); + XQExpression expr = conn.createExpression(); + expr.bindString(new QName("name"), name, conn.createAtomicType(XQItemType.XQBASETYPE_STRING)); + XQResultSequence result = expr.executeQuery(query); + while (result.next()){ + System.out.println(result.getItemAsString(null)); + } + } +} \ No newline at end of file diff --git a/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQConnection.java b/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQConnection.java index 3cff7592168..dce756e9646 100644 --- a/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQConnection.java +++ b/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQConnection.java @@ -4,6 +4,8 @@ import java.io.InputStream; import java.io.Reader; public interface XQConnection extends XQDataFactory { + + XQExpression createExpression() throws XQException; XQPreparedExpression prepareExpression(String var1) throws XQException; diff --git a/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQExpression.java b/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQExpression.java new file mode 100644 index 00000000000..5f2e9235bc5 --- /dev/null +++ b/java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQExpression.java @@ -0,0 +1,25 @@ +package javax.xml.xquery; + +import java.io.InputStream; +import java.io.Reader; + +public interface XQExpression extends XQDynamicContext { + + void cancel() throws XQException; + + boolean isClosed(); + + void close() throws XQException; + + void executeCommand(String var1) throws XQException; + + void executeCommand(Reader var1) throws XQException; + + XQResultSequence executeQuery(String var1) throws XQException; + + XQResultSequence executeQuery(Reader var1) throws XQException; + + XQResultSequence executeQuery(InputStream var1) throws XQException; + + XQStaticContext getStaticContext() throws XQException; +} \ No newline at end of file diff --git a/java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/xqj/SaxonXQConnection.java b/java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/xqj/SaxonXQConnection.java index 85bae6e7540..94bd38fa175 100644 --- a/java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/xqj/SaxonXQConnection.java +++ b/java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/xqj/SaxonXQConnection.java @@ -15,6 +15,10 @@ public class SaxonXQConnection extends SaxonXQDataFactory implements XQConnecti SaxonXQConnection(SaxonXQDataSource dataSource) { } + public XQExpression createExpression() throws XQException { + return null; + } + public XQPreparedExpression prepareExpression(InputStream xquery) throws XQException { return null; } From dbb3d458f5488e3d5e71098325f0bfa933bd3d03 Mon Sep 17 00:00:00 2001 From: haby0 Date: Fri, 12 Feb 2021 10:47:41 +0800 Subject: [PATCH 043/725] *)add XQExpression.executeCommand(0) sink --- .../Security/CWE/CWE-652/XQueryInjection.java | 9 +++ .../Security/CWE/CWE-652/XQueryInjection.ql | 3 +- .../CWE/CWE-652/XQueryInjectionLib.qll | 16 +++++ .../security/CWE-652/XQueryInjection.expected | 72 ++++++++++--------- .../security/CWE-652/XQueryInjection.java | 63 +++++++++++----- .../net/sf/saxon/xqj/SaxonXQConnection.java | 1 + 6 files changed, 112 insertions(+), 52 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-652/XQueryInjection.java b/java/ql/src/Security/CWE/CWE-652/XQueryInjection.java index f00df84968c..1b6be030249 100644 --- a/java/ql/src/Security/CWE/CWE-652/XQueryInjection.java +++ b/java/ql/src/Security/CWE/CWE-652/XQueryInjection.java @@ -32,6 +32,15 @@ public void bad1(HttpServletRequest request) throws XQException { } } +public void bad2(HttpServletRequest request) throws XQException { + String name = request.getParameter("name"); + XQDataSource xqds = new SaxonXQDataSource(); + XQConnection conn = xqds.getConnection(); + XQExpression expr = conn.createExpression(); + //bad code + expr.executeCommand(name); +} + public void good(HttpServletRequest request) throws XQException { String name = request.getParameter("name"); XQDataSource ds = new SaxonXQDataSource(); diff --git a/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql b/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql index 796df6b68da..69617cad629 100644 --- a/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql +++ b/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql @@ -25,7 +25,8 @@ class XQueryInjectionConfig extends TaintTracking::Configuration { override predicate isSink(DataFlow::Node sink) { sink.asExpr() = any(XQueryPreparedExecuteCall xpec).getPreparedExpression() or - sink.asExpr() = any(XQueryExecuteCall xec).getExecuteQueryArgument() + sink.asExpr() = any(XQueryExecuteCall xec).getExecuteQueryArgument() or + sink.asExpr() = any(XQueryExecuteCommandCall xecc).getExecuteCommandArgument() } /** diff --git a/java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll b/java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll index 756caf2cd75..2a4019f2c9a 100644 --- a/java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll +++ b/java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll @@ -50,3 +50,19 @@ class XQueryExecuteCall extends MethodAccess { /** Return this execute query argument. */ Expr getExecuteQueryArgument() { result = this.getArgument(0) } } + +/** A call to `XQExpression.executeCommand`. */ +class XQueryExecuteCommandCall extends MethodAccess { + XQueryExecuteCommandCall() { + exists(Method m | + this.getMethod() = m and + m.hasName("executeCommand") and + m.getDeclaringType() + .getASourceSupertype*() + .hasQualifiedName("javax.xml.xquery", "XQExpression") + ) + } + + /** Return this execute command argument. */ + Expr getExecuteCommandArgument() { result = this.getArgument(0) } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.expected b/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.expected index e2b04e1e020..b3ae0ff90fb 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.expected @@ -1,35 +1,43 @@ edges -| XQueryInjection.java:42:23:42:50 | getParameter(...) : String | XQueryInjection.java:47:35:47:38 | xqpe | -| XQueryInjection.java:55:23:55:50 | getParameter(...) : String | XQueryInjection.java:60:53:60:57 | query | -| XQueryInjection.java:68:32:68:59 | nameStr : String | XQueryInjection.java:73:35:73:38 | xqpe | -| XQueryInjection.java:80:33:80:60 | nameStr : String | XQueryInjection.java:85:53:85:57 | query | -| XQueryInjection.java:93:28:93:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:97:35:97:38 | xqpe | -| XQueryInjection.java:105:28:105:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:109:53:109:56 | name | -| XQueryInjection.java:117:28:117:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:122:35:122:38 | xqpe | -| XQueryInjection.java:130:28:130:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:135:53:135:54 | br | +| XQueryInjection.java:45:23:45:50 | getParameter(...) : String | XQueryInjection.java:51:35:51:38 | xqpe | +| XQueryInjection.java:59:23:59:50 | getParameter(...) : String | XQueryInjection.java:65:53:65:57 | query | +| XQueryInjection.java:73:32:73:59 | nameStr : String | XQueryInjection.java:79:35:79:38 | xqpe | +| XQueryInjection.java:86:33:86:60 | nameStr : String | XQueryInjection.java:92:53:92:57 | query | +| XQueryInjection.java:100:28:100:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:104:35:104:38 | xqpe | +| XQueryInjection.java:112:28:112:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:116:53:116:56 | name | +| XQueryInjection.java:124:28:124:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:129:35:129:38 | xqpe | +| XQueryInjection.java:137:28:137:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:142:53:142:54 | br | +| XQueryInjection.java:150:23:150:50 | getParameter(...) : String | XQueryInjection.java:155:29:155:32 | name | +| XQueryInjection.java:157:26:157:49 | getInputStream(...) : ServletInputStream | XQueryInjection.java:159:29:159:30 | br | nodes -| XQueryInjection.java:42:23:42:50 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| XQueryInjection.java:47:35:47:38 | xqpe | semmle.label | xqpe | -| XQueryInjection.java:55:23:55:50 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| XQueryInjection.java:60:53:60:57 | query | semmle.label | query | -| XQueryInjection.java:68:32:68:59 | nameStr : String | semmle.label | nameStr : String | -| XQueryInjection.java:73:35:73:38 | xqpe | semmle.label | xqpe | -| XQueryInjection.java:80:33:80:60 | nameStr : String | semmle.label | nameStr : String | -| XQueryInjection.java:85:53:85:57 | query | semmle.label | query | -| XQueryInjection.java:93:28:93:51 | getInputStream(...) : ServletInputStream | semmle.label | getInputStream(...) : ServletInputStream | -| XQueryInjection.java:97:35:97:38 | xqpe | semmle.label | xqpe | -| XQueryInjection.java:105:28:105:51 | getInputStream(...) : ServletInputStream | semmle.label | getInputStream(...) : ServletInputStream | -| XQueryInjection.java:109:53:109:56 | name | semmle.label | name | -| XQueryInjection.java:117:28:117:51 | getInputStream(...) : ServletInputStream | semmle.label | getInputStream(...) : ServletInputStream | -| XQueryInjection.java:122:35:122:38 | xqpe | semmle.label | xqpe | -| XQueryInjection.java:130:28:130:51 | getInputStream(...) : ServletInputStream | semmle.label | getInputStream(...) : ServletInputStream | -| XQueryInjection.java:135:53:135:54 | br | semmle.label | br | +| XQueryInjection.java:45:23:45:50 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| XQueryInjection.java:51:35:51:38 | xqpe | semmle.label | xqpe | +| XQueryInjection.java:59:23:59:50 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| XQueryInjection.java:65:53:65:57 | query | semmle.label | query | +| XQueryInjection.java:73:32:73:59 | nameStr : String | semmle.label | nameStr : String | +| XQueryInjection.java:79:35:79:38 | xqpe | semmle.label | xqpe | +| XQueryInjection.java:86:33:86:60 | nameStr : String | semmle.label | nameStr : String | +| XQueryInjection.java:92:53:92:57 | query | semmle.label | query | +| XQueryInjection.java:100:28:100:51 | getInputStream(...) : ServletInputStream | semmle.label | getInputStream(...) : ServletInputStream | +| XQueryInjection.java:104:35:104:38 | xqpe | semmle.label | xqpe | +| XQueryInjection.java:112:28:112:51 | getInputStream(...) : ServletInputStream | semmle.label | getInputStream(...) : ServletInputStream | +| XQueryInjection.java:116:53:116:56 | name | semmle.label | name | +| XQueryInjection.java:124:28:124:51 | getInputStream(...) : ServletInputStream | semmle.label | getInputStream(...) : ServletInputStream | +| XQueryInjection.java:129:35:129:38 | xqpe | semmle.label | xqpe | +| XQueryInjection.java:137:28:137:51 | getInputStream(...) : ServletInputStream | semmle.label | getInputStream(...) : ServletInputStream | +| XQueryInjection.java:142:53:142:54 | br | semmle.label | br | +| XQueryInjection.java:150:23:150:50 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| XQueryInjection.java:155:29:155:32 | name | semmle.label | name | +| XQueryInjection.java:157:26:157:49 | getInputStream(...) : ServletInputStream | semmle.label | getInputStream(...) : ServletInputStream | +| XQueryInjection.java:159:29:159:30 | br | semmle.label | br | #select -| XQueryInjection.java:47:35:47:38 | xqpe | XQueryInjection.java:42:23:42:50 | getParameter(...) : String | XQueryInjection.java:47:35:47:38 | xqpe | XQuery query might include code from $@. | XQueryInjection.java:42:23:42:50 | getParameter(...) | this user input | -| XQueryInjection.java:60:53:60:57 | query | XQueryInjection.java:55:23:55:50 | getParameter(...) : String | XQueryInjection.java:60:53:60:57 | query | XQuery query might include code from $@. | XQueryInjection.java:55:23:55:50 | getParameter(...) | this user input | -| XQueryInjection.java:73:35:73:38 | xqpe | XQueryInjection.java:68:32:68:59 | nameStr : String | XQueryInjection.java:73:35:73:38 | xqpe | XQuery query might include code from $@. | XQueryInjection.java:68:32:68:59 | nameStr | this user input | -| XQueryInjection.java:85:53:85:57 | query | XQueryInjection.java:80:33:80:60 | nameStr : String | XQueryInjection.java:85:53:85:57 | query | XQuery query might include code from $@. | XQueryInjection.java:80:33:80:60 | nameStr | this user input | -| XQueryInjection.java:97:35:97:38 | xqpe | XQueryInjection.java:93:28:93:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:97:35:97:38 | xqpe | XQuery query might include code from $@. | XQueryInjection.java:93:28:93:51 | getInputStream(...) | this user input | -| XQueryInjection.java:109:53:109:56 | name | XQueryInjection.java:105:28:105:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:109:53:109:56 | name | XQuery query might include code from $@. | XQueryInjection.java:105:28:105:51 | getInputStream(...) | this user input | -| XQueryInjection.java:122:35:122:38 | xqpe | XQueryInjection.java:117:28:117:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:122:35:122:38 | xqpe | XQuery query might include code from $@. | XQueryInjection.java:117:28:117:51 | getInputStream(...) | this user input | -| XQueryInjection.java:135:53:135:54 | br | XQueryInjection.java:130:28:130:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:135:53:135:54 | br | XQuery query might include code from $@. | XQueryInjection.java:130:28:130:51 | getInputStream(...) | this user input | +| XQueryInjection.java:51:35:51:38 | xqpe | XQueryInjection.java:45:23:45:50 | getParameter(...) : String | XQueryInjection.java:51:35:51:38 | xqpe | XQuery query might include code from $@. | XQueryInjection.java:45:23:45:50 | getParameter(...) | this user input | +| XQueryInjection.java:65:53:65:57 | query | XQueryInjection.java:59:23:59:50 | getParameter(...) : String | XQueryInjection.java:65:53:65:57 | query | XQuery query might include code from $@. | XQueryInjection.java:59:23:59:50 | getParameter(...) | this user input | +| XQueryInjection.java:79:35:79:38 | xqpe | XQueryInjection.java:73:32:73:59 | nameStr : String | XQueryInjection.java:79:35:79:38 | xqpe | XQuery query might include code from $@. | XQueryInjection.java:73:32:73:59 | nameStr | this user input | +| XQueryInjection.java:92:53:92:57 | query | XQueryInjection.java:86:33:86:60 | nameStr : String | XQueryInjection.java:92:53:92:57 | query | XQuery query might include code from $@. | XQueryInjection.java:86:33:86:60 | nameStr | this user input | +| XQueryInjection.java:104:35:104:38 | xqpe | XQueryInjection.java:100:28:100:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:104:35:104:38 | xqpe | XQuery query might include code from $@. | XQueryInjection.java:100:28:100:51 | getInputStream(...) | this user input | +| XQueryInjection.java:116:53:116:56 | name | XQueryInjection.java:112:28:112:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:116:53:116:56 | name | XQuery query might include code from $@. | XQueryInjection.java:112:28:112:51 | getInputStream(...) | this user input | +| XQueryInjection.java:129:35:129:38 | xqpe | XQueryInjection.java:124:28:124:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:129:35:129:38 | xqpe | XQuery query might include code from $@. | XQueryInjection.java:124:28:124:51 | getInputStream(...) | this user input | +| XQueryInjection.java:142:53:142:54 | br | XQueryInjection.java:137:28:137:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:142:53:142:54 | br | XQuery query might include code from $@. | XQueryInjection.java:137:28:137:51 | getInputStream(...) | this user input | +| XQueryInjection.java:155:29:155:32 | name | XQueryInjection.java:150:23:150:50 | getParameter(...) : String | XQueryInjection.java:155:29:155:32 | name | XQuery query might include code from $@. | XQueryInjection.java:150:23:150:50 | getParameter(...) | this user input | +| XQueryInjection.java:159:29:159:30 | br | XQueryInjection.java:157:26:157:49 | getInputStream(...) : ServletInputStream | XQueryInjection.java:159:29:159:30 | br | XQuery query might include code from $@. | XQueryInjection.java:157:26:157:49 | getInputStream(...) | this user input | diff --git a/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.java b/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.java index 36f829d81bd..d8df8057cc6 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.java +++ b/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.java @@ -1,3 +1,5 @@ +package com.vuln.v2.controller; + import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; @@ -27,9 +29,10 @@ public class XQueryInjection { + " for $user in doc(\"users.xml\")/Users/User[name=$name] return $user/password"; conn = xqds.getConnection(); XQExpression expr = conn.createExpression(); - expr.bindString(new QName("name"), name, conn.createAtomicType(XQItemType.XQBASETYPE_STRING)); + expr.bindString(new QName("name"), name, + conn.createAtomicType(XQItemType.XQBASETYPE_STRING)); XQResultSequence result = expr.executeQuery(query); - while (result.next()){ + while (result.next()) { System.out.println(result.getItemAsString(null)); } } catch (XQException e) { @@ -42,10 +45,11 @@ public class XQueryInjection { String name = request.getParameter("name"); XQDataSource ds = new SaxonXQDataSource(); XQConnection conn = ds.getConnection(); - String query = "for $user in doc(\"users.xml\")/Users/User[name='" + name + "'] return $user/password"; + String query = "for $user in doc(\"users.xml\")/Users/User[name='" + name + + "'] return $user/password"; XQPreparedExpression xqpe = conn.prepareExpression(query); XQResultSequence result = xqpe.executeQuery(); - while (result.next()){ + while (result.next()) { System.out.println(result.getItemAsString(null)); } } @@ -54,11 +58,12 @@ public class XQueryInjection { public void testRequestbad1(HttpServletRequest request) throws Exception { String name = request.getParameter("name"); XQDataSource xqds = new SaxonXQDataSource(); - String query = "for $user in doc(\"users.xml\")/Users/User[name='" + name + "'] return $user/password"; + String query = "for $user in doc(\"users.xml\")/Users/User[name='" + name + + "'] return $user/password"; XQConnection conn = xqds.getConnection(); XQExpression expr = conn.createExpression(); XQResultSequence result = expr.executeQuery(query); - while (result.next()){ + while (result.next()) { System.out.println(result.getItemAsString(null)); } } @@ -68,10 +73,11 @@ public class XQueryInjection { public void testStringtbad(@RequestParam String nameStr) throws XQException { XQDataSource ds = new SaxonXQDataSource(); XQConnection conn = ds.getConnection(); - String query = "for $user in doc(\"users.xml\")/Users/User[name='" + nameStr + "'] return $user/password"; + String query = "for $user in doc(\"users.xml\")/Users/User[name='" + nameStr + + "'] return $user/password"; XQPreparedExpression xqpe = conn.prepareExpression(query); XQResultSequence result = xqpe.executeQuery(); - while (result.next()){ + while (result.next()) { System.out.println(result.getItemAsString(null)); } } @@ -79,11 +85,12 @@ public class XQueryInjection { @RequestMapping public void testStringtbad1(@RequestParam String nameStr) throws XQException { XQDataSource xqds = new SaxonXQDataSource(); - String query = "for $user in doc(\"users.xml\")/Users/User[name='" + nameStr + "'] return $user/password"; + String query = "for $user in doc(\"users.xml\")/Users/User[name='" + nameStr + + "'] return $user/password"; XQConnection conn = xqds.getConnection(); XQExpression expr = conn.createExpression(); XQResultSequence result = expr.executeQuery(query); - while (result.next()){ + while (result.next()) { System.out.println(result.getItemAsString(null)); } } @@ -95,7 +102,7 @@ public class XQueryInjection { XQConnection conn = ds.getConnection(); XQPreparedExpression xqpe = conn.prepareExpression(name); XQResultSequence result = xqpe.executeQuery(); - while (result.next()){ + while (result.next()) { System.out.println(result.getItemAsString(null)); } } @@ -107,7 +114,7 @@ public class XQueryInjection { XQConnection conn = xqds.getConnection(); XQExpression expr = conn.createExpression(); XQResultSequence result = expr.executeQuery(name); - while (result.next()){ + while (result.next()) { System.out.println(result.getItemAsString(null)); } } @@ -120,7 +127,7 @@ public class XQueryInjection { XQConnection conn = ds.getConnection(); XQPreparedExpression xqpe = conn.prepareExpression(br); XQResultSequence result = xqpe.executeQuery(); - while (result.next()){ + while (result.next()) { System.out.println(result.getItemAsString(null)); } } @@ -133,11 +140,26 @@ public class XQueryInjection { XQConnection conn = xqds.getConnection(); XQExpression expr = conn.createExpression(); XQResultSequence result = expr.executeQuery(br); - while (result.next()){ + while (result.next()) { System.out.println(result.getItemAsString(null)); } } + @RequestMapping + public void testExecuteCommandbad(HttpServletRequest request) throws Exception { + String name = request.getParameter("name"); + XQDataSource xqds = new SaxonXQDataSource(); + XQConnection conn = xqds.getConnection(); + XQExpression expr = conn.createExpression(); + //bad code + expr.executeCommand(name); + //bad code + InputStream is = request.getInputStream(); + BufferedReader br = new BufferedReader(new InputStreamReader(is)); + expr.executeCommand(br); + expr.close(); + } + @RequestMapping public void good(HttpServletRequest request) throws XQException { String name = request.getParameter("name"); @@ -146,9 +168,10 @@ public class XQueryInjection { String query = "declare variable $name as xs:string external;" + " for $user in doc(\"users.xml\")/Users/User[name=$name] return $user/password"; XQPreparedExpression xqpe = conn.prepareExpression(query); - xqpe.bindString(new QName("name"), name, conn.createAtomicType(XQItemType.XQBASETYPE_STRING)); + xqpe.bindString(new QName("name"), name, + conn.createAtomicType(XQItemType.XQBASETYPE_STRING)); XQResultSequence result = xqpe.executeQuery(); - while (result.next()){ + while (result.next()) { System.out.println(result.getItemAsString(null)); } } @@ -161,10 +184,12 @@ public class XQueryInjection { XQDataSource xqds = new SaxonXQDataSource(); XQConnection conn = xqds.getConnection(); XQExpression expr = conn.createExpression(); - expr.bindString(new QName("name"), name, conn.createAtomicType(XQItemType.XQBASETYPE_STRING)); + expr.bindString(new QName("name"), name, + conn.createAtomicType(XQItemType.XQBASETYPE_STRING)); XQResultSequence result = expr.executeQuery(query); - while (result.next()){ + while (result.next()) { System.out.println(result.getItemAsString(null)); } } -} \ No newline at end of file +} + diff --git a/java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/xqj/SaxonXQConnection.java b/java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/xqj/SaxonXQConnection.java index 94bd38fa175..0263588e8b4 100644 --- a/java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/xqj/SaxonXQConnection.java +++ b/java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/xqj/SaxonXQConnection.java @@ -5,6 +5,7 @@ import net.sf.saxon.Configuration; import javax.xml.xquery.XQConnection; import javax.xml.xquery.XQPreparedExpression; import javax.xml.xquery.XQException; +import javax.xml.xquery.XQExpression; import javax.xml.xquery.XQStaticContext; import java.io.InputStream; From 22e741c7a3ae86332d48df3ba64f964e181a9569 Mon Sep 17 00:00:00 2001 From: haby0 Date: Fri, 12 Feb 2021 11:17:42 +0800 Subject: [PATCH 044/725] *)add XQExpression.executeCommand(0) sink --- .../Security/CWE/CWE-652/XQueryInjection.java | 9 +++ .../Security/CWE/CWE-652/XQueryInjection.ql | 3 +- .../CWE/CWE-652/XQueryInjectionLib.qll | 16 +++++ .../security/CWE-652/XQueryInjection.expected | 72 ++++++++++--------- .../security/CWE-652/XQueryInjection.java | 63 +++++++++++----- .../net/sf/saxon/xqj/SaxonXQConnection.java | 1 + 6 files changed, 112 insertions(+), 52 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-652/XQueryInjection.java b/java/ql/src/Security/CWE/CWE-652/XQueryInjection.java index f00df84968c..1b6be030249 100644 --- a/java/ql/src/Security/CWE/CWE-652/XQueryInjection.java +++ b/java/ql/src/Security/CWE/CWE-652/XQueryInjection.java @@ -32,6 +32,15 @@ public void bad1(HttpServletRequest request) throws XQException { } } +public void bad2(HttpServletRequest request) throws XQException { + String name = request.getParameter("name"); + XQDataSource xqds = new SaxonXQDataSource(); + XQConnection conn = xqds.getConnection(); + XQExpression expr = conn.createExpression(); + //bad code + expr.executeCommand(name); +} + public void good(HttpServletRequest request) throws XQException { String name = request.getParameter("name"); XQDataSource ds = new SaxonXQDataSource(); diff --git a/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql b/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql index 796df6b68da..69617cad629 100644 --- a/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql +++ b/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql @@ -25,7 +25,8 @@ class XQueryInjectionConfig extends TaintTracking::Configuration { override predicate isSink(DataFlow::Node sink) { sink.asExpr() = any(XQueryPreparedExecuteCall xpec).getPreparedExpression() or - sink.asExpr() = any(XQueryExecuteCall xec).getExecuteQueryArgument() + sink.asExpr() = any(XQueryExecuteCall xec).getExecuteQueryArgument() or + sink.asExpr() = any(XQueryExecuteCommandCall xecc).getExecuteCommandArgument() } /** diff --git a/java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll b/java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll index 756caf2cd75..2a4019f2c9a 100644 --- a/java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll +++ b/java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll @@ -50,3 +50,19 @@ class XQueryExecuteCall extends MethodAccess { /** Return this execute query argument. */ Expr getExecuteQueryArgument() { result = this.getArgument(0) } } + +/** A call to `XQExpression.executeCommand`. */ +class XQueryExecuteCommandCall extends MethodAccess { + XQueryExecuteCommandCall() { + exists(Method m | + this.getMethod() = m and + m.hasName("executeCommand") and + m.getDeclaringType() + .getASourceSupertype*() + .hasQualifiedName("javax.xml.xquery", "XQExpression") + ) + } + + /** Return this execute command argument. */ + Expr getExecuteCommandArgument() { result = this.getArgument(0) } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.expected b/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.expected index e2b04e1e020..b3ae0ff90fb 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.expected @@ -1,35 +1,43 @@ edges -| XQueryInjection.java:42:23:42:50 | getParameter(...) : String | XQueryInjection.java:47:35:47:38 | xqpe | -| XQueryInjection.java:55:23:55:50 | getParameter(...) : String | XQueryInjection.java:60:53:60:57 | query | -| XQueryInjection.java:68:32:68:59 | nameStr : String | XQueryInjection.java:73:35:73:38 | xqpe | -| XQueryInjection.java:80:33:80:60 | nameStr : String | XQueryInjection.java:85:53:85:57 | query | -| XQueryInjection.java:93:28:93:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:97:35:97:38 | xqpe | -| XQueryInjection.java:105:28:105:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:109:53:109:56 | name | -| XQueryInjection.java:117:28:117:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:122:35:122:38 | xqpe | -| XQueryInjection.java:130:28:130:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:135:53:135:54 | br | +| XQueryInjection.java:45:23:45:50 | getParameter(...) : String | XQueryInjection.java:51:35:51:38 | xqpe | +| XQueryInjection.java:59:23:59:50 | getParameter(...) : String | XQueryInjection.java:65:53:65:57 | query | +| XQueryInjection.java:73:32:73:59 | nameStr : String | XQueryInjection.java:79:35:79:38 | xqpe | +| XQueryInjection.java:86:33:86:60 | nameStr : String | XQueryInjection.java:92:53:92:57 | query | +| XQueryInjection.java:100:28:100:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:104:35:104:38 | xqpe | +| XQueryInjection.java:112:28:112:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:116:53:116:56 | name | +| XQueryInjection.java:124:28:124:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:129:35:129:38 | xqpe | +| XQueryInjection.java:137:28:137:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:142:53:142:54 | br | +| XQueryInjection.java:150:23:150:50 | getParameter(...) : String | XQueryInjection.java:155:29:155:32 | name | +| XQueryInjection.java:157:26:157:49 | getInputStream(...) : ServletInputStream | XQueryInjection.java:159:29:159:30 | br | nodes -| XQueryInjection.java:42:23:42:50 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| XQueryInjection.java:47:35:47:38 | xqpe | semmle.label | xqpe | -| XQueryInjection.java:55:23:55:50 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| XQueryInjection.java:60:53:60:57 | query | semmle.label | query | -| XQueryInjection.java:68:32:68:59 | nameStr : String | semmle.label | nameStr : String | -| XQueryInjection.java:73:35:73:38 | xqpe | semmle.label | xqpe | -| XQueryInjection.java:80:33:80:60 | nameStr : String | semmle.label | nameStr : String | -| XQueryInjection.java:85:53:85:57 | query | semmle.label | query | -| XQueryInjection.java:93:28:93:51 | getInputStream(...) : ServletInputStream | semmle.label | getInputStream(...) : ServletInputStream | -| XQueryInjection.java:97:35:97:38 | xqpe | semmle.label | xqpe | -| XQueryInjection.java:105:28:105:51 | getInputStream(...) : ServletInputStream | semmle.label | getInputStream(...) : ServletInputStream | -| XQueryInjection.java:109:53:109:56 | name | semmle.label | name | -| XQueryInjection.java:117:28:117:51 | getInputStream(...) : ServletInputStream | semmle.label | getInputStream(...) : ServletInputStream | -| XQueryInjection.java:122:35:122:38 | xqpe | semmle.label | xqpe | -| XQueryInjection.java:130:28:130:51 | getInputStream(...) : ServletInputStream | semmle.label | getInputStream(...) : ServletInputStream | -| XQueryInjection.java:135:53:135:54 | br | semmle.label | br | +| XQueryInjection.java:45:23:45:50 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| XQueryInjection.java:51:35:51:38 | xqpe | semmle.label | xqpe | +| XQueryInjection.java:59:23:59:50 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| XQueryInjection.java:65:53:65:57 | query | semmle.label | query | +| XQueryInjection.java:73:32:73:59 | nameStr : String | semmle.label | nameStr : String | +| XQueryInjection.java:79:35:79:38 | xqpe | semmle.label | xqpe | +| XQueryInjection.java:86:33:86:60 | nameStr : String | semmle.label | nameStr : String | +| XQueryInjection.java:92:53:92:57 | query | semmle.label | query | +| XQueryInjection.java:100:28:100:51 | getInputStream(...) : ServletInputStream | semmle.label | getInputStream(...) : ServletInputStream | +| XQueryInjection.java:104:35:104:38 | xqpe | semmle.label | xqpe | +| XQueryInjection.java:112:28:112:51 | getInputStream(...) : ServletInputStream | semmle.label | getInputStream(...) : ServletInputStream | +| XQueryInjection.java:116:53:116:56 | name | semmle.label | name | +| XQueryInjection.java:124:28:124:51 | getInputStream(...) : ServletInputStream | semmle.label | getInputStream(...) : ServletInputStream | +| XQueryInjection.java:129:35:129:38 | xqpe | semmle.label | xqpe | +| XQueryInjection.java:137:28:137:51 | getInputStream(...) : ServletInputStream | semmle.label | getInputStream(...) : ServletInputStream | +| XQueryInjection.java:142:53:142:54 | br | semmle.label | br | +| XQueryInjection.java:150:23:150:50 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| XQueryInjection.java:155:29:155:32 | name | semmle.label | name | +| XQueryInjection.java:157:26:157:49 | getInputStream(...) : ServletInputStream | semmle.label | getInputStream(...) : ServletInputStream | +| XQueryInjection.java:159:29:159:30 | br | semmle.label | br | #select -| XQueryInjection.java:47:35:47:38 | xqpe | XQueryInjection.java:42:23:42:50 | getParameter(...) : String | XQueryInjection.java:47:35:47:38 | xqpe | XQuery query might include code from $@. | XQueryInjection.java:42:23:42:50 | getParameter(...) | this user input | -| XQueryInjection.java:60:53:60:57 | query | XQueryInjection.java:55:23:55:50 | getParameter(...) : String | XQueryInjection.java:60:53:60:57 | query | XQuery query might include code from $@. | XQueryInjection.java:55:23:55:50 | getParameter(...) | this user input | -| XQueryInjection.java:73:35:73:38 | xqpe | XQueryInjection.java:68:32:68:59 | nameStr : String | XQueryInjection.java:73:35:73:38 | xqpe | XQuery query might include code from $@. | XQueryInjection.java:68:32:68:59 | nameStr | this user input | -| XQueryInjection.java:85:53:85:57 | query | XQueryInjection.java:80:33:80:60 | nameStr : String | XQueryInjection.java:85:53:85:57 | query | XQuery query might include code from $@. | XQueryInjection.java:80:33:80:60 | nameStr | this user input | -| XQueryInjection.java:97:35:97:38 | xqpe | XQueryInjection.java:93:28:93:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:97:35:97:38 | xqpe | XQuery query might include code from $@. | XQueryInjection.java:93:28:93:51 | getInputStream(...) | this user input | -| XQueryInjection.java:109:53:109:56 | name | XQueryInjection.java:105:28:105:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:109:53:109:56 | name | XQuery query might include code from $@. | XQueryInjection.java:105:28:105:51 | getInputStream(...) | this user input | -| XQueryInjection.java:122:35:122:38 | xqpe | XQueryInjection.java:117:28:117:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:122:35:122:38 | xqpe | XQuery query might include code from $@. | XQueryInjection.java:117:28:117:51 | getInputStream(...) | this user input | -| XQueryInjection.java:135:53:135:54 | br | XQueryInjection.java:130:28:130:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:135:53:135:54 | br | XQuery query might include code from $@. | XQueryInjection.java:130:28:130:51 | getInputStream(...) | this user input | +| XQueryInjection.java:51:35:51:38 | xqpe | XQueryInjection.java:45:23:45:50 | getParameter(...) : String | XQueryInjection.java:51:35:51:38 | xqpe | XQuery query might include code from $@. | XQueryInjection.java:45:23:45:50 | getParameter(...) | this user input | +| XQueryInjection.java:65:53:65:57 | query | XQueryInjection.java:59:23:59:50 | getParameter(...) : String | XQueryInjection.java:65:53:65:57 | query | XQuery query might include code from $@. | XQueryInjection.java:59:23:59:50 | getParameter(...) | this user input | +| XQueryInjection.java:79:35:79:38 | xqpe | XQueryInjection.java:73:32:73:59 | nameStr : String | XQueryInjection.java:79:35:79:38 | xqpe | XQuery query might include code from $@. | XQueryInjection.java:73:32:73:59 | nameStr | this user input | +| XQueryInjection.java:92:53:92:57 | query | XQueryInjection.java:86:33:86:60 | nameStr : String | XQueryInjection.java:92:53:92:57 | query | XQuery query might include code from $@. | XQueryInjection.java:86:33:86:60 | nameStr | this user input | +| XQueryInjection.java:104:35:104:38 | xqpe | XQueryInjection.java:100:28:100:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:104:35:104:38 | xqpe | XQuery query might include code from $@. | XQueryInjection.java:100:28:100:51 | getInputStream(...) | this user input | +| XQueryInjection.java:116:53:116:56 | name | XQueryInjection.java:112:28:112:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:116:53:116:56 | name | XQuery query might include code from $@. | XQueryInjection.java:112:28:112:51 | getInputStream(...) | this user input | +| XQueryInjection.java:129:35:129:38 | xqpe | XQueryInjection.java:124:28:124:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:129:35:129:38 | xqpe | XQuery query might include code from $@. | XQueryInjection.java:124:28:124:51 | getInputStream(...) | this user input | +| XQueryInjection.java:142:53:142:54 | br | XQueryInjection.java:137:28:137:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:142:53:142:54 | br | XQuery query might include code from $@. | XQueryInjection.java:137:28:137:51 | getInputStream(...) | this user input | +| XQueryInjection.java:155:29:155:32 | name | XQueryInjection.java:150:23:150:50 | getParameter(...) : String | XQueryInjection.java:155:29:155:32 | name | XQuery query might include code from $@. | XQueryInjection.java:150:23:150:50 | getParameter(...) | this user input | +| XQueryInjection.java:159:29:159:30 | br | XQueryInjection.java:157:26:157:49 | getInputStream(...) : ServletInputStream | XQueryInjection.java:159:29:159:30 | br | XQuery query might include code from $@. | XQueryInjection.java:157:26:157:49 | getInputStream(...) | this user input | diff --git a/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.java b/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.java index 36f829d81bd..d8df8057cc6 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.java +++ b/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.java @@ -1,3 +1,5 @@ +package com.vuln.v2.controller; + import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; @@ -27,9 +29,10 @@ public class XQueryInjection { + " for $user in doc(\"users.xml\")/Users/User[name=$name] return $user/password"; conn = xqds.getConnection(); XQExpression expr = conn.createExpression(); - expr.bindString(new QName("name"), name, conn.createAtomicType(XQItemType.XQBASETYPE_STRING)); + expr.bindString(new QName("name"), name, + conn.createAtomicType(XQItemType.XQBASETYPE_STRING)); XQResultSequence result = expr.executeQuery(query); - while (result.next()){ + while (result.next()) { System.out.println(result.getItemAsString(null)); } } catch (XQException e) { @@ -42,10 +45,11 @@ public class XQueryInjection { String name = request.getParameter("name"); XQDataSource ds = new SaxonXQDataSource(); XQConnection conn = ds.getConnection(); - String query = "for $user in doc(\"users.xml\")/Users/User[name='" + name + "'] return $user/password"; + String query = "for $user in doc(\"users.xml\")/Users/User[name='" + name + + "'] return $user/password"; XQPreparedExpression xqpe = conn.prepareExpression(query); XQResultSequence result = xqpe.executeQuery(); - while (result.next()){ + while (result.next()) { System.out.println(result.getItemAsString(null)); } } @@ -54,11 +58,12 @@ public class XQueryInjection { public void testRequestbad1(HttpServletRequest request) throws Exception { String name = request.getParameter("name"); XQDataSource xqds = new SaxonXQDataSource(); - String query = "for $user in doc(\"users.xml\")/Users/User[name='" + name + "'] return $user/password"; + String query = "for $user in doc(\"users.xml\")/Users/User[name='" + name + + "'] return $user/password"; XQConnection conn = xqds.getConnection(); XQExpression expr = conn.createExpression(); XQResultSequence result = expr.executeQuery(query); - while (result.next()){ + while (result.next()) { System.out.println(result.getItemAsString(null)); } } @@ -68,10 +73,11 @@ public class XQueryInjection { public void testStringtbad(@RequestParam String nameStr) throws XQException { XQDataSource ds = new SaxonXQDataSource(); XQConnection conn = ds.getConnection(); - String query = "for $user in doc(\"users.xml\")/Users/User[name='" + nameStr + "'] return $user/password"; + String query = "for $user in doc(\"users.xml\")/Users/User[name='" + nameStr + + "'] return $user/password"; XQPreparedExpression xqpe = conn.prepareExpression(query); XQResultSequence result = xqpe.executeQuery(); - while (result.next()){ + while (result.next()) { System.out.println(result.getItemAsString(null)); } } @@ -79,11 +85,12 @@ public class XQueryInjection { @RequestMapping public void testStringtbad1(@RequestParam String nameStr) throws XQException { XQDataSource xqds = new SaxonXQDataSource(); - String query = "for $user in doc(\"users.xml\")/Users/User[name='" + nameStr + "'] return $user/password"; + String query = "for $user in doc(\"users.xml\")/Users/User[name='" + nameStr + + "'] return $user/password"; XQConnection conn = xqds.getConnection(); XQExpression expr = conn.createExpression(); XQResultSequence result = expr.executeQuery(query); - while (result.next()){ + while (result.next()) { System.out.println(result.getItemAsString(null)); } } @@ -95,7 +102,7 @@ public class XQueryInjection { XQConnection conn = ds.getConnection(); XQPreparedExpression xqpe = conn.prepareExpression(name); XQResultSequence result = xqpe.executeQuery(); - while (result.next()){ + while (result.next()) { System.out.println(result.getItemAsString(null)); } } @@ -107,7 +114,7 @@ public class XQueryInjection { XQConnection conn = xqds.getConnection(); XQExpression expr = conn.createExpression(); XQResultSequence result = expr.executeQuery(name); - while (result.next()){ + while (result.next()) { System.out.println(result.getItemAsString(null)); } } @@ -120,7 +127,7 @@ public class XQueryInjection { XQConnection conn = ds.getConnection(); XQPreparedExpression xqpe = conn.prepareExpression(br); XQResultSequence result = xqpe.executeQuery(); - while (result.next()){ + while (result.next()) { System.out.println(result.getItemAsString(null)); } } @@ -133,11 +140,26 @@ public class XQueryInjection { XQConnection conn = xqds.getConnection(); XQExpression expr = conn.createExpression(); XQResultSequence result = expr.executeQuery(br); - while (result.next()){ + while (result.next()) { System.out.println(result.getItemAsString(null)); } } + @RequestMapping + public void testExecuteCommandbad(HttpServletRequest request) throws Exception { + String name = request.getParameter("name"); + XQDataSource xqds = new SaxonXQDataSource(); + XQConnection conn = xqds.getConnection(); + XQExpression expr = conn.createExpression(); + //bad code + expr.executeCommand(name); + //bad code + InputStream is = request.getInputStream(); + BufferedReader br = new BufferedReader(new InputStreamReader(is)); + expr.executeCommand(br); + expr.close(); + } + @RequestMapping public void good(HttpServletRequest request) throws XQException { String name = request.getParameter("name"); @@ -146,9 +168,10 @@ public class XQueryInjection { String query = "declare variable $name as xs:string external;" + " for $user in doc(\"users.xml\")/Users/User[name=$name] return $user/password"; XQPreparedExpression xqpe = conn.prepareExpression(query); - xqpe.bindString(new QName("name"), name, conn.createAtomicType(XQItemType.XQBASETYPE_STRING)); + xqpe.bindString(new QName("name"), name, + conn.createAtomicType(XQItemType.XQBASETYPE_STRING)); XQResultSequence result = xqpe.executeQuery(); - while (result.next()){ + while (result.next()) { System.out.println(result.getItemAsString(null)); } } @@ -161,10 +184,12 @@ public class XQueryInjection { XQDataSource xqds = new SaxonXQDataSource(); XQConnection conn = xqds.getConnection(); XQExpression expr = conn.createExpression(); - expr.bindString(new QName("name"), name, conn.createAtomicType(XQItemType.XQBASETYPE_STRING)); + expr.bindString(new QName("name"), name, + conn.createAtomicType(XQItemType.XQBASETYPE_STRING)); XQResultSequence result = expr.executeQuery(query); - while (result.next()){ + while (result.next()) { System.out.println(result.getItemAsString(null)); } } -} \ No newline at end of file +} + diff --git a/java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/xqj/SaxonXQConnection.java b/java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/xqj/SaxonXQConnection.java index 94bd38fa175..0263588e8b4 100644 --- a/java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/xqj/SaxonXQConnection.java +++ b/java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/xqj/SaxonXQConnection.java @@ -5,6 +5,7 @@ import net.sf.saxon.Configuration; import javax.xml.xquery.XQConnection; import javax.xml.xquery.XQPreparedExpression; import javax.xml.xquery.XQException; +import javax.xml.xquery.XQExpression; import javax.xml.xquery.XQStaticContext; import java.io.InputStream; From 6a6727fc80b67efd0c647eb8a9814e7799f63b83 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Sun, 14 Feb 2021 14:59:53 +0000 Subject: [PATCH 045/725] Reduce the scope of the query to reduce FPs --- .../Security/CWE/CWE-759/HashWithoutSalt.ql | 149 ++++++++++-------- .../security/CWE-759/HashWithoutSalt.expected | 12 +- .../security/CWE-759/HashWithoutSalt.java | 30 ++-- .../query-tests/security/CWE-759/SHA512.java | 21 +++ 4 files changed, 123 insertions(+), 89 deletions(-) create mode 100644 java/ql/test/experimental/query-tests/security/CWE-759/SHA512.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql b/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql index d9fcc22c02b..c69c9739d64 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql @@ -8,10 +8,8 @@ */ import java -import semmle.code.java.dataflow.DataFlow3 import semmle.code.java.dataflow.TaintTracking import semmle.code.java.dataflow.TaintTracking2 -import semmle.code.java.dataflow.TaintTracking3 import DataFlow::PathGraph /** The Java class `java.security.MessageDigest`. */ @@ -44,38 +42,91 @@ class MDUpdateMethod extends Method { } } +/** The hashing method that could taint the input. */ +class MDHashMethodAccess extends MethodAccess { + MDHashMethodAccess() { + ( + this.getMethod() instanceof MDDigestMethod or + this.getMethod() instanceof MDUpdateMethod + ) and + this.getNumArgument() != 0 + } +} + /** Gets a regular expression for matching common names of variables that indicate the value being held is a password. */ string getPasswordRegex() { result = "(?i).*pass(wd|word|code|phrase).*" } /** Finds variables that hold password information judging by their names. */ class PasswordVarExpr extends Expr { PasswordVarExpr() { - exists(Variable v | this = v.getAnAccess() | - ( - v.getName().toLowerCase().regexpMatch(getPasswordRegex()) and - not v.getName().toLowerCase().matches("%hash%") // Exclude variable names such as `passwordHash` since their values were already hashed - ) + this.(VarAccess).getVariable().getName().toLowerCase().regexpMatch(getPasswordRegex()) and + not this.(VarAccess).getVariable().getName().toLowerCase().matches("%hash%") // Exclude variable names such as `passwordHash` since their values were already hashed + } +} + +/** Holds if `Expr` e is an operand of `AddExpr`. */ +predicate hasAddExpr(AddExpr ae, Expr e) { + ae.getAnOperand() = e or + hasAddExpr(ae.getAnOperand(), e) +} + +/** Holds if `MethodAccess` ma has a flow to another `MDHashMethodAccess` call. */ +predicate hasAnotherHashCall(MethodAccess ma) { + exists(MethodAccess ma2, DataFlow2::Node node1, DataFlow2::Node node2 | + ma2 instanceof MDHashMethodAccess and + ma2 != ma and + node1.asExpr() = ma.getAChildExpr() and + node2.asExpr() = ma2.getAChildExpr() and + ( + TaintTracking2::localTaint(node1, node2) or + TaintTracking2::localTaint(node2, node1) + ) + ) +} + +/** Holds if `MethodAccess` ma is a hashing call without a sibling node making another hashing call. */ +predicate isSingleHashMethodCall(MethodAccess ma) { + ( + ma instanceof MDHashMethodAccess and + not hasAnotherHashCall(ma) + ) +} + +/** Holds if `MethodAccess` ma is invoked by `MethodAccess` ma2 either directly or indirectly. */ +predicate hasParentCall(MethodAccess ma2, MethodAccess ma) { + ma.getCaller() = ma2.getMethod() and + not ma2 instanceof MDHashMethodAccess + or + exists(MethodAccess ma3 | + ma.getCaller() = ma3.getMethod() and + not ma3 instanceof MDHashMethodAccess and + hasParentCall(ma2, ma3) + ) +} + +/** Holds if `MethodAccess` is a single hashing call. */ +predicate isSink(MethodAccess ma) { + isSingleHashMethodCall(ma) and + not exists(MethodAccess ma2 | hasParentCall(ma2, ma)) +} + +/** Sink of hashing calls. */ +class HashWithoutSaltSink extends DataFlow::ExprNode { + HashWithoutSaltSink() { + exists(MethodAccess ma | + this.asExpr() = ma.getAnArgument() and + isSink(ma) ) } } /** Taint configuration tracking flow from an expression whose name suggests it holds password data to a method call that generates a hash without a salt. */ -class PasswordHashConfiguration extends TaintTracking3::Configuration { - PasswordHashConfiguration() { this = "PasswordHashConfiguration" } +class HashWithoutSaltConfiguration extends TaintTracking::Configuration { + HashWithoutSaltConfiguration() { this = "HashWithoutSaltConfiguration" } - override predicate isSource(DataFlow3::Node source) { source.asExpr() instanceof PasswordVarExpr } + override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof PasswordVarExpr } - override predicate isSink(DataFlow3::Node sink) { - exists( - MethodAccess ma // invoke `md.update(password)` without the call of `md.update(digest)` - | - sink.asExpr() = ma.getArgument(0) and - ( - ma.getMethod() instanceof MDUpdateMethod or // md.update(password) - ma.getMethod() instanceof MDDigestMethod // md.digest(password) - ) - ) - } + override predicate isSink(DataFlow::Node sink) { sink instanceof HashWithoutSaltSink } /** * Holds if a password is concatenated with a salt then hashed together through the call `System.arraycopy(password.getBytes(), ...)`, for example, @@ -84,60 +135,26 @@ class PasswordHashConfiguration extends TaintTracking3::Configuration { * `byte[] messageDigest = md.digest(allBytes);` * Or the password is concatenated with a salt as a string. */ - override predicate isSanitizer(DataFlow3::Node node) { + override predicate isSanitizer(DataFlow::Node node) { exists(MethodAccess ma | ma.getMethod().getDeclaringType().hasQualifiedName("java.lang", "System") and ma.getMethod().hasName("arraycopy") and ma.getArgument(0) = node.asExpr() ) // System.arraycopy(password.getBytes(), ...) or - exists(AddExpr e | node.asExpr() = e.getAnOperand()) // password+salt - } -} - -class PasswordDigestConfiguration extends TaintTracking2::Configuration { - PasswordDigestConfiguration() { this = "PasswordDigestConfiguration" } - - override predicate isSource(DataFlow2::Node source) { - exists(MDConstructor mc | source.asExpr() = mc) - } - - override predicate isSink(DataFlow2::Node sink) { + exists(AddExpr e | hasAddExpr(e, node.asExpr())) // password+salt + or + exists(ConditionalExpr ce | ce = node.asExpr()) // useSalt?password+":"+salt:password + or exists(MethodAccess ma | - ( - ma.getMethod() instanceof MDUpdateMethod or - ma.getMethod() instanceof MDDigestMethod - ) and - exists(PasswordHashConfiguration cc | cc.hasFlowToExpr(ma.getAnArgument())) and - sink.asExpr() = ma.getQualifier() + ma.getMethod().getDeclaringType().hasQualifiedName("java.lang", "StringBuilder") and + ma.getMethod().hasName("append") and + ma.getArgument(0) = node.asExpr() // stringBuilder.append(password).append(salt) ) - } -} - -class HashWithoutSaltConfiguration extends TaintTracking::Configuration { - HashWithoutSaltConfiguration() { this = "HashWithoutSaltConfiguration" } - - override predicate isSource(DataFlow::Node source) { - exists(PasswordDigestConfiguration pc | pc.hasFlow(source, _)) - } - - override predicate isSink(DataFlow::Node sink) { + or exists(MethodAccess ma | - ma.getMethod() instanceof MDDigestMethod and // md.digest(password) - sink.asExpr() = ma.getQualifier() - ) - } - - /** Holds if `md.update` or `md.digest` calls integrate something other than the password, perhaps a salt. */ - override predicate isSanitizer(DataFlow::Node node) { - exists(MethodAccess ma | - ( - ma.getMethod() instanceof MDUpdateMethod - or - ma.getMethod() instanceof MDDigestMethod and ma.getNumArgument() != 0 - ) and - node.asExpr() = ma.getQualifier() and - not exists(PasswordHashConfiguration cc | cc.hasFlowToExpr(ma.getAnArgument())) + ma.getQualifier().(VarAccess).getVariable().getType() instanceof Interface and + ma.getAnArgument() = node.asExpr() // Method access of interface type variables requires runtime determination ) } } diff --git a/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.expected b/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.expected index 7fc5fe115e4..fa36297a8a1 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.expected @@ -1,19 +1,11 @@ edges | HashWithoutSalt.java:10:36:10:43 | password : String | HashWithoutSalt.java:10:36:10:54 | getBytes(...) | | HashWithoutSalt.java:17:13:17:20 | password : String | HashWithoutSalt.java:17:13:17:31 | getBytes(...) | -| HashWithoutSalt.java:98:22:98:29 | password : String | HashWithoutSalt.java:99:17:99:25 | passBytes : byte[] | -| HashWithoutSalt.java:99:17:99:25 | passBytes : byte[] | SHA256.java:14:22:14:31 | foo : byte[] | -| SHA256.java:14:22:14:31 | foo : byte[] | SHA256.java:15:15:15:17 | foo | nodes | HashWithoutSalt.java:10:36:10:43 | password : String | semmle.label | password : String | | HashWithoutSalt.java:10:36:10:54 | getBytes(...) | semmle.label | getBytes(...) | | HashWithoutSalt.java:17:13:17:20 | password : String | semmle.label | password : String | | HashWithoutSalt.java:17:13:17:31 | getBytes(...) | semmle.label | getBytes(...) | -| HashWithoutSalt.java:98:22:98:29 | password : String | semmle.label | password : String | -| HashWithoutSalt.java:99:17:99:25 | passBytes : byte[] | semmle.label | passBytes : byte[] | -| SHA256.java:14:22:14:31 | foo : byte[] | semmle.label | foo : byte[] | -| SHA256.java:15:15:15:17 | foo | semmle.label | foo | #select -| HashWithoutSalt.java:10:36:10:54 | getBytes(...) | HashWithoutSalt.java:10:36:10:43 | password : String | HashWithoutSalt.java:10:36:10:54 | getBytes(...) | $@ is hashed without a salt. | HashWithoutSalt.java:10:36:10:43 | password | The password | -| HashWithoutSalt.java:17:13:17:31 | getBytes(...) | HashWithoutSalt.java:17:13:17:20 | password : String | HashWithoutSalt.java:17:13:17:31 | getBytes(...) | $@ is hashed without a salt. | HashWithoutSalt.java:17:13:17:20 | password | The password | -| SHA256.java:15:15:15:17 | foo | HashWithoutSalt.java:98:22:98:29 | password : String | SHA256.java:15:15:15:17 | foo | $@ is hashed without a salt. | HashWithoutSalt.java:98:22:98:29 | password | The password | +| HashWithoutSalt.java:10:36:10:54 | getBytes(...) | HashWithoutSalt.java:10:36:10:43 | password : String | HashWithoutSalt.java:10:36:10:54 | getBytes(...) | $@ is hashed without a salt. | HashWithoutSalt.java:10:36:10:43 | password : String | The password | +| HashWithoutSalt.java:17:13:17:31 | getBytes(...) | HashWithoutSalt.java:17:13:17:20 | password : String | HashWithoutSalt.java:17:13:17:31 | getBytes(...) | $@ is hashed without a salt. | HashWithoutSalt.java:17:13:17:20 | password : String | The password | diff --git a/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.java b/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.java index 9535e4d01e5..ef2fef8dd9c 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.java +++ b/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.java @@ -54,7 +54,12 @@ public class HashWithoutSalt { // GOOD - Hash with a given salt stored somewhere else. public String getSHA256Hash(String password, String salt) throws NoSuchAlgorithmException { - return hash(password+salt); + return hash(password+":"+salt); + } + + // GOOD - Hash with a given salt stored somewhere else. + public String getSHA256Hash2(String password, String salt, boolean useSalt) throws NoSuchAlgorithmException { + return hash(useSalt?password+":"+salt:password); } // GOOD - Hash with a salt for a variable named passwordHash, whose value is a hash used as an input for a hashing function. @@ -71,9 +76,9 @@ public class HashWithoutSalt { public void update2(SHA256 sha256, byte[] foo, int start, int len) throws NoSuchAlgorithmException { sha256.update(foo, start, len); } - - // GOOD - Invoke a wrapper implementation with a salt. - public String getSHA256Hash4(String password) throws NoSuchAlgorithmException { + + // BAD - Invoking a wrapper implementation without a salt is not detected. + public String getSHA256Hash4(String password) throws NoSuchAlgorithmException, ClassNotFoundException, IllegalAccessException, InstantiationException { SHA256 sha256 = new SHA256(); byte[] salt = getSalt(); byte[] passBytes = password.getBytes(); @@ -82,7 +87,7 @@ public class HashWithoutSalt { return Base64.getEncoder().encodeToString(sha256.digest()); } - // GOOD - Invoke a wrapper implementation with a salt. + // BAD - Invoking a wrapper implementation without a salt is not detected. public String getSHA256Hash5(String password) throws NoSuchAlgorithmException { SHA256 sha256 = new SHA256(); byte[] salt = getSalt(); @@ -92,7 +97,7 @@ public class HashWithoutSalt { return Base64.getEncoder().encodeToString(sha256.digest()); } - // BAD - Invoke a wrapper implementation without a salt. + // BAD - Invoking a wrapper implementation without a salt is not detected. public String getSHA256Hash6(String password) throws NoSuchAlgorithmException { SHA256 sha256 = new SHA256(); byte[] passBytes = password.getBytes(); @@ -100,18 +105,17 @@ public class HashWithoutSalt { return Base64.getEncoder().encodeToString(sha256.digest()); } - // GOOD - Invoke a wrapper implementation with a salt, which is only detectable when a class type is declared (not interface). + // BAD - Invoke a wrapper implementation with a salt, which is not detected with an interface type variable. public String getSHA256Hash7(byte[] passphrase) throws NoSuchAlgorithmException, ClassNotFoundException, IllegalAccessException, InstantiationException { - Class c = Class.forName("SHA256"); - HASH sha256 = (HASH) (c.newInstance()); + Class c = Class.forName("SHA512"); + HASH sha512 = (HASH) (c.newInstance()); byte[] tmp = new byte[4]; byte[] key = new byte[32 * 2]; for (int i = 0; i < 2; i++) { - sha256.init(); + sha512.init(); tmp[3] = (byte) i; - sha256.update(tmp, 0, tmp.length); - sha256.update(passphrase, 0, passphrase.length); - System.arraycopy(sha256.digest(), 0, key, i * 32, 32); + sha512.update(passphrase, 0, passphrase.length); + System.arraycopy(sha512.digest(), 0, key, i * 32, 32); } return Base64.getEncoder().encodeToString(key); } diff --git a/java/ql/test/experimental/query-tests/security/CWE-759/SHA512.java b/java/ql/test/experimental/query-tests/security/CWE-759/SHA512.java new file mode 100644 index 00000000000..ec41fbf2d1a --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-759/SHA512.java @@ -0,0 +1,21 @@ +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public class SHA512 implements HASH { + MessageDigest md; + public int getBlockSize() {return 32;} + public void init() throws NoSuchAlgorithmException { + try { md = MessageDigest.getInstance("SHA-512"); } + catch (Exception e){ + System.err.println(e); + } + } + + public void update(byte[] foo, int start, int len) throws NoSuchAlgorithmException { + md.update(foo, start, len); + } + + public byte[] digest() throws NoSuchAlgorithmException { + return md.digest(); + } +} \ No newline at end of file From 23f620d255423ace5ede1c1cf7373ffe6018a8bd Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Mon, 15 Feb 2021 05:31:29 +0000 Subject: [PATCH 046/725] Query to detect insecure LDAP endpoint configuration --- .../CWE/CWE-297/InsecureLdapEndpoint.java | 23 +++++++ .../CWE/CWE-297/InsecureLdapEndpoint.qhelp | 32 +++++++++ .../CWE/CWE-297/InsecureLdapEndpoint.ql | 65 +++++++++++++++++++ .../CWE-297/InsecureLdapEndpoint.expected | 2 + .../CWE-297/InsecureLdapEndpoint.java | 52 +++++++++++++++ .../CWE-297/InsecureLdapEndpoint.qlref | 1 + 6 files changed, 175 insertions(+) create mode 100644 java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.java create mode 100644 java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.ql create mode 100644 java/ql/test/experimental/query-tests/security/CWE-297/InsecureLdapEndpoint.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-297/InsecureLdapEndpoint.java create mode 100644 java/ql/test/experimental/query-tests/security/CWE-297/InsecureLdapEndpoint.qlref diff --git a/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.java b/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.java new file mode 100644 index 00000000000..0af5200a150 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.java @@ -0,0 +1,23 @@ +public class InsecureLdapEndpoint { + public Hashtable createConnectionEnv() { + Hashtable env = new Hashtable(); + env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); + env.put(Context.PROVIDER_URL, "ldaps://ad.your-server.com:636"); + + env.put(Context.SECURITY_AUTHENTICATION, "simple"); + env.put(Context.SECURITY_PRINCIPAL, "username"); + env.put(Context.SECURITY_CREDENTIALS, "secpassword"); + + // BAD - Test configuration with disabled SSL endpoint check. + { + System.setProperty("com.sun.jndi.ldap.object.disableEndpointIdentification", "true"); + } + + // GOOD - No configuration to disable SSL endpoint check since it is enabled by default. + { + } + + return env; + } + +} diff --git a/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.qhelp b/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.qhelp new file mode 100644 index 00000000000..3aee17f9777 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.qhelp @@ -0,0 +1,32 @@ + + + + +

    Java versions 8u181 or greater have enabled LDAPS endpoint identification by default. Nowadays infrastructure services like LDAP are commonly deployed behind load balancers therefore the LDAP server name can be different from the FQDN of the LDAPS endpoint. If a service certificate does not properly contain a matching DNS name as part of the certificate, Java will reject it by default.

    +

    Instead of addressing the issue properly by having a compliant certificate deployed, frequently developers simply disable SSL endpoint check.

    +

    This query checks whether LDAPS endpoint check is disabled in system properties.

    +
    + + +

    Replace any non-conforming LDAP server certificates to include a DNS name in the subjectAltName field of the certificate that matches the FQDN of the service.

    +
    + + +

    The following two examples show two ways of configuring SSL endpoint. In the 'BAD' case, +endpoint check is disabled. In the 'GOOD' case, endpoint check is left enabled through the default Java configuration.

    + +
    + + +
  • + Oracle Java 8 Update 181 (8u181): + Endpoint identification enabled on LDAPS connections +
  • +
  • + IBM: + Fix this LDAP SSL error +
  • +
    +
    diff --git a/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.ql b/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.ql new file mode 100644 index 00000000000..266b2b999a8 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.ql @@ -0,0 +1,65 @@ +/** + * @name Insecure LDAP Endpoint Configuration + * @description Java application configured to disable LDAP endpoint identification does not validate the SSL certificate to properly ensure that it is actually associated with that host. + * @kind problem + * @id java/insecure-ldap-endpoint + * @tags security + * external/cwe-297 + */ + +import java + +/** + * The method to set a system property. + */ +class SetSystemPropertyMethod extends Method { + SetSystemPropertyMethod() { + this.hasName("setProperty") and + this.getDeclaringType().hasQualifiedName("java.lang", "System") + } +} + +/** + * The method to set Java properties. + */ +class SetPropertyMethod extends Method { + SetPropertyMethod() { + this.hasName("setProperty") and + this.getDeclaringType().hasQualifiedName("java.util", "Properties") + } +} + +/** + * The method to set system properties. + */ +class SetSystemPropertiesMethod extends Method { + SetSystemPropertiesMethod() { + this.hasName("setProperties") and + this.getDeclaringType().hasQualifiedName("java.lang", "System") + } +} + +/** Holds if `MethodAccess` ma disables SSL endpoint check. */ +predicate isInsecureSSLEndpoint(MethodAccess ma) { + ( + ma.getMethod() instanceof SetSystemPropertyMethod and + ( + ma.getArgument(0).(CompileTimeConstantExpr).getStringValue() = + "com.sun.jndi.ldap.object.disableEndpointIdentification" and + ma.getArgument(1).(CompileTimeConstantExpr).getStringValue() = "true" //com.sun.jndi.ldap.object.disableEndpointIdentification=true + ) + or + ma.getMethod() instanceof SetSystemPropertiesMethod and + exists(MethodAccess ma2 | + ma2.getMethod() instanceof SetPropertyMethod and + ma2.getArgument(0).(CompileTimeConstantExpr).getStringValue() = + "com.sun.jndi.ldap.object.disableEndpointIdentification" and + ma2.getArgument(1).(CompileTimeConstantExpr).getStringValue() = "true" and //com.sun.jndi.ldap.object.disableEndpointIdentification=true + ma2.getQualifier().(VarAccess).getVariable().getAnAccess() = ma.getArgument(0) // systemProps.setProperties(properties) + ) + ) +} + +from MethodAccess ma +where isInsecureSSLEndpoint(ma) +select ma, "SSL configuration allows insecure endpoint configuration" diff --git a/java/ql/test/experimental/query-tests/security/CWE-297/InsecureLdapEndpoint.expected b/java/ql/test/experimental/query-tests/security/CWE-297/InsecureLdapEndpoint.expected new file mode 100644 index 00000000000..29eb44937ee --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-297/InsecureLdapEndpoint.expected @@ -0,0 +1,2 @@ +| InsecureLdapEndpoint.java:17:9:17:92 | setProperty(...) | SSL configuration allows insecure endpoint configuration | +| InsecureLdapEndpoint.java:48:3:48:34 | setProperties(...) | SSL configuration allows insecure endpoint configuration | diff --git a/java/ql/test/experimental/query-tests/security/CWE-297/InsecureLdapEndpoint.java b/java/ql/test/experimental/query-tests/security/CWE-297/InsecureLdapEndpoint.java new file mode 100644 index 00000000000..44c37864af0 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-297/InsecureLdapEndpoint.java @@ -0,0 +1,52 @@ +import java.util.Hashtable; +import java.util.Properties; +import javax.naming.Context; + +public class InsecureLdapEndpoint { + // BAD - Test configuration with disabled SSL endpoint check. + public Hashtable createConnectionEnv() { + Hashtable env = new Hashtable(); + env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); + env.put(Context.PROVIDER_URL, "ldaps://ad.your-server.com:636"); + + env.put(Context.SECURITY_AUTHENTICATION, "simple"); + env.put(Context.SECURITY_PRINCIPAL, "username"); + env.put(Context.SECURITY_CREDENTIALS, "secpassword"); + + // Disable SSL endpoint check + System.setProperty("com.sun.jndi.ldap.object.disableEndpointIdentification", "true"); + + return env; + } + + // GOOD - Test configuration without disabling SSL endpoint check. + public Hashtable createConnectionEnv2() { + Hashtable env = new Hashtable(); + env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); + env.put(Context.PROVIDER_URL, "ldaps://ad.your-server.com:636"); + + env.put(Context.SECURITY_AUTHENTICATION, "simple"); + env.put(Context.SECURITY_PRINCIPAL, "username"); + env.put(Context.SECURITY_CREDENTIALS, "secpassword"); + + return env; + } + + // BAD - Test configuration with disabled SSL endpoint check. + public Hashtable createConnectionEnv3() { + Hashtable env = new Hashtable(); + env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); + env.put(Context.PROVIDER_URL, "ldaps://ad.your-server.com:636"); + + env.put(Context.SECURITY_AUTHENTICATION, "simple"); + env.put(Context.SECURITY_PRINCIPAL, "username"); + env.put(Context.SECURITY_CREDENTIALS, "secpassword"); + + // Disable SSL endpoint check + Properties properties = new Properties(); + properties.setProperty("com.sun.jndi.ldap.object.disableEndpointIdentification", "true"); + System.setProperties(properties); + + return env; + } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-297/InsecureLdapEndpoint.qlref b/java/ql/test/experimental/query-tests/security/CWE-297/InsecureLdapEndpoint.qlref new file mode 100644 index 00000000000..1c4d99bb6a3 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-297/InsecureLdapEndpoint.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.ql From 409d95c5222a35e35f9d383f6021fd3472c3f963 Mon Sep 17 00:00:00 2001 From: Francis Alexander Date: Mon, 15 Feb 2021 14:01:14 +0530 Subject: [PATCH 047/725] Sanitizer checks to decrease FP --- .../Security/CWE/CWE-346/UnvalidatedCors.ql | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql b/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql index 3d98237b104..17cf94d2c1e 100644 --- a/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql +++ b/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql @@ -28,6 +28,14 @@ private predicate setsAllowCredentials(MethodAccess header) { header.getArgument(1).(CompileTimeConstantExpr).getStringValue() = "true" } +class CorsProbableCheckAccess extends MethodAccess { + CorsProbableCheckAccess() { + getMethod().getName() = ["contains", "equals"] and + getMethod().getDeclaringType().getQualifiedName() = + ["java.util.List", "java.util.ArrayList", "java.lang.String"] + } +} + private Expr getAccessControlAllowOriginHeaderName() { result.(CompileTimeConstantExpr).getStringValue().toLowerCase() = "access-control-allow-origin" } @@ -49,6 +57,21 @@ class CorsOriginConfig extends TaintTracking::Configuration { sink.asExpr() = corsheader.getArgument(1) ) } + + /* + * This should ideally check, the origin being validated against a list/array-list. + * or function being used to validate the origin, which has a flow from its parameter to any of the CorsProbableCheckAccess functions + */ + + override predicate isSanitizer(DataFlow::Node node) { + node.asExpr() = any(CorsProbableCheckAccess ma).getAnArgument() + or + exists(MethodAccess ma, CorsProbableCheckAccess ca | + ma.getMethod().calls(ca.getMethod()) and + DataFlow::localExprFlow(ma.getMethod().getAParameter().getAnAccess(), ca.getAnArgument()) and + (node.asExpr() = ma.getAnArgument() or node.asExpr() = ma.getAnArgument().getAChildExpr()) + ) + } } from DataFlow::PathNode source, DataFlow::PathNode sink, CorsOriginConfig conf From a03e6faf376b6c0a55a1f3d3ea7b79e43ede0ad0 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Mon, 15 Feb 2021 14:10:17 +0000 Subject: [PATCH 048/725] Optimize the query and update qldoc --- .../Security/CWE/CWE-759/HashWithoutSalt.ql | 25 ++-- .../code/java/dataflow/TaintTracking3.qll | 7 -- .../tainttracking3/TaintTrackingImpl.qll | 115 ------------------ .../tainttracking3/TaintTrackingParameter.qll | 5 - 4 files changed, 7 insertions(+), 145 deletions(-) delete mode 100644 java/ql/src/semmle/code/java/dataflow/TaintTracking3.qll delete mode 100644 java/ql/src/semmle/code/java/dataflow/internal/tainttracking3/TaintTrackingImpl.qll delete mode 100644 java/ql/src/semmle/code/java/dataflow/internal/tainttracking3/TaintTrackingParameter.qll diff --git a/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql b/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql index c69c9739d64..e1ac21e9200 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql @@ -64,16 +64,12 @@ class PasswordVarExpr extends Expr { } } -/** Holds if `Expr` e is an operand of `AddExpr`. */ -predicate hasAddExpr(AddExpr ae, Expr e) { - ae.getAnOperand() = e or - hasAddExpr(ae.getAnOperand(), e) -} +/** Holds if `Expr` e is a direct or indirect operand of `ae`. */ +predicate hasAddExpr(AddExpr ae, Expr e) { ae.getAnOperand+() = e } /** Holds if `MethodAccess` ma has a flow to another `MDHashMethodAccess` call. */ predicate hasAnotherHashCall(MethodAccess ma) { - exists(MethodAccess ma2, DataFlow2::Node node1, DataFlow2::Node node2 | - ma2 instanceof MDHashMethodAccess and + exists(MDHashMethodAccess ma2, DataFlow::Node node1, DataFlow::Node node2 | ma2 != ma and node1.asExpr() = ma.getAChildExpr() and node2.asExpr() = ma2.getAChildExpr() and @@ -85,29 +81,22 @@ predicate hasAnotherHashCall(MethodAccess ma) { } /** Holds if `MethodAccess` ma is a hashing call without a sibling node making another hashing call. */ -predicate isSingleHashMethodCall(MethodAccess ma) { - ( - ma instanceof MDHashMethodAccess and - not hasAnotherHashCall(ma) - ) -} +predicate isSingleHashMethodCall(MDHashMethodAccess ma) { not hasAnotherHashCall(ma) } /** Holds if `MethodAccess` ma is invoked by `MethodAccess` ma2 either directly or indirectly. */ predicate hasParentCall(MethodAccess ma2, MethodAccess ma) { - ma.getCaller() = ma2.getMethod() and - not ma2 instanceof MDHashMethodAccess + ma.getCaller() = ma2.getMethod() or exists(MethodAccess ma3 | ma.getCaller() = ma3.getMethod() and - not ma3 instanceof MDHashMethodAccess and hasParentCall(ma2, ma3) ) } -/** Holds if `MethodAccess` is a single hashing call. */ +/** Holds if `MethodAccess` is a single hashing call that is not invoked by a wrapper method. */ predicate isSink(MethodAccess ma) { isSingleHashMethodCall(ma) and - not exists(MethodAccess ma2 | hasParentCall(ma2, ma)) + not exists(MethodAccess ma2 | hasParentCall(ma2, ma)) // Not invoked by a wrapper method which could invoke MDHashMethod in another call stack to reduce FPs } /** Sink of hashing calls. */ diff --git a/java/ql/src/semmle/code/java/dataflow/TaintTracking3.qll b/java/ql/src/semmle/code/java/dataflow/TaintTracking3.qll deleted file mode 100644 index 49c43ed1418..00000000000 --- a/java/ql/src/semmle/code/java/dataflow/TaintTracking3.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** - * Provides classes for performing local (intra-procedural) and - * global (inter-procedural) taint-tracking analyses. - */ -module TaintTracking3 { - import semmle.code.java.dataflow.internal.tainttracking3.TaintTrackingImpl -} diff --git a/java/ql/src/semmle/code/java/dataflow/internal/tainttracking3/TaintTrackingImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/tainttracking3/TaintTrackingImpl.qll deleted file mode 100644 index b509fad9cd2..00000000000 --- a/java/ql/src/semmle/code/java/dataflow/internal/tainttracking3/TaintTrackingImpl.qll +++ /dev/null @@ -1,115 +0,0 @@ -/** - * Provides an implementation of global (interprocedural) taint tracking. - * This file re-exports the local (intraprocedural) taint-tracking analysis - * from `TaintTrackingParameter::Public` and adds a global analysis, mainly - * exposed through the `Configuration` class. For some languages, this file - * exists in several identical copies, allowing queries to use multiple - * `Configuration` classes that depend on each other without introducing - * mutual recursion among those configurations. - */ - -import TaintTrackingParameter::Public -private import TaintTrackingParameter::Private - -/** - * A configuration of interprocedural taint tracking analysis. This defines - * sources, sinks, and any other configurable aspect of the analysis. Each - * use of the taint tracking library must define its own unique extension of - * this abstract class. - * - * A taint-tracking configuration is a special data flow configuration - * (`DataFlow::Configuration`) that allows for flow through nodes that do not - * necessarily preserve values but are still relevant from a taint tracking - * perspective. (For example, string concatenation, where one of the operands - * is tainted.) - * - * To create a configuration, extend this class with a subclass whose - * characteristic predicate is a unique singleton string. For example, write - * - * ```ql - * class MyAnalysisConfiguration extends TaintTracking::Configuration { - * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } - * // Override `isSource` and `isSink`. - * // Optionally override `isSanitizer`. - * // Optionally override `isSanitizerIn`. - * // Optionally override `isSanitizerOut`. - * // Optionally override `isSanitizerGuard`. - * // Optionally override `isAdditionalTaintStep`. - * } - * ``` - * - * Then, to query whether there is flow between some `source` and `sink`, - * write - * - * ```ql - * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) - * ``` - * - * Multiple configurations can coexist, but it is unsupported to depend on - * another `TaintTracking::Configuration` or a `DataFlow::Configuration` in the - * overridden predicates that define sources, sinks, or additional steps. - * Instead, the dependency should go to a `TaintTracking2::Configuration` or a - * `DataFlow2::Configuration`, `DataFlow3::Configuration`, etc. - */ -abstract class Configuration extends DataFlow::Configuration { - bindingset[this] - Configuration() { any() } - - /** - * Holds if `source` is a relevant taint source. - * - * The smaller this predicate is, the faster `hasFlow()` will converge. - */ - // overridden to provide taint-tracking specific qldoc - abstract override predicate isSource(DataFlow::Node source); - - /** - * Holds if `sink` is a relevant taint sink. - * - * The smaller this predicate is, the faster `hasFlow()` will converge. - */ - // overridden to provide taint-tracking specific qldoc - abstract override predicate isSink(DataFlow::Node sink); - - /** Holds if the node `node` is a taint sanitizer. */ - predicate isSanitizer(DataFlow::Node node) { none() } - - final override predicate isBarrier(DataFlow::Node node) { - isSanitizer(node) or - defaultTaintSanitizer(node) - } - - /** Holds if taint propagation into `node` is prohibited. */ - predicate isSanitizerIn(DataFlow::Node node) { none() } - - final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) } - - /** Holds if taint propagation out of `node` is prohibited. */ - predicate isSanitizerOut(DataFlow::Node node) { none() } - - final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) } - - /** Holds if taint propagation through nodes guarded by `guard` is prohibited. */ - predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() } - - final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) } - - /** - * Holds if the additional taint propagation step from `node1` to `node2` - * must be taken into account in the analysis. - */ - predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() } - - final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { - isAdditionalTaintStep(node1, node2) or - defaultAdditionalTaintStep(node1, node2) - } - - /** - * Holds if taint may flow from `source` to `sink` for this configuration. - */ - // overridden to provide taint-tracking specific qldoc - override predicate hasFlow(DataFlow::Node source, DataFlow::Node sink) { - super.hasFlow(source, sink) - } -} diff --git a/java/ql/src/semmle/code/java/dataflow/internal/tainttracking3/TaintTrackingParameter.qll b/java/ql/src/semmle/code/java/dataflow/internal/tainttracking3/TaintTrackingParameter.qll deleted file mode 100644 index 10fb6b09fa8..00000000000 --- a/java/ql/src/semmle/code/java/dataflow/internal/tainttracking3/TaintTrackingParameter.qll +++ /dev/null @@ -1,5 +0,0 @@ -import semmle.code.java.dataflow.internal.TaintTrackingUtil as Public - -module Private { - import semmle.code.java.dataflow.DataFlow3::DataFlow3 as DataFlow -} From f1e44bce4abaa982976decbc669c2a327621eee3 Mon Sep 17 00:00:00 2001 From: haby0 Date: Tue, 16 Feb 2021 00:07:44 +0800 Subject: [PATCH 049/725] Update java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql Co-authored-by: Chris Smowton --- java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql b/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql index 69617cad629..dfa900f81ad 100644 --- a/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql +++ b/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql @@ -16,7 +16,7 @@ import XQueryInjectionLib import DataFlow::PathGraph /** - * Taint-tracking configuration tracing flow from remote sources, through an XQuery parser, to its eventual execution. + * A taint-tracking configuration tracing flow from remote sources, through an XQuery parser, to its eventual execution. */ class XQueryInjectionConfig extends TaintTracking::Configuration { XQueryInjectionConfig() { this = "XQueryInjectionConfig" } From 92c00cb741ccdab82e7d0d8999e62a7243a989dd Mon Sep 17 00:00:00 2001 From: haby0 Date: Tue, 16 Feb 2021 00:09:21 +0800 Subject: [PATCH 050/725] Update java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql Co-authored-by: Chris Smowton --- java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql b/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql index dfa900f81ad..0bb85272f08 100644 --- a/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql +++ b/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql @@ -30,7 +30,7 @@ class XQueryInjectionConfig extends TaintTracking::Configuration { } /** - * Conveys taint from the input to a `prepareExpression` call to the returned prepared expression. + * Holds if taint from the input `pred` to a `prepareExpression` call flows to the returned prepared expression `succ`. */ override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { exists(XQueryParserCall parser | pred.asExpr() = parser.getInput() and succ.asExpr() = parser) From 5ce3af05910fefdbc8e07c793ded5593f1a0e706 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Mon, 15 Feb 2021 21:38:54 +0000 Subject: [PATCH 051/725] Enhance the query and update qldoc --- .../CWE/CWE-297/InsecureLdapEndpoint.java | 13 +-- .../CWE/CWE-297/InsecureLdapEndpoint.qhelp | 9 +- .../CWE/CWE-297/InsecureLdapEndpoint.ql | 86 +++++++++++++------ .../CWE/CWE-297/InsecureLdapEndpoint2.java | 17 ++++ .../CWE-297/InsecureLdapEndpoint.expected | 7 +- .../CWE-297/InsecureLdapEndpoint.java | 60 ++++++++++++- 6 files changed, 149 insertions(+), 43 deletions(-) create mode 100644 java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint2.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.java b/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.java index 0af5200a150..6f7494f8811 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.java +++ b/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.java @@ -8,16 +8,11 @@ public class InsecureLdapEndpoint { env.put(Context.SECURITY_PRINCIPAL, "username"); env.put(Context.SECURITY_CREDENTIALS, "secpassword"); - // BAD - Test configuration with disabled SSL endpoint check. - { - System.setProperty("com.sun.jndi.ldap.object.disableEndpointIdentification", "true"); - } - - // GOOD - No configuration to disable SSL endpoint check since it is enabled by default. - { - } + // BAD - Test configuration with disabled SSL endpoint check. + { + System.setProperty("com.sun.jndi.ldap.object.disableEndpointIdentification", "true"); + } return env; } - } diff --git a/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.qhelp b/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.qhelp index 3aee17f9777..671f713ca0d 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.qhelp +++ b/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.qhelp @@ -5,8 +5,8 @@

    Java versions 8u181 or greater have enabled LDAPS endpoint identification by default. Nowadays infrastructure services like LDAP are commonly deployed behind load balancers therefore the LDAP server name can be different from the FQDN of the LDAPS endpoint. If a service certificate does not properly contain a matching DNS name as part of the certificate, Java will reject it by default.

    -

    Instead of addressing the issue properly by having a compliant certificate deployed, frequently developers simply disable SSL endpoint check.

    -

    This query checks whether LDAPS endpoint check is disabled in system properties.

    +

    Instead of addressing the issue properly by having a compliant certificate deployed, frequently developers simply disable LDAPS endpoint check.

    +

    Failing to validate the certificate makes the SSL session susceptible to a man-in-the-middle attack. This query checks whether LDAPS endpoint check is disabled in system properties.

    @@ -14,9 +14,10 @@ -

    The following two examples show two ways of configuring SSL endpoint. In the 'BAD' case, +

    The following two examples show two ways of configuring LDAPS endpoint. In the 'BAD' case, endpoint check is disabled. In the 'GOOD' case, endpoint check is left enabled through the default Java configuration.

    - + +>
    diff --git a/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.ql b/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.ql index 266b2b999a8..144f92875e7 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.ql @@ -1,17 +1,15 @@ /** - * @name Insecure LDAP Endpoint Configuration - * @description Java application configured to disable LDAP endpoint identification does not validate the SSL certificate to properly ensure that it is actually associated with that host. + * @name Insecure LDAPS Endpoint Configuration + * @description Java application configured to disable LDAPS endpoint identification does not validate the SSL certificate to properly ensure that it is actually associated with that host. * @kind problem - * @id java/insecure-ldap-endpoint + * @id java/insecure-ldaps-endpoint * @tags security * external/cwe-297 */ import java -/** - * The method to set a system property. - */ +/** The method to set a system property. */ class SetSystemPropertyMethod extends Method { SetSystemPropertyMethod() { this.hasName("setProperty") and @@ -19,19 +17,22 @@ class SetSystemPropertyMethod extends Method { } } -/** - * The method to set Java properties. - */ -class SetPropertyMethod extends Method { - SetPropertyMethod() { - this.hasName("setProperty") and - this.getDeclaringType().hasQualifiedName("java.util", "Properties") - } +/** The class `java.util.Hashtable`. */ +class TypeHashtable extends Class { + TypeHashtable() { this.getSourceDeclaration().hasQualifiedName("java.util", "Hashtable") } } /** - * The method to set system properties. + * The method to set Java properties either through `setProperty` declared in the class `Properties` or `put` declared in its parent class `HashTable`. */ +class SetPropertyMethod extends Method { + SetPropertyMethod() { + this.getDeclaringType().getAnAncestor() instanceof TypeHashtable and + this.hasName(["put", "setProperty"]) + } +} + +/** The method to set system properties. */ class SetSystemPropertiesMethod extends Method { SetSystemPropertiesMethod() { this.hasName("setProperties") and @@ -39,27 +40,62 @@ class SetSystemPropertiesMethod extends Method { } } +/** Holds if an expression is evaluated to the string literal `com.sun.jndi.ldap.object.disableEndpointIdentification`. */ +predicate isPropertyDisableLdapEndpointId(Expr expr) { + expr.(CompileTimeConstantExpr).getStringValue() = + "com.sun.jndi.ldap.object.disableEndpointIdentification" + or + exists(Field f | + expr = f.getAnAccess() and + f.getAnAssignedValue().(StringLiteral).getValue() = + "com.sun.jndi.ldap.object.disableEndpointIdentification" + ) +} + +/** Holds if an expression is evaluated to the boolean value true. */ +predicate isBooleanTrue(Expr expr) { + expr.(CompileTimeConstantExpr).getStringValue() = "true" // "true" + or + expr.(BooleanLiteral).getBooleanValue() = true // true + or + exists(MethodAccess ma | + expr = ma and + ma.getMethod().hasName("toString") and + ma.getQualifier().(FieldAccess).getField().hasName("TRUE") and + ma.getQualifier() + .(FieldAccess) + .getField() + .getDeclaringType() + .hasQualifiedName("java.lang", "Boolean") // Boolean.TRUE.toString() + ) +} + +/** Holds if `ma` is in a test class or method. */ +predicate isTestMethod(MethodAccess ma) { + ma.getMethod() instanceof TestMethod or + ma.getEnclosingCallable().getDeclaringType().getPackage().getName().matches("%test%") or + ma.getEnclosingCallable().getDeclaringType().getName().toLowerCase().matches("%test%") +} + /** Holds if `MethodAccess` ma disables SSL endpoint check. */ predicate isInsecureSSLEndpoint(MethodAccess ma) { ( ma.getMethod() instanceof SetSystemPropertyMethod and - ( - ma.getArgument(0).(CompileTimeConstantExpr).getStringValue() = - "com.sun.jndi.ldap.object.disableEndpointIdentification" and - ma.getArgument(1).(CompileTimeConstantExpr).getStringValue() = "true" //com.sun.jndi.ldap.object.disableEndpointIdentification=true - ) + isPropertyDisableLdapEndpointId(ma.getArgument(0)) and + isBooleanTrue(ma.getArgument(1)) //com.sun.jndi.ldap.object.disableEndpointIdentification=true or ma.getMethod() instanceof SetSystemPropertiesMethod and exists(MethodAccess ma2 | ma2.getMethod() instanceof SetPropertyMethod and - ma2.getArgument(0).(CompileTimeConstantExpr).getStringValue() = - "com.sun.jndi.ldap.object.disableEndpointIdentification" and - ma2.getArgument(1).(CompileTimeConstantExpr).getStringValue() = "true" and //com.sun.jndi.ldap.object.disableEndpointIdentification=true + isPropertyDisableLdapEndpointId(ma2.getArgument(0)) and + isBooleanTrue(ma2.getArgument(1)) and //com.sun.jndi.ldap.object.disableEndpointIdentification=true ma2.getQualifier().(VarAccess).getVariable().getAnAccess() = ma.getArgument(0) // systemProps.setProperties(properties) ) ) } from MethodAccess ma -where isInsecureSSLEndpoint(ma) -select ma, "SSL configuration allows insecure endpoint configuration" +where + isInsecureSSLEndpoint(ma) and + not isTestMethod(ma) +select ma, "LDAPS configuration allows insecure endpoint identification" diff --git a/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint2.java b/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint2.java new file mode 100644 index 00000000000..2a5c3c87bc7 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint2.java @@ -0,0 +1,17 @@ +public class InsecureLdapEndpoint2 { + public Hashtable createConnectionEnv() { + Hashtable env = new Hashtable(); + env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); + env.put(Context.PROVIDER_URL, "ldaps://ad.your-server.com:636"); + + env.put(Context.SECURITY_AUTHENTICATION, "simple"); + env.put(Context.SECURITY_PRINCIPAL, "username"); + env.put(Context.SECURITY_CREDENTIALS, "secpassword"); + + // GOOD - No configuration to disable SSL endpoint check since it is enabled by default. + { + } + + return env; + } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-297/InsecureLdapEndpoint.expected b/java/ql/test/experimental/query-tests/security/CWE-297/InsecureLdapEndpoint.expected index 29eb44937ee..f37e49e30e0 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-297/InsecureLdapEndpoint.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-297/InsecureLdapEndpoint.expected @@ -1,2 +1,5 @@ -| InsecureLdapEndpoint.java:17:9:17:92 | setProperty(...) | SSL configuration allows insecure endpoint configuration | -| InsecureLdapEndpoint.java:48:3:48:34 | setProperties(...) | SSL configuration allows insecure endpoint configuration | +| InsecureLdapEndpoint.java:19:9:19:92 | setProperty(...) | LDAPS configuration allows insecure endpoint identification | +| InsecureLdapEndpoint.java:50:9:50:40 | setProperties(...) | LDAPS configuration allows insecure endpoint identification | +| InsecureLdapEndpoint.java:68:9:68:40 | setProperties(...) | LDAPS configuration allows insecure endpoint identification | +| InsecureLdapEndpoint.java:84:9:84:94 | setProperty(...) | LDAPS configuration allows insecure endpoint identification | +| InsecureLdapEndpoint.java:102:9:102:40 | setProperties(...) | LDAPS configuration allows insecure endpoint identification | diff --git a/java/ql/test/experimental/query-tests/security/CWE-297/InsecureLdapEndpoint.java b/java/ql/test/experimental/query-tests/security/CWE-297/InsecureLdapEndpoint.java index 44c37864af0..72f6bee118a 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-297/InsecureLdapEndpoint.java +++ b/java/ql/test/experimental/query-tests/security/CWE-297/InsecureLdapEndpoint.java @@ -3,7 +3,9 @@ import java.util.Properties; import javax.naming.Context; public class InsecureLdapEndpoint { - // BAD - Test configuration with disabled SSL endpoint check. + private static String PROP_DISABLE_LDAP_ENDPOINT_IDENTIFICATION = "com.sun.jndi.ldap.object.disableEndpointIdentification"; + + // BAD - Test configuration with disabled LDAPS endpoint check using `System.setProperty()`. public Hashtable createConnectionEnv() { Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); @@ -19,7 +21,7 @@ public class InsecureLdapEndpoint { return env; } - // GOOD - Test configuration without disabling SSL endpoint check. + // GOOD - Test configuration without disabling LDAPS endpoint check. public Hashtable createConnectionEnv2() { Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); @@ -32,7 +34,7 @@ public class InsecureLdapEndpoint { return env; } - // BAD - Test configuration with disabled SSL endpoint check. + // BAD - Test configuration with disabled LDAPS endpoint check using `System.setProperties()`. public Hashtable createConnectionEnv3() { Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); @@ -49,4 +51,56 @@ public class InsecureLdapEndpoint { return env; } + + // BAD - Test configuration with disabled LDAPS endpoint check using `HashTable.put()`. + public Hashtable createConnectionEnv4() { + Hashtable env = new Hashtable(); + env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); + env.put(Context.PROVIDER_URL, "ldaps://ad.your-server.com:636"); + + env.put(Context.SECURITY_AUTHENTICATION, "simple"); + env.put(Context.SECURITY_PRINCIPAL, "username"); + env.put(Context.SECURITY_CREDENTIALS, "secpassword"); + + // Disable SSL endpoint check + Properties properties = new Properties(); + properties.put("com.sun.jndi.ldap.object.disableEndpointIdentification", "true"); + System.setProperties(properties); + + return env; + } + + // BAD - Test configuration with disabled LDAPS endpoint check using the `TRUE` boolean field. + public Hashtable createConnectionEnv5() { + Hashtable env = new Hashtable(); + env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); + env.put(Context.PROVIDER_URL, "ldaps://ad.your-server.com:636"); + + env.put(Context.SECURITY_AUTHENTICATION, "simple"); + env.put(Context.SECURITY_PRINCIPAL, "username"); + env.put(Context.SECURITY_CREDENTIALS, "secpassword"); + + // Disable SSL endpoint check + System.setProperty(PROP_DISABLE_LDAP_ENDPOINT_IDENTIFICATION, Boolean.TRUE.toString()); + + return env; + } + + // BAD - Test configuration with disabled LDAPS endpoint check using a boolean value. + public Hashtable createConnectionEnv6() { + Hashtable env = new Hashtable(); + env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); + env.put(Context.PROVIDER_URL, "ldaps://ad.your-server.com:636"); + + env.put(Context.SECURITY_AUTHENTICATION, "simple"); + env.put(Context.SECURITY_PRINCIPAL, "username"); + env.put(Context.SECURITY_CREDENTIALS, "secpassword"); + + // Disable SSL endpoint check + Properties properties = new Properties(); + properties.put("com.sun.jndi.ldap.object.disableEndpointIdentification", true); + System.setProperties(properties); + + return env; + } } From e698ee77f7aa1ceb2034100429003ba0211681c6 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Tue, 16 Feb 2021 14:11:39 +0000 Subject: [PATCH 052/725] Update qldoc and test method --- .../Security/CWE/CWE-297/InsecureLdapEndpoint.qhelp | 4 ++-- .../Security/CWE/CWE-297/InsecureLdapEndpoint.ql | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.qhelp b/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.qhelp index 671f713ca0d..cb43f52515b 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.qhelp +++ b/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.qhelp @@ -5,8 +5,8 @@

    Java versions 8u181 or greater have enabled LDAPS endpoint identification by default. Nowadays infrastructure services like LDAP are commonly deployed behind load balancers therefore the LDAP server name can be different from the FQDN of the LDAPS endpoint. If a service certificate does not properly contain a matching DNS name as part of the certificate, Java will reject it by default.

    -

    Instead of addressing the issue properly by having a compliant certificate deployed, frequently developers simply disable LDAPS endpoint check.

    -

    Failing to validate the certificate makes the SSL session susceptible to a man-in-the-middle attack. This query checks whether LDAPS endpoint check is disabled in system properties.

    +

    Instead of addressing the issue properly by having a compliant certificate deployed, frequently developers simply disable the LDAPS endpoint check.

    +

    Failing to validate the certificate makes the SSL session susceptible to a man-in-the-middle attack. This query checks whether the LDAPS endpoint check is disabled in system properties.

    diff --git a/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.ql b/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.ql index 144f92875e7..c83aeb4a6a5 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.ql @@ -32,7 +32,7 @@ class SetPropertyMethod extends Method { } } -/** The method to set system properties. */ +/** The `setProperties` method declared in `java.lang.System`. */ class SetSystemPropertiesMethod extends Method { SetSystemPropertiesMethod() { this.hasName("setProperties") and @@ -40,7 +40,7 @@ class SetSystemPropertiesMethod extends Method { } } -/** Holds if an expression is evaluated to the string literal `com.sun.jndi.ldap.object.disableEndpointIdentification`. */ +/** Holds if `expr` is evaluated to the string literal `com.sun.jndi.ldap.object.disableEndpointIdentification`. */ predicate isPropertyDisableLdapEndpointId(Expr expr) { expr.(CompileTimeConstantExpr).getStringValue() = "com.sun.jndi.ldap.object.disableEndpointIdentification" @@ -72,7 +72,8 @@ predicate isBooleanTrue(Expr expr) { /** Holds if `ma` is in a test class or method. */ predicate isTestMethod(MethodAccess ma) { - ma.getMethod() instanceof TestMethod or + ma.getEnclosingCallable() instanceof TestMethod or + ma.getEnclosingCallable().getDeclaringType() instanceof TestClass or ma.getEnclosingCallable().getDeclaringType().getPackage().getName().matches("%test%") or ma.getEnclosingCallable().getDeclaringType().getName().toLowerCase().matches("%test%") } From 520ba472934962033fd1b11f222ca0c0cfc7e145 Mon Sep 17 00:00:00 2001 From: Francis Alexander Date: Wed, 17 Feb 2021 08:35:50 +0530 Subject: [PATCH 053/725] Sanitizer improvements from code review --- .../Security/CWE/CWE-346/UnvalidatedCors.ql | 36 ++++++++++++------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql b/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql index 17cf94d2c1e..31de9821a96 100644 --- a/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql +++ b/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql @@ -30,9 +30,14 @@ private predicate setsAllowCredentials(MethodAccess header) { class CorsProbableCheckAccess extends MethodAccess { CorsProbableCheckAccess() { - getMethod().getName() = ["contains", "equals"] and - getMethod().getDeclaringType().getQualifiedName() = - ["java.util.List", "java.util.ArrayList", "java.lang.String"] + getMethod().hasName("contains") and + getMethod() + .getDeclaringType() + .getASourceSupertype*() + .hasQualifiedName("java.util", "Collection") + or + getMethod().hasName("equals") and + getQualifier().getType() instanceof TypeString } } @@ -58,18 +63,23 @@ class CorsOriginConfig extends TaintTracking::Configuration { ) } - /* - * This should ideally check, the origin being validated against a list/array-list. - * or function being used to validate the origin, which has a flow from its parameter to any of the CorsProbableCheckAccess functions + /** + * this sanitizer is oversimplistic: + * - it only considers local dataflows + * - it will consider any method calling `Collection.contains` or `String.equals` as a sanitizer + * no matter if that check is taken into account and its result reaches the + * return statement of the wrapper. */ - override predicate isSanitizer(DataFlow::Node node) { - node.asExpr() = any(CorsProbableCheckAccess ma).getAnArgument() - or - exists(MethodAccess ma, CorsProbableCheckAccess ca | - ma.getMethod().calls(ca.getMethod()) and - DataFlow::localExprFlow(ma.getMethod().getAParameter().getAnAccess(), ca.getAnArgument()) and - (node.asExpr() = ma.getAnArgument() or node.asExpr() = ma.getAnArgument().getAChildExpr()) + exists(CorsProbableCheckAccess check | + TaintTracking::localTaint(node, DataFlow::exprNode(check.getAnArgument())) + or + exists(MethodAccess wrapperAccess, Method wrapper, int i | + TaintTracking::localTaint(node, DataFlow::exprNode(wrapperAccess.getArgument(i))) and + wrapperAccess.getMethod() = wrapper and + TaintTracking::localTaint(DataFlow::parameterNode(wrapper.getParameter(i)), + DataFlow::exprNode(check.getAnArgument())) + ) ) } } From 58971f9f4e78789f546ce60fa7b5837d198cd288 Mon Sep 17 00:00:00 2001 From: Francis Alexander Date: Wed, 17 Feb 2021 16:01:27 +0530 Subject: [PATCH 054/725] Switch qualified name to available CollectionType --- java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql b/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql index 31de9821a96..2a7152b1cad 100644 --- a/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql +++ b/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql @@ -31,10 +31,7 @@ private predicate setsAllowCredentials(MethodAccess header) { class CorsProbableCheckAccess extends MethodAccess { CorsProbableCheckAccess() { getMethod().hasName("contains") and - getMethod() - .getDeclaringType() - .getASourceSupertype*() - .hasQualifiedName("java.util", "Collection") + getMethod().getDeclaringType().getASourceSupertype*() instanceof CollectionType or getMethod().hasName("equals") and getQualifier().getType() instanceof TypeString From 2baf2aa5c194e356dc563054a176c24d3ccb7311 Mon Sep 17 00:00:00 2001 From: Francis Alexander Date: Wed, 17 Feb 2021 18:58:32 +0530 Subject: [PATCH 055/725] Apply suggestions from code review - improved sanitizer checks. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Alvaro Muñoz --- java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql | 3 +++ 1 file changed, 3 insertions(+) diff --git a/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql b/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql index 2a7152b1cad..9f9c12b2295 100644 --- a/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql +++ b/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql @@ -33,6 +33,9 @@ class CorsProbableCheckAccess extends MethodAccess { getMethod().hasName("contains") and getMethod().getDeclaringType().getASourceSupertype*() instanceof CollectionType or + getMethod().hasName("containsKey") and + getMethod().getDeclaringType().getASourceSupertype*() instanceof MapType + or getMethod().hasName("equals") and getQualifier().getType() instanceof TypeString } From 8119fd2ad1e2d009991f9a12969ccd55054163c4 Mon Sep 17 00:00:00 2001 From: haby0 Date: Thu, 18 Feb 2021 18:11:10 +0800 Subject: [PATCH 056/725] *)add JsonHijacking ql query --- .../Security/CWE/CWE-352/JsonHijacking.java | 119 ++++++++++++++++++ .../Security/CWE/CWE-352/JsonHijacking.qhelp | 35 ++++++ .../src/Security/CWE/CWE-352/JsonHijacking.ql | 32 +++++ .../Security/CWE/CWE-352/JsonHijackingLib.qll | 92 ++++++++++++++ .../Security/CWE/CWE-352/JsonStringLib.qll | 42 +++++++ .../security/CWE-352/JsonHijacking.expected | 48 +++++++ .../security/CWE-352/JsonHijacking.java | 119 ++++++++++++++++++ .../security/CWE-352/JsonHijacking.qlref | 1 + .../query-tests/security/CWE-352/options | 1 + .../com/alibaba/fastjson/JSON.java | 4 + .../stereotype/Controller.java | 14 +++ .../core/annotation/AliasFor.class | Bin 0 -> 385 bytes .../core/annotation/AliasFor.java | 10 ++ .../web/bind/annotation/GetMapping.class | Bin 0 -> 504 bytes .../web/bind/annotation/GetMapping.java | 19 +++ .../web/bind/annotation/RequestMapping.java | 13 ++ .../web/bind/annotation/ResponseBody.class | Bin 0 -> 184 bytes .../web/bind/annotation/ResponseBody.java | 4 + 18 files changed, 553 insertions(+) create mode 100644 java/ql/src/Security/CWE/CWE-352/JsonHijacking.java create mode 100644 java/ql/src/Security/CWE/CWE-352/JsonHijacking.qhelp create mode 100644 java/ql/src/Security/CWE/CWE-352/JsonHijacking.ql create mode 100644 java/ql/src/Security/CWE/CWE-352/JsonHijackingLib.qll create mode 100644 java/ql/src/Security/CWE/CWE-352/JsonStringLib.qll create mode 100644 java/ql/test/experimental/query-tests/security/CWE-352/JsonHijacking.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-352/JsonHijacking.java create mode 100644 java/ql/test/experimental/query-tests/security/CWE-352/JsonHijacking.qlref create mode 100644 java/ql/test/experimental/query-tests/security/CWE-352/options create mode 100644 java/ql/test/stubs/spring-context-5.3.2/org/springframework/stereotype/Controller.java create mode 100644 java/ql/test/stubs/spring-core-5.3.2/org/springframework/core/annotation/AliasFor.class create mode 100644 java/ql/test/stubs/spring-core-5.3.2/org/springframework/core/annotation/AliasFor.java create mode 100644 java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/bind/annotation/GetMapping.class create mode 100644 java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/bind/annotation/GetMapping.java create mode 100644 java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/bind/annotation/RequestMapping.java create mode 100644 java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/bind/annotation/ResponseBody.class create mode 100644 java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/bind/annotation/ResponseBody.java diff --git a/java/ql/src/Security/CWE/CWE-352/JsonHijacking.java b/java/ql/src/Security/CWE/CWE-352/JsonHijacking.java new file mode 100644 index 00000000000..d08d436fa07 --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-352/JsonHijacking.java @@ -0,0 +1,119 @@ +import com.alibaba.fastjson.JSONObject; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.Random; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +@Controller +public class JsonHijacking { + + private static HashMap hashMap = new HashMap(); + + static { + hashMap.put("username","admin"); + hashMap.put("password","123456"); + } + + + @GetMapping(value = "jsonp1") + @ResponseBody + public String bad1(HttpServletRequest request) { + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + + Gson gson = new Gson(); + String result = gson.toJson(hashMap); + resultStr = jsonpCallback + "(" + result + ")"; + return resultStr; + } + + @GetMapping(value = "jsonp2") + @ResponseBody + public String bad2(HttpServletRequest request) { + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + + resultStr = jsonpCallback + "(" + JSONObject.toJSONString(hashMap) + ")"; + + return resultStr; + } + + @GetMapping(value = "jsonp3") + @ResponseBody + public String bad3(HttpServletRequest request) { + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + String jsonStr = getJsonStr(hashMap); + resultStr = jsonpCallback + "(" + jsonStr + ")"; + return resultStr; + } + + @GetMapping(value = "jsonp4") + @ResponseBody + public String bad4(HttpServletRequest request) { + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + String restr = JSONObject.toJSONString(hashMap); + resultStr = jsonpCallback + "(" + restr + ");"; + return resultStr; + } + + @GetMapping(value = "jsonp5") + @ResponseBody + public void bad5(HttpServletRequest request, + HttpServletResponse response) throws Exception { + response.setContentType("application/json"); + String jsonpCallback = request.getParameter("jsonpCallback"); + PrintWriter pw = null; + Gson gson = new Gson(); + String result = gson.toJson(hashMap); + + String resultStr = null; + pw = response.getWriter(); + resultStr = jsonpCallback + "(" + result + ")"; + pw.println(resultStr); + } + + @GetMapping(value = "jsonp6") + @ResponseBody + public void bad6(HttpServletRequest request, + HttpServletResponse response) throws Exception { + response.setContentType("application/json"); + String jsonpCallback = request.getParameter("jsonpCallback"); + PrintWriter pw = null; + ObjectMapper mapper = new ObjectMapper(); + String result = mapper.writeValueAsString(hashMap); + String resultStr = null; + pw = response.getWriter(); + resultStr = jsonpCallback + "(" + result + ")"; + pw.println(resultStr); + } + + @GetMapping(value = "jsonp7") + @ResponseBody + public String good(HttpServletRequest request) { + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + + String val = ""; + Random random = new Random(); + for (int i = 0; i < 10; i++) { + val += String.valueOf(random.nextInt(10)); + } + // good + jsonpCallback = jsonpCallback + "_" + val; + String jsonStr = getJsonStr(hashMap); + resultStr = jsonpCallback + "(" + jsonStr + ")"; + return resultStr; + } + + public static String getJsonStr(Object result) { + return JSONObject.toJSONString(result); + } +} \ No newline at end of file diff --git a/java/ql/src/Security/CWE/CWE-352/JsonHijacking.qhelp b/java/ql/src/Security/CWE/CWE-352/JsonHijacking.qhelp new file mode 100644 index 00000000000..38e1845f992 --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-352/JsonHijacking.qhelp @@ -0,0 +1,35 @@ + + + +

    The software uses external input as the function name to wrap JSON data and return it to the client as a request response. When there is a cross-domain problem, +there is a problem of sensitive information leakage.

    + +
    + + +

    The function name verification processing for external input can effectively prevent the leakage of sensitive information.

    + +
    + + +

    The following example shows the case of no verification processing and verification processing for the external input function name.

    + + + +
    + + +
  • +OWASPLondon20161124_JSON_Hijacking_Gareth_Heyes: +JSON hijacking. +
  • +
  • +Practical JSONP Injection: + + Completely controllable from the URL (GET variable) +. +
  • +
    +
    diff --git a/java/ql/src/Security/CWE/CWE-352/JsonHijacking.ql b/java/ql/src/Security/CWE/CWE-352/JsonHijacking.ql new file mode 100644 index 00000000000..a6a6d2475f0 --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-352/JsonHijacking.ql @@ -0,0 +1,32 @@ +/** + * @name JSON Hijacking + * @description User-controlled callback function names that are not verified are vulnerable + * to json hijacking attacks. + * @kind path-problem + * @problem.severity error + * @precision high + * @id java/Json-hijacking + * @tags security + * external/cwe/cwe-352 + */ + +import java +import JsonHijackingLib +import semmle.code.java.dataflow.FlowSources +import DataFlow::PathGraph + +/** Taint-tracking configuration tracing flow from remote sources to output jsonp data. */ +class JsonHijackingConfig extends TaintTracking::Configuration { + JsonHijackingConfig() { this = "JsonHijackingConfig" } + + override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } + + override predicate isSink(DataFlow::Node sink) { sink instanceof JsonHijackingSink } +} + +from DataFlow::PathNode source, DataFlow::PathNode sink, JsonHijackingConfig conf +where + conf.hasFlowPath(source, sink) and + exists(JsonHijackingFlowConfig jhfc | jhfc.hasFlowTo(sink.getNode())) +select sink.getNode(), source, sink, "Json Hijacking query might include code from $@.", + source.getNode(), "this user input" diff --git a/java/ql/src/Security/CWE/CWE-352/JsonHijackingLib.qll b/java/ql/src/Security/CWE/CWE-352/JsonHijackingLib.qll new file mode 100644 index 00000000000..ba91a6670bf --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-352/JsonHijackingLib.qll @@ -0,0 +1,92 @@ +import java +import DataFlow +import JsonStringLib +import semmle.code.java.dataflow.DataFlow +import semmle.code.java.dataflow.FlowSources +import semmle.code.java.frameworks.spring.SpringController + +/** A data flow sink for unvalidated user input that is used to jsonp. */ +abstract class JsonHijackingSink extends DataFlow::Node { } + +/** Use ```print```, ```println```, ```write``` to output result. */ +private class WriterPrintln extends JsonHijackingSink { + WriterPrintln() { + exists(MethodAccess ma | + ma.getMethod().getName().regexpMatch("print|println|write") and + ma.getMethod() + .getDeclaringType() + .getASourceSupertype*() + .hasQualifiedName("java.io", "PrintWriter") and + ma.getArgument(0) = this.asExpr() + ) + } +} + +/** Spring Request Method return result. */ +private class SpringReturn extends JsonHijackingSink { + SpringReturn() { + exists(ReturnStmt rs, Method m | m = rs.getEnclosingCallable() | + m instanceof SpringRequestMappingMethod and + rs.getResult() = this.asExpr() + ) + } +} + +/** A concatenate expression using `(` and `)` or `);`. */ +class JsonHijackingExpr extends AddExpr { + JsonHijackingExpr() { + getRightOperand().toString().regexpMatch("\"\\)\"|\"\\);\"") and + getLeftOperand() + .(AddExpr) + .getLeftOperand() + .(AddExpr) + .getRightOperand() + .toString() + .regexpMatch("\"\\(\"") + } + + /** Get the jsonp function name of this expression */ + Expr getFunctionName() { + result = getLeftOperand().(AddExpr).getLeftOperand().(AddExpr).getLeftOperand() + } + + /** Get the json data of this expression */ + Expr getJsonExpr() { result = getLeftOperand().(AddExpr).getRightOperand() } +} + +/** A data flow configuration tracing flow from remote sources to jsonp function name. */ +class RemoteFlowConfig extends DataFlow2::Configuration { + RemoteFlowConfig() { this = "RemoteFlowConfig" } + + override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource } + + override predicate isSink(DataFlow::Node sink) { + exists(JsonHijackingExpr jhe | jhe.getFunctionName() = sink.asExpr()) + } +} + +/** A data flow configuration tracing flow from json data to splicing jsonp data. */ +class JsonDataFlowConfig extends DataFlow2::Configuration { + JsonDataFlowConfig() { this = "JsonDataFlowConfig" } + + override predicate isSource(DataFlow::Node src) { src instanceof JsonpStringSource } + + override predicate isSink(DataFlow::Node sink) { + exists(JsonHijackingExpr jhe | jhe.getJsonExpr() = sink.asExpr()) + } +} + +/** Taint-tracking configuration tracing flow from user-controllable function name jsonp data to output jsonp data. */ +class JsonHijackingFlowConfig extends TaintTracking::Configuration { + JsonHijackingFlowConfig() { this = "JsonHijackingFlowConfig" } + + override predicate isSource(DataFlow::Node src) { + exists(JsonHijackingExpr jhe, JsonDataFlowConfig jdfc, RemoteFlowConfig rfc | + jhe = src.asExpr() and + jdfc.hasFlowTo(DataFlow::exprNode(jhe.getJsonExpr())) and + rfc.hasFlowTo(DataFlow::exprNode(jhe.getFunctionName())) + ) + } + + override predicate isSink(DataFlow::Node sink) { sink instanceof JsonHijackingSink } +} diff --git a/java/ql/src/Security/CWE/CWE-352/JsonStringLib.qll b/java/ql/src/Security/CWE/CWE-352/JsonStringLib.qll new file mode 100644 index 00000000000..0da8bc860d1 --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-352/JsonStringLib.qll @@ -0,0 +1,42 @@ +import java +import semmle.code.java.dataflow.DataFlow +import semmle.code.java.dataflow.FlowSources +import DataFlow::PathGraph + +/** Json string type data */ +abstract class JsonpStringSource extends DataFlow::Node { } + +/** Convert to String using Gson library. */ +private class GsonString extends JsonpStringSource { + GsonString() { + exists(MethodAccess ma, Method m | ma.getMethod() = m | + m.hasName("toJson") and + m.getDeclaringType().getASupertype*().hasQualifiedName("com.google.gson", "Gson") and + this.asExpr() = ma + ) + } +} + +/** Convert to String using Fastjson library. */ +private class FastjsonString extends JsonpStringSource { + FastjsonString() { + exists(MethodAccess ma, Method m | ma.getMethod() = m | + m.hasName("toJSONString") and + m.getDeclaringType().getASupertype*().hasQualifiedName("com.alibaba.fastjson", "JSON") and + this.asExpr() = ma + ) + } +} + +/** Convert to String using Jackson library. */ +private class JacksonString extends JsonpStringSource { + JacksonString() { + exists(MethodAccess ma, Method m | ma.getMethod() = m | + m.hasName("writeValueAsString") and + m.getDeclaringType() + .getASupertype*() + .hasQualifiedName("com.fasterxml.jackson.databind", "ObjectMapper") and + this.asExpr() = ma + ) + } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonHijacking.expected b/java/ql/test/experimental/query-tests/security/CWE-352/JsonHijacking.expected new file mode 100644 index 00000000000..8efc3be1673 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-352/JsonHijacking.expected @@ -0,0 +1,48 @@ +edges +| JsonHijacking.java:28:32:28:68 | getParameter(...) : String | JsonHijacking.java:33:16:33:24 | resultStr | +| JsonHijacking.java:32:21:32:54 | ... + ... : String | JsonHijacking.java:33:16:33:24 | resultStr | +| JsonHijacking.java:40:32:40:68 | getParameter(...) : String | JsonHijacking.java:44:16:44:24 | resultStr | +| JsonHijacking.java:42:21:42:80 | ... + ... : String | JsonHijacking.java:44:16:44:24 | resultStr | +| JsonHijacking.java:51:32:51:68 | getParameter(...) : String | JsonHijacking.java:54:16:54:24 | resultStr | +| JsonHijacking.java:53:21:53:55 | ... + ... : String | JsonHijacking.java:54:16:54:24 | resultStr | +| JsonHijacking.java:61:32:61:68 | getParameter(...) : String | JsonHijacking.java:64:16:64:24 | resultStr | +| JsonHijacking.java:63:21:63:54 | ... + ... : String | JsonHijacking.java:64:16:64:24 | resultStr | +| JsonHijacking.java:72:32:72:68 | getParameter(...) : String | JsonHijacking.java:80:20:80:28 | resultStr | +| JsonHijacking.java:79:21:79:54 | ... + ... : String | JsonHijacking.java:80:20:80:28 | resultStr | +| JsonHijacking.java:88:32:88:68 | getParameter(...) : String | JsonHijacking.java:95:20:95:28 | resultStr | +| JsonHijacking.java:94:21:94:54 | ... + ... : String | JsonHijacking.java:95:20:95:28 | resultStr | +| JsonHijacking.java:102:32:102:68 | getParameter(...) : String | JsonHijacking.java:113:16:113:24 | resultStr | +nodes +| JsonHijacking.java:28:32:28:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonHijacking.java:32:21:32:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonHijacking.java:33:16:33:24 | resultStr | semmle.label | resultStr | +| JsonHijacking.java:33:16:33:24 | resultStr | semmle.label | resultStr | +| JsonHijacking.java:40:32:40:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonHijacking.java:42:21:42:80 | ... + ... : String | semmle.label | ... + ... : String | +| JsonHijacking.java:44:16:44:24 | resultStr | semmle.label | resultStr | +| JsonHijacking.java:44:16:44:24 | resultStr | semmle.label | resultStr | +| JsonHijacking.java:51:32:51:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonHijacking.java:53:21:53:55 | ... + ... : String | semmle.label | ... + ... : String | +| JsonHijacking.java:54:16:54:24 | resultStr | semmle.label | resultStr | +| JsonHijacking.java:54:16:54:24 | resultStr | semmle.label | resultStr | +| JsonHijacking.java:61:32:61:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonHijacking.java:63:21:63:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonHijacking.java:64:16:64:24 | resultStr | semmle.label | resultStr | +| JsonHijacking.java:64:16:64:24 | resultStr | semmle.label | resultStr | +| JsonHijacking.java:72:32:72:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonHijacking.java:79:21:79:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonHijacking.java:80:20:80:28 | resultStr | semmle.label | resultStr | +| JsonHijacking.java:80:20:80:28 | resultStr | semmle.label | resultStr | +| JsonHijacking.java:88:32:88:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonHijacking.java:94:21:94:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonHijacking.java:95:20:95:28 | resultStr | semmle.label | resultStr | +| JsonHijacking.java:95:20:95:28 | resultStr | semmle.label | resultStr | +| JsonHijacking.java:102:32:102:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonHijacking.java:113:16:113:24 | resultStr | semmle.label | resultStr | +#select +| JsonHijacking.java:33:16:33:24 | resultStr | JsonHijacking.java:28:32:28:68 | getParameter(...) : String | JsonHijacking.java:33:16:33:24 | resultStr | Json Hijacking query might include code from $@. | JsonHijacking.java:28:32:28:68 | getParameter(...) | this user input | +| JsonHijacking.java:44:16:44:24 | resultStr | JsonHijacking.java:40:32:40:68 | getParameter(...) : String | JsonHijacking.java:44:16:44:24 | resultStr | Json Hijacking query might include code from $@. | JsonHijacking.java:40:32:40:68 | getParameter(...) | this user input | +| JsonHijacking.java:54:16:54:24 | resultStr | JsonHijacking.java:51:32:51:68 | getParameter(...) : String | JsonHijacking.java:54:16:54:24 | resultStr | Json Hijacking query might include code from $@. | JsonHijacking.java:51:32:51:68 | getParameter(...) | this user input | +| JsonHijacking.java:64:16:64:24 | resultStr | JsonHijacking.java:61:32:61:68 | getParameter(...) : String | JsonHijacking.java:64:16:64:24 | resultStr | Json Hijacking query might include code from $@. | JsonHijacking.java:61:32:61:68 | getParameter(...) | this user input | +| JsonHijacking.java:80:20:80:28 | resultStr | JsonHijacking.java:72:32:72:68 | getParameter(...) : String | JsonHijacking.java:80:20:80:28 | resultStr | Json Hijacking query might include code from $@. | JsonHijacking.java:72:32:72:68 | getParameter(...) | this user input | +| JsonHijacking.java:95:20:95:28 | resultStr | JsonHijacking.java:88:32:88:68 | getParameter(...) : String | JsonHijacking.java:95:20:95:28 | resultStr | Json Hijacking query might include code from $@. | JsonHijacking.java:88:32:88:68 | getParameter(...) | this user input | diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonHijacking.java b/java/ql/test/experimental/query-tests/security/CWE-352/JsonHijacking.java new file mode 100644 index 00000000000..9b473e0610c --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-352/JsonHijacking.java @@ -0,0 +1,119 @@ +import com.alibaba.fastjson.JSONObject; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.Random; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +@Controller +public class JsonHijacking { + + private static HashMap hashMap = new HashMap(); + + static { + hashMap.put("username","admin"); + hashMap.put("password","123456"); + } + + + @GetMapping(value = "jsonp1") + @ResponseBody + public String bad1(HttpServletRequest request) { + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + + Gson gson = new Gson(); + String result = gson.toJson(hashMap); + resultStr = jsonpCallback + "(" + result + ")"; + return resultStr; + } + + @GetMapping(value = "jsonp2") + @ResponseBody + public String bad2(HttpServletRequest request) { + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + + resultStr = jsonpCallback + "(" + JSONObject.toJSONString(hashMap) + ")"; + + return resultStr; + } + + @GetMapping(value = "jsonp3") + @ResponseBody + public String bad3(HttpServletRequest request) { + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + String jsonStr = getJsonStr(hashMap); + resultStr = jsonpCallback + "(" + jsonStr + ")"; + return resultStr; + } + + @GetMapping(value = "jsonp4") + @ResponseBody + public String bad4(HttpServletRequest request) { + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + String restr = JSONObject.toJSONString(hashMap); + resultStr = jsonpCallback + "(" + restr + ");"; + return resultStr; + } + + @GetMapping(value = "jsonp5") + @ResponseBody + public void bad5(HttpServletRequest request, + HttpServletResponse response) throws Exception { + response.setContentType("application/json"); + String jsonpCallback = request.getParameter("jsonpCallback"); + PrintWriter pw = null; + Gson gson = new Gson(); + String result = gson.toJson(hashMap); + + String resultStr = null; + pw = response.getWriter(); + resultStr = jsonpCallback + "(" + result + ")"; + pw.println(resultStr); + } + + @GetMapping(value = "jsonp6") + @ResponseBody + public void bad6(HttpServletRequest request, + HttpServletResponse response) throws Exception { + response.setContentType("application/json"); + String jsonpCallback = request.getParameter("jsonpCallback"); + PrintWriter pw = null; + ObjectMapper mapper = new ObjectMapper(); + String result = mapper.writeValueAsString(hashMap); + String resultStr = null; + pw = response.getWriter(); + resultStr = jsonpCallback + "(" + result + ")"; + pw.println(resultStr); + } + + @GetMapping(value = "jsonp7") + @ResponseBody + public String good(HttpServletRequest request) { + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + + String val = ""; + Random random = new Random(); + for (int i = 0; i < 10; i++) { + val += String.valueOf(random.nextInt(10)); + } + // good + jsonpCallback = jsonpCallback + "_" + val; + String jsonStr = getJsonStr(hashMap); + resultStr = jsonpCallback + "(" + jsonStr + ")"; + return resultStr; + } + + public static String getJsonStr(Object result) { + return JSONObject.toJSONString(result); + } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonHijacking.qlref b/java/ql/test/experimental/query-tests/security/CWE-352/JsonHijacking.qlref new file mode 100644 index 00000000000..e79471b3c1e --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-352/JsonHijacking.qlref @@ -0,0 +1 @@ +Security/CWE/CWE-352/JsonHijacking.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/options b/java/ql/test/experimental/query-tests/security/CWE-352/options new file mode 100644 index 00000000000..3676b8e38b6 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-352/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/apache-http-4.4.13/:${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/fastjson-1.2.74/:${testdir}/../../../../stubs/gson-2.8.6/:${testdir}/../../../../stubs/jackson-databind-2.10/:${testdir}/../../../../stubs/springframework-5.2.3/:${testdir}/../../../../stubs/spring-context-5.3.2/:${testdir}/../../../../stubs/spring-web-5.3.2/:${testdir}/../../../../stubs/spring-core-5.3.2/ diff --git a/java/ql/test/stubs/fastjson-1.2.74/com/alibaba/fastjson/JSON.java b/java/ql/test/stubs/fastjson-1.2.74/com/alibaba/fastjson/JSON.java index b71e890e9b7..99e2873d375 100644 --- a/java/ql/test/stubs/fastjson-1.2.74/com/alibaba/fastjson/JSON.java +++ b/java/ql/test/stubs/fastjson-1.2.74/com/alibaba/fastjson/JSON.java @@ -26,6 +26,10 @@ import com.alibaba.fastjson.parser.*; import com.alibaba.fastjson.parser.deserializer.ParseProcess; public abstract class JSON { + public static String toJSONString(Object object) { + return null; + } + public static Object parse(String text) { return null; } diff --git a/java/ql/test/stubs/spring-context-5.3.2/org/springframework/stereotype/Controller.java b/java/ql/test/stubs/spring-context-5.3.2/org/springframework/stereotype/Controller.java new file mode 100644 index 00000000000..9b1751fa2ae --- /dev/null +++ b/java/ql/test/stubs/spring-context-5.3.2/org/springframework/stereotype/Controller.java @@ -0,0 +1,14 @@ +package org.springframework.stereotype; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface Controller { + String value() default ""; +} diff --git a/java/ql/test/stubs/spring-core-5.3.2/org/springframework/core/annotation/AliasFor.class b/java/ql/test/stubs/spring-core-5.3.2/org/springframework/core/annotation/AliasFor.class new file mode 100644 index 0000000000000000000000000000000000000000..438065489278b92503abc2ad8d75716c5e56ac08 GIT binary patch literal 385 zcmb7=!Ab)$5QhJ0x31kDdrH&Kx0=)qG#3PM4!PcXZrOKO@(l3m};gAd?CiL-}x zJqaEL=Fj~6^G&|KKRyB6W0qr@<21(^Vbrp1G~wdrcD3b}m1S3}bqdDS4}|lDb3So0 z-aYCKH#QMKxO{0`GCTd`S`$rab#IG=`O1e{#kVeF6L_cJeRx%s4_fgdPA#nAxb#7` zj5*1|vPl9`tbG$Iy);(DbZ?q>Y=pc21QTZcMbG6{R|0?4KmBGoU|o}(H;@|2R}C^k ghLPwaQNxHF$I?t>JeJBL3UL&FIx;a%x-6Xh0OC_*bpQYW literal 0 HcmV?d00001 diff --git a/java/ql/test/stubs/spring-core-5.3.2/org/springframework/core/annotation/AliasFor.java b/java/ql/test/stubs/spring-core-5.3.2/org/springframework/core/annotation/AliasFor.java new file mode 100644 index 00000000000..3a823fade5b --- /dev/null +++ b/java/ql/test/stubs/spring-core-5.3.2/org/springframework/core/annotation/AliasFor.java @@ -0,0 +1,10 @@ +package org.springframework.core.annotation; + +public @interface AliasFor { + @AliasFor("attribute") + String value() default ""; + + @AliasFor("value") + String attribute() default ""; + +} diff --git a/java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/bind/annotation/GetMapping.class b/java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/bind/annotation/GetMapping.class new file mode 100644 index 0000000000000000000000000000000000000000..5392ca0ebc1593d6bfa2f7d765ee4ca169fb260f GIT binary patch literal 504 zcma)&y-ve06orr5G%4k$Ewlp@8)_FUu~3N#3Bgi?)JiO!oYW02i5(KVeK!UkfQLfd z3?&dTFj%_xlg>TI=i~G39l#Za0geNl1Q;-QTBMR;Fd9$SVk3AWbj;^AS316C=-+5< ztgy=HTe%W0u?%2nZA9WoH5`o>f62T|*k=Ym6S+tWhIV9h;Zj+SS#FjtD#y;;xIB_~ zDxp)|dubm;mXYs88HC|<=CoC*d{Tu96Imr8>11m1m={?Yb44Ckk!ycGS!yuAF9#FEVXJbh%nj0^%G u-TFC+dFlH8Nm;4MC5#O62q7eGj&Kvy7#SEDn1GlW=t>44%>pEu7+3+XjWw+R literal 0 HcmV?d00001 diff --git a/java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/bind/annotation/ResponseBody.java b/java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/bind/annotation/ResponseBody.java new file mode 100644 index 00000000000..b2134009968 --- /dev/null +++ b/java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/bind/annotation/ResponseBody.java @@ -0,0 +1,4 @@ +package org.springframework.web.bind.annotation; + +public @interface ResponseBody { +} From 45bdb22db840589f232f46c31717b96c91053ee9 Mon Sep 17 00:00:00 2001 From: Francis Alexander Date: Sun, 21 Feb 2021 16:45:48 +0530 Subject: [PATCH 057/725] Switch from sanitizer to tainttracking, formatting and qldoc changes --- .../Security/CWE/CWE-346/UnvalidatedCors.java | 9 +++ .../CWE/CWE-346/UnvalidatedCors.qhelp | 12 ++-- .../Security/CWE/CWE-346/UnvalidatedCors.ql | 64 +++++++++---------- .../security/CWE-346/UnvalidatedCors.expected | 2 +- 4 files changed, 46 insertions(+), 41 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.java b/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.java index 772a64969ea..fd562d44f30 100644 --- a/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.java +++ b/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.java @@ -29,6 +29,15 @@ public class CorsFilter implements Filter { } } + if (!StringUtils.isEmpty(url)) { + List checkorigins = Arrays.asList("www.example.com", "www.sub.example.com"); + + if (checkorigins.contains(url)) { // GOOD -> Origin is validated here. + response.addHeader("Access-Control-Allow-Origin", url); + response.addHeader("Access-Control-Allow-Credentials", "true"); + } + } + chain.doFilter(req, res); } diff --git a/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.qhelp b/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.qhelp index d01c27c23ca..da98e896a60 100644 --- a/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.qhelp +++ b/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.qhelp @@ -16,9 +16,9 @@ When the Access-Control-Allow-Credentials header is true, the Access-Control-Allow-Origin - header must have a value different from * in order to - make browsers accept the header. Therefore, to allow multiple origins - for Cross-Origin requests with credentials, the server must + header must have a value different from * in order + for browsers to accept the header. Therefore, to allow multiple origins + for cross-origin requests with credentials, the server must dynamically compute the value of the Access-Control-Allow-Origin header. Computing this header value from information in the request to the server can @@ -47,8 +47,8 @@ attacker, it is never safe to use null as the value of the Access-Control-Allow-Origin header when the Access-Control-Allow-Credentials header value is - true.This can be done using a sandboxed iframe. A more detailed - explanation is available in the portswigger blogpost referenced below. + true.A null origin can be set by an attacker using a sandboxed iframe. + A more detailed explanation is available in the portswigger blogpost referenced below.

    @@ -57,7 +57,7 @@

    In the example below, the server allows the browser to send - user credentials in a Cross-Origin request. The request header + user credentials in a cross-origin request. The request header origins controls the allowed origins for such a Cross-Origin request. diff --git a/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql b/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql index 9f9c12b2295..0cd99aea68a 100644 --- a/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql +++ b/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql @@ -1,6 +1,6 @@ /** - * @name Cors header being set from remote source - * @description Cors header is being set from remote source, allowing to control the origin. + * @name CORS is derived from untrusted input + * @description CORS header is derived from untrusted input, allowing a remote user to control which origins are trusted. * @kind path-problem * @problem.severity error * @precision high @@ -13,6 +13,7 @@ import java import semmle.code.java.dataflow.FlowSources import semmle.code.java.frameworks.Servlets import semmle.code.java.dataflow.TaintTracking +import semmle.code.java.dataflow.TaintTracking2 import DataFlow::PathGraph /** @@ -25,10 +26,10 @@ private predicate setsAllowCredentials(MethodAccess header) { ) and header.getArgument(0).(CompileTimeConstantExpr).getStringValue().toLowerCase() = "access-control-allow-credentials" and - header.getArgument(1).(CompileTimeConstantExpr).getStringValue() = "true" + header.getArgument(1).(CompileTimeConstantExpr).getStringValue().toLowerCase() = "true" } -class CorsProbableCheckAccess extends MethodAccess { +private class CorsProbableCheckAccess extends MethodAccess { CorsProbableCheckAccess() { getMethod().hasName("contains") and getMethod().getDeclaringType().getASourceSupertype*() instanceof CollectionType @@ -45,46 +46,41 @@ private Expr getAccessControlAllowOriginHeaderName() { result.(CompileTimeConstantExpr).getStringValue().toLowerCase() = "access-control-allow-origin" } +/** + * This taintflow2 configuration checks if there is a flow from source node towards CorsProbableCheckAccess methods. + */ +class CorsSourceReachesCheckConfig extends TaintTracking2::Configuration { + CorsSourceReachesCheckConfig() { this = "CorsOriginConfig" } + + override predicate isSource(DataFlow::Node source) { any(CorsOriginConfig c).hasFlow(source, _) } + + override predicate isSink(DataFlow::Node sink) { + sink.asExpr() = any(CorsProbableCheckAccess check).getAnArgument() + } +} + class CorsOriginConfig extends TaintTracking::Configuration { CorsOriginConfig() { this = "CorsOriginConfig" } override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } override predicate isSink(DataFlow::Node sink) { - exists(MethodAccess corsheader, MethodAccess allowcredentialsheader | + exists(MethodAccess corsHeader, MethodAccess allowCredentialsHeader | ( - corsheader.getMethod() instanceof ResponseSetHeaderMethod or - corsheader.getMethod() instanceof ResponseAddHeaderMethod + corsHeader.getMethod() instanceof ResponseSetHeaderMethod or + corsHeader.getMethod() instanceof ResponseAddHeaderMethod ) and - getAccessControlAllowOriginHeaderName() = corsheader.getArgument(0) and - setsAllowCredentials(allowcredentialsheader) and - corsheader.getEnclosingCallable() = allowcredentialsheader.getEnclosingCallable() and - sink.asExpr() = corsheader.getArgument(1) - ) - } - - /** - * this sanitizer is oversimplistic: - * - it only considers local dataflows - * - it will consider any method calling `Collection.contains` or `String.equals` as a sanitizer - * no matter if that check is taken into account and its result reaches the - * return statement of the wrapper. - */ - override predicate isSanitizer(DataFlow::Node node) { - exists(CorsProbableCheckAccess check | - TaintTracking::localTaint(node, DataFlow::exprNode(check.getAnArgument())) - or - exists(MethodAccess wrapperAccess, Method wrapper, int i | - TaintTracking::localTaint(node, DataFlow::exprNode(wrapperAccess.getArgument(i))) and - wrapperAccess.getMethod() = wrapper and - TaintTracking::localTaint(DataFlow::parameterNode(wrapper.getParameter(i)), - DataFlow::exprNode(check.getAnArgument())) - ) + getAccessControlAllowOriginHeaderName() = corsHeader.getArgument(0) and + setsAllowCredentials(allowCredentialsHeader) and + corsHeader.getEnclosingCallable() = allowCredentialsHeader.getEnclosingCallable() and + sink.asExpr() = corsHeader.getArgument(1) ) } } -from DataFlow::PathNode source, DataFlow::PathNode sink, CorsOriginConfig conf -where conf.hasFlowPath(source, sink) -select sink.getNode(), source, sink, "Cors header is being set using user controlled value $@.", +from + DataFlow::PathNode source, DataFlow::PathNode sink, CorsOriginConfig conf, + CorsSourceReachesCheckConfig sanconf +where conf.hasFlowPath(source, sink) and not sanconf.hasFlow(source.getNode(), _) +select sink.getNode(), source, sink, "CORS header is being set using user controlled value $@.", source.getNode(), "user-provided value" diff --git a/java/ql/test/query-tests/security/CWE-346/UnvalidatedCors.expected b/java/ql/test/query-tests/security/CWE-346/UnvalidatedCors.expected index b7954950deb..d215f034fd2 100644 --- a/java/ql/test/query-tests/security/CWE-346/UnvalidatedCors.expected +++ b/java/ql/test/query-tests/security/CWE-346/UnvalidatedCors.expected @@ -4,4 +4,4 @@ nodes | UnvalidatedCors.java:21:22:21:48 | getHeader(...) : String | semmle.label | getHeader(...) : String | | UnvalidatedCors.java:27:67:27:69 | url | semmle.label | url | #select -| UnvalidatedCors.java:27:67:27:69 | url | UnvalidatedCors.java:21:22:21:48 | getHeader(...) : String | UnvalidatedCors.java:27:67:27:69 | url | Cors header is being set using user controlled value $@. | UnvalidatedCors.java:21:22:21:48 | getHeader(...) | user-provided value | +| UnvalidatedCors.java:27:67:27:69 | url | UnvalidatedCors.java:21:22:21:48 | getHeader(...) : String | UnvalidatedCors.java:27:67:27:69 | url | CORS header is being set using user controlled value $@. | UnvalidatedCors.java:21:22:21:48 | getHeader(...) | user-provided value | From 872a000a33e1b0d6fb2efeb926c7ed9e18725bd5 Mon Sep 17 00:00:00 2001 From: haby0 Date: Wed, 24 Feb 2021 20:36:12 +0800 Subject: [PATCH 058/725] *)update to JSONP injection --- .../Security/CWE/CWE-352/JsonpInjection.java | 170 +++++++++++++++++ .../Security/CWE/CWE-352/JsonpInjection.qhelp | 35 ++++ .../Security/CWE/CWE-352/JsonpInjection.ql | 55 ++++++ .../CWE/CWE-352/JsonpInjectionLib.qll | 92 ++++++++++ .../security/CWE-352/JsonpInjection.expected | 60 ++++++ .../security/CWE-352/JsonpInjection.java | 171 ++++++++++++++++++ .../security/CWE-352/JsonpInjection.qlref | 1 + 7 files changed, 584 insertions(+) create mode 100644 java/ql/src/Security/CWE/CWE-352/JsonpInjection.java create mode 100644 java/ql/src/Security/CWE/CWE-352/JsonpInjection.qhelp create mode 100644 java/ql/src/Security/CWE/CWE-352/JsonpInjection.ql create mode 100644 java/ql/src/Security/CWE/CWE-352/JsonpInjectionLib.qll create mode 100644 java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection.java create mode 100644 java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection.qlref diff --git a/java/ql/src/Security/CWE/CWE-352/JsonpInjection.java b/java/ql/src/Security/CWE/CWE-352/JsonpInjection.java new file mode 100644 index 00000000000..8b4e7cc005e --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-352/JsonpInjection.java @@ -0,0 +1,170 @@ +import com.alibaba.fastjson.JSONObject; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.Random; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +@Controller +public class JsonpInjection { +private static HashMap hashMap = new HashMap(); + + static { + hashMap.put("username","admin"); + hashMap.put("password","123456"); + } + + + @GetMapping(value = "jsonp1") + @ResponseBody + public String bad1(HttpServletRequest request) { + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + + Gson gson = new Gson(); + String result = gson.toJson(hashMap); + resultStr = jsonpCallback + "(" + result + ")"; + return resultStr; + } + + @GetMapping(value = "jsonp2") + @ResponseBody + public String bad2(HttpServletRequest request) { + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + + resultStr = jsonpCallback + "(" + JSONObject.toJSONString(hashMap) + ")"; + + return resultStr; + } + + @GetMapping(value = "jsonp3") + @ResponseBody + public String bad3(HttpServletRequest request) { + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + String jsonStr = getJsonStr(hashMap); + resultStr = jsonpCallback + "(" + jsonStr + ")"; + return resultStr; + } + + @GetMapping(value = "jsonp4") + @ResponseBody + public String bad4(HttpServletRequest request) { + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + String restr = JSONObject.toJSONString(hashMap); + resultStr = jsonpCallback + "(" + restr + ");"; + return resultStr; + } + + @GetMapping(value = "jsonp5") + @ResponseBody + public void bad5(HttpServletRequest request, + HttpServletResponse response) throws Exception { + response.setContentType("application/json"); + String jsonpCallback = request.getParameter("jsonpCallback"); + PrintWriter pw = null; + Gson gson = new Gson(); + String result = gson.toJson(hashMap); + + String resultStr = null; + pw = response.getWriter(); + resultStr = jsonpCallback + "(" + result + ")"; + pw.println(resultStr); + } + + @GetMapping(value = "jsonp6") + @ResponseBody + public void bad6(HttpServletRequest request, + HttpServletResponse response) throws Exception { + response.setContentType("application/json"); + String jsonpCallback = request.getParameter("jsonpCallback"); + PrintWriter pw = null; + ObjectMapper mapper = new ObjectMapper(); + String result = mapper.writeValueAsString(hashMap); + String resultStr = null; + pw = response.getWriter(); + resultStr = jsonpCallback + "(" + result + ")"; + pw.println(resultStr); + } + + @GetMapping(value = "jsonp7") + @ResponseBody + public String good(HttpServletRequest request) { + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + + String val = ""; + Random random = new Random(); + for (int i = 0; i < 10; i++) { + val += String.valueOf(random.nextInt(10)); + } + // good + jsonpCallback = jsonpCallback + "_" + val; + String jsonStr = getJsonStr(hashMap); + resultStr = jsonpCallback + "(" + jsonStr + ")"; + return resultStr; + } + + @GetMapping(value = "jsonp8") + @ResponseBody + public String good1(HttpServletRequest request) { + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + + String token = request.getParameter("token"); + + // good + if (verifToken(token)){ + System.out.println(token); + String jsonStr = getJsonStr(hashMap); + resultStr = jsonpCallback + "(" + jsonStr + ")"; + return resultStr; + } + + return "error"; + } + + @GetMapping(value = "jsonp9") + @ResponseBody + public String good2(HttpServletRequest request) { + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + + String referer = request.getHeader("Referer"); + + boolean result = verifReferer(referer); + // good + if (result){ + String jsonStr = getJsonStr(hashMap); + resultStr = jsonpCallback + "(" + jsonStr + ")"; + return resultStr; + } + + return "error"; + } + + public static String getJsonStr(Object result) { + return JSONObject.toJSONString(result); + } + + public static boolean verifToken(String token){ + if (token != "xxxx"){ + return false; + } + return true; + } + + public static boolean verifReferer(String referer){ + if (!referer.startsWith("http://test.com/")){ + return false; + } + return true; + } +} \ No newline at end of file diff --git a/java/ql/src/Security/CWE/CWE-352/JsonpInjection.qhelp b/java/ql/src/Security/CWE/CWE-352/JsonpInjection.qhelp new file mode 100644 index 00000000000..b063b409d3a --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-352/JsonpInjection.qhelp @@ -0,0 +1,35 @@ + + + +

    The software uses external input as the function name to wrap JSON data and return it to the client as a request response. When there is a cross-domain problem, +there is a problem of sensitive information leakage.

    + + + + +

    Adding `Referer` or random `token` verification processing can effectively prevent the leakage of sensitive information.

    + +
    + + +

    The following example shows the case of no verification processing and verification processing for the external input function name.

    + + + +
    + + +
  • +OWASPLondon20161124_JSON_Hijacking_Gareth_Heyes: +JSON hijacking. +
  • +
  • +Practical JSONP Injection: + + Completely controllable from the URL (GET variable) +. +
  • +
    +
    diff --git a/java/ql/src/Security/CWE/CWE-352/JsonpInjection.ql b/java/ql/src/Security/CWE/CWE-352/JsonpInjection.ql new file mode 100644 index 00000000000..e7ca2d41e34 --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-352/JsonpInjection.ql @@ -0,0 +1,55 @@ +/** + * @name JSON Hijacking + * @description User-controlled callback function names that are not verified are vulnerable + * to json hijacking attacks. + * @kind path-problem + * @problem.severity error + * @precision high + * @id java/Json-hijacking + * @tags security + * external/cwe/cwe-352 + */ + +import java +import JsonpInjectionLib +import semmle.code.java.dataflow.FlowSources +import semmle.code.java.deadcode.WebEntryPoints +import DataFlow::PathGraph + +class VerifAuth extends DataFlow::BarrierGuard { + VerifAuth() { + exists(MethodAccess ma, Node prod, Node succ | + this = ma and + ma.getMethod().getName().regexpMatch("(?i).*(token|auth|referer).*") and + prod instanceof RemoteFlowSource and + succ.asExpr() = ma.getAnArgument() and + ma.getMethod().getAParameter().getName().regexpMatch("(?i).*(token|auth|referer).*") and + localFlowStep*(prod, succ) + ) + } + + override predicate checks(Expr e, boolean branch) { + exists(ReturnStmt rs | + e = rs.getResult() and + branch = true + ) + } +} + +/** Taint-tracking configuration tracing flow from remote sources to output jsonp data. */ +class JsonpInjectionConfig extends TaintTracking::Configuration { + JsonpInjectionConfig() { this = "JsonpInjectionConfig" } + + override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } + + override predicate isSink(DataFlow::Node sink) { sink instanceof JsonpInjectionSink } + + override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { guard instanceof VerifAuth } +} + +from DataFlow::PathNode source, DataFlow::PathNode sink, JsonpInjectionConfig conf +where + conf.hasFlowPath(source, sink) and + exists(JsonpInjectionFlowConfig jhfc | jhfc.hasFlowTo(sink.getNode())) +select sink.getNode(), source, sink, "Json Hijacking query might include code from $@.", + source.getNode(), "this user input" \ No newline at end of file diff --git a/java/ql/src/Security/CWE/CWE-352/JsonpInjectionLib.qll b/java/ql/src/Security/CWE/CWE-352/JsonpInjectionLib.qll new file mode 100644 index 00000000000..4294a5e8c8f --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-352/JsonpInjectionLib.qll @@ -0,0 +1,92 @@ +import java +import DataFlow +import JsonStringLib +import semmle.code.java.dataflow.DataFlow +import semmle.code.java.dataflow.FlowSources +import semmle.code.java.frameworks.spring.SpringController + +/** A data flow sink for unvalidated user input that is used to jsonp. */ +abstract class JsonpInjectionSink extends DataFlow::Node { } + +/** Use ```print```, ```println```, ```write``` to output result. */ +private class WriterPrintln extends JsonpInjectionSink { + WriterPrintln() { + exists(MethodAccess ma | + ma.getMethod().getName().regexpMatch("print|println|write") and + ma.getMethod() + .getDeclaringType() + .getASourceSupertype*() + .hasQualifiedName("java.io", "PrintWriter") and + ma.getArgument(0) = this.asExpr() + ) + } +} + +/** Spring Request Method return result. */ +private class SpringReturn extends JsonpInjectionSink { + SpringReturn() { + exists(ReturnStmt rs, Method m | m = rs.getEnclosingCallable() | + m instanceof SpringRequestMappingMethod and + rs.getResult() = this.asExpr() + ) + } +} + +/** A concatenate expression using `(` and `)` or `);`. */ +class JsonpInjectionExpr extends AddExpr { + JsonpInjectionExpr() { + getRightOperand().toString().regexpMatch("\"\\)\"|\"\\);\"") and + getLeftOperand() + .(AddExpr) + .getLeftOperand() + .(AddExpr) + .getRightOperand() + .toString() + .regexpMatch("\"\\(\"") + } + + /** Get the jsonp function name of this expression */ + Expr getFunctionName() { + result = getLeftOperand().(AddExpr).getLeftOperand().(AddExpr).getLeftOperand() + } + + /** Get the json data of this expression */ + Expr getJsonExpr() { result = getLeftOperand().(AddExpr).getRightOperand() } +} + +/** A data flow configuration tracing flow from remote sources to jsonp function name. */ +class RemoteFlowConfig extends DataFlow2::Configuration { + RemoteFlowConfig() { this = "RemoteFlowConfig" } + + override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource } + + override predicate isSink(DataFlow::Node sink) { + exists(JsonpInjectionExpr jhe | jhe.getFunctionName() = sink.asExpr()) + } +} + +/** A data flow configuration tracing flow from json data to splicing jsonp data. */ +class JsonDataFlowConfig extends DataFlow2::Configuration { + JsonDataFlowConfig() { this = "JsonDataFlowConfig" } + + override predicate isSource(DataFlow::Node src) { src instanceof JsonpStringSource } + + override predicate isSink(DataFlow::Node sink) { + exists(JsonpInjectionExpr jhe | jhe.getJsonExpr() = sink.asExpr()) + } +} + +/** Taint-tracking configuration tracing flow from user-controllable function name jsonp data to output jsonp data. */ +class JsonpInjectionFlowConfig extends DataFlow::Configuration { + JsonpInjectionFlowConfig() { this = "JsonpInjectionFlowConfig" } + + override predicate isSource(DataFlow::Node src) { + exists(JsonpInjectionExpr jhe, JsonDataFlowConfig jdfc, RemoteFlowConfig rfc | + jhe = src.asExpr() and + jdfc.hasFlowTo(DataFlow::exprNode(jhe.getJsonExpr())) and + rfc.hasFlowTo(DataFlow::exprNode(jhe.getFunctionName())) + ) + } + + override predicate isSink(DataFlow::Node sink) { sink instanceof JsonpInjectionSink } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection.expected b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection.expected new file mode 100644 index 00000000000..019af8f5c05 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection.expected @@ -0,0 +1,60 @@ +edges +| JsonpInjection.java:28:32:28:68 | getParameter(...) : String | JsonpInjection.java:33:16:33:24 | resultStr | +| JsonpInjection.java:32:21:32:54 | ... + ... : String | JsonpInjection.java:33:16:33:24 | resultStr | +| JsonpInjection.java:40:32:40:68 | getParameter(...) : String | JsonpInjection.java:44:16:44:24 | resultStr | +| JsonpInjection.java:42:21:42:80 | ... + ... : String | JsonpInjection.java:44:16:44:24 | resultStr | +| JsonpInjection.java:51:32:51:68 | getParameter(...) : String | JsonpInjection.java:54:16:54:24 | resultStr | +| JsonpInjection.java:53:21:53:55 | ... + ... : String | JsonpInjection.java:54:16:54:24 | resultStr | +| JsonpInjection.java:61:32:61:68 | getParameter(...) : String | JsonpInjection.java:64:16:64:24 | resultStr | +| JsonpInjection.java:63:21:63:54 | ... + ... : String | JsonpInjection.java:64:16:64:24 | resultStr | +| JsonpInjection.java:72:32:72:68 | getParameter(...) : String | JsonpInjection.java:80:20:80:28 | resultStr | +| JsonpInjection.java:79:21:79:54 | ... + ... : String | JsonpInjection.java:80:20:80:28 | resultStr | +| JsonpInjection.java:88:32:88:68 | getParameter(...) : String | JsonpInjection.java:95:20:95:28 | resultStr | +| JsonpInjection.java:94:21:94:54 | ... + ... : String | JsonpInjection.java:95:20:95:28 | resultStr | +| JsonpInjection.java:102:32:102:68 | getParameter(...) : String | JsonpInjection.java:113:16:113:24 | resultStr | +| JsonpInjection.java:128:25:128:59 | ... + ... : String | JsonpInjection.java:129:20:129:28 | resultStr | +| JsonpInjection.java:147:25:147:59 | ... + ... : String | JsonpInjection.java:148:20:148:28 | resultStr | +nodes +| JsonpInjection.java:28:32:28:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpInjection.java:32:21:32:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpInjection.java:33:16:33:24 | resultStr | semmle.label | resultStr | +| JsonpInjection.java:33:16:33:24 | resultStr | semmle.label | resultStr | +| JsonpInjection.java:40:32:40:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpInjection.java:42:21:42:80 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpInjection.java:44:16:44:24 | resultStr | semmle.label | resultStr | +| JsonpInjection.java:44:16:44:24 | resultStr | semmle.label | resultStr | +| JsonpInjection.java:51:32:51:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpInjection.java:53:21:53:55 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpInjection.java:54:16:54:24 | resultStr | semmle.label | resultStr | +| JsonpInjection.java:54:16:54:24 | resultStr | semmle.label | resultStr | +| JsonpInjection.java:61:32:61:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpInjection.java:63:21:63:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpInjection.java:64:16:64:24 | resultStr | semmle.label | resultStr | +| JsonpInjection.java:64:16:64:24 | resultStr | semmle.label | resultStr | +| JsonpInjection.java:72:32:72:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpInjection.java:79:21:79:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpInjection.java:80:20:80:28 | resultStr | semmle.label | resultStr | +| JsonpInjection.java:80:20:80:28 | resultStr | semmle.label | resultStr | +| JsonpInjection.java:88:32:88:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpInjection.java:94:21:94:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpInjection.java:95:20:95:28 | resultStr | semmle.label | resultStr | +| JsonpInjection.java:95:20:95:28 | resultStr | semmle.label | resultStr | +| JsonpInjection.java:102:32:102:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpInjection.java:113:16:113:24 | resultStr | semmle.label | resultStr | +| JsonpInjection.java:128:25:128:59 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpInjection.java:129:20:129:28 | resultStr | semmle.label | resultStr | +| JsonpInjection.java:147:25:147:59 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpInjection.java:148:20:148:28 | resultStr | semmle.label | resultStr | +#select +| JsonpInjection.java:33:16:33:24 | resultStr | JsonpInjection.java:28:32:28:68 | getParameter(...) : String | JsonpInjection.java:33:16:33:24 | resultStr | Json Hijacking query +might include code from $@. | JsonpInjection.java:28:32:28:68 | getParameter(...) | this user input | +| JsonpInjection.java:44:16:44:24 | resultStr | JsonpInjection.java:40:32:40:68 | getParameter(...) : String | JsonpInjection.java:44:16:44:24 | resultStr | Json Hijacking query +might include code from $@. | JsonpInjection.java:40:32:40:68 | getParameter(...) | this user input | +| JsonpInjection.java:54:16:54:24 | resultStr | JsonpInjection.java:51:32:51:68 | getParameter(...) : String | JsonpInjection.java:54:16:54:24 | resultStr | Json Hijacking query +might include code from $@. | JsonpInjection.java:51:32:51:68 | getParameter(...) | this user input | +| JsonpInjection.java:64:16:64:24 | resultStr | JsonpInjection.java:61:32:61:68 | getParameter(...) : String | JsonpInjection.java:64:16:64:24 | resultStr | Json Hijacking query +might include code from $@. | JsonpInjection.java:61:32:61:68 | getParameter(...) | this user input | +| JsonpInjection.java:80:20:80:28 | resultStr | JsonpInjection.java:72:32:72:68 | getParameter(...) : String | JsonpInjection.java:80:20:80:28 | resultStr | Json Hijacking query +might include code from $@. | JsonpInjection.java:72:32:72:68 | getParameter(...) | this user input | +| JsonpInjection.java:95:20:95:28 | resultStr | JsonpInjection.java:88:32:88:68 | getParameter(...) : String | JsonpInjection.java:95:20:95:28 | resultStr | Json Hijacking query +might include code from $@. | JsonpInjection.java:88:32:88:68 | getParameter(...) | this user input | \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection.java b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection.java new file mode 100644 index 00000000000..df3aa2c02fe --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection.java @@ -0,0 +1,171 @@ +import com.alibaba.fastjson.JSONObject; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.Random; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +@Controller +public class JsonpInjection { + + private static HashMap hashMap = new HashMap(); + + static { + hashMap.put("username","admin"); + hashMap.put("password","123456"); + } + + + @GetMapping(value = "jsonp1") + @ResponseBody + public String bad1(HttpServletRequest request) { + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + + Gson gson = new Gson(); + String result = gson.toJson(hashMap); + resultStr = jsonpCallback + "(" + result + ")"; + return resultStr; + } + + @GetMapping(value = "jsonp2") + @ResponseBody + public String bad2(HttpServletRequest request) { + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + + resultStr = jsonpCallback + "(" + JSONObject.toJSONString(hashMap) + ")"; + + return resultStr; + } + + @GetMapping(value = "jsonp3") + @ResponseBody + public String bad3(HttpServletRequest request) { + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + String jsonStr = getJsonStr(hashMap); + resultStr = jsonpCallback + "(" + jsonStr + ")"; + return resultStr; + } + + @GetMapping(value = "jsonp4") + @ResponseBody + public String bad4(HttpServletRequest request) { + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + String restr = JSONObject.toJSONString(hashMap); + resultStr = jsonpCallback + "(" + restr + ");"; + return resultStr; + } + + @GetMapping(value = "jsonp5") + @ResponseBody + public void bad5(HttpServletRequest request, + HttpServletResponse response) throws Exception { + response.setContentType("application/json"); + String jsonpCallback = request.getParameter("jsonpCallback"); + PrintWriter pw = null; + Gson gson = new Gson(); + String result = gson.toJson(hashMap); + + String resultStr = null; + pw = response.getWriter(); + resultStr = jsonpCallback + "(" + result + ")"; + pw.println(resultStr); + } + + @GetMapping(value = "jsonp6") + @ResponseBody + public void bad6(HttpServletRequest request, + HttpServletResponse response) throws Exception { + response.setContentType("application/json"); + String jsonpCallback = request.getParameter("jsonpCallback"); + PrintWriter pw = null; + ObjectMapper mapper = new ObjectMapper(); + String result = mapper.writeValueAsString(hashMap); + String resultStr = null; + pw = response.getWriter(); + resultStr = jsonpCallback + "(" + result + ")"; + pw.println(resultStr); + } + + @GetMapping(value = "jsonp7") + @ResponseBody + public String good(HttpServletRequest request) { + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + + String val = ""; + Random random = new Random(); + for (int i = 0; i < 10; i++) { + val += String.valueOf(random.nextInt(10)); + } + // good + jsonpCallback = jsonpCallback + "_" + val; + String jsonStr = getJsonStr(hashMap); + resultStr = jsonpCallback + "(" + jsonStr + ")"; + return resultStr; + } + + @GetMapping(value = "jsonp8") + @ResponseBody + public String good1(HttpServletRequest request) { + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + + String token = request.getParameter("token"); + + // good + if (verifToken(token)){ + System.out.println(token); + String jsonStr = getJsonStr(hashMap); + resultStr = jsonpCallback + "(" + jsonStr + ")"; + return resultStr; + } + + return "error"; + } + + @GetMapping(value = "jsonp9") + @ResponseBody + public String good2(HttpServletRequest request) { + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + + String referer = request.getHeader("Referer"); + + boolean result = verifReferer(referer); + // good + if (result){ + String jsonStr = getJsonStr(hashMap); + resultStr = jsonpCallback + "(" + jsonStr + ")"; + return resultStr; + } + + return "error"; + } + + public static String getJsonStr(Object result) { + return JSONObject.toJSONString(result); + } + + public static boolean verifToken(String token){ + if (token != "xxxx"){ + return false; + } + return true; + } + + public static boolean verifReferer(String referer){ + if (!referer.startsWith("http://test.com/")){ + return false; + } + return true; + } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection.qlref b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection.qlref new file mode 100644 index 00000000000..6ad4b8acda7 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection.qlref @@ -0,0 +1 @@ +Security/CWE/CWE-352/JsonpInjection.ql From 6fe8bafc7d35f77d5db38d0802b192b6abb45dd1 Mon Sep 17 00:00:00 2001 From: haby0 Date: Wed, 24 Feb 2021 20:59:51 +0800 Subject: [PATCH 059/725] *)update --- .../Security/CWE/CWE-352/JsonHijacking.java | 119 ------------------ .../Security/CWE/CWE-352/JsonHijacking.qhelp | 35 ------ .../src/Security/CWE/CWE-352/JsonHijacking.ql | 32 ----- .../Security/CWE/CWE-352/JsonHijackingLib.qll | 92 -------------- .../security/CWE-352/JsonHijacking.expected | 48 ------- .../security/CWE-352/JsonHijacking.java | 119 ------------------ .../security/CWE-352/JsonHijacking.qlref | 1 - 7 files changed, 446 deletions(-) delete mode 100644 java/ql/src/Security/CWE/CWE-352/JsonHijacking.java delete mode 100644 java/ql/src/Security/CWE/CWE-352/JsonHijacking.qhelp delete mode 100644 java/ql/src/Security/CWE/CWE-352/JsonHijacking.ql delete mode 100644 java/ql/src/Security/CWE/CWE-352/JsonHijackingLib.qll delete mode 100644 java/ql/test/experimental/query-tests/security/CWE-352/JsonHijacking.expected delete mode 100644 java/ql/test/experimental/query-tests/security/CWE-352/JsonHijacking.java delete mode 100644 java/ql/test/experimental/query-tests/security/CWE-352/JsonHijacking.qlref diff --git a/java/ql/src/Security/CWE/CWE-352/JsonHijacking.java b/java/ql/src/Security/CWE/CWE-352/JsonHijacking.java deleted file mode 100644 index d08d436fa07..00000000000 --- a/java/ql/src/Security/CWE/CWE-352/JsonHijacking.java +++ /dev/null @@ -1,119 +0,0 @@ -import com.alibaba.fastjson.JSONObject; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.gson.Gson; -import java.io.PrintWriter; -import java.util.HashMap; -import java.util.Random; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.ResponseBody; - -@Controller -public class JsonHijacking { - - private static HashMap hashMap = new HashMap(); - - static { - hashMap.put("username","admin"); - hashMap.put("password","123456"); - } - - - @GetMapping(value = "jsonp1") - @ResponseBody - public String bad1(HttpServletRequest request) { - String resultStr = null; - String jsonpCallback = request.getParameter("jsonpCallback"); - - Gson gson = new Gson(); - String result = gson.toJson(hashMap); - resultStr = jsonpCallback + "(" + result + ")"; - return resultStr; - } - - @GetMapping(value = "jsonp2") - @ResponseBody - public String bad2(HttpServletRequest request) { - String resultStr = null; - String jsonpCallback = request.getParameter("jsonpCallback"); - - resultStr = jsonpCallback + "(" + JSONObject.toJSONString(hashMap) + ")"; - - return resultStr; - } - - @GetMapping(value = "jsonp3") - @ResponseBody - public String bad3(HttpServletRequest request) { - String resultStr = null; - String jsonpCallback = request.getParameter("jsonpCallback"); - String jsonStr = getJsonStr(hashMap); - resultStr = jsonpCallback + "(" + jsonStr + ")"; - return resultStr; - } - - @GetMapping(value = "jsonp4") - @ResponseBody - public String bad4(HttpServletRequest request) { - String resultStr = null; - String jsonpCallback = request.getParameter("jsonpCallback"); - String restr = JSONObject.toJSONString(hashMap); - resultStr = jsonpCallback + "(" + restr + ");"; - return resultStr; - } - - @GetMapping(value = "jsonp5") - @ResponseBody - public void bad5(HttpServletRequest request, - HttpServletResponse response) throws Exception { - response.setContentType("application/json"); - String jsonpCallback = request.getParameter("jsonpCallback"); - PrintWriter pw = null; - Gson gson = new Gson(); - String result = gson.toJson(hashMap); - - String resultStr = null; - pw = response.getWriter(); - resultStr = jsonpCallback + "(" + result + ")"; - pw.println(resultStr); - } - - @GetMapping(value = "jsonp6") - @ResponseBody - public void bad6(HttpServletRequest request, - HttpServletResponse response) throws Exception { - response.setContentType("application/json"); - String jsonpCallback = request.getParameter("jsonpCallback"); - PrintWriter pw = null; - ObjectMapper mapper = new ObjectMapper(); - String result = mapper.writeValueAsString(hashMap); - String resultStr = null; - pw = response.getWriter(); - resultStr = jsonpCallback + "(" + result + ")"; - pw.println(resultStr); - } - - @GetMapping(value = "jsonp7") - @ResponseBody - public String good(HttpServletRequest request) { - String resultStr = null; - String jsonpCallback = request.getParameter("jsonpCallback"); - - String val = ""; - Random random = new Random(); - for (int i = 0; i < 10; i++) { - val += String.valueOf(random.nextInt(10)); - } - // good - jsonpCallback = jsonpCallback + "_" + val; - String jsonStr = getJsonStr(hashMap); - resultStr = jsonpCallback + "(" + jsonStr + ")"; - return resultStr; - } - - public static String getJsonStr(Object result) { - return JSONObject.toJSONString(result); - } -} \ No newline at end of file diff --git a/java/ql/src/Security/CWE/CWE-352/JsonHijacking.qhelp b/java/ql/src/Security/CWE/CWE-352/JsonHijacking.qhelp deleted file mode 100644 index 38e1845f992..00000000000 --- a/java/ql/src/Security/CWE/CWE-352/JsonHijacking.qhelp +++ /dev/null @@ -1,35 +0,0 @@ - - - -

    The software uses external input as the function name to wrap JSON data and return it to the client as a request response. When there is a cross-domain problem, -there is a problem of sensitive information leakage.

    - -
    - - -

    The function name verification processing for external input can effectively prevent the leakage of sensitive information.

    - -
    - - -

    The following example shows the case of no verification processing and verification processing for the external input function name.

    - - - -
    - - -
  • -OWASPLondon20161124_JSON_Hijacking_Gareth_Heyes: -JSON hijacking. -
  • -
  • -Practical JSONP Injection: - - Completely controllable from the URL (GET variable) -. -
  • -
    -
    diff --git a/java/ql/src/Security/CWE/CWE-352/JsonHijacking.ql b/java/ql/src/Security/CWE/CWE-352/JsonHijacking.ql deleted file mode 100644 index a6a6d2475f0..00000000000 --- a/java/ql/src/Security/CWE/CWE-352/JsonHijacking.ql +++ /dev/null @@ -1,32 +0,0 @@ -/** - * @name JSON Hijacking - * @description User-controlled callback function names that are not verified are vulnerable - * to json hijacking attacks. - * @kind path-problem - * @problem.severity error - * @precision high - * @id java/Json-hijacking - * @tags security - * external/cwe/cwe-352 - */ - -import java -import JsonHijackingLib -import semmle.code.java.dataflow.FlowSources -import DataFlow::PathGraph - -/** Taint-tracking configuration tracing flow from remote sources to output jsonp data. */ -class JsonHijackingConfig extends TaintTracking::Configuration { - JsonHijackingConfig() { this = "JsonHijackingConfig" } - - override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } - - override predicate isSink(DataFlow::Node sink) { sink instanceof JsonHijackingSink } -} - -from DataFlow::PathNode source, DataFlow::PathNode sink, JsonHijackingConfig conf -where - conf.hasFlowPath(source, sink) and - exists(JsonHijackingFlowConfig jhfc | jhfc.hasFlowTo(sink.getNode())) -select sink.getNode(), source, sink, "Json Hijacking query might include code from $@.", - source.getNode(), "this user input" diff --git a/java/ql/src/Security/CWE/CWE-352/JsonHijackingLib.qll b/java/ql/src/Security/CWE/CWE-352/JsonHijackingLib.qll deleted file mode 100644 index ba91a6670bf..00000000000 --- a/java/ql/src/Security/CWE/CWE-352/JsonHijackingLib.qll +++ /dev/null @@ -1,92 +0,0 @@ -import java -import DataFlow -import JsonStringLib -import semmle.code.java.dataflow.DataFlow -import semmle.code.java.dataflow.FlowSources -import semmle.code.java.frameworks.spring.SpringController - -/** A data flow sink for unvalidated user input that is used to jsonp. */ -abstract class JsonHijackingSink extends DataFlow::Node { } - -/** Use ```print```, ```println```, ```write``` to output result. */ -private class WriterPrintln extends JsonHijackingSink { - WriterPrintln() { - exists(MethodAccess ma | - ma.getMethod().getName().regexpMatch("print|println|write") and - ma.getMethod() - .getDeclaringType() - .getASourceSupertype*() - .hasQualifiedName("java.io", "PrintWriter") and - ma.getArgument(0) = this.asExpr() - ) - } -} - -/** Spring Request Method return result. */ -private class SpringReturn extends JsonHijackingSink { - SpringReturn() { - exists(ReturnStmt rs, Method m | m = rs.getEnclosingCallable() | - m instanceof SpringRequestMappingMethod and - rs.getResult() = this.asExpr() - ) - } -} - -/** A concatenate expression using `(` and `)` or `);`. */ -class JsonHijackingExpr extends AddExpr { - JsonHijackingExpr() { - getRightOperand().toString().regexpMatch("\"\\)\"|\"\\);\"") and - getLeftOperand() - .(AddExpr) - .getLeftOperand() - .(AddExpr) - .getRightOperand() - .toString() - .regexpMatch("\"\\(\"") - } - - /** Get the jsonp function name of this expression */ - Expr getFunctionName() { - result = getLeftOperand().(AddExpr).getLeftOperand().(AddExpr).getLeftOperand() - } - - /** Get the json data of this expression */ - Expr getJsonExpr() { result = getLeftOperand().(AddExpr).getRightOperand() } -} - -/** A data flow configuration tracing flow from remote sources to jsonp function name. */ -class RemoteFlowConfig extends DataFlow2::Configuration { - RemoteFlowConfig() { this = "RemoteFlowConfig" } - - override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource } - - override predicate isSink(DataFlow::Node sink) { - exists(JsonHijackingExpr jhe | jhe.getFunctionName() = sink.asExpr()) - } -} - -/** A data flow configuration tracing flow from json data to splicing jsonp data. */ -class JsonDataFlowConfig extends DataFlow2::Configuration { - JsonDataFlowConfig() { this = "JsonDataFlowConfig" } - - override predicate isSource(DataFlow::Node src) { src instanceof JsonpStringSource } - - override predicate isSink(DataFlow::Node sink) { - exists(JsonHijackingExpr jhe | jhe.getJsonExpr() = sink.asExpr()) - } -} - -/** Taint-tracking configuration tracing flow from user-controllable function name jsonp data to output jsonp data. */ -class JsonHijackingFlowConfig extends TaintTracking::Configuration { - JsonHijackingFlowConfig() { this = "JsonHijackingFlowConfig" } - - override predicate isSource(DataFlow::Node src) { - exists(JsonHijackingExpr jhe, JsonDataFlowConfig jdfc, RemoteFlowConfig rfc | - jhe = src.asExpr() and - jdfc.hasFlowTo(DataFlow::exprNode(jhe.getJsonExpr())) and - rfc.hasFlowTo(DataFlow::exprNode(jhe.getFunctionName())) - ) - } - - override predicate isSink(DataFlow::Node sink) { sink instanceof JsonHijackingSink } -} diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonHijacking.expected b/java/ql/test/experimental/query-tests/security/CWE-352/JsonHijacking.expected deleted file mode 100644 index 8efc3be1673..00000000000 --- a/java/ql/test/experimental/query-tests/security/CWE-352/JsonHijacking.expected +++ /dev/null @@ -1,48 +0,0 @@ -edges -| JsonHijacking.java:28:32:28:68 | getParameter(...) : String | JsonHijacking.java:33:16:33:24 | resultStr | -| JsonHijacking.java:32:21:32:54 | ... + ... : String | JsonHijacking.java:33:16:33:24 | resultStr | -| JsonHijacking.java:40:32:40:68 | getParameter(...) : String | JsonHijacking.java:44:16:44:24 | resultStr | -| JsonHijacking.java:42:21:42:80 | ... + ... : String | JsonHijacking.java:44:16:44:24 | resultStr | -| JsonHijacking.java:51:32:51:68 | getParameter(...) : String | JsonHijacking.java:54:16:54:24 | resultStr | -| JsonHijacking.java:53:21:53:55 | ... + ... : String | JsonHijacking.java:54:16:54:24 | resultStr | -| JsonHijacking.java:61:32:61:68 | getParameter(...) : String | JsonHijacking.java:64:16:64:24 | resultStr | -| JsonHijacking.java:63:21:63:54 | ... + ... : String | JsonHijacking.java:64:16:64:24 | resultStr | -| JsonHijacking.java:72:32:72:68 | getParameter(...) : String | JsonHijacking.java:80:20:80:28 | resultStr | -| JsonHijacking.java:79:21:79:54 | ... + ... : String | JsonHijacking.java:80:20:80:28 | resultStr | -| JsonHijacking.java:88:32:88:68 | getParameter(...) : String | JsonHijacking.java:95:20:95:28 | resultStr | -| JsonHijacking.java:94:21:94:54 | ... + ... : String | JsonHijacking.java:95:20:95:28 | resultStr | -| JsonHijacking.java:102:32:102:68 | getParameter(...) : String | JsonHijacking.java:113:16:113:24 | resultStr | -nodes -| JsonHijacking.java:28:32:28:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonHijacking.java:32:21:32:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonHijacking.java:33:16:33:24 | resultStr | semmle.label | resultStr | -| JsonHijacking.java:33:16:33:24 | resultStr | semmle.label | resultStr | -| JsonHijacking.java:40:32:40:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonHijacking.java:42:21:42:80 | ... + ... : String | semmle.label | ... + ... : String | -| JsonHijacking.java:44:16:44:24 | resultStr | semmle.label | resultStr | -| JsonHijacking.java:44:16:44:24 | resultStr | semmle.label | resultStr | -| JsonHijacking.java:51:32:51:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonHijacking.java:53:21:53:55 | ... + ... : String | semmle.label | ... + ... : String | -| JsonHijacking.java:54:16:54:24 | resultStr | semmle.label | resultStr | -| JsonHijacking.java:54:16:54:24 | resultStr | semmle.label | resultStr | -| JsonHijacking.java:61:32:61:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonHijacking.java:63:21:63:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonHijacking.java:64:16:64:24 | resultStr | semmle.label | resultStr | -| JsonHijacking.java:64:16:64:24 | resultStr | semmle.label | resultStr | -| JsonHijacking.java:72:32:72:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonHijacking.java:79:21:79:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonHijacking.java:80:20:80:28 | resultStr | semmle.label | resultStr | -| JsonHijacking.java:80:20:80:28 | resultStr | semmle.label | resultStr | -| JsonHijacking.java:88:32:88:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonHijacking.java:94:21:94:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonHijacking.java:95:20:95:28 | resultStr | semmle.label | resultStr | -| JsonHijacking.java:95:20:95:28 | resultStr | semmle.label | resultStr | -| JsonHijacking.java:102:32:102:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonHijacking.java:113:16:113:24 | resultStr | semmle.label | resultStr | -#select -| JsonHijacking.java:33:16:33:24 | resultStr | JsonHijacking.java:28:32:28:68 | getParameter(...) : String | JsonHijacking.java:33:16:33:24 | resultStr | Json Hijacking query might include code from $@. | JsonHijacking.java:28:32:28:68 | getParameter(...) | this user input | -| JsonHijacking.java:44:16:44:24 | resultStr | JsonHijacking.java:40:32:40:68 | getParameter(...) : String | JsonHijacking.java:44:16:44:24 | resultStr | Json Hijacking query might include code from $@. | JsonHijacking.java:40:32:40:68 | getParameter(...) | this user input | -| JsonHijacking.java:54:16:54:24 | resultStr | JsonHijacking.java:51:32:51:68 | getParameter(...) : String | JsonHijacking.java:54:16:54:24 | resultStr | Json Hijacking query might include code from $@. | JsonHijacking.java:51:32:51:68 | getParameter(...) | this user input | -| JsonHijacking.java:64:16:64:24 | resultStr | JsonHijacking.java:61:32:61:68 | getParameter(...) : String | JsonHijacking.java:64:16:64:24 | resultStr | Json Hijacking query might include code from $@. | JsonHijacking.java:61:32:61:68 | getParameter(...) | this user input | -| JsonHijacking.java:80:20:80:28 | resultStr | JsonHijacking.java:72:32:72:68 | getParameter(...) : String | JsonHijacking.java:80:20:80:28 | resultStr | Json Hijacking query might include code from $@. | JsonHijacking.java:72:32:72:68 | getParameter(...) | this user input | -| JsonHijacking.java:95:20:95:28 | resultStr | JsonHijacking.java:88:32:88:68 | getParameter(...) : String | JsonHijacking.java:95:20:95:28 | resultStr | Json Hijacking query might include code from $@. | JsonHijacking.java:88:32:88:68 | getParameter(...) | this user input | diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonHijacking.java b/java/ql/test/experimental/query-tests/security/CWE-352/JsonHijacking.java deleted file mode 100644 index 9b473e0610c..00000000000 --- a/java/ql/test/experimental/query-tests/security/CWE-352/JsonHijacking.java +++ /dev/null @@ -1,119 +0,0 @@ -import com.alibaba.fastjson.JSONObject; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.gson.Gson; -import java.io.PrintWriter; -import java.util.HashMap; -import java.util.Random; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.ResponseBody; - -@Controller -public class JsonHijacking { - - private static HashMap hashMap = new HashMap(); - - static { - hashMap.put("username","admin"); - hashMap.put("password","123456"); - } - - - @GetMapping(value = "jsonp1") - @ResponseBody - public String bad1(HttpServletRequest request) { - String resultStr = null; - String jsonpCallback = request.getParameter("jsonpCallback"); - - Gson gson = new Gson(); - String result = gson.toJson(hashMap); - resultStr = jsonpCallback + "(" + result + ")"; - return resultStr; - } - - @GetMapping(value = "jsonp2") - @ResponseBody - public String bad2(HttpServletRequest request) { - String resultStr = null; - String jsonpCallback = request.getParameter("jsonpCallback"); - - resultStr = jsonpCallback + "(" + JSONObject.toJSONString(hashMap) + ")"; - - return resultStr; - } - - @GetMapping(value = "jsonp3") - @ResponseBody - public String bad3(HttpServletRequest request) { - String resultStr = null; - String jsonpCallback = request.getParameter("jsonpCallback"); - String jsonStr = getJsonStr(hashMap); - resultStr = jsonpCallback + "(" + jsonStr + ")"; - return resultStr; - } - - @GetMapping(value = "jsonp4") - @ResponseBody - public String bad4(HttpServletRequest request) { - String resultStr = null; - String jsonpCallback = request.getParameter("jsonpCallback"); - String restr = JSONObject.toJSONString(hashMap); - resultStr = jsonpCallback + "(" + restr + ");"; - return resultStr; - } - - @GetMapping(value = "jsonp5") - @ResponseBody - public void bad5(HttpServletRequest request, - HttpServletResponse response) throws Exception { - response.setContentType("application/json"); - String jsonpCallback = request.getParameter("jsonpCallback"); - PrintWriter pw = null; - Gson gson = new Gson(); - String result = gson.toJson(hashMap); - - String resultStr = null; - pw = response.getWriter(); - resultStr = jsonpCallback + "(" + result + ")"; - pw.println(resultStr); - } - - @GetMapping(value = "jsonp6") - @ResponseBody - public void bad6(HttpServletRequest request, - HttpServletResponse response) throws Exception { - response.setContentType("application/json"); - String jsonpCallback = request.getParameter("jsonpCallback"); - PrintWriter pw = null; - ObjectMapper mapper = new ObjectMapper(); - String result = mapper.writeValueAsString(hashMap); - String resultStr = null; - pw = response.getWriter(); - resultStr = jsonpCallback + "(" + result + ")"; - pw.println(resultStr); - } - - @GetMapping(value = "jsonp7") - @ResponseBody - public String good(HttpServletRequest request) { - String resultStr = null; - String jsonpCallback = request.getParameter("jsonpCallback"); - - String val = ""; - Random random = new Random(); - for (int i = 0; i < 10; i++) { - val += String.valueOf(random.nextInt(10)); - } - // good - jsonpCallback = jsonpCallback + "_" + val; - String jsonStr = getJsonStr(hashMap); - resultStr = jsonpCallback + "(" + jsonStr + ")"; - return resultStr; - } - - public static String getJsonStr(Object result) { - return JSONObject.toJSONString(result); - } -} diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonHijacking.qlref b/java/ql/test/experimental/query-tests/security/CWE-352/JsonHijacking.qlref deleted file mode 100644 index e79471b3c1e..00000000000 --- a/java/ql/test/experimental/query-tests/security/CWE-352/JsonHijacking.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/CWE/CWE-352/JsonHijacking.ql From 476309af6dc21295312598a6cd0fb406539dc2a6 Mon Sep 17 00:00:00 2001 From: Artem Smotrakov Date: Sun, 21 Feb 2021 19:45:12 +0100 Subject: [PATCH 060/725] Added SpringHttpInvokerUnsafeDeserialization.ql --- .../SpringHttpInvokerUnsafeDeserialization.ql | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 java/ql/src/experimental/Security/CWE/CWE-502/SpringHttpInvokerUnsafeDeserialization.ql diff --git a/java/ql/src/experimental/Security/CWE/CWE-502/SpringHttpInvokerUnsafeDeserialization.ql b/java/ql/src/experimental/Security/CWE/CWE-502/SpringHttpInvokerUnsafeDeserialization.ql new file mode 100644 index 00000000000..73c67582692 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-502/SpringHttpInvokerUnsafeDeserialization.ql @@ -0,0 +1,56 @@ +/** + * @name Unsafe deserialization with spring's remote service exporters. + * @description Creating a bean based on RemoteInvocationSerializingExporter + * may lead to arbitrary code execution. + * @kind problem + * @problem.severity error + * @precision high + * @id java/spring-exporter-unsafe-deserialization + * @tags security + * external/cwe/cwe-502 + */ + +import java + +/** + * Holds if `method` initializes a bean. + */ +private predicate createsBean(Method method) { + method.hasAnnotation("org.springframework.context.annotation", "Bean") +} + +/** + * Holds if `type` is `RemoteInvocationSerializingExporter`. + */ +private predicate isRemoteInvocationSerializingExporter(RefType type) { + type.hasQualifiedName("org.springframework.remoting.rmi", "RemoteInvocationSerializingExporter") +} + +/** + * Holds if `method` returns an object that extends `RemoteInvocationSerializingExporter`. + */ +private predicate returnsRemoteInvocationSerializingExporter(Method method) { + isRemoteInvocationSerializingExporter(method.getReturnType()) or + isRemoteInvocationSerializingExporter(method.getReturnType().(RefType).getASupertype*()) +} + +/** + * Holds if `method` belongs to a Spring configuration. + */ +private predicate isInConfiguration(Method method) { + method.getDeclaringType().hasAnnotation("org.springframework.context.annotation", "Configuration") +} + +/** + * Holds if `method` initializes a bean that is based on `RemoteInvocationSerializingExporter`. + */ +private predicate createsRemoteInvocationSerializingExporterBean(Method method) { + isInConfiguration(method) and + createsBean(method) and + returnsRemoteInvocationSerializingExporter(method) +} + +from Method method +where createsRemoteInvocationSerializingExporterBean(method) +select method, + "Unasafe deserialization in a remote service exporter in '" + method.getName() + "' method" From 95284ad71ddc87e91baaf1dc4edd5d1494c8d806 Mon Sep 17 00:00:00 2001 From: Artem Smotrakov Date: Sun, 21 Feb 2021 21:43:17 +0100 Subject: [PATCH 061/725] Added SpringHttpInvokerUnsafeDeserialization.qhelp and example --- ...ringHttpInvokerUnsafeDeserialization.qhelp | 69 +++++++++++++++++++ .../CWE-502/UnsafeHttpInvokerEndpoint.java | 24 +++++++ 2 files changed, 93 insertions(+) create mode 100644 java/ql/src/experimental/Security/CWE/CWE-502/SpringHttpInvokerUnsafeDeserialization.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-502/UnsafeHttpInvokerEndpoint.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-502/SpringHttpInvokerUnsafeDeserialization.qhelp b/java/ql/src/experimental/Security/CWE/CWE-502/SpringHttpInvokerUnsafeDeserialization.qhelp new file mode 100644 index 00000000000..11a3333007a --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-502/SpringHttpInvokerUnsafeDeserialization.qhelp @@ -0,0 +1,69 @@ + + + + +

    +Spring Framework provides an abstract base class RemoteInvocationSerializingExporter +for defining remote service exporters. +A Spring exporter, which is based on this class, deserializes incoming data using ObjectInputStream. +Deserializing untrusted data is easily exploitable and in many cases allows an attacker +to execute arbitrary code. +

    +

    +Spring Framework also provides two classes that extend RemoteInvocationSerializingExporter: +

  • +HttpInvokerServiceExporter +
  • +
  • +SimpleHttpInvokerServiceExporter +
  • +

    +

    +These classes export specified beans as HTTP endpoints that deserialize data from an HTTP request +using unsafe ObjectInputStream. If a remote attacker can reach such endpoints, +it results in remote code execution. +

    +
    + + +

    +Avoid using HttpInvokerServiceExporter, SimpleHttpInvokerServiceExporter +and other exporters that are based on RemoteInvocationSerializingExporter. +Instead, use other message formats for API endpoints (for example, JSON), +but make sure that the underlying deserialization mechanism is properly configured +so that deserialization attacks are not possible. If the vulnerable exporters can not be replaced, +consider using global deserialization filters introduced by JEP 290. +In general, avoid deserialization of untrusted data. +

    +
    + + +

    +The following example defines a vulnerable HTTP endpoint: +

    + +
    + + +
  • +OWASP: +Deserialization of untrusted data. +
  • +
  • +National Vulnerability Database: +CVE-2016-1000027 +
  • +
  • +Tenable Research Advisory: +[R2] Pivotal Spring Framework HttpInvokerServiceExporter readRemoteInvocation Method Untrusted Java Deserialization +
  • +
  • +Spring Framework bug tracker: +Sonatype vulnerability CVE-2016-1000027 in Spring-web project +
  • +
  • +OpenJDK: +JEP 290: Filter Incoming Serialization Data +
  • +
    +
    \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeHttpInvokerEndpoint.java b/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeHttpInvokerEndpoint.java new file mode 100644 index 00000000000..a4c6dadf17c --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeHttpInvokerEndpoint.java @@ -0,0 +1,24 @@ +@Configuration +public class Server { + + @Bean(name = "/account") + HttpInvokerServiceExporter accountService() { + HttpInvokerServiceExporter exporter = new HttpInvokerServiceExporter(); + exporter.setService(new AccountServiceImpl()); + exporter.setServiceInterface(AccountService.class); + return exporter; + } + +} + +class AccountServiceImpl implements AccountService { + + @Override + public String echo(String data) { + return data; + } +} + +interface AccountService { + String echo(String data); +} \ No newline at end of file From aac0c27dcd25fc37b9a56b5235f2e7ea09404009 Mon Sep 17 00:00:00 2001 From: Artem Smotrakov Date: Sun, 21 Feb 2021 22:19:53 +0100 Subject: [PATCH 062/725] Added tests for SpringHttpInvokerUnsafeDeserialization.ql --- ...gHttpInvokerUnsafeDeserialization.expected | 1 + ...pringHttpInvokerUnsafeDeserialization.java | 45 +++++++++++++++++++ ...ringHttpInvokerUnsafeDeserialization.qlref | 1 + .../query-tests/security/CWE-502/options | 1 + .../context/annotation/Bean.java | 10 +++++ .../context/annotation/Configuration.java | 7 +++ .../HttpInvokerServiceExporter.java | 8 ++++ .../RemoteInvocationSerializingExporter.java | 5 +++ 8 files changed, 78 insertions(+) create mode 100644 java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.java create mode 100644 java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.qlref create mode 100644 java/ql/test/experimental/query-tests/security/CWE-502/options create mode 100644 java/ql/test/stubs/springframework-5.2.3/org/springframework/context/annotation/Bean.java create mode 100644 java/ql/test/stubs/springframework-5.2.3/org/springframework/context/annotation/Configuration.java create mode 100644 java/ql/test/stubs/springframework-5.2.3/org/springframework/remoting/httpinvoker/HttpInvokerServiceExporter.java create mode 100644 java/ql/test/stubs/springframework-5.2.3/org/springframework/remoting/rmi/RemoteInvocationSerializingExporter.java diff --git a/java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.expected b/java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.expected new file mode 100644 index 00000000000..0ce0efca838 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.expected @@ -0,0 +1 @@ +| SpringHttpInvokerUnsafeDeserialization.java:9:32:9:37 | unsafe | Unasafe deserialization in a remote service exporter in 'unsafe' method | diff --git a/java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.java b/java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.java new file mode 100644 index 00000000000..d678c8f0191 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.java @@ -0,0 +1,45 @@ +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter; + +@Configuration +public class SpringHttpInvokerUnsafeDeserialization { + + @Bean(name = "/unsafe") + HttpInvokerServiceExporter unsafe() { + HttpInvokerServiceExporter exporter = new HttpInvokerServiceExporter(); + exporter.setService(new AccountServiceImpl()); + exporter.setServiceInterface(AccountService.class); + return exporter; + } + + HttpInvokerServiceExporter notABean() { + HttpInvokerServiceExporter exporter = new HttpInvokerServiceExporter(); + exporter.setService(new AccountServiceImpl()); + exporter.setServiceInterface(AccountService.class); + return exporter; + } +} + +class NotAConfiguration { + + @Bean(name = "/notAnEndpoint") + HttpInvokerServiceExporter notAnEndpoint() { + HttpInvokerServiceExporter exporter = new HttpInvokerServiceExporter(); + exporter.setService(new AccountServiceImpl()); + exporter.setServiceInterface(AccountService.class); + return exporter; + } +} + +class AccountServiceImpl implements AccountService { + + @Override + public String echo(String data) { + return data; + } +} + +interface AccountService { + String echo(String data); +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.qlref b/java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.qlref new file mode 100644 index 00000000000..014b0872ea4 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-502/SpringHttpInvokerUnsafeDeserialization.ql \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-502/options b/java/ql/test/experimental/query-tests/security/CWE-502/options new file mode 100644 index 00000000000..31b8e3f6935 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-502/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3 \ No newline at end of file diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/context/annotation/Bean.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/context/annotation/Bean.java new file mode 100644 index 00000000000..24d7be0f817 --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/context/annotation/Bean.java @@ -0,0 +1,10 @@ +package org.springframework.context.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; + +@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) +public @interface Bean { + + String[] name() default {}; +} \ No newline at end of file diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/context/annotation/Configuration.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/context/annotation/Configuration.java new file mode 100644 index 00000000000..0024b3ba833 --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/context/annotation/Configuration.java @@ -0,0 +1,7 @@ +package org.springframework.context.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE) +public @interface Configuration {} \ No newline at end of file diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/remoting/httpinvoker/HttpInvokerServiceExporter.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/remoting/httpinvoker/HttpInvokerServiceExporter.java new file mode 100644 index 00000000000..5eb56c0897b --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/remoting/httpinvoker/HttpInvokerServiceExporter.java @@ -0,0 +1,8 @@ +package org.springframework.remoting.httpinvoker; + +public class HttpInvokerServiceExporter extends org.springframework.remoting.rmi.RemoteInvocationSerializingExporter { + + public void setService(Object service) {} + + public void setServiceInterface(Class clazz) {} +} \ No newline at end of file diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/remoting/rmi/RemoteInvocationSerializingExporter.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/remoting/rmi/RemoteInvocationSerializingExporter.java new file mode 100644 index 00000000000..a6f6fec194f --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/remoting/rmi/RemoteInvocationSerializingExporter.java @@ -0,0 +1,5 @@ +package org.springframework.remoting.rmi; + +public abstract class RemoteInvocationSerializingExporter { + +} From e02b51f42bad96acbdf29a22c3768af894a942af Mon Sep 17 00:00:00 2001 From: Artem Smotrakov Date: Wed, 24 Feb 2021 22:23:11 +0100 Subject: [PATCH 063/725] Improved SpringHttpInvokerUnsafeDeserialization.qhelp --- .../SpringHttpInvokerUnsafeDeserialization.qhelp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-502/SpringHttpInvokerUnsafeDeserialization.qhelp b/java/ql/src/experimental/Security/CWE/CWE-502/SpringHttpInvokerUnsafeDeserialization.qhelp index 11a3333007a..49237a8500e 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-502/SpringHttpInvokerUnsafeDeserialization.qhelp +++ b/java/ql/src/experimental/Security/CWE/CWE-502/SpringHttpInvokerUnsafeDeserialization.qhelp @@ -21,14 +21,17 @@ Spring Framework also provides two classes that extend RemoteInvocationSer

    These classes export specified beans as HTTP endpoints that deserialize data from an HTTP request using unsafe ObjectInputStream. If a remote attacker can reach such endpoints, -it results in remote code execution. +it results in remote code execution in the worst case. +

    +

    +CVE-2016-1000027 has been assigned to this issue in Spring Framework. There is no fix for that.

    Avoid using HttpInvokerServiceExporter, SimpleHttpInvokerServiceExporter -and other exporters that are based on RemoteInvocationSerializingExporter. +and any other exporter that is based on RemoteInvocationSerializingExporter. Instead, use other message formats for API endpoints (for example, JSON), but make sure that the underlying deserialization mechanism is properly configured so that deserialization attacks are not possible. If the vulnerable exporters can not be replaced, @@ -50,6 +53,14 @@ OWASP: Deserialization of untrusted data.

  • +Spring Framework API documentation: +RemoteInvocationSerializingExporter class +
  • +
  • +Spring Framework API documentation: +HttpInvokerServiceExporter class +
  • +
  • National Vulnerability Database: CVE-2016-1000027
  • @@ -66,4 +77,5 @@ OpenJDK: JEP 290: Filter Incoming Serialization Data
    +
    \ No newline at end of file From 2e02625f22aeebb0c9ef3dfc02e71c714196b3d8 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Thu, 25 Feb 2021 12:53:39 -0500 Subject: [PATCH 064/725] C++: Summary metrics queries This is a first attempt at implementing, for C++, the set of summary queries that we expect all languages to implement to help diagnose extraction failures and build configuration problems. See the spec in [this document](https://docs.google.com/document/d/1V3zpkj0OGh8GEUVwACRx7fiafE5zklujAftZaYUyf9s/edit?usp=sharing). The five queries are: - Total number of source files (including .c/.cpp and header files) - Total number of lines of text across all text files - Total number of lines of code across all text files - Number of lines of text in each source file - Number of lines of code in each source file I've added some simple unit tests that cover all five of these. --- cpp/ql/src/Diagnostics/Files.ql | 10 ++ cpp/ql/src/Diagnostics/Lines.ql | 10 ++ cpp/ql/src/Diagnostics/LinesOfCode.ql | 10 ++ cpp/ql/src/Diagnostics/LinesOfCodePerFile.ql | 12 ++ cpp/ql/src/Diagnostics/LinesPerFile.ql | 12 ++ .../query-tests/Diagnostics/Files.expected | 1 + .../test/query-tests/Diagnostics/Files.qlref | 1 + .../query-tests/Diagnostics/Lines.expected | 1 + .../test/query-tests/Diagnostics/Lines.qlref | 1 + .../Diagnostics/LinesOfCode.expected | 1 + .../query-tests/Diagnostics/LinesOfCode.qlref | 1 + .../Diagnostics/LinesOfCodePerFile.expected | 3 + .../Diagnostics/LinesOfCodePerFile.qlref | 1 + .../Diagnostics/LinesPerFile.expected | 3 + .../Diagnostics/LinesPerFile.qlref | 1 + .../query-tests/Diagnostics/empty-file.cpp | 0 .../query-tests/Diagnostics/large-file.cpp | 119 ++++++++++++++++++ .../query-tests/Diagnostics/short-file.cpp | 3 + 18 files changed, 190 insertions(+) create mode 100644 cpp/ql/src/Diagnostics/Files.ql create mode 100644 cpp/ql/src/Diagnostics/Lines.ql create mode 100644 cpp/ql/src/Diagnostics/LinesOfCode.ql create mode 100644 cpp/ql/src/Diagnostics/LinesOfCodePerFile.ql create mode 100644 cpp/ql/src/Diagnostics/LinesPerFile.ql create mode 100644 cpp/ql/test/query-tests/Diagnostics/Files.expected create mode 100644 cpp/ql/test/query-tests/Diagnostics/Files.qlref create mode 100644 cpp/ql/test/query-tests/Diagnostics/Lines.expected create mode 100644 cpp/ql/test/query-tests/Diagnostics/Lines.qlref create mode 100644 cpp/ql/test/query-tests/Diagnostics/LinesOfCode.expected create mode 100644 cpp/ql/test/query-tests/Diagnostics/LinesOfCode.qlref create mode 100644 cpp/ql/test/query-tests/Diagnostics/LinesOfCodePerFile.expected create mode 100644 cpp/ql/test/query-tests/Diagnostics/LinesOfCodePerFile.qlref create mode 100644 cpp/ql/test/query-tests/Diagnostics/LinesPerFile.expected create mode 100644 cpp/ql/test/query-tests/Diagnostics/LinesPerFile.qlref create mode 100644 cpp/ql/test/query-tests/Diagnostics/empty-file.cpp create mode 100644 cpp/ql/test/query-tests/Diagnostics/large-file.cpp create mode 100644 cpp/ql/test/query-tests/Diagnostics/short-file.cpp diff --git a/cpp/ql/src/Diagnostics/Files.ql b/cpp/ql/src/Diagnostics/Files.ql new file mode 100644 index 00000000000..0759284541f --- /dev/null +++ b/cpp/ql/src/Diagnostics/Files.ql @@ -0,0 +1,10 @@ +/** + * @name Total source files + * @description The total number of source files. + * @kind metric + * @id cpp/metrics/files + */ + +import cpp + +select count(File f | f.fromSource()) diff --git a/cpp/ql/src/Diagnostics/Lines.ql b/cpp/ql/src/Diagnostics/Lines.ql new file mode 100644 index 00000000000..cce3e42c00f --- /dev/null +++ b/cpp/ql/src/Diagnostics/Lines.ql @@ -0,0 +1,10 @@ +/** + * @name Total lines of text + * @description The total number of lines of text across all source files. + * @kind metric + * @id cpp/metrics/lines + */ + +import cpp + +select sum(File f | f.fromSource() | f.getMetrics().getNumberOfLines()) diff --git a/cpp/ql/src/Diagnostics/LinesOfCode.ql b/cpp/ql/src/Diagnostics/LinesOfCode.ql new file mode 100644 index 00000000000..9553e39b3e4 --- /dev/null +++ b/cpp/ql/src/Diagnostics/LinesOfCode.ql @@ -0,0 +1,10 @@ +/** + * @name Total lines of code + * @description The total number of lines of code across all source files. + * @kind metric + * @id cpp/metrics/lines-of-code + */ + +import cpp + +select sum(File f | f.fromSource() | f.getMetrics().getNumberOfLinesOfCode()) diff --git a/cpp/ql/src/Diagnostics/LinesOfCodePerFile.ql b/cpp/ql/src/Diagnostics/LinesOfCodePerFile.ql new file mode 100644 index 00000000000..ebb9a19c447 --- /dev/null +++ b/cpp/ql/src/Diagnostics/LinesOfCodePerFile.ql @@ -0,0 +1,12 @@ +/** + * @name Lines of code per source file + * @description The number of lines of code for each source file. + * @kind metric + * @id cpp/metrics/lines-of-code-per-file + */ + +import cpp + +from File f +where f.fromSource() +select f, f.getMetrics().getNumberOfLinesOfCode() diff --git a/cpp/ql/src/Diagnostics/LinesPerFile.ql b/cpp/ql/src/Diagnostics/LinesPerFile.ql new file mode 100644 index 00000000000..4fa3608d293 --- /dev/null +++ b/cpp/ql/src/Diagnostics/LinesPerFile.ql @@ -0,0 +1,12 @@ +/** + * @name Lines of text per source file + * @description The number of lines of text for each source file. + * @kind metric + * @id cpp/metrics/lines-per-file + */ + +import cpp + +from File f +where f.fromSource() +select f, f.getMetrics().getNumberOfLines() diff --git a/cpp/ql/test/query-tests/Diagnostics/Files.expected b/cpp/ql/test/query-tests/Diagnostics/Files.expected new file mode 100644 index 00000000000..7621cebdd5f --- /dev/null +++ b/cpp/ql/test/query-tests/Diagnostics/Files.expected @@ -0,0 +1 @@ +| 3 | diff --git a/cpp/ql/test/query-tests/Diagnostics/Files.qlref b/cpp/ql/test/query-tests/Diagnostics/Files.qlref new file mode 100644 index 00000000000..f29d0010003 --- /dev/null +++ b/cpp/ql/test/query-tests/Diagnostics/Files.qlref @@ -0,0 +1 @@ +Diagnostics/Files.ql \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Diagnostics/Lines.expected b/cpp/ql/test/query-tests/Diagnostics/Lines.expected new file mode 100644 index 00000000000..d847b050658 --- /dev/null +++ b/cpp/ql/test/query-tests/Diagnostics/Lines.expected @@ -0,0 +1 @@ +| 122 | diff --git a/cpp/ql/test/query-tests/Diagnostics/Lines.qlref b/cpp/ql/test/query-tests/Diagnostics/Lines.qlref new file mode 100644 index 00000000000..0b62ca77ec6 --- /dev/null +++ b/cpp/ql/test/query-tests/Diagnostics/Lines.qlref @@ -0,0 +1 @@ +Diagnostics/Lines.ql diff --git a/cpp/ql/test/query-tests/Diagnostics/LinesOfCode.expected b/cpp/ql/test/query-tests/Diagnostics/LinesOfCode.expected new file mode 100644 index 00000000000..a75c288c151 --- /dev/null +++ b/cpp/ql/test/query-tests/Diagnostics/LinesOfCode.expected @@ -0,0 +1 @@ +| 93 | diff --git a/cpp/ql/test/query-tests/Diagnostics/LinesOfCode.qlref b/cpp/ql/test/query-tests/Diagnostics/LinesOfCode.qlref new file mode 100644 index 00000000000..b07f3413688 --- /dev/null +++ b/cpp/ql/test/query-tests/Diagnostics/LinesOfCode.qlref @@ -0,0 +1 @@ +Diagnostics/LinesOfCode.ql \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Diagnostics/LinesOfCodePerFile.expected b/cpp/ql/test/query-tests/Diagnostics/LinesOfCodePerFile.expected new file mode 100644 index 00000000000..076ee4121a4 --- /dev/null +++ b/cpp/ql/test/query-tests/Diagnostics/LinesOfCodePerFile.expected @@ -0,0 +1,3 @@ +| empty-file.cpp:0:0:0:0 | empty-file.cpp | 0 | +| large-file.cpp:0:0:0:0 | large-file.cpp | 90 | +| short-file.cpp:0:0:0:0 | short-file.cpp | 3 | diff --git a/cpp/ql/test/query-tests/Diagnostics/LinesOfCodePerFile.qlref b/cpp/ql/test/query-tests/Diagnostics/LinesOfCodePerFile.qlref new file mode 100644 index 00000000000..ea50143078c --- /dev/null +++ b/cpp/ql/test/query-tests/Diagnostics/LinesOfCodePerFile.qlref @@ -0,0 +1 @@ +Diagnostics/LinesOfCodePerFile.ql \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Diagnostics/LinesPerFile.expected b/cpp/ql/test/query-tests/Diagnostics/LinesPerFile.expected new file mode 100644 index 00000000000..e02d0591ab2 --- /dev/null +++ b/cpp/ql/test/query-tests/Diagnostics/LinesPerFile.expected @@ -0,0 +1,3 @@ +| empty-file.cpp:0:0:0:0 | empty-file.cpp | 0 | +| large-file.cpp:0:0:0:0 | large-file.cpp | 119 | +| short-file.cpp:0:0:0:0 | short-file.cpp | 3 | diff --git a/cpp/ql/test/query-tests/Diagnostics/LinesPerFile.qlref b/cpp/ql/test/query-tests/Diagnostics/LinesPerFile.qlref new file mode 100644 index 00000000000..768a83875e6 --- /dev/null +++ b/cpp/ql/test/query-tests/Diagnostics/LinesPerFile.qlref @@ -0,0 +1 @@ +Diagnostics/LinesPerFile.ql \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Diagnostics/empty-file.cpp b/cpp/ql/test/query-tests/Diagnostics/empty-file.cpp new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cpp/ql/test/query-tests/Diagnostics/large-file.cpp b/cpp/ql/test/query-tests/Diagnostics/large-file.cpp new file mode 100644 index 00000000000..d6d06518b66 --- /dev/null +++ b/cpp/ql/test/query-tests/Diagnostics/large-file.cpp @@ -0,0 +1,119 @@ +int a00(float x) { + return (int)x; +} + +int a01(float x) { + return (int)x; +} + +int a02(float x) { + return (int)x; +} + +int a03(float x) { + return (int)x; +} + +int a04(float x) { + return (int)x; +} + +int a05(float x) { + return (int)x; +} + +int a06(float x) { + return (int)x; +} + +int a07(float x) { + return (int)x; +} + +int a08(float x) { + return (int)x; +} + +int a09(float x) { + return (int)x; +} + +int a10(float x) { + return (int)x; +} + +int a11(float x) { + return (int)x; +} + +int a12(float x) { + return (int)x; +} + +int a13(float x) { + return (int)x; +} + +int a14(float x) { + return (int)x; +} + +int a15(float x) { + return (int)x; +} + +int a16(float x) { + return (int)x; +} + +int a17(float x) { + return (int)x; +} + +int a18(float x) { + return (int)x; +} + +int a19(float x) { + return (int)x; +} + +int a20(float x) { + return (int)x; +} + +int a21(float x) { + return (int)x; +} + +int a22(float x) { + return (int)x; +} + +int a23(float x) { + return (int)x; +} + +int a24(float x) { + return (int)x; +} + +int a25(float x) { + return (int)x; +} + +int a26(float x) { + return (int)x; +} + +int a27(float x) { + return (int)x; +} + +int a28(float x) { + return (int)x; +} + +int a29(float x) { + return (int)x; +} diff --git a/cpp/ql/test/query-tests/Diagnostics/short-file.cpp b/cpp/ql/test/query-tests/Diagnostics/short-file.cpp new file mode 100644 index 00000000000..e4055360d37 --- /dev/null +++ b/cpp/ql/test/query-tests/Diagnostics/short-file.cpp @@ -0,0 +1,3 @@ +int g(float x) { + return (int)x; +} From f795d5e0d3b4f1a7fc5446755020786c3faecae1 Mon Sep 17 00:00:00 2001 From: haby0 Date: Sat, 27 Feb 2021 16:25:17 +0800 Subject: [PATCH 065/725] update JSONP Injection ql --- .../Security/CWE/CWE-352/JsonpInjection.ql | 45 +++++--- .../CWE/CWE-352/JsonpInjectionFilterLib.qll | 77 +++++++++++++ .../CWE/CWE-352/JsonpInjectionLib.qll | 65 ++++++++++- .../CWE/CWE-352/JsonpInjectionServlet.java | 60 ++++++++++ .../CWE/CWE-352/JsonpInjectionServlet1.java | 64 +++++++++++ .../CWE/CWE-352/JsonpInjectionServlet2.java | 50 +++++++++ .../semmle/code/java/frameworks/Servlets.qll | 27 +++++ .../security/CWE-352/JsonpInjection.expected | 106 +++++++++--------- .../security/CWE-352/JsonpInjection.java | 13 ++- .../core/annotation/AliasFor.class | Bin 385 -> 0 bytes .../web/bind/annotation/GetMapping.class | Bin 504 -> 0 bytes .../web/bind/annotation/RequestMapping.java | 2 + .../web/bind/annotation/RequestMethod.java | 15 +++ .../web/bind/annotation/ResponseBody.class | Bin 184 -> 0 bytes 14 files changed, 448 insertions(+), 76 deletions(-) create mode 100644 java/ql/src/Security/CWE/CWE-352/JsonpInjectionFilterLib.qll create mode 100644 java/ql/src/Security/CWE/CWE-352/JsonpInjectionServlet.java create mode 100644 java/ql/src/Security/CWE/CWE-352/JsonpInjectionServlet1.java create mode 100644 java/ql/src/Security/CWE/CWE-352/JsonpInjectionServlet2.java delete mode 100644 java/ql/test/stubs/spring-core-5.3.2/org/springframework/core/annotation/AliasFor.class delete mode 100644 java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/bind/annotation/GetMapping.class create mode 100644 java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/bind/annotation/RequestMethod.java delete mode 100644 java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/bind/annotation/ResponseBody.class diff --git a/java/ql/src/Security/CWE/CWE-352/JsonpInjection.ql b/java/ql/src/Security/CWE/CWE-352/JsonpInjection.ql index e7ca2d41e34..53ee6182511 100644 --- a/java/ql/src/Security/CWE/CWE-352/JsonpInjection.ql +++ b/java/ql/src/Security/CWE/CWE-352/JsonpInjection.ql @@ -1,55 +1,68 @@ /** - * @name JSON Hijacking + * @name JSONP Injection * @description User-controlled callback function names that are not verified are vulnerable - * to json hijacking attacks. + * to jsonp injection attacks. * @kind path-problem * @problem.severity error * @precision high - * @id java/Json-hijacking + * @id java/JSONP-Injection * @tags security * external/cwe/cwe-352 */ import java import JsonpInjectionLib +import JsonpInjectionFilterLib import semmle.code.java.dataflow.FlowSources import semmle.code.java.deadcode.WebEntryPoints import DataFlow::PathGraph -class VerifAuth extends DataFlow::BarrierGuard { - VerifAuth() { + +/** If there is a method to verify `token`, `auth`, `referer`, and `origin`, it will not pass. */ +class ServletVerifAuth extends DataFlow::BarrierGuard { + ServletVerifAuth() { exists(MethodAccess ma, Node prod, Node succ | - this = ma and - ma.getMethod().getName().regexpMatch("(?i).*(token|auth|referer).*") and + ma.getMethod().getName().regexpMatch("(?i).*(token|auth|referer|origin).*") and prod instanceof RemoteFlowSource and succ.asExpr() = ma.getAnArgument() and - ma.getMethod().getAParameter().getName().regexpMatch("(?i).*(token|auth|referer).*") and - localFlowStep*(prod, succ) + ma.getMethod().getAParameter().getName().regexpMatch("(?i).*(token|auth|referer|origin).*") and + localFlowStep*(prod, succ) and + this = ma ) } override predicate checks(Expr e, boolean branch) { - exists(ReturnStmt rs | - e = rs.getResult() and + exists(Node node | + node instanceof JsonpInjectionSink and + e = node.asExpr() and branch = true ) } } -/** Taint-tracking configuration tracing flow from remote sources to output jsonp data. */ +/** Taint-tracking configuration tracing flow from get method request sources to output jsonp data. */ class JsonpInjectionConfig extends TaintTracking::Configuration { JsonpInjectionConfig() { this = "JsonpInjectionConfig" } - override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } + override predicate isSource(DataFlow::Node source) { source instanceof GetHttpRequestSource } override predicate isSink(DataFlow::Node sink) { sink instanceof JsonpInjectionSink } - override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { guard instanceof VerifAuth } + override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { + guard instanceof ServletVerifAuth + } + + override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { + exists(MethodAccess ma | + isRequestGetParamMethod(ma) and pred.asExpr() = ma.getQualifier() and succ.asExpr() = ma + ) + } } from DataFlow::PathNode source, DataFlow::PathNode sink, JsonpInjectionConfig conf where + not checks() = false and conf.hasFlowPath(source, sink) and exists(JsonpInjectionFlowConfig jhfc | jhfc.hasFlowTo(sink.getNode())) -select sink.getNode(), source, sink, "Json Hijacking query might include code from $@.", - source.getNode(), "this user input" \ No newline at end of file +select sink.getNode(), source, sink, "Jsonp Injection query might include code from $@.", + source.getNode(), "this user input" diff --git a/java/ql/src/Security/CWE/CWE-352/JsonpInjectionFilterLib.qll b/java/ql/src/Security/CWE/CWE-352/JsonpInjectionFilterLib.qll new file mode 100644 index 00000000000..b349bed2641 --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-352/JsonpInjectionFilterLib.qll @@ -0,0 +1,77 @@ +/** + * @name JSONP Injection + * @description User-controlled callback function names that are not verified are vulnerable + * to json hijacking attacks. + * @kind path-problem + */ + +import java +import DataFlow +import semmle.code.java.dataflow.FlowSources +import semmle.code.java.dataflow.TaintTracking2 +import DataFlow::PathGraph + +class FilterVerifAuth extends DataFlow::BarrierGuard { + FilterVerifAuth() { + exists(MethodAccess ma, Node prod, Node succ | + ma.getMethod().getName().regexpMatch("(?i).*(token|auth|referer|origin).*") and + prod instanceof RemoteFlowSource and + succ.asExpr() = ma.getAnArgument() and + ma.getMethod().getAParameter().getName().regexpMatch("(?i).*(token|auth|referer|origin).*") and + localFlowStep*(prod, succ) and + this = ma + ) + } + + override predicate checks(Expr e, boolean branch) { + exists(Node node | + node instanceof DoFilterMethodSink and + e = node.asExpr() and + branch = true + ) + } +} + +/** A data flow source for `Filter.doFilter` method paramters. */ +private class DoFilterMethodSource extends DataFlow::Node { + DoFilterMethodSource() { + exists(Method m | + isDoFilterMethod(m) and + m.getAParameter().getAnAccess() = this.asExpr() + ) + } +} + +/** A data flow sink for `FilterChain.doFilter` method qualifying expression. */ +private class DoFilterMethodSink extends DataFlow::Node { + DoFilterMethodSink() { + exists(MethodAccess ma, Method m | ma.getMethod() = m | + m.hasName("doFilter") and + m.getDeclaringType*().hasQualifiedName("javax.servlet", "FilterChain") and + ma.getQualifier() = this.asExpr() + ) + } +} + +/** Taint-tracking configuration tracing flow from `doFilter` method paramter source to output + * `FilterChain.doFilter` method qualifying expression. + * */ +class DoFilterMethodConfig extends TaintTracking::Configuration { + DoFilterMethodConfig() { this = "DoFilterMethodConfig" } + + override predicate isSource(DataFlow::Node source) { source instanceof DoFilterMethodSource } + + override predicate isSink(DataFlow::Node sink) { sink instanceof DoFilterMethodSink } + + override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { + guard instanceof FilterVerifAuth + } +} + +/** Implement class modeling verification for `Filter.doFilter`, return false if it fails. */ +boolean checks() { + exists(DataFlow::PathNode source, DataFlow::PathNode sink, DoFilterMethodConfig conf | + conf.hasFlowPath(source, sink) and + result = false + ) +} diff --git a/java/ql/src/Security/CWE/CWE-352/JsonpInjectionLib.qll b/java/ql/src/Security/CWE/CWE-352/JsonpInjectionLib.qll index 4294a5e8c8f..3f730425823 100644 --- a/java/ql/src/Security/CWE/CWE-352/JsonpInjectionLib.qll +++ b/java/ql/src/Security/CWE/CWE-352/JsonpInjectionLib.qll @@ -5,6 +5,69 @@ import semmle.code.java.dataflow.DataFlow import semmle.code.java.dataflow.FlowSources import semmle.code.java.frameworks.spring.SpringController +/** Holds if `m` is a method of some override of `HttpServlet.doGet`. */ +private predicate isGetServletMethod(Method m) { + isServletRequestMethod(m) and m.getName() = "doGet" +} + +/** Holds if `m` is a method of some override of `HttpServlet.doGet`. */ +private predicate isGetSpringControllerMethod(Method m) { + exists(Annotation a | + a = m.getAnAnnotation() and + a.getType().hasQualifiedName("org.springframework.web.bind.annotation", "GetMapping") + ) + or + exists(Annotation a | + a = m.getAnAnnotation() and + a.getType().hasQualifiedName("org.springframework.web.bind.annotation", "RequestMapping") and + a.getValue("method").toString().regexpMatch("RequestMethod.GET|\\{...\\}") + ) +} + +/** Method parameters use the annotation `@RequestParam` or the parameter type is `ServletRequest`, `String`, `Object` */ +predicate checkSpringMethodParameterType(Method m, int i) { + m.getParameter(i).getType() instanceof ServletRequest + or + exists(Parameter p | + p = m.getParameter(i) and + p.hasAnnotation() and + p.getAnAnnotation() + .getType() + .hasQualifiedName("org.springframework.web.bind.annotation", "RequestParam") and + p.getType().getName().regexpMatch("String|Object") + ) + or + exists(Parameter p | + p = m.getParameter(i) and + not p.hasAnnotation() and + p.getType().getName().regexpMatch("String|Object") + ) +} + +/** A data flow source for get method request parameters. */ +abstract class GetHttpRequestSource extends DataFlow::Node { } + +/** A data flow source for servlet get method request parameters. */ +private class ServletGetHttpRequestSource extends GetHttpRequestSource { + ServletGetHttpRequestSource() { + exists(Method m | + isGetServletMethod(m) and + m.getParameter(0).getAnAccess() = this.asExpr() + ) + } +} + +/** A data flow source for spring controller get method request parameters. */ +private class SpringGetHttpRequestSource extends GetHttpRequestSource { + SpringGetHttpRequestSource() { + exists(SpringControllerMethod scm, int i | + isGetSpringControllerMethod(scm) and + checkSpringMethodParameterType(scm, i) and + scm.getParameter(i).getAnAccess() = this.asExpr() + ) + } +} + /** A data flow sink for unvalidated user input that is used to jsonp. */ abstract class JsonpInjectionSink extends DataFlow::Node { } @@ -26,7 +89,7 @@ private class WriterPrintln extends JsonpInjectionSink { private class SpringReturn extends JsonpInjectionSink { SpringReturn() { exists(ReturnStmt rs, Method m | m = rs.getEnclosingCallable() | - m instanceof SpringRequestMappingMethod and + isGetSpringControllerMethod(m) and rs.getResult() = this.asExpr() ) } diff --git a/java/ql/src/Security/CWE/CWE-352/JsonpInjectionServlet.java b/java/ql/src/Security/CWE/CWE-352/JsonpInjectionServlet.java new file mode 100644 index 00000000000..916cd9bf676 --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-352/JsonpInjectionServlet.java @@ -0,0 +1,60 @@ +import com.google.gson.Gson; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashMap; +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class JsonpInjectionServlet extends HttpServlet { + + private static HashMap hashMap = new HashMap(); + + static { + hashMap.put("username","admin"); + hashMap.put("password","123456"); + } + + private static final long serialVersionUID = 1L; + + private String key = "test"; + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String jsonpCallback = req.getParameter("jsonpCallback"); + + PrintWriter pw = null; + Gson gson = new Gson(); + String result = gson.toJson(hashMap); + + String resultStr = null; + pw = resp.getWriter(); + resultStr = jsonpCallback + "(" + result + ")"; + pw.println(resultStr); + pw.flush(); + } + + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String jsonpCallback = req.getParameter("jsonpCallback"); + PrintWriter pw = null; + Gson gson = new Gson(); + String result = gson.toJson(hashMap); + + String resultStr = null; + pw = resp.getWriter(); + resultStr = jsonpCallback + "(" + result + ")"; + pw.println(resultStr); + pw.flush(); + } + + @Override + public void init(ServletConfig config) throws ServletException { + this.key = config.getInitParameter("key"); + System.out.println("初始化" + this.key); + super.init(config); + } + +} diff --git a/java/ql/src/Security/CWE/CWE-352/JsonpInjectionServlet1.java b/java/ql/src/Security/CWE/CWE-352/JsonpInjectionServlet1.java new file mode 100644 index 00000000000..14ef76275b1 --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-352/JsonpInjectionServlet1.java @@ -0,0 +1,64 @@ +import com.google.gson.Gson; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashMap; +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class JsonpInjectionServlet1 extends HttpServlet { + + private static HashMap hashMap = new HashMap(); + + static { + hashMap.put("username","admin"); + hashMap.put("password","123456"); + } + + private static final long serialVersionUID = 1L; + + private String key = "test"; + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + doPost(req, resp); + } + + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + resp.setContentType("application/json"); + String jsonpCallback = req.getParameter("jsonpCallback"); + PrintWriter pw = null; + Gson gson = new Gson(); + String jsonResult = gson.toJson(hashMap); + + String referer = req.getHeader("Referer"); + + boolean result = verifReferer(referer); + + // good + if (result){ + String resultStr = null; + pw = resp.getWriter(); + resultStr = jsonpCallback + "(" + jsonResult + ")"; + pw.println(resultStr); + pw.flush(); + } + } + + public static boolean verifReferer(String referer){ + if (!referer.startsWith("http://test.com/")){ + return false; + } + return true; + } + + @Override + public void init(ServletConfig config) throws ServletException { + this.key = config.getInitParameter("key"); + System.out.println("初始化" + this.key); + super.init(config); + } + +} diff --git a/java/ql/src/Security/CWE/CWE-352/JsonpInjectionServlet2.java b/java/ql/src/Security/CWE/CWE-352/JsonpInjectionServlet2.java new file mode 100644 index 00000000000..bbfbc2dc436 --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-352/JsonpInjectionServlet2.java @@ -0,0 +1,50 @@ +import com.google.gson.Gson; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashMap; +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class JsonpInjectionServlet2 extends HttpServlet { + + private static HashMap hashMap = new HashMap(); + + static { + hashMap.put("username","admin"); + hashMap.put("password","123456"); + } + + private static final long serialVersionUID = 1L; + + private String key = "test"; + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + doPost(req, resp); + } + + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + resp.setContentType("application/json"); + String jsonpCallback = req.getParameter("jsonpCallback"); + PrintWriter pw = null; + Gson gson = new Gson(); + String result = gson.toJson(hashMap); + + String resultStr = null; + pw = resp.getWriter(); + resultStr = jsonpCallback + "(" + result + ")"; + pw.println(resultStr); + pw.flush(); + } + + @Override + public void init(ServletConfig config) throws ServletException { + this.key = config.getInitParameter("key"); + System.out.println("初始化" + this.key); + super.init(config); + } + +} diff --git a/java/ql/src/semmle/code/java/frameworks/Servlets.qll b/java/ql/src/semmle/code/java/frameworks/Servlets.qll index 3fad8c4e18b..b2054dc30cb 100644 --- a/java/ql/src/semmle/code/java/frameworks/Servlets.qll +++ b/java/ql/src/semmle/code/java/frameworks/Servlets.qll @@ -337,3 +337,30 @@ predicate isRequestGetParamMethod(MethodAccess ma) { ma.getMethod() instanceof ServletRequestGetParameterMapMethod or ma.getMethod() instanceof HttpServletRequestGetQueryStringMethod } + + +/** + * A class that has `javax.servlet.Filter` as an ancestor. + */ +class FilterClass extends Class { + FilterClass() { getAnAncestor().hasQualifiedName("javax.servlet", "Filter") } +} + + +/** + * The interface `javax.servlet.FilterChain` + */ +class FilterChain extends RefType { + FilterChain() { + hasQualifiedName("javax.servlet", "FilterChain") + } +} + +/** Holds if `m` is a request handler method (for example `doGet` or `doPost`). */ +predicate isDoFilterMethod(Method m) { + m.getDeclaringType() instanceof FilterClass and + m.getNumberOfParameters() = 3 and + m.getParameter(0).getType() instanceof ServletRequest and + m.getParameter(1).getType() instanceof ServletResponse and + m.getParameter(2).getType() instanceof FilterChain +} \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection.expected b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection.expected index 019af8f5c05..7e3069cf1d9 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection.expected @@ -1,60 +1,60 @@ edges -| JsonpInjection.java:28:32:28:68 | getParameter(...) : String | JsonpInjection.java:33:16:33:24 | resultStr | -| JsonpInjection.java:32:21:32:54 | ... + ... : String | JsonpInjection.java:33:16:33:24 | resultStr | -| JsonpInjection.java:40:32:40:68 | getParameter(...) : String | JsonpInjection.java:44:16:44:24 | resultStr | -| JsonpInjection.java:42:21:42:80 | ... + ... : String | JsonpInjection.java:44:16:44:24 | resultStr | -| JsonpInjection.java:51:32:51:68 | getParameter(...) : String | JsonpInjection.java:54:16:54:24 | resultStr | -| JsonpInjection.java:53:21:53:55 | ... + ... : String | JsonpInjection.java:54:16:54:24 | resultStr | -| JsonpInjection.java:61:32:61:68 | getParameter(...) : String | JsonpInjection.java:64:16:64:24 | resultStr | -| JsonpInjection.java:63:21:63:54 | ... + ... : String | JsonpInjection.java:64:16:64:24 | resultStr | -| JsonpInjection.java:72:32:72:68 | getParameter(...) : String | JsonpInjection.java:80:20:80:28 | resultStr | +| JsonpInjection.java:29:32:29:38 | request : HttpServletRequest | JsonpInjection.java:34:16:34:24 | resultStr | +| JsonpInjection.java:33:21:33:54 | ... + ... : String | JsonpInjection.java:34:16:34:24 | resultStr | +| JsonpInjection.java:41:32:41:38 | request : HttpServletRequest | JsonpInjection.java:45:16:45:24 | resultStr | +| JsonpInjection.java:43:21:43:80 | ... + ... : String | JsonpInjection.java:45:16:45:24 | resultStr | +| JsonpInjection.java:52:32:52:38 | request : HttpServletRequest | JsonpInjection.java:55:16:55:24 | resultStr | +| JsonpInjection.java:54:21:54:55 | ... + ... : String | JsonpInjection.java:55:16:55:24 | resultStr | +| JsonpInjection.java:62:32:62:38 | request : HttpServletRequest | JsonpInjection.java:65:16:65:24 | resultStr | +| JsonpInjection.java:64:21:64:54 | ... + ... : String | JsonpInjection.java:65:16:65:24 | resultStr | +| JsonpInjection.java:72:32:72:38 | request : HttpServletRequest | JsonpInjection.java:80:20:80:28 | resultStr | | JsonpInjection.java:79:21:79:54 | ... + ... : String | JsonpInjection.java:80:20:80:28 | resultStr | -| JsonpInjection.java:88:32:88:68 | getParameter(...) : String | JsonpInjection.java:95:20:95:28 | resultStr | -| JsonpInjection.java:94:21:94:54 | ... + ... : String | JsonpInjection.java:95:20:95:28 | resultStr | -| JsonpInjection.java:102:32:102:68 | getParameter(...) : String | JsonpInjection.java:113:16:113:24 | resultStr | -| JsonpInjection.java:128:25:128:59 | ... + ... : String | JsonpInjection.java:129:20:129:28 | resultStr | -| JsonpInjection.java:147:25:147:59 | ... + ... : String | JsonpInjection.java:148:20:148:28 | resultStr | +| JsonpInjection.java:87:32:87:38 | request : HttpServletRequest | JsonpInjection.java:94:20:94:28 | resultStr | +| JsonpInjection.java:93:21:93:54 | ... + ... : String | JsonpInjection.java:94:20:94:28 | resultStr | +| JsonpInjection.java:101:32:101:38 | request : HttpServletRequest | JsonpInjection.java:112:16:112:24 | resultStr | +| JsonpInjection.java:127:25:127:59 | ... + ... : String | JsonpInjection.java:128:20:128:28 | resultStr | +| JsonpInjection.java:148:25:148:59 | ... + ... : String | JsonpInjection.java:149:20:149:28 | resultStr | nodes -| JsonpInjection.java:28:32:28:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpInjection.java:32:21:32:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpInjection.java:33:16:33:24 | resultStr | semmle.label | resultStr | -| JsonpInjection.java:33:16:33:24 | resultStr | semmle.label | resultStr | -| JsonpInjection.java:40:32:40:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpInjection.java:42:21:42:80 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpInjection.java:44:16:44:24 | resultStr | semmle.label | resultStr | -| JsonpInjection.java:44:16:44:24 | resultStr | semmle.label | resultStr | -| JsonpInjection.java:51:32:51:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpInjection.java:53:21:53:55 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpInjection.java:54:16:54:24 | resultStr | semmle.label | resultStr | -| JsonpInjection.java:54:16:54:24 | resultStr | semmle.label | resultStr | -| JsonpInjection.java:61:32:61:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpInjection.java:63:21:63:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpInjection.java:64:16:64:24 | resultStr | semmle.label | resultStr | -| JsonpInjection.java:64:16:64:24 | resultStr | semmle.label | resultStr | -| JsonpInjection.java:72:32:72:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpInjection.java:29:32:29:38 | request : HttpServletRequest | semmle.label | request : HttpServletRequest | +| JsonpInjection.java:33:21:33:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpInjection.java:34:16:34:24 | resultStr | semmle.label | resultStr | +| JsonpInjection.java:34:16:34:24 | resultStr | semmle.label | resultStr | +| JsonpInjection.java:41:32:41:38 | request : HttpServletRequest | semmle.label | request : HttpServletRequest | +| JsonpInjection.java:43:21:43:80 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpInjection.java:45:16:45:24 | resultStr | semmle.label | resultStr | +| JsonpInjection.java:45:16:45:24 | resultStr | semmle.label | resultStr | +| JsonpInjection.java:52:32:52:38 | request : HttpServletRequest | semmle.label | request : HttpServletRequest | +| JsonpInjection.java:54:21:54:55 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpInjection.java:55:16:55:24 | resultStr | semmle.label | resultStr | +| JsonpInjection.java:55:16:55:24 | resultStr | semmle.label | resultStr | +| JsonpInjection.java:62:32:62:38 | request : HttpServletRequest | semmle.label | request : HttpServletRequest | +| JsonpInjection.java:64:21:64:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpInjection.java:65:16:65:24 | resultStr | semmle.label | resultStr | +| JsonpInjection.java:65:16:65:24 | resultStr | semmle.label | resultStr | +| JsonpInjection.java:72:32:72:38 | request : HttpServletRequest | semmle.label | request : HttpServletRequest | | JsonpInjection.java:79:21:79:54 | ... + ... : String | semmle.label | ... + ... : String | | JsonpInjection.java:80:20:80:28 | resultStr | semmle.label | resultStr | | JsonpInjection.java:80:20:80:28 | resultStr | semmle.label | resultStr | -| JsonpInjection.java:88:32:88:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpInjection.java:94:21:94:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpInjection.java:95:20:95:28 | resultStr | semmle.label | resultStr | -| JsonpInjection.java:95:20:95:28 | resultStr | semmle.label | resultStr | -| JsonpInjection.java:102:32:102:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpInjection.java:113:16:113:24 | resultStr | semmle.label | resultStr | -| JsonpInjection.java:128:25:128:59 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpInjection.java:129:20:129:28 | resultStr | semmle.label | resultStr | -| JsonpInjection.java:147:25:147:59 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpInjection.java:148:20:148:28 | resultStr | semmle.label | resultStr | +| JsonpInjection.java:87:32:87:38 | request : HttpServletRequest | semmle.label | request : HttpServletRequest | +| JsonpInjection.java:93:21:93:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpInjection.java:94:20:94:28 | resultStr | semmle.label | resultStr | +| JsonpInjection.java:94:20:94:28 | resultStr | semmle.label | resultStr | +| JsonpInjection.java:101:32:101:38 | request : HttpServletRequest | semmle.label | request : HttpServletRequest | +| JsonpInjection.java:112:16:112:24 | resultStr | semmle.label | resultStr | +| JsonpInjection.java:127:25:127:59 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpInjection.java:128:20:128:28 | resultStr | semmle.label | resultStr | +| JsonpInjection.java:148:25:148:59 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpInjection.java:149:20:149:28 | resultStr | semmle.label | resultStr | #select -| JsonpInjection.java:33:16:33:24 | resultStr | JsonpInjection.java:28:32:28:68 | getParameter(...) : String | JsonpInjection.java:33:16:33:24 | resultStr | Json Hijacking query -might include code from $@. | JsonpInjection.java:28:32:28:68 | getParameter(...) | this user input | -| JsonpInjection.java:44:16:44:24 | resultStr | JsonpInjection.java:40:32:40:68 | getParameter(...) : String | JsonpInjection.java:44:16:44:24 | resultStr | Json Hijacking query -might include code from $@. | JsonpInjection.java:40:32:40:68 | getParameter(...) | this user input | -| JsonpInjection.java:54:16:54:24 | resultStr | JsonpInjection.java:51:32:51:68 | getParameter(...) : String | JsonpInjection.java:54:16:54:24 | resultStr | Json Hijacking query -might include code from $@. | JsonpInjection.java:51:32:51:68 | getParameter(...) | this user input | -| JsonpInjection.java:64:16:64:24 | resultStr | JsonpInjection.java:61:32:61:68 | getParameter(...) : String | JsonpInjection.java:64:16:64:24 | resultStr | Json Hijacking query -might include code from $@. | JsonpInjection.java:61:32:61:68 | getParameter(...) | this user input | -| JsonpInjection.java:80:20:80:28 | resultStr | JsonpInjection.java:72:32:72:68 | getParameter(...) : String | JsonpInjection.java:80:20:80:28 | resultStr | Json Hijacking query -might include code from $@. | JsonpInjection.java:72:32:72:68 | getParameter(...) | this user input | -| JsonpInjection.java:95:20:95:28 | resultStr | JsonpInjection.java:88:32:88:68 | getParameter(...) : String | JsonpInjection.java:95:20:95:28 | resultStr | Json Hijacking query -might include code from $@. | JsonpInjection.java:88:32:88:68 | getParameter(...) | this user input | \ No newline at end of file +| JsonpInjection.java:34:16:34:24 | resultStr | JsonpInjection.java:29:32:29:38 | request : HttpServletRequest | JsonpInjection.java:34:16:34:24 | +resultStr | Jsonp Injection query might include code from $@. | JsonpInjection.java:29:32:29:38 | request | this user input | +| JsonpInjection.java:45:16:45:24 | resultStr | JsonpInjection.java:41:32:41:38 | request : HttpServletRequest | JsonpInjection.java:45:16:45:24 | +resultStr | Jsonp Injection query might include code from $@. | JsonpInjection.java:41:32:41:38 | request | this user input | +| JsonpInjection.java:55:16:55:24 | resultStr | JsonpInjection.java:52:32:52:38 | request : HttpServletRequest | JsonpInjection.java:55:16:55:24 | +resultStr | Jsonp Injection query might include code from $@. | JsonpInjection.java:52:32:52:38 | request | this user input | +| JsonpInjection.java:65:16:65:24 | resultStr | JsonpInjection.java:62:32:62:38 | request : HttpServletRequest | JsonpInjection.java:65:16:65:24 | +resultStr | Jsonp Injection query might include code from $@. | JsonpInjection.java:62:32:62:38 | request | this user input | +| JsonpInjection.java:80:20:80:28 | resultStr | JsonpInjection.java:72:32:72:38 | request : HttpServletRequest | JsonpInjection.java:80:20:80:28 | +resultStr | Jsonp Injection query might include code from $@. | JsonpInjection.java:72:32:72:38 | request | this user input | +| JsonpInjection.java:94:20:94:28 | resultStr | JsonpInjection.java:87:32:87:38 | request : HttpServletRequest | JsonpInjection.java:94:20:94:28 | +resultStr | Jsonp Injection query might include code from $@. | JsonpInjection.java:87:32:87:38 | request | this user input | \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection.java b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection.java index df3aa2c02fe..9f079513a8b 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection.java +++ b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection.java @@ -8,11 +8,12 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class JsonpInjection { - private static HashMap hashMap = new HashMap(); static { @@ -21,7 +22,7 @@ public class JsonpInjection { } - @GetMapping(value = "jsonp1") + @GetMapping(value = "jsonp1", produces="text/javascript") @ResponseBody public String bad1(HttpServletRequest request) { String resultStr = null; @@ -68,7 +69,6 @@ public class JsonpInjection { @ResponseBody public void bad5(HttpServletRequest request, HttpServletResponse response) throws Exception { - response.setContentType("application/json"); String jsonpCallback = request.getParameter("jsonpCallback"); PrintWriter pw = null; Gson gson = new Gson(); @@ -84,7 +84,6 @@ public class JsonpInjection { @ResponseBody public void bad6(HttpServletRequest request, HttpServletResponse response) throws Exception { - response.setContentType("application/json"); String jsonpCallback = request.getParameter("jsonpCallback"); PrintWriter pw = null; ObjectMapper mapper = new ObjectMapper(); @@ -141,8 +140,10 @@ public class JsonpInjection { String referer = request.getHeader("Referer"); boolean result = verifReferer(referer); + + boolean test = result; // good - if (result){ + if (test){ String jsonStr = getJsonStr(hashMap); resultStr = jsonpCallback + "(" + jsonStr + ")"; return resultStr; @@ -168,4 +169,4 @@ public class JsonpInjection { } return true; } -} +} \ No newline at end of file diff --git a/java/ql/test/stubs/spring-core-5.3.2/org/springframework/core/annotation/AliasFor.class b/java/ql/test/stubs/spring-core-5.3.2/org/springframework/core/annotation/AliasFor.class deleted file mode 100644 index 438065489278b92503abc2ad8d75716c5e56ac08..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 385 zcmb7=!Ab)$5QhJ0x31kDdrH&Kx0=)qG#3PM4!PcXZrOKO@(l3m};gAd?CiL-}x zJqaEL=Fj~6^G&|KKRyB6W0qr@<21(^Vbrp1G~wdrcD3b}m1S3}bqdDS4}|lDb3So0 z-aYCKH#QMKxO{0`GCTd`S`$rab#IG=`O1e{#kVeF6L_cJeRx%s4_fgdPA#nAxb#7` zj5*1|vPl9`tbG$Iy);(DbZ?q>Y=pc21QTZcMbG6{R|0?4KmBGoU|o}(H;@|2R}C^k ghLPwaQNxHF$I?t>JeJBL3UL&FIx;a%x-6Xh0OC_*bpQYW diff --git a/java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/bind/annotation/GetMapping.class b/java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/bind/annotation/GetMapping.class deleted file mode 100644 index 5392ca0ebc1593d6bfa2f7d765ee4ca169fb260f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 504 zcma)&y-ve06orr5G%4k$Ewlp@8)_FUu~3N#3Bgi?)JiO!oYW02i5(KVeK!UkfQLfd z3?&dTFj%_xlg>TI=i~G39l#Za0geNl1Q;-QTBMR;Fd9$SVk3AWbj;^AS316C=-+5< ztgy=HTe%W0u?%2nZA9WoH5`o>f62T|*k=Ym6S+tWhIV9h;Zj+SS#FjtD#y;;xIB_~ zDxp)|dubm;mXYs88HC|<=CoC*d{Tu96Imr8>11m1m={?Yb44Ckk!ycGS!yuAF9#FEVXJbh%nj0^%G u-TFC+dFlH8Nm;4MC5#O62q7eGj&Kvy7#SEDn1GlW=t>44%>pEu7+3+XjWw+R From 15a43ffe36e1a77eaf33ed17b3edbf6843dfc9df Mon Sep 17 00:00:00 2001 From: Artem Smotrakov Date: Sat, 27 Feb 2021 13:41:20 +0100 Subject: [PATCH 066/725] Simplified returnsRemoteInvocationSerializingExporter() --- .../SpringHttpInvokerUnsafeDeserialization.ql | 1 - .../SpringHttpInvokerUnsafeDeserialization.expected | 3 ++- .../SpringHttpInvokerUnsafeDeserialization.java | 12 ++++++++++-- .../rmi/RemoteInvocationSerializingExporter.java | 4 +--- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-502/SpringHttpInvokerUnsafeDeserialization.ql b/java/ql/src/experimental/Security/CWE/CWE-502/SpringHttpInvokerUnsafeDeserialization.ql index 73c67582692..df01ae478cc 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-502/SpringHttpInvokerUnsafeDeserialization.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-502/SpringHttpInvokerUnsafeDeserialization.ql @@ -30,7 +30,6 @@ private predicate isRemoteInvocationSerializingExporter(RefType type) { * Holds if `method` returns an object that extends `RemoteInvocationSerializingExporter`. */ private predicate returnsRemoteInvocationSerializingExporter(Method method) { - isRemoteInvocationSerializingExporter(method.getReturnType()) or isRemoteInvocationSerializingExporter(method.getReturnType().(RefType).getASupertype*()) } diff --git a/java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.expected b/java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.expected index 0ce0efca838..b76f3edc57e 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.expected @@ -1 +1,2 @@ -| SpringHttpInvokerUnsafeDeserialization.java:9:32:9:37 | unsafe | Unasafe deserialization in a remote service exporter in 'unsafe' method | +| SpringHttpInvokerUnsafeDeserialization.java:10:32:10:63 | unsafeHttpInvokerServiceExporter | Unasafe deserialization in a remote service exporter in 'unsafeHttpInvokerServiceExporter' method | +| SpringHttpInvokerUnsafeDeserialization.java:18:41:18:88 | unsafeCustomeRemoteInvocationSerializingExporter | Unasafe deserialization in a remote service exporter in 'unsafeCustomeRemoteInvocationSerializingExporter' method | diff --git a/java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.java b/java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.java index d678c8f0191..9d99aa1cbce 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.java +++ b/java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.java @@ -1,18 +1,24 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter; +import org.springframework.remoting.rmi.RemoteInvocationSerializingExporter; @Configuration public class SpringHttpInvokerUnsafeDeserialization { - @Bean(name = "/unsafe") - HttpInvokerServiceExporter unsafe() { + @Bean(name = "/unsafeHttpInvokerServiceExporter") + HttpInvokerServiceExporter unsafeHttpInvokerServiceExporter() { HttpInvokerServiceExporter exporter = new HttpInvokerServiceExporter(); exporter.setService(new AccountServiceImpl()); exporter.setServiceInterface(AccountService.class); return exporter; } + @Bean(name = "/unsafeCustomeRemoteInvocationSerializingExporter") + RemoteInvocationSerializingExporter unsafeCustomeRemoteInvocationSerializingExporter() { + return new CustomeRemoteInvocationSerializingExporter(); + } + HttpInvokerServiceExporter notABean() { HttpInvokerServiceExporter exporter = new HttpInvokerServiceExporter(); exporter.setService(new AccountServiceImpl()); @@ -21,6 +27,8 @@ public class SpringHttpInvokerUnsafeDeserialization { } } +class CustomeRemoteInvocationSerializingExporter extends RemoteInvocationSerializingExporter {} + class NotAConfiguration { @Bean(name = "/notAnEndpoint") diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/remoting/rmi/RemoteInvocationSerializingExporter.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/remoting/rmi/RemoteInvocationSerializingExporter.java index a6f6fec194f..5449b83ba86 100644 --- a/java/ql/test/stubs/springframework-5.2.3/org/springframework/remoting/rmi/RemoteInvocationSerializingExporter.java +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/remoting/rmi/RemoteInvocationSerializingExporter.java @@ -1,5 +1,3 @@ package org.springframework.remoting.rmi; -public abstract class RemoteInvocationSerializingExporter { - -} +public abstract class RemoteInvocationSerializingExporter {} From 95d1994196dc52ad516b7c6df06e673be8906d9b Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Mon, 1 Mar 2021 22:06:52 +0000 Subject: [PATCH 067/725] Query to check sensitive cookies without the HttpOnly flag set --- .../CWE-1004/SensitiveCookieNotHttpOnly.java | 44 +++ .../CWE-1004/SensitiveCookieNotHttpOnly.qhelp | 27 ++ .../CWE-1004/SensitiveCookieNotHttpOnly.ql | 194 ++++++++++ .../SensitiveCookieNotHttpOnly.expected | 13 + .../CWE-1004/SensitiveCookieNotHttpOnly.java | 57 +++ .../CWE-1004/SensitiveCookieNotHttpOnly.qlref | 1 + .../query-tests/security/CWE-1004/options | 1 + .../javax/ws/rs/core/Cookie.java | 187 +++++++++ .../javax/ws/rs/core/NewCookie.java | 359 ++++++++++++++++++ .../javax/servlet/http/Cookie.java | 33 ++ .../servlet/http/HttpServletResponse.java | 6 + 11 files changed, 922 insertions(+) create mode 100644 java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.java create mode 100644 java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql create mode 100644 java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.java create mode 100644 java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.qlref create mode 100644 java/ql/test/experimental/query-tests/security/CWE-1004/options create mode 100644 java/ql/test/stubs/jsr311-api-1.1.1/javax/ws/rs/core/Cookie.java create mode 100644 java/ql/test/stubs/jsr311-api-1.1.1/javax/ws/rs/core/NewCookie.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.java b/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.java new file mode 100644 index 00000000000..48d80707ff8 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.java @@ -0,0 +1,44 @@ +class SensitiveCookieNotHttpOnly { + // GOOD - Create a sensitive cookie with the `HttpOnly` flag set. + public void addCookie(String jwt_token, HttpServletRequest request, HttpServletResponse response) { + Cookie jwtCookie =new Cookie("jwt_token", jwt_token); + jwtCookie.setPath("/"); + jwtCookie.setMaxAge(3600*24*7); + jwtCookie.setHttpOnly(true); + response.addCookie(jwtCookie); + } + + // BAD - Create a sensitive cookie without the `HttpOnly` flag set. + public void addCookie2(String jwt_token, String userId, HttpServletRequest request, HttpServletResponse response) { + Cookie jwtCookie =new Cookie("jwt_token", jwt_token); + jwtCookie.setPath("/"); + jwtCookie.setMaxAge(3600*24*7); + response.addCookie(jwtCookie); + } + + // GOOD - Set a sensitive cookie header with the `HttpOnly` flag set. + public void addCookie3(String authId, HttpServletRequest request, HttpServletResponse response) { + response.addHeader("Set-Cookie", "token=" +authId + ";HttpOnly;Secure"); + } + + // BAD - Set a sensitive cookie header without the `HttpOnly` flag set. + public void addCookie4(String authId, HttpServletRequest request, HttpServletResponse response) { + response.addHeader("Set-Cookie", "token=" +authId + ";Secure"); + } + + // GOOD - Set a sensitive cookie header using the class `javax.ws.rs.core.Cookie` with the `HttpOnly` flag set through string concatenation. + public void addCookie5(String accessKey, HttpServletRequest request, HttpServletResponse response) { + response.setHeader("Set-Cookie", new NewCookie("session-access-key", accessKey, "/", null, null, 0, true) + ";HttpOnly"); + } + + // BAD - Set a sensitive cookie header using the class `javax.ws.rs.core.Cookie` without the `HttpOnly` flag set. + public void addCookie6(String accessKey, HttpServletRequest request, HttpServletResponse response) { + response.setHeader("Set-Cookie", new NewCookie("session-access-key", accessKey, "/", null, null, 0, true).toString()); + } + + // GOOD - Set a sensitive cookie header using the class `javax.ws.rs.core.Cookie` with the `HttpOnly` flag set through the constructor. + public void addCookie7(String accessKey, HttpServletRequest request, HttpServletResponse response) { + NewCookie accessKeyCookie = new NewCookie("session-access-key", accessKey, "/", null, null, 0, true, true); + response.setHeader("Set-Cookie", accessKeyCookie.toString()); + } +} diff --git a/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.qhelp b/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.qhelp new file mode 100644 index 00000000000..880ed767be9 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.qhelp @@ -0,0 +1,27 @@ + + + + +

    Cross-Site Scripting (XSS) is categorized as one of the OWASP Top 10 Security Vulnerabilities. The HttpOnly flag directs compatible browsers to prevent client-side script from accessing cookies. Including the HttpOnly flag in the Set-Cookie HTTP response header for a sensitive cookie helps mitigate the risk associated with XSS where an attacker's script code attempts to read the contents of a cookie and exfiltrate information obtained.

    +
    + + +

    Use the HttpOnly flag when generating a cookie containing sensitive information to help mitigate the risk of client side script accessing the protected cookie.

    +
    + + +

    The following example shows two ways of generating sensitive cookies. In the 'BAD' cases, the HttpOnly flag is not set. In the 'GOOD' cases, the HttpOnly flag is set.

    + +
    + + +
  • + PortSwigger: + Cookie without HttpOnly flag set +
  • +
  • + OWASP: + HttpOnly +
  • +
    +
    diff --git a/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql b/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql new file mode 100644 index 00000000000..bf4e60134c9 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql @@ -0,0 +1,194 @@ +/** + * @name Sensitive cookies without the HttpOnly response header set + * @description Sensitive cookies without 'HttpOnly' leaves session cookies vulnerable to an XSS attack. + * @kind path-problem + * @id java/sensitive-cookie-not-httponly + * @tags security + * external/cwe/cwe-1004 + */ + +import java +import semmle.code.java.frameworks.Servlets +import semmle.code.java.dataflow.FlowSources +import semmle.code.java.dataflow.TaintTracking +import DataFlow::PathGraph + +/** Gets a regular expression for matching common names of sensitive cookies. */ +string getSensitiveCookieNameRegex() { result = "(?i).*(auth|session|token|key|credential).*" } + +/** Holds if a string is concatenated with the name of a sensitive cookie. */ +predicate isSensitiveCookieNameExpr(Expr expr) { + expr.(StringLiteral) + .getRepresentedString() + .toLowerCase() + .regexpMatch(getSensitiveCookieNameRegex()) or + isSensitiveCookieNameExpr(expr.(AddExpr).getAnOperand()) +} + +/** Holds if a string is concatenated with the `HttpOnly` flag. */ +predicate hasHttpOnlyExpr(Expr expr) { + expr.(StringLiteral).getRepresentedString().toLowerCase().matches("%httponly%") or + hasHttpOnlyExpr(expr.(AddExpr).getAnOperand()) +} + +/** The method call `Set-Cookie` of `addHeader` or `setHeader`. */ +class SetCookieMethodAccess extends MethodAccess { + SetCookieMethodAccess() { + ( + this.getMethod() instanceof ResponseAddHeaderMethod or + this.getMethod() instanceof ResponseSetHeaderMethod + ) and + this.getArgument(0).(StringLiteral).getRepresentedString().toLowerCase() = "set-cookie" + } +} + +/** Sensitive cookie name used in a `Cookie` constructor or a `Set-Cookie` call. */ +class SensitiveCookieNameExpr extends Expr { + SensitiveCookieNameExpr() { + isSensitiveCookieNameExpr(this) and + ( + exists( + ClassInstanceExpr cie // new Cookie("jwt_token", token) + | + ( + cie.getConstructor().getDeclaringType().hasQualifiedName("javax.servlet.http", "Cookie") or + cie.getConstructor() + .getDeclaringType() + .getASupertype*() + .hasQualifiedName("javax.ws.rs.core", "Cookie") or + cie.getConstructor() + .getDeclaringType() + .getASupertype*() + .hasQualifiedName("jakarta.ws.rs.core", "Cookie") + ) and + DataFlow::localExprFlow(this, cie.getArgument(0)) + ) + or + exists( + SetCookieMethodAccess ma // response.addHeader("Set-Cookie: token=" +authId + ";HttpOnly;Secure") + | + DataFlow::localExprFlow(this, ma.getArgument(1)) + ) + ) + } +} + +/** Sink of adding a cookie to the HTTP response. */ +class CookieResponseSink extends DataFlow::ExprNode { + CookieResponseSink() { + exists(MethodAccess ma | + ( + ma.getMethod() instanceof ResponseAddCookieMethod or + ma instanceof SetCookieMethodAccess + ) and + ma.getAnArgument() = this.getExpr() + ) + } +} + +/** Holds if the `node` is a method call of `setHttpOnly(true)` on a cookie. */ +predicate setHttpOnlyMethodAccess(DataFlow::Node node) { + exists( + MethodAccess addCookie, Variable cookie, MethodAccess m // jwtCookie.setHttpOnly(true) + | + addCookie.getMethod() instanceof ResponseAddCookieMethod and + addCookie.getArgument(0) = cookie.getAnAccess() and + m.getMethod().getName() = "setHttpOnly" and + m.getArgument(0).(BooleanLiteral).getBooleanValue() = true and + m.getQualifier() = cookie.getAnAccess() and + node.asExpr() = cookie.getAnAccess() + ) +} + +/** Holds if the `node` is a method call of `Set-Cookie` header with the `HttpOnly` flag whose cookie name is sensitive. */ +predicate setHttpOnlyInSetCookie(DataFlow::Node node) { + exists(SetCookieMethodAccess sa | + hasHttpOnlyExpr(node.asExpr()) and + DataFlow::localExprFlow(node.asExpr(), sa.getArgument(1)) + ) +} + +/** Holds if the `node` is an invocation of a JAX-RS `NewCookie` constructor that sets `HttpOnly` to true. */ +predicate setHttpOnlyInNewCookie(DataFlow::Node node) { + exists(ClassInstanceExpr cie | + cie.getConstructor().getDeclaringType().hasName("NewCookie") and + DataFlow::localExprFlow(node.asExpr(), cie.getArgument(0)) and + ( + cie.getNumArgument() = 6 and cie.getArgument(5).(BooleanLiteral).getBooleanValue() = true // NewCookie(Cookie cookie, String comment, int maxAge, Date expiry, boolean secure, boolean httpOnly) + or + cie.getNumArgument() = 8 and + cie.getArgument(6).getType() instanceof BooleanType and + cie.getArgument(7).(BooleanLiteral).getBooleanValue() = true // NewCookie(String name, String value, String path, String domain, String comment, int maxAge, boolean secure, boolean httpOnly) + or + cie.getNumArgument() = 10 and cie.getArgument(9).(BooleanLiteral).getBooleanValue() = true // NewCookie(String name, String value, String path, String domain, int version, String comment, int maxAge, Date expiry, boolean secure, boolean httpOnly) + ) + ) +} + +/** + * Holds if the node is a test method indicated by: + * a) in a test directory such as `src/test/java` + * b) in a test package whose name has the word `test` + * c) in a test class whose name has the word `test` + * d) in a test class implementing a test framework such as JUnit or TestNG + */ +predicate isTestMethod(DataFlow::Node node) { + exists(MethodAccess ma, Method m | + node.asExpr() = ma.getAnArgument() and + m = ma.getEnclosingCallable() and + ( + m.getDeclaringType().getName().toLowerCase().matches("%test%") or // Simple check to exclude test classes to reduce FPs + m.getDeclaringType().getPackage().getName().toLowerCase().matches("%test%") or // Simple check to exclude classes in test packages to reduce FPs + exists(m.getLocation().getFile().getAbsolutePath().indexOf("/src/test/java")) or // Match test directory structure of build tools like maven + m instanceof TestMethod // Test method of a test case implementing a test framework such as JUnit or TestNG + ) + ) +} + +/** A taint configuration tracking flow from a sensitive cookie without HttpOnly flag set to its HTTP response. */ +class MissingHttpOnlyConfiguration extends TaintTracking::Configuration { + MissingHttpOnlyConfiguration() { this = "MissingHttpOnlyConfiguration" } + + override predicate isSource(DataFlow::Node source) { + source.asExpr() instanceof SensitiveCookieNameExpr + } + + override predicate isSink(DataFlow::Node sink) { sink instanceof CookieResponseSink } + + override predicate isSanitizer(DataFlow::Node node) { + // cookie.setHttpOnly(true) + setHttpOnlyMethodAccess(node) + or + // response.addHeader("Set-Cookie: token=" +authId + ";HttpOnly;Secure") + setHttpOnlyInSetCookie(node) + or + // new NewCookie("session-access-key", accessKey, "/", null, null, 0, true, true) + setHttpOnlyInNewCookie(node) + or + // Test class or method + isTestMethod(node) + } + + override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { + exists( + ClassInstanceExpr cie // `NewCookie` constructor + | + cie.getAnArgument() = pred.asExpr() and + cie = succ.asExpr() and + cie.getConstructor().getDeclaringType().hasName("NewCookie") + ) + or + exists( + MethodAccess ma // `toString` call on a cookie object + | + ma.getQualifier() = pred.asExpr() and + ma.getMethod().hasName("toString") and + ma = succ.asExpr() + ) + } +} + +from DataFlow::PathNode source, DataFlow::PathNode sink, MissingHttpOnlyConfiguration c +where c.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "$@ doesn't have the HttpOnly flag set.", source.getNode(), + "This sensitive cookie" diff --git a/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.expected b/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.expected new file mode 100644 index 00000000000..84d6be3863a --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.expected @@ -0,0 +1,13 @@ +edges +| SensitiveCookieNotHttpOnly.java:22:38:22:48 | "jwt_token" : String | SensitiveCookieNotHttpOnly.java:28:28:28:36 | jwtCookie | +| SensitiveCookieNotHttpOnly.java:49:56:49:75 | "session-access-key" : String | SensitiveCookieNotHttpOnly.java:49:42:49:124 | toString(...) | +nodes +| SensitiveCookieNotHttpOnly.java:22:38:22:48 | "jwt_token" : String | semmle.label | "jwt_token" : String | +| SensitiveCookieNotHttpOnly.java:28:28:28:36 | jwtCookie | semmle.label | jwtCookie | +| SensitiveCookieNotHttpOnly.java:39:42:39:69 | ... + ... | semmle.label | ... + ... | +| SensitiveCookieNotHttpOnly.java:49:42:49:124 | toString(...) | semmle.label | toString(...) | +| SensitiveCookieNotHttpOnly.java:49:56:49:75 | "session-access-key" : String | semmle.label | "session-access-key" : String | +#select +| SensitiveCookieNotHttpOnly.java:28:28:28:36 | jwtCookie | SensitiveCookieNotHttpOnly.java:22:38:22:48 | "jwt_token" : String | SensitiveCookieNotHttpOnly.java:28:28:28:36 | jwtCookie | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:22:38:22:48 | "jwt_token" | This sensitive cookie | +| SensitiveCookieNotHttpOnly.java:39:42:39:69 | ... + ... | SensitiveCookieNotHttpOnly.java:39:42:39:69 | ... + ... | SensitiveCookieNotHttpOnly.java:39:42:39:69 | ... + ... | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:39:42:39:69 | ... + ... | This sensitive cookie | +| SensitiveCookieNotHttpOnly.java:49:42:49:124 | toString(...) | SensitiveCookieNotHttpOnly.java:49:56:49:75 | "session-access-key" : String | SensitiveCookieNotHttpOnly.java:49:42:49:124 | toString(...) | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:49:56:49:75 | "session-access-key" | This sensitive cookie | diff --git a/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.java b/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.java new file mode 100644 index 00000000000..5e4f349f7c8 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.java @@ -0,0 +1,57 @@ +import java.io.IOException; + +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.ServletException; + +import javax.ws.rs.core.NewCookie; + +class SensitiveCookieNotHttpOnly { + // GOOD - Tests adding a sensitive cookie with the `HttpOnly` flag set. + public void addCookie(String jwt_token, HttpServletRequest request, HttpServletResponse response) { + Cookie jwtCookie =new Cookie("jwt_token", jwt_token); + jwtCookie.setPath("/"); + jwtCookie.setMaxAge(3600*24*7); + jwtCookie.setHttpOnly(true); + response.addCookie(jwtCookie); + } + + // BAD - Tests adding a sensitive cookie without the `HttpOnly` flag set. + public void addCookie2(String jwt_token, String userId, HttpServletRequest request, HttpServletResponse response) { + Cookie jwtCookie =new Cookie("jwt_token", jwt_token); + Cookie userIdCookie =new Cookie("user_id", userId.toString()); + jwtCookie.setPath("/"); + userIdCookie.setPath("/"); + jwtCookie.setMaxAge(3600*24*7); + userIdCookie.setMaxAge(3600*24*7); + response.addCookie(jwtCookie); + response.addCookie(userIdCookie); + } + + // GOOD - Tests set a sensitive cookie header with the `HttpOnly` flag set. + public void addCookie3(String authId, HttpServletRequest request, HttpServletResponse response) { + response.addHeader("Set-Cookie", "token=" +authId + ";HttpOnly;Secure"); + } + + // BAD - Tests set a sensitive cookie header without the `HttpOnly` flag set. + public void addCookie4(String authId, HttpServletRequest request, HttpServletResponse response) { + response.addHeader("Set-Cookie", "token=" +authId + ";Secure"); + } + + // GOOD - Tests set a sensitive cookie header using the class `javax.ws.rs.core.Cookie` with the `HttpOnly` flag set through string concatenation. + public void addCookie5(String accessKey, HttpServletRequest request, HttpServletResponse response) { + response.setHeader("Set-Cookie", new NewCookie("session-access-key", accessKey, "/", null, null, 0, true) + ";HttpOnly"); + } + + // BAD - Tests set a sensitive cookie header using the class `javax.ws.rs.core.Cookie` without the `HttpOnly` flag set. + public void addCookie6(String accessKey, HttpServletRequest request, HttpServletResponse response) { + response.setHeader("Set-Cookie", new NewCookie("session-access-key", accessKey, "/", null, null, 0, true).toString()); + } + + // GOOD - Tests set a sensitive cookie header using the class `javax.ws.rs.core.Cookie` with the `HttpOnly` flag set through the constructor. + public void addCookie7(String accessKey, HttpServletRequest request, HttpServletResponse response) { + NewCookie accessKeyCookie = new NewCookie("session-access-key", accessKey, "/", null, null, 0, true, true); + response.setHeader("Set-Cookie", accessKeyCookie.toString()); + } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.qlref b/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.qlref new file mode 100644 index 00000000000..cc2baaf6f7b --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-1004/options b/java/ql/test/experimental/query-tests/security/CWE-1004/options new file mode 100644 index 00000000000..7f2b253fb20 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-1004/options @@ -0,0 +1 @@ +// semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/jsr311-api-1.1.1 \ No newline at end of file diff --git a/java/ql/test/stubs/jsr311-api-1.1.1/javax/ws/rs/core/Cookie.java b/java/ql/test/stubs/jsr311-api-1.1.1/javax/ws/rs/core/Cookie.java new file mode 100644 index 00000000000..4e4c7585c35 --- /dev/null +++ b/java/ql/test/stubs/jsr311-api-1.1.1/javax/ws/rs/core/Cookie.java @@ -0,0 +1,187 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) 2010-2015 Oracle and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * http://glassfish.java.net/public/CDDL+GPL_1_1.html + * or packager/legal/LICENSE.txt. See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at packager/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * Oracle designates this particular file as subject to the "Classpath" + * exception as provided by Oracle in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ + +package javax.ws.rs.core; + +/** + * Represents the value of a HTTP cookie, transferred in a request. + * RFC 2109 specifies the legal characters for name, + * value, path and domain. The default version of 1 corresponds to RFC 2109. + * + * @author Paul Sandoz + * @author Marc Hadley + * @see IETF RFC 2109 + * @since 1.0 + */ +public class Cookie { + /** + * Cookies using the default version correspond to RFC 2109. + */ + public static final int DEFAULT_VERSION = 1; + + /** + * Create a new instance. + * + * @param name the name of the cookie. + * @param value the value of the cookie. + * @param path the URI path for which the cookie is valid. + * @param domain the host domain for which the cookie is valid. + * @param version the version of the specification to which the cookie complies. + * @throws IllegalArgumentException if name is {@code null}. + */ + public Cookie(final String name, final String value, final String path, final String domain, final int version) + throws IllegalArgumentException { + } + + /** + * Create a new instance. + * + * @param name the name of the cookie. + * @param value the value of the cookie. + * @param path the URI path for which the cookie is valid. + * @param domain the host domain for which the cookie is valid. + * @throws IllegalArgumentException if name is {@code null}. + */ + public Cookie(final String name, final String value, final String path, final String domain) + throws IllegalArgumentException { + } + + /** + * Create a new instance. + * + * @param name the name of the cookie. + * @param value the value of the cookie. + * @throws IllegalArgumentException if name is {@code null}. + */ + public Cookie(final String name, final String value) + throws IllegalArgumentException { + } + + /** + * Creates a new instance of {@code Cookie} by parsing the supplied string. + * + * @param value the cookie string. + * @return the newly created {@code Cookie}. + * @throws IllegalArgumentException if the supplied string cannot be parsed + * or is {@code null}. + */ + public static Cookie valueOf(final String value) { + return null; + } + + /** + * Get the name of the cookie. + * + * @return the cookie name. + */ + public String getName() { + return null; + } + + /** + * Get the value of the cookie. + * + * @return the cookie value. + */ + public String getValue() { + return null; + } + + /** + * Get the version of the cookie. + * + * @return the cookie version. + */ + public int getVersion() { + return -1; + } + + /** + * Get the domain of the cookie. + * + * @return the cookie domain. + */ + public String getDomain() { + return null; + } + + /** + * Get the path of the cookie. + * + * @return the cookie path. + */ + public String getPath() { + return null; + } + + /** + * Convert the cookie to a string suitable for use as the value of the + * corresponding HTTP header. + * + * @return a stringified cookie. + */ + @Override + public String toString() { + return null; + } + + /** + * Generate a hash code by hashing all of the cookies properties. + * + * @return the cookie hash code. + */ + @Override + public int hashCode() { + return -1; + } + + /** + * Compare for equality. + * + * @param obj the object to compare to. + * @return {@code true}, if the object is a {@code Cookie} with the same + * value for all properties, {@code false} otherwise. + */ + @SuppressWarnings({"StringEquality", "RedundantIfStatement"}) + @Override + public boolean equals(final Object obj) { + return true; + } +} \ No newline at end of file diff --git a/java/ql/test/stubs/jsr311-api-1.1.1/javax/ws/rs/core/NewCookie.java b/java/ql/test/stubs/jsr311-api-1.1.1/javax/ws/rs/core/NewCookie.java new file mode 100644 index 00000000000..43a4899e0ca --- /dev/null +++ b/java/ql/test/stubs/jsr311-api-1.1.1/javax/ws/rs/core/NewCookie.java @@ -0,0 +1,359 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) 2010-2015 Oracle and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * http://glassfish.java.net/public/CDDL+GPL_1_1.html + * or packager/legal/LICENSE.txt. See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at packager/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * Oracle designates this particular file as subject to the "Classpath" + * exception as provided by Oracle in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ + +package javax.ws.rs.core; + +import java.util.Date; + +/** + * Used to create a new HTTP cookie, transferred in a response. + * + * @author Paul Sandoz + * @author Marc Hadley + * @see IETF RFC 2109 + * @since 1.0 + */ +public class NewCookie extends Cookie { + + /** + * Specifies that the cookie expires with the current application/browser session. + */ + public static final int DEFAULT_MAX_AGE = -1; + + private final String comment; + private final int maxAge; + private final Date expiry; + private final boolean secure; + private final boolean httpOnly; + + /** + * Create a new instance. + * + * @param name the name of the cookie. + * @param value the value of the cookie. + * @throws IllegalArgumentException if name is {@code null}. + */ + public NewCookie(String name, String value) { + this(name, value, null, null, DEFAULT_VERSION, null, DEFAULT_MAX_AGE, null, false, false); + } + + /** + * Create a new instance. + * + * @param name the name of the cookie. + * @param value the value of the cookie. + * @param path the URI path for which the cookie is valid. + * @param domain the host domain for which the cookie is valid. + * @param comment the comment. + * @param maxAge the maximum age of the cookie in seconds. + * @param secure specifies whether the cookie will only be sent over a secure connection. + * @throws IllegalArgumentException if name is {@code null}. + */ + public NewCookie(String name, + String value, + String path, + String domain, + String comment, + int maxAge, + boolean secure) { + this(name, value, path, domain, DEFAULT_VERSION, comment, maxAge, null, secure, false); + } + + /** + * Create a new instance. + * + * @param name the name of the cookie. + * @param value the value of the cookie. + * @param path the URI path for which the cookie is valid. + * @param domain the host domain for which the cookie is valid. + * @param comment the comment. + * @param maxAge the maximum age of the cookie in seconds. + * @param secure specifies whether the cookie will only be sent over a secure connection. + * @param httpOnly if {@code true} make the cookie HTTP only, i.e. only visible as part of an HTTP request. + * @throws IllegalArgumentException if name is {@code null}. + * @since 2.0 + */ + public NewCookie(String name, + String value, + String path, + String domain, + String comment, + int maxAge, + boolean secure, + boolean httpOnly) { + this(name, value, path, domain, DEFAULT_VERSION, comment, maxAge, null, secure, httpOnly); + } + + /** + * Create a new instance. + * + * @param name the name of the cookie + * @param value the value of the cookie + * @param path the URI path for which the cookie is valid + * @param domain the host domain for which the cookie is valid + * @param version the version of the specification to which the cookie complies + * @param comment the comment + * @param maxAge the maximum age of the cookie in seconds + * @param secure specifies whether the cookie will only be sent over a secure connection + * @throws IllegalArgumentException if name is {@code null}. + */ + public NewCookie(String name, + String value, + String path, + String domain, + int version, + String comment, + int maxAge, + boolean secure) { + this(name, value, path, domain, version, comment, maxAge, null, secure, false); + } + + /** + * Create a new instance. + * + * @param name the name of the cookie + * @param value the value of the cookie + * @param path the URI path for which the cookie is valid + * @param domain the host domain for which the cookie is valid + * @param version the version of the specification to which the cookie complies + * @param comment the comment + * @param maxAge the maximum age of the cookie in seconds + * @param expiry the cookie expiry date. + * @param secure specifies whether the cookie will only be sent over a secure connection + * @param httpOnly if {@code true} make the cookie HTTP only, i.e. only visible as part of an HTTP request. + * @throws IllegalArgumentException if name is {@code null}. + * @since 2.0 + */ + public NewCookie(String name, + String value, + String path, + String domain, + int version, + String comment, + int maxAge, + Date expiry, + boolean secure, + boolean httpOnly) { + super(name, value, path, domain, version); + this.comment = comment; + this.maxAge = maxAge; + this.expiry = expiry; + this.secure = secure; + this.httpOnly = httpOnly; + } + + /** + * Create a new instance copying the information in the supplied cookie. + * + * @param cookie the cookie to clone. + * @throws IllegalArgumentException if cookie is {@code null}. + */ + public NewCookie(Cookie cookie) { + this(cookie, null, DEFAULT_MAX_AGE, null, false, false); + } + + /** + * Create a new instance supplementing the information in the supplied cookie. + * + * @param cookie the cookie to clone. + * @param comment the comment. + * @param maxAge the maximum age of the cookie in seconds. + * @param secure specifies whether the cookie will only be sent over a secure connection. + * @throws IllegalArgumentException if cookie is {@code null}. + */ + public NewCookie(Cookie cookie, String comment, int maxAge, boolean secure) { + this(cookie, comment, maxAge, null, secure, false); + } + + /** + * Create a new instance supplementing the information in the supplied cookie. + * + * @param cookie the cookie to clone. + * @param comment the comment. + * @param maxAge the maximum age of the cookie in seconds. + * @param expiry the cookie expiry date. + * @param secure specifies whether the cookie will only be sent over a secure connection. + * @param httpOnly if {@code true} make the cookie HTTP only, i.e. only visible as part of an HTTP request. + * @throws IllegalArgumentException if cookie is {@code null}. + * @since 2.0 + */ + public NewCookie(Cookie cookie, String comment, int maxAge, Date expiry, boolean secure, boolean httpOnly) { + super(cookie == null ? null : cookie.getName(), + cookie == null ? null : cookie.getValue(), + cookie == null ? null : cookie.getPath(), + cookie == null ? null : cookie.getDomain(), + cookie == null ? Cookie.DEFAULT_VERSION : cookie.getVersion()); + this.comment = comment; + this.maxAge = maxAge; + this.expiry = expiry; + this.secure = secure; + this.httpOnly = httpOnly; + } + + /** + * Creates a new instance of NewCookie by parsing the supplied string. + * + * @param value the cookie string. + * @return the newly created {@code NewCookie}. + * @throws IllegalArgumentException if the supplied string cannot be parsed + * or is {@code null}. + */ + public static NewCookie valueOf(String value) { + return null; + } + + /** + * Get the comment associated with the cookie. + * + * @return the comment or null if none set + */ + public String getComment() { + return null; + } + + /** + * Get the maximum age of the the cookie in seconds. Cookies older than + * the maximum age are discarded. A cookie can be unset by sending a new + * cookie with maximum age of 0 since it will overwrite any existing cookie + * and then be immediately discarded. The default value of {@code -1} indicates + * that the cookie will be discarded at the end of the browser/application session. + *

    + * Note that it is recommended to use {@code Max-Age} to control cookie + * expiration, however some browsers do not understand {@code Max-Age}, in which case + * setting {@link #getExpiry()} Expires} parameter may be necessary. + *

    + * + * @return the maximum age in seconds. + * @see #getExpiry() + */ + public int getMaxAge() { + return -1; + } + + /** + * Get the cookie expiry date. Cookies whose expiry date has passed are discarded. + * A cookie can be unset by setting a new cookie with an expiry date in the past, + * typically the lowest possible date that can be set. + *

    + * Note that it is recommended to use {@link #getMaxAge() Max-Age} to control cookie + * expiration, however some browsers do not understand {@code Max-Age}, in which case + * setting {@code Expires} parameter may be necessary. + *

    + * + * @return cookie expiry date or {@code null} if no expiry date was set. + * @see #getMaxAge() + * @since 2.0 + */ + public Date getExpiry() { + return null; + } + + /** + * Whether the cookie will only be sent over a secure connection. Defaults + * to {@code false}. + * + * @return {@code true} if the cookie will only be sent over a secure connection, + * {@code false} otherwise. + */ + public boolean isSecure() { + return false; + } + + /** + * Returns {@code true} if this cookie contains the {@code HttpOnly} attribute. + * This means that the cookie should not be accessible to scripting engines, + * like javascript. + * + * @return {@code true} if this cookie should be considered http only, {@code false} + * otherwise. + * @since 2.0 + */ + public boolean isHttpOnly() { + return false; + } + + /** + * Obtain a new instance of a {@link Cookie} with the same name, value, path, + * domain and version as this {@code NewCookie}. This method can be used to + * obtain an object that can be compared for equality with another {@code Cookie}; + * since a {@code Cookie} will never compare equal to a {@code NewCookie}. + * + * @return a {@link Cookie} + */ + public Cookie toCookie() { + return null; + } + + /** + * Convert the cookie to a string suitable for use as the value of the + * corresponding HTTP header. + * + * @return a stringified cookie. + */ + @Override + public String toString() { + return null; + } + + /** + * Generate a hash code by hashing all of the properties. + * + * @return the hash code. + */ + @Override + public int hashCode() { + return -1; + } + + /** + * Compare for equality. Use {@link #toCookie()} to compare a + * {@code NewCookie} to a {@code Cookie} considering only the common + * properties. + * + * @param obj the object to compare to + * @return true if the object is a {@code NewCookie} with the same value for + * all properties, false otherwise. + */ + @SuppressWarnings({"StringEquality", "RedundantIfStatement"}) + @Override + public boolean equals(Object obj) { + return true; + } +} \ No newline at end of file diff --git a/java/ql/test/stubs/servlet-api-2.4/javax/servlet/http/Cookie.java b/java/ql/test/stubs/servlet-api-2.4/javax/servlet/http/Cookie.java index d8348e13e2e..a93fec853e0 100644 --- a/java/ql/test/stubs/servlet-api-2.4/javax/servlet/http/Cookie.java +++ b/java/ql/test/stubs/servlet-api-2.4/javax/servlet/http/Cookie.java @@ -32,6 +32,7 @@ public class Cookie implements Cloneable { private String path; // ;Path=VALUE ... URLs that see the cookie private boolean secure; // ;Secure ... e.g. use SSL private int version = 0; // ;Version=1 ... means RFC 2109++ style + private boolean isHttpOnly = false; public Cookie(String name, String value) { this.name = name; @@ -81,4 +82,36 @@ public class Cookie implements Cloneable { } public void setVersion(int v) { } + + /** + * Marks or unmarks this Cookie as HttpOnly. + * + *

    If isHttpOnly is set to true, this cookie is + * marked as HttpOnly, by adding the HttpOnly attribute + * to it. + * + *

    HttpOnly cookies are not supposed to be exposed to + * client-side scripting code, and may therefore help mitigate certain + * kinds of cross-site scripting attacks. + * + * @param isHttpOnly true if this cookie is to be marked as + * HttpOnly, false otherwise + * + * @since Servlet 3.0 + */ + public void setHttpOnly(boolean isHttpOnly) { + this.isHttpOnly = isHttpOnly; + } + + /** + * Checks whether this Cookie has been marked as HttpOnly. + * + * @return true if this Cookie has been marked as HttpOnly, + * false otherwise + * + * @since Servlet 3.0 + */ + public boolean isHttpOnly() { + return isHttpOnly; + } } diff --git a/java/ql/test/stubs/servlet-api-2.4/javax/servlet/http/HttpServletResponse.java b/java/ql/test/stubs/servlet-api-2.4/javax/servlet/http/HttpServletResponse.java index 2971e023390..162ac0db3cc 100644 --- a/java/ql/test/stubs/servlet-api-2.4/javax/servlet/http/HttpServletResponse.java +++ b/java/ql/test/stubs/servlet-api-2.4/javax/servlet/http/HttpServletResponse.java @@ -24,6 +24,7 @@ package javax.servlet.http; import java.io.IOException; +import java.util.Collection; import javax.servlet.ServletResponse; public interface HttpServletResponse extends ServletResponse { @@ -44,6 +45,11 @@ public interface HttpServletResponse extends ServletResponse { public void addIntHeader(String name, int value); public void setStatus(int sc); public void setStatus(int sc, String sm); + public int getStatus(); + public String getHeader(String name); + public Collection getHeaders(String name); + public Collection getHeaderNames(); + public static final int SC_CONTINUE = 100; public static final int SC_SWITCHING_PROTOCOLS = 101; From ffc6af73b70b9bf8aa49c17938629f90e4ddb89d Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 2 Mar 2021 11:00:43 +0100 Subject: [PATCH 068/725] C++: Accept test changes. --- .../dataflow/taint-tests/standalone_iterators.cpp | 4 ++-- .../library-tests/dataflow/taint-tests/string.cpp | 4 ++-- .../dataflow/taint-tests/stringstream.cpp | 4 ++-- .../library-tests/dataflow/taint-tests/taint.cpp | 6 +++--- .../dataflow/taint-tests/taint.expected | 13 ------------- 5 files changed, 9 insertions(+), 22 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/standalone_iterators.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/standalone_iterators.cpp index 362784eeb1a..376582381ac 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/standalone_iterators.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/standalone_iterators.cpp @@ -39,13 +39,13 @@ public: void test_typedefs(int_iterator_by_typedefs source1) { sink(*source1); // $ ast,ir sink(*(source1++)); // $ ast,ir - sink(*(++source1)); // $ ast MISSING: ir + sink(*(++source1)); // $ ast,ir } void test_trait(int_iterator_by_trait source1) { sink(*source1); // $ ast,ir sink(*(source1++)); // $ ast,ir - sink(*(++source1)); // $ ast MISSING: ir + sink(*(++source1)); // $ ast,ir } void test_non_iterator(non_iterator source1) { diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/string.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/string.cpp index 9169113c1d9..43b6e9bc53b 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/string.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/string.cpp @@ -396,9 +396,9 @@ void test_string_iterators() { sink(*(i2+1)); // $ ast,ir sink(*(i2-1)); // $ ast,ir i3 = i2; - sink(*(++i3)); // $ ast MISSING: ir + sink(*(++i3)); // $ ast,ir i4 = i2; - sink(*(--i4)); // $ ast MISSING: ir + sink(*(--i4)); // $ ast,ir i5 = i2; i5++; sink(*i5); // $ ast,ir diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/stringstream.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/stringstream.cpp index 7b7712f0c01..7a6c5e51820 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/stringstream.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/stringstream.cpp @@ -229,7 +229,7 @@ void test_getline() sink(ss2.getline(b7, 1000).getline(b8, 1000)); // $ ast,ir sink(b7); // $ ast,ir - sink(b8); // $ ast MISSING: ir + sink(b8); // $ ast,ir sink(getline(ss1, s1)); sink(getline(ss2, s2)); // $ ast,ir @@ -261,7 +261,7 @@ void test_chaining() sink(ss1.get(b1, 100).unget().get(b2, 100)); // $ ast,ir sink(b1); // $ ast,ir - sink(b2); // $ ast MISSING: ir + sink(b2); // $ ast,ir sink(ss2.write("abc", 3).flush().write(source(), 3).flush().write("xyz", 3)); // $ ast MISSING: ir sink(ss2); // $ ast MISSING: ir diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp index 6db77f37ac1..baf26ee9af4 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp @@ -192,7 +192,7 @@ void *memcpy(void *dest, void *src, int len); void test_memcpy(int *source) { int x; memcpy(&x, source, sizeof(int)); - sink(x); // $ ast=192:23 MISSING: ir SPURIOUS: ast=193:6 + sink(x); // $ ast=192:23 ir SPURIOUS: ast=193:6 } // --- std::swap --- @@ -518,7 +518,7 @@ void *mempcpy(void *dest, const void *src, size_t n); void test_mempcpy(int *source) { int x; mempcpy(&x, source, sizeof(int)); - sink(x); // $ ast=518:24 MISSING: ir SPURIOUS: ast=519:6 + sink(x); // $ ast=518:24 ir SPURIOUS: ast=519:6 } // --- memccpy --- @@ -528,7 +528,7 @@ void *memccpy(void *dest, const void *src, int c, size_t n); void test_memccpy(int *source) { int dest[16]; memccpy(dest, source, 42, sizeof(dest)); - sink(dest); // $ ast=528:24 MISSING: ir SPURIOUS: ast=529:6 + sink(dest); // $ ast=528:24 ir SPURIOUS: ast=529:6 } // --- strcat and related functions --- diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected index e42e84d80cd..e69de29bb2d 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected @@ -1,13 +0,0 @@ -| standalone_iterators.cpp:42:10:42:10 | call to operator* | Fixed missing result:ir= | -| standalone_iterators.cpp:48:10:48:10 | call to operator* | Fixed missing result:ir= | -| string.cpp:399:8:399:8 | call to operator* | Fixed missing result:ir= | -| string.cpp:399:8:399:15 | (reference dereference) | Fixed missing result:ir= | -| string.cpp:401:8:401:8 | call to operator* | Fixed missing result:ir= | -| string.cpp:401:8:401:15 | (reference dereference) | Fixed missing result:ir= | -| stringstream.cpp:232:7:232:8 | Argument 0 indirection | Fixed missing result:ir= | -| stringstream.cpp:232:7:232:8 | call to basic_string | Fixed missing result:ir= | -| stringstream.cpp:264:7:264:8 | Argument 0 indirection | Fixed missing result:ir= | -| stringstream.cpp:264:7:264:8 | call to basic_string | Fixed missing result:ir= | -| taint.cpp:195:7:195:7 | x | Fixed missing result:ir= | -| taint.cpp:521:7:521:7 | x | Fixed missing result:ir= | -| taint.cpp:531:7:531:10 | Argument 0 indirection | Fixed missing result:ir= | From 9f02c144a89cfc7f976a3b1b2b4a7d5705eb35ea Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 2 Mar 2021 11:09:19 +0100 Subject: [PATCH 069/725] C++: Remove files that were incorrectly added when resolving merge conflicts. --- .../DefaultTaintTracking/tainted.expected | 246 -------- .../dataflow/DefaultTaintTracking/tainted.ql | 9 - .../DefaultTaintTracking/test_diff.expected | 133 ---- .../DefaultTaintTracking/test_diff.ql | 28 - .../dataflow/taint-tests/test_diff.expected | 269 -------- .../dataflow/taint-tests/test_ir.expected | 580 ------------------ 6 files changed, 1265 deletions(-) delete mode 100644 cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected delete mode 100644 cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.ql delete mode 100644 cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected delete mode 100644 cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.ql delete mode 100644 cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected delete mode 100644 cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected deleted file mode 100644 index 9f8ed0d28d3..00000000000 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected +++ /dev/null @@ -1,246 +0,0 @@ -| defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:16:16:16:21 | call to getenv | -| defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:16:16:16:28 | (const char *)... | -| defaulttainttracking.cpp:17:15:17:20 | call to getenv | defaulttainttracking.cpp:17:15:17:20 | call to getenv | -| defaulttainttracking.cpp:17:15:17:20 | call to getenv | defaulttainttracking.cpp:17:15:17:27 | (const char *)... | -| defaulttainttracking.cpp:18:27:18:32 | call to getenv | defaulttainttracking.cpp:18:27:18:32 | call to getenv | -| defaulttainttracking.cpp:18:27:18:32 | call to getenv | defaulttainttracking.cpp:18:27:18:39 | (const char *)... | -| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:22:20:22:25 | call to getenv | -| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:22:20:22:32 | (const char *)... | -| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:24:8:24:10 | buf | -| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:38:25:38:30 | call to getenv | -| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:38:25:38:37 | (void *)... | -| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:39:26:39:34 | call to inet_addr | -| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:39:50:39:61 | & ... | -| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:40:10:40:10 | a | -| defaulttainttracking.cpp:64:10:64:15 | call to getenv | defaulttainttracking.cpp:58:14:58:14 | p | -| defaulttainttracking.cpp:64:10:64:15 | call to getenv | defaulttainttracking.cpp:64:10:64:15 | call to getenv | -| defaulttainttracking.cpp:64:10:64:15 | call to getenv | defaulttainttracking.cpp:64:10:64:22 | (const char *)... | -| defaulttainttracking.cpp:66:17:66:22 | call to getenv | defaulttainttracking.cpp:58:14:58:14 | p | -| defaulttainttracking.cpp:66:17:66:22 | call to getenv | defaulttainttracking.cpp:66:17:66:22 | call to getenv | -| defaulttainttracking.cpp:66:17:66:22 | call to getenv | defaulttainttracking.cpp:66:17:66:29 | (const char *)... | -| defaulttainttracking.cpp:67:28:67:33 | call to getenv | defaulttainttracking.cpp:58:14:58:14 | p | -| defaulttainttracking.cpp:67:28:67:33 | call to getenv | defaulttainttracking.cpp:67:28:67:33 | call to getenv | -| defaulttainttracking.cpp:67:28:67:33 | call to getenv | defaulttainttracking.cpp:67:28:67:40 | (const char *)... | -| defaulttainttracking.cpp:68:29:68:34 | call to getenv | defaulttainttracking.cpp:58:14:58:14 | p | -| defaulttainttracking.cpp:68:29:68:34 | call to getenv | defaulttainttracking.cpp:68:29:68:34 | call to getenv | -| defaulttainttracking.cpp:68:29:68:34 | call to getenv | defaulttainttracking.cpp:68:29:68:41 | (const char *)... | -| defaulttainttracking.cpp:69:33:69:38 | call to getenv | defaulttainttracking.cpp:58:14:58:14 | p | -| defaulttainttracking.cpp:69:33:69:38 | call to getenv | defaulttainttracking.cpp:69:33:69:38 | call to getenv | -| defaulttainttracking.cpp:69:33:69:38 | call to getenv | defaulttainttracking.cpp:69:33:69:45 | (const char *)... | -| defaulttainttracking.cpp:72:11:72:16 | call to getenv | defaulttainttracking.cpp:72:11:72:16 | call to getenv | -| defaulttainttracking.cpp:72:11:72:16 | call to getenv | defaulttainttracking.cpp:72:11:72:23 | (const char *)... | -| defaulttainttracking.cpp:74:18:74:23 | call to getenv | defaulttainttracking.cpp:74:18:74:23 | call to getenv | -| defaulttainttracking.cpp:74:18:74:23 | call to getenv | defaulttainttracking.cpp:74:18:74:30 | (const char *)... | -| defaulttainttracking.cpp:75:29:75:34 | call to getenv | defaulttainttracking.cpp:75:29:75:34 | call to getenv | -| defaulttainttracking.cpp:75:29:75:34 | call to getenv | defaulttainttracking.cpp:75:29:75:41 | (const char *)... | -| defaulttainttracking.cpp:76:30:76:35 | call to getenv | defaulttainttracking.cpp:76:30:76:35 | call to getenv | -| defaulttainttracking.cpp:76:30:76:35 | call to getenv | defaulttainttracking.cpp:76:30:76:42 | (const char *)... | -| defaulttainttracking.cpp:77:34:77:39 | call to getenv | defaulttainttracking.cpp:77:34:77:39 | call to getenv | -| defaulttainttracking.cpp:77:34:77:39 | call to getenv | defaulttainttracking.cpp:77:34:77:46 | (const char *)... | -| defaulttainttracking.cpp:79:30:79:35 | call to getenv | defaulttainttracking.cpp:58:14:58:14 | p | -| defaulttainttracking.cpp:79:30:79:35 | call to getenv | defaulttainttracking.cpp:79:30:79:35 | call to getenv | -| defaulttainttracking.cpp:79:30:79:35 | call to getenv | defaulttainttracking.cpp:79:30:79:42 | (const char *)... | -| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:8:88:16 | call to move | -| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:8:88:32 | (const char *)... | -| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:8:88:32 | (reference dereference) | -| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:18:88:23 | call to getenv | -| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:18:88:30 | (reference to) | -| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:18:88:30 | temporary object | -| defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:92:12:92:14 | arg | -| defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:97:27:97:32 | call to getenv | -| defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:98:10:98:11 | (const char *)... | -| defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:98:10:98:11 | p2 | -| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:110:17:110:22 | call to getenv | -| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:110:17:110:32 | (int)... | -| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:110:17:110:32 | access to array | -| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:111:12:111:18 | tainted | -| defaulttainttracking.cpp:133:9:133:14 | call to getenv | defaulttainttracking.cpp:126:16:126:16 | x | -| defaulttainttracking.cpp:133:9:133:14 | call to getenv | defaulttainttracking.cpp:133:9:133:14 | call to getenv | -| defaulttainttracking.cpp:133:9:133:14 | call to getenv | defaulttainttracking.cpp:133:9:133:24 | (int)... | -| defaulttainttracking.cpp:133:9:133:14 | call to getenv | defaulttainttracking.cpp:133:9:133:24 | access to array | -| defaulttainttracking.cpp:133:9:133:14 | call to getenv | defaulttainttracking.cpp:134:10:134:10 | x | -| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:140:11:140:16 | call to getenv | -| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:140:11:140:26 | (int)... | -| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:140:11:140:26 | access to array | -| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:166:10:166:10 | x | -| defaulttainttracking.cpp:157:9:157:14 | call to getenv | defaulttainttracking.cpp:157:9:157:14 | call to getenv | -| defaulttainttracking.cpp:157:9:157:14 | call to getenv | defaulttainttracking.cpp:157:9:157:24 | (int)... | -| defaulttainttracking.cpp:157:9:157:14 | call to getenv | defaulttainttracking.cpp:157:9:157:24 | access to array | -| defaulttainttracking.cpp:157:9:157:14 | call to getenv | defaulttainttracking.cpp:159:10:159:10 | x | -| defaulttainttracking.cpp:170:11:170:16 | call to getenv | defaulttainttracking.cpp:170:11:170:16 | call to getenv | -| defaulttainttracking.cpp:170:11:170:16 | call to getenv | defaulttainttracking.cpp:170:11:170:26 | (int)... | -| defaulttainttracking.cpp:170:11:170:16 | call to getenv | defaulttainttracking.cpp:170:11:170:26 | access to array | -| defaulttainttracking.cpp:181:11:181:16 | call to getenv | defaulttainttracking.cpp:181:11:181:16 | call to getenv | -| defaulttainttracking.cpp:181:11:181:16 | call to getenv | defaulttainttracking.cpp:181:11:181:26 | (int)... | -| defaulttainttracking.cpp:181:11:181:16 | call to getenv | defaulttainttracking.cpp:181:11:181:26 | access to array | -| defaulttainttracking.cpp:195:11:195:16 | call to getenv | defaulttainttracking.cpp:195:11:195:16 | call to getenv | -| defaulttainttracking.cpp:195:11:195:16 | call to getenv | defaulttainttracking.cpp:195:11:195:26 | (int)... | -| defaulttainttracking.cpp:195:11:195:16 | call to getenv | defaulttainttracking.cpp:195:11:195:26 | access to array | -| defaulttainttracking.cpp:201:13:201:18 | call to getenv | defaulttainttracking.cpp:201:13:201:18 | call to getenv | -| defaulttainttracking.cpp:201:13:201:18 | call to getenv | defaulttainttracking.cpp:201:13:201:28 | (int)... | -| defaulttainttracking.cpp:201:13:201:18 | call to getenv | defaulttainttracking.cpp:201:13:201:28 | access to array | -| defaulttainttracking.cpp:208:27:208:32 | call to getenv | defaulttainttracking.cpp:208:27:208:32 | call to getenv | -| defaulttainttracking.cpp:208:27:208:32 | call to getenv | defaulttainttracking.cpp:208:27:208:42 | (int)... | -| defaulttainttracking.cpp:208:27:208:32 | call to getenv | defaulttainttracking.cpp:208:27:208:42 | access to array | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:218:12:218:17 | call to getenv | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:224:17:224:17 | (const void *)... | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:224:17:224:17 | s | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:228:7:228:12 | buffer | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:229:7:229:10 | ptr1 | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:232:7:232:10 | ptr3 | -| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:240:12:240:17 | call to getenv | -| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:246:16:246:16 | (const void *)... | -| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:246:16:246:16 | s | -| dispatch.cpp:28:29:28:34 | call to getenv | dispatch.cpp:28:24:28:27 | call to atoi | -| dispatch.cpp:28:29:28:34 | call to getenv | dispatch.cpp:28:29:28:34 | call to getenv | -| dispatch.cpp:28:29:28:34 | call to getenv | dispatch.cpp:28:29:28:45 | (const char *)... | -| dispatch.cpp:29:32:29:37 | call to getenv | dispatch.cpp:29:27:29:30 | call to atoi | -| dispatch.cpp:29:32:29:37 | call to getenv | dispatch.cpp:29:32:29:37 | call to getenv | -| dispatch.cpp:29:32:29:37 | call to getenv | dispatch.cpp:29:32:29:48 | (const char *)... | -| dispatch.cpp:31:28:31:33 | call to getenv | dispatch.cpp:8:8:8:16 | sinkParam | -| dispatch.cpp:31:28:31:33 | call to getenv | dispatch.cpp:31:23:31:26 | call to atoi | -| dispatch.cpp:31:28:31:33 | call to getenv | dispatch.cpp:31:28:31:33 | call to getenv | -| dispatch.cpp:31:28:31:33 | call to getenv | dispatch.cpp:31:28:31:44 | (const char *)... | -| dispatch.cpp:32:31:32:36 | call to getenv | dispatch.cpp:8:8:8:16 | sinkParam | -| dispatch.cpp:32:31:32:36 | call to getenv | dispatch.cpp:32:26:32:29 | call to atoi | -| dispatch.cpp:32:31:32:36 | call to getenv | dispatch.cpp:32:31:32:36 | call to getenv | -| dispatch.cpp:32:31:32:36 | call to getenv | dispatch.cpp:32:31:32:47 | (const char *)... | -| dispatch.cpp:34:22:34:27 | call to getenv | dispatch.cpp:8:8:8:16 | sinkParam | -| dispatch.cpp:34:22:34:27 | call to getenv | dispatch.cpp:34:17:34:20 | call to atoi | -| dispatch.cpp:34:22:34:27 | call to getenv | dispatch.cpp:34:22:34:27 | call to getenv | -| dispatch.cpp:34:22:34:27 | call to getenv | dispatch.cpp:34:22:34:38 | (const char *)... | -| globals.cpp:5:20:5:25 | call to getenv | globals.cpp:5:20:5:25 | call to getenv | -| globals.cpp:5:20:5:25 | call to getenv | globals.cpp:6:10:6:14 | (const char *)... | -| globals.cpp:5:20:5:25 | call to getenv | globals.cpp:6:10:6:14 | local | -| globals.cpp:13:15:13:20 | call to getenv | globals.cpp:13:15:13:20 | call to getenv | -| globals.cpp:23:15:23:20 | call to getenv | globals.cpp:23:15:23:20 | call to getenv | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:62:25:62:30 | call to getenv | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:68:12:68:17 | call to source | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:70:16:70:21 | call to source | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:70:16:70:23 | (const char *)... | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:70:16:70:24 | call to basic_string | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:72:7:72:7 | (const char *)... | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:72:7:72:7 | a | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:74:7:74:7 | c | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:76:7:76:7 | c | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:76:9:76:13 | call to c_str | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:82:16:82:21 | call to source | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:82:16:82:23 | (const char *)... | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:82:16:82:24 | call to basic_string | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:85:6:85:6 | call to operator<< | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:85:6:85:17 | (reference dereference) | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:85:9:85:14 | call to source | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:85:9:85:16 | (const char *)... | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:86:15:86:15 | call to operator<< | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:86:15:86:26 | (reference dereference) | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:86:18:86:23 | call to source | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:86:18:86:25 | (const char *)... | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:6:87:6 | call to operator<< | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:6:87:19 | (reference dereference) | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:6:87:19 | (reference to) | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:9:87:14 | call to source | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:9:87:16 | (const char *)... | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:18:87:18 | call to operator<< | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:18:87:26 | (reference dereference) | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:88:9:88:9 | t | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:91:7:91:9 | ss2 | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:93:7:93:9 | ss4 | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:96:7:96:9 | ss2 | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:96:7:96:15 | (const string)... | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:96:7:96:15 | (reference to) | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:96:7:96:15 | temporary object | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:96:11:96:13 | call to str | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:98:7:98:9 | ss4 | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:98:7:98:15 | (const string)... | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:98:7:98:15 | (reference to) | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:98:7:98:15 | temporary object | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:98:11:98:13 | call to str | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:118:10:118:15 | call to source | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:125:16:125:28 | call to basic_string | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:125:17:125:26 | call to user_input | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:125:17:125:28 | (const char *)... | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:126:7:126:11 | path1 | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:126:13:126:17 | call to c_str | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:129:10:129:19 | call to user_input | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:129:10:129:21 | (const char *)... | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:129:10:129:21 | call to basic_string | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:129:10:129:21 | temporary object | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:130:7:130:11 | path2 | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:130:13:130:17 | call to c_str | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:132:15:132:24 | call to user_input | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:132:15:132:26 | (const char *)... | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:132:15:132:27 | call to basic_string | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:133:7:133:11 | path3 | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:133:13:133:17 | call to c_str | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:138:19:138:24 | call to source | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:138:19:138:26 | (const char *)... | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:141:17:141:18 | cs | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:141:17:141:19 | call to basic_string | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:143:7:143:8 | cs | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:144:7:144:8 | ss | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:149:19:149:24 | call to source | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:149:19:149:26 | (const char *)... | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:152:17:152:18 | cs | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:152:17:152:19 | call to basic_string | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:155:7:155:8 | ss | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:155:10:155:14 | call to c_str | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:157:7:157:8 | cs | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:158:7:158:8 | ss | -| test_diff.cpp:92:10:92:13 | argv | test_diff.cpp:92:10:92:13 | argv | -| test_diff.cpp:92:10:92:13 | argv | test_diff.cpp:92:10:92:16 | (const char *)... | -| test_diff.cpp:92:10:92:13 | argv | test_diff.cpp:92:10:92:16 | access to array | -| test_diff.cpp:94:32:94:35 | argv | test_diff.cpp:94:10:94:36 | reinterpret_cast... | -| test_diff.cpp:94:32:94:35 | argv | test_diff.cpp:94:32:94:35 | argv | -| test_diff.cpp:96:26:96:29 | argv | test_diff.cpp:17:10:17:10 | a | -| test_diff.cpp:96:26:96:29 | argv | test_diff.cpp:96:26:96:29 | argv | -| test_diff.cpp:96:26:96:29 | argv | test_diff.cpp:96:26:96:32 | (const char *)... | -| test_diff.cpp:96:26:96:29 | argv | test_diff.cpp:96:26:96:32 | access to array | -| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:17:10:17:10 | a | -| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:98:17:98:21 | & ... | -| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:98:18:98:21 | argv | -| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:100:10:100:14 | (const char *)... | -| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:100:10:100:14 | * ... | -| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:100:11:100:11 | p | -| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:100:11:100:14 | access to array | -| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:102:26:102:30 | (const char *)... | -| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:102:26:102:30 | * ... | -| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:102:27:102:27 | p | -| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:102:27:102:30 | access to array | -| test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:10:104:20 | (const char *)... | -| test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:10:104:20 | * ... | -| test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:11:104:20 | (...) | -| test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:12:104:15 | argv | -| test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:12:104:19 | ... + ... | -| test_diff.cpp:108:10:108:13 | argv | test_diff.cpp:30:14:30:14 | p | -| test_diff.cpp:108:10:108:13 | argv | test_diff.cpp:108:10:108:13 | argv | -| test_diff.cpp:108:10:108:13 | argv | test_diff.cpp:108:10:108:16 | (const char *)... | -| test_diff.cpp:108:10:108:13 | argv | test_diff.cpp:108:10:108:16 | access to array | -| test_diff.cpp:111:10:111:13 | argv | test_diff.cpp:111:10:111:13 | argv | -| test_diff.cpp:111:10:111:13 | argv | test_diff.cpp:111:10:111:16 | (const char *)... | -| test_diff.cpp:111:10:111:13 | argv | test_diff.cpp:111:10:111:16 | access to array | -| test_diff.cpp:115:11:115:14 | argv | test_diff.cpp:42:14:42:14 | p | -| test_diff.cpp:115:11:115:14 | argv | test_diff.cpp:53:37:53:37 | p | -| test_diff.cpp:115:11:115:14 | argv | test_diff.cpp:115:11:115:14 | argv | -| test_diff.cpp:115:11:115:14 | argv | test_diff.cpp:115:11:115:17 | (const char *)... | -| test_diff.cpp:115:11:115:14 | argv | test_diff.cpp:115:11:115:17 | access to array | -| test_diff.cpp:118:26:118:29 | argv | test_diff.cpp:61:34:61:34 | p | -| test_diff.cpp:118:26:118:29 | argv | test_diff.cpp:118:26:118:29 | argv | -| test_diff.cpp:118:26:118:29 | argv | test_diff.cpp:118:26:118:32 | (const char *)... | -| test_diff.cpp:118:26:118:29 | argv | test_diff.cpp:118:26:118:32 | access to array | -| test_diff.cpp:121:23:121:26 | argv | test_diff.cpp:61:34:61:34 | p | -| test_diff.cpp:121:23:121:26 | argv | test_diff.cpp:68:14:68:14 | p | -| test_diff.cpp:121:23:121:26 | argv | test_diff.cpp:121:23:121:26 | argv | -| test_diff.cpp:121:23:121:26 | argv | test_diff.cpp:121:23:121:29 | (const char *)... | -| test_diff.cpp:121:23:121:26 | argv | test_diff.cpp:121:23:121:29 | access to array | -| test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:82:14:82:14 | p | -| test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:124:19:124:22 | argv | -| test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:124:19:124:25 | (const char *)... | -| test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:124:19:124:25 | access to array | -| test_diff.cpp:126:43:126:46 | argv | test_diff.cpp:82:14:82:14 | p | -| test_diff.cpp:126:43:126:46 | argv | test_diff.cpp:126:43:126:46 | argv | -| test_diff.cpp:126:43:126:46 | argv | test_diff.cpp:126:43:126:49 | (const char *)... | -| test_diff.cpp:126:43:126:46 | argv | test_diff.cpp:126:43:126:49 | access to array | -| test_diff.cpp:128:44:128:47 | argv | test_diff.cpp:82:14:82:14 | p | -| test_diff.cpp:128:44:128:47 | argv | test_diff.cpp:128:44:128:47 | argv | -| test_diff.cpp:128:44:128:47 | argv | test_diff.cpp:128:44:128:50 | (const char *)... | -| test_diff.cpp:128:44:128:47 | argv | test_diff.cpp:128:44:128:50 | access to array | diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.ql b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.ql deleted file mode 100644 index 240418f9bf4..00000000000 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.ql +++ /dev/null @@ -1,9 +0,0 @@ -import semmle.code.cpp.ir.dataflow.DefaultTaintTracking - -class SourceConfiguration extends TaintedWithPath::TaintTrackingConfiguration { - override predicate isSink(Element e) { any() } -} - -from Expr source, Element tainted -where TaintedWithPath::taintedWithPath(source, tainted, _, _) -select source, tainted diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected deleted file mode 100644 index ffc640c15f3..00000000000 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected +++ /dev/null @@ -1,133 +0,0 @@ -| defaulttainttracking.cpp:17:15:17:20 | call to getenv | defaulttainttracking.cpp:17:8:17:13 | call to strdup | AST only | -| defaulttainttracking.cpp:17:15:17:20 | call to getenv | defaulttainttracking.cpp:17:8:17:28 | (const char *)... | AST only | -| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:21:8:21:10 | buf | AST only | -| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:22:8:22:13 | call to strcat | AST only | -| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:22:8:22:33 | (const char *)... | AST only | -| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:22:15:22:17 | buf | AST only | -| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:38:11:38:21 | env_pointer | AST only | -| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:39:22:39:22 | a | AST only | -| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:39:36:39:61 | (const char *)... | AST only | -| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:39:51:39:61 | env_pointer | AST only | -| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:8:88:16 | call to move | IR only | -| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:8:88:32 | (const char *)... | IR only | -| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:8:88:32 | (reference dereference) | IR only | -| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:18:88:30 | (reference to) | IR only | -| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:18:88:30 | temporary object | IR only | -| defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:92:5:92:8 | * ... | AST only | -| defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:92:6:92:8 | ret | AST only | -| defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:98:10:98:11 | (const char *)... | IR only | -| defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:98:10:98:11 | p2 | IR only | -| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:110:7:110:13 | tainted | AST only | -| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:111:8:111:8 | y | AST only | -| defaulttainttracking.cpp:133:9:133:14 | call to getenv | defaulttainttracking.cpp:126:16:126:16 | x | IR only | -| defaulttainttracking.cpp:133:9:133:14 | call to getenv | defaulttainttracking.cpp:133:5:133:5 | x | AST only | -| defaulttainttracking.cpp:133:9:133:14 | call to getenv | defaulttainttracking.cpp:134:10:134:10 | x | IR only | -| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:140:7:140:7 | x | AST only | -| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:166:10:166:10 | x | IR only | -| defaulttainttracking.cpp:157:9:157:14 | call to getenv | defaulttainttracking.cpp:157:5:157:5 | x | AST only | -| defaulttainttracking.cpp:157:9:157:14 | call to getenv | defaulttainttracking.cpp:159:10:159:10 | x | IR only | -| defaulttainttracking.cpp:170:11:170:16 | call to getenv | defaulttainttracking.cpp:170:7:170:7 | x | AST only | -| defaulttainttracking.cpp:181:11:181:16 | call to getenv | defaulttainttracking.cpp:181:7:181:7 | x | AST only | -| defaulttainttracking.cpp:195:11:195:16 | call to getenv | defaulttainttracking.cpp:195:7:195:7 | x | AST only | -| defaulttainttracking.cpp:201:13:201:18 | call to getenv | defaulttainttracking.cpp:201:9:201:9 | x | AST only | -| defaulttainttracking.cpp:208:27:208:32 | call to getenv | defaulttainttracking.cpp:208:23:208:23 | x | AST only | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:217:7:217:12 | buffer | AST only | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:218:8:218:8 | s | AST only | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:219:8:219:11 | ptr1 | AST only | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:219:16:219:19 | ptr2 | AST only | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:220:8:220:11 | ptr3 | AST only | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:220:16:220:19 | ptr4 | AST only | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:222:2:222:5 | ptr1 | AST only | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:222:9:222:14 | buffer | AST only | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:223:2:223:5 | ptr2 | AST only | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:223:9:223:13 | & ... | AST only | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:223:10:223:13 | ptr1 | AST only | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:224:2:224:7 | call to memcpy | AST only | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:224:9:224:14 | buffer | AST only | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:225:2:225:5 | ptr3 | AST only | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:225:9:225:14 | buffer | AST only | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:226:2:226:5 | ptr4 | AST only | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:226:9:226:13 | & ... | AST only | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:226:10:226:13 | ptr3 | AST only | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:229:7:229:10 | (const char *)... | AST only | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:230:7:230:10 | ptr2 | AST only | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:231:7:231:11 | (const char *)... | AST only | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:231:7:231:11 | * ... | AST only | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:231:8:231:11 | ptr2 | AST only | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:232:7:232:10 | (const char *)... | AST only | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:233:7:233:10 | ptr4 | AST only | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:234:7:234:11 | (const char *)... | AST only | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:234:7:234:11 | * ... | AST only | -| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:234:8:234:11 | ptr4 | AST only | -| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:240:8:240:8 | s | AST only | -| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:241:8:241:11 | ptr1 | AST only | -| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:241:16:241:19 | ptr2 | AST only | -| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:245:2:245:5 | ptr2 | AST only | -| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:245:9:245:13 | & ... | AST only | -| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:245:10:245:13 | ptr1 | AST only | -| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:246:2:246:7 | call to memcpy | AST only | -| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:246:9:246:13 | * ... | AST only | -| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:246:10:246:13 | ptr2 | AST only | -| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:251:7:251:10 | (const char *)... | AST only | -| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:251:7:251:10 | ptr1 | AST only | -| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:252:7:252:10 | ptr2 | AST only | -| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:253:7:253:11 | (const char *)... | AST only | -| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:253:7:253:11 | * ... | AST only | -| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:253:8:253:11 | ptr2 | AST only | -| globals.cpp:5:20:5:25 | call to getenv | globals.cpp:5:12:5:16 | local | AST only | -| globals.cpp:13:15:13:20 | call to getenv | globals.cpp:9:8:9:14 | global1 | AST only | -| globals.cpp:13:15:13:20 | call to getenv | globals.cpp:13:5:13:11 | global1 | AST only | -| globals.cpp:23:15:23:20 | call to getenv | globals.cpp:16:15:16:21 | global2 | AST only | -| globals.cpp:23:15:23:20 | call to getenv | globals.cpp:23:5:23:11 | global2 | AST only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:62:7:62:12 | source | AST only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:68:8:68:8 | a | AST only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:70:16:70:24 | call to basic_string | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:74:7:74:7 | c | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:76:7:76:7 | c | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:76:9:76:13 | call to c_str | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:82:16:82:24 | call to basic_string | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:85:6:85:6 | call to operator<< | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:85:6:85:17 | (reference dereference) | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:86:15:86:15 | call to operator<< | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:86:15:86:26 | (reference dereference) | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:6:87:6 | call to operator<< | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:6:87:19 | (reference dereference) | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:6:87:19 | (reference to) | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:9:87:16 | (const char *)... | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:18:87:18 | call to operator<< | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:18:87:26 | (reference dereference) | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:88:9:88:9 | t | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:91:7:91:9 | ss2 | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:93:7:93:9 | ss4 | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:96:7:96:9 | ss2 | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:96:7:96:15 | (const string)... | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:96:7:96:15 | (reference to) | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:96:7:96:15 | temporary object | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:96:11:96:13 | call to str | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:98:7:98:9 | ss4 | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:98:7:98:15 | (const string)... | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:98:7:98:15 | (reference to) | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:98:7:98:15 | temporary object | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:98:11:98:13 | call to str | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:117:7:117:16 | user_input | AST only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:125:16:125:28 | call to basic_string | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:126:7:126:11 | path1 | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:126:13:126:17 | call to c_str | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:129:10:129:21 | call to basic_string | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:129:10:129:21 | temporary object | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:130:7:130:11 | path2 | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:130:13:130:17 | call to c_str | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:132:15:132:27 | call to basic_string | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:133:7:133:11 | path3 | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:133:13:133:17 | call to c_str | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:138:14:138:15 | cs | AST only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:141:17:141:19 | call to basic_string | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:144:7:144:8 | ss | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:149:14:149:15 | cs | AST only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:152:17:152:19 | call to basic_string | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:155:7:155:8 | ss | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:155:10:155:14 | call to c_str | IR only | -| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:158:7:158:8 | ss | IR only | -| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:98:13:98:13 | p | AST only | -| test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:11:104:20 | (...) | IR only | -| test_diff.cpp:111:10:111:13 | argv | test_diff.cpp:30:14:30:14 | p | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.ql b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.ql deleted file mode 100644 index 40bed5680c0..00000000000 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.ql +++ /dev/null @@ -1,28 +0,0 @@ -import cpp -import semmle.code.cpp.security.Security -import semmle.code.cpp.security.TaintTrackingImpl as ASTTaintTracking -import semmle.code.cpp.ir.dataflow.DefaultTaintTracking as IRDefaultTaintTracking - -class SourceConfiguration extends IRDefaultTaintTracking::TaintedWithPath::TaintTrackingConfiguration { - override predicate isSink(Element e) { any() } -} - -predicate astFlow(Expr source, Element sink) { ASTTaintTracking::tainted(source, sink) } - -predicate irFlow(Expr source, Element sink) { - IRDefaultTaintTracking::TaintedWithPath::taintedWithPath(source, sink, _, _) -} - -from Expr source, Element sink, string note -where - not sink instanceof Parameter and - ( - astFlow(source, sink) and - not irFlow(source, sink) and - note = "AST only" - or - irFlow(source, sink) and - not astFlow(source, sink) and - note = "IR only" - ) -select source, sink, note diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected deleted file mode 100644 index 88f79183d2a..00000000000 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected +++ /dev/null @@ -1,269 +0,0 @@ -| arrayassignment.cpp:16:7:16:7 | arrayassignment.cpp:14:9:14:14 | IR only | -| arrayassignment.cpp:18:7:18:11 | arrayassignment.cpp:14:9:14:14 | IR only | -| arrayassignment.cpp:19:7:19:9 | arrayassignment.cpp:14:9:14:14 | IR only | -| arrayassignment.cpp:31:7:31:7 | arrayassignment.cpp:29:8:29:13 | IR only | -| arrayassignment.cpp:32:7:32:10 | arrayassignment.cpp:29:8:29:13 | IR only | -| arrayassignment.cpp:34:7:34:10 | arrayassignment.cpp:29:8:29:13 | IR only | -| arrayassignment.cpp:56:7:56:8 | arrayassignment.cpp:54:9:54:14 | IR only | -| arrayassignment.cpp:57:10:57:12 | arrayassignment.cpp:54:9:54:14 | AST only | -| arrayassignment.cpp:57:10:57:15 | arrayassignment.cpp:54:9:54:14 | IR only | -| arrayassignment.cpp:66:7:66:8 | arrayassignment.cpp:64:13:64:18 | IR only | -| arrayassignment.cpp:67:10:67:12 | arrayassignment.cpp:64:13:64:18 | AST only | -| arrayassignment.cpp:67:10:67:15 | arrayassignment.cpp:64:13:64:18 | IR only | -| arrayassignment.cpp:136:7:136:13 | arrayassignment.cpp:134:9:134:14 | IR only | -| arrayassignment.cpp:141:7:141:13 | arrayassignment.cpp:139:10:139:15 | IR only | -| arrayassignment.cpp:146:7:146:13 | arrayassignment.cpp:144:12:144:17 | IR only | -| copyableclass.cpp:67:11:67:11 | copyableclass.cpp:67:13:67:18 | AST only | -| copyableclass.cpp:67:11:67:21 | copyableclass.cpp:67:13:67:18 | IR only | -| copyableclass_declonly.cpp:67:11:67:11 | copyableclass_declonly.cpp:67:13:67:18 | AST only | -| map.cpp:49:9:49:13 | map.cpp:48:37:48:42 | IR only | -| map.cpp:54:9:54:13 | map.cpp:48:37:48:42 | IR only | -| map.cpp:60:9:60:13 | map.cpp:48:37:48:42 | IR only | -| map.cpp:70:9:70:13 | map.cpp:65:37:65:42 | IR only | -| map.cpp:71:9:71:14 | map.cpp:65:37:65:42 | IR only | -| map.cpp:73:9:73:13 | map.cpp:65:37:65:42 | IR only | -| map.cpp:76:9:76:13 | map.cpp:66:37:66:42 | IR only | -| map.cpp:79:9:79:13 | map.cpp:66:37:66:42 | IR only | -| map.cpp:80:9:80:14 | map.cpp:66:37:66:42 | IR only | -| map.cpp:90:34:90:38 | map.cpp:90:24:90:29 | IR only | -| map.cpp:108:7:108:54 | map.cpp:108:39:108:44 | IR only | -| map.cpp:111:7:111:48 | map.cpp:111:34:111:39 | IR only | -| map.cpp:155:12:155:16 | map.cpp:108:39:108:44 | IR only | -| map.cpp:156:12:156:17 | map.cpp:108:39:108:44 | IR only | -| map.cpp:161:12:161:16 | map.cpp:108:39:108:44 | IR only | -| map.cpp:162:12:162:17 | map.cpp:108:39:108:44 | IR only | -| map.cpp:172:10:172:10 | map.cpp:168:20:168:25 | AST only | -| map.cpp:174:10:174:10 | map.cpp:170:23:170:28 | AST only | -| map.cpp:184:7:184:31 | map.cpp:108:39:108:44 | IR only | -| map.cpp:185:7:185:32 | map.cpp:108:39:108:44 | IR only | -| map.cpp:187:7:187:32 | map.cpp:108:39:108:44 | IR only | -| map.cpp:235:7:235:40 | map.cpp:235:26:235:31 | IR only | -| map.cpp:246:7:246:44 | map.cpp:246:30:246:35 | IR only | -| map.cpp:260:7:260:54 | map.cpp:260:39:260:44 | IR only | -| map.cpp:263:7:263:48 | map.cpp:263:34:263:39 | IR only | -| map.cpp:307:12:307:16 | map.cpp:260:39:260:44 | IR only | -| map.cpp:308:12:308:17 | map.cpp:260:39:260:44 | IR only | -| map.cpp:313:12:313:16 | map.cpp:260:39:260:44 | IR only | -| map.cpp:314:12:314:17 | map.cpp:260:39:260:44 | IR only | -| map.cpp:324:10:324:10 | map.cpp:320:20:320:25 | AST only | -| map.cpp:326:10:326:10 | map.cpp:322:23:322:28 | AST only | -| map.cpp:334:7:334:31 | map.cpp:260:39:260:44 | IR only | -| map.cpp:335:7:335:32 | map.cpp:260:39:260:44 | IR only | -| map.cpp:336:7:336:32 | map.cpp:260:39:260:44 | IR only | -| map.cpp:384:7:384:40 | map.cpp:384:26:384:31 | IR only | -| map.cpp:396:7:396:44 | map.cpp:396:30:396:35 | IR only | -| map.cpp:397:40:397:45 | map.cpp:396:30:396:35 | IR only | -| map.cpp:397:40:397:45 | map.cpp:397:30:397:35 | IR only | -| map.cpp:418:7:418:16 | map.cpp:416:30:416:35 | AST only | -| map.cpp:421:7:421:16 | map.cpp:419:33:419:38 | AST only | -| map.cpp:431:7:431:67 | map.cpp:431:52:431:57 | IR only | -| movableclass.cpp:65:11:65:11 | movableclass.cpp:65:13:65:18 | AST only | -| movableclass.cpp:65:11:65:21 | movableclass.cpp:65:13:65:18 | IR only | -| set.cpp:20:7:20:31 | set.cpp:20:17:20:22 | IR only | -| set.cpp:61:8:61:11 | set.cpp:20:17:20:22 | IR only | -| set.cpp:71:7:71:32 | set.cpp:67:13:67:18 | IR only | -| set.cpp:72:7:72:33 | set.cpp:67:13:67:18 | IR only | -| set.cpp:120:7:120:33 | set.cpp:120:19:120:24 | IR only | -| set.cpp:134:7:134:31 | set.cpp:134:17:134:22 | IR only | -| set.cpp:175:8:175:11 | set.cpp:134:17:134:22 | IR only | -| set.cpp:183:7:183:32 | set.cpp:181:13:181:18 | IR only | -| set.cpp:184:7:184:33 | set.cpp:181:13:181:18 | IR only | -| set.cpp:232:7:232:33 | set.cpp:232:19:232:24 | IR only | -| smart_pointer.cpp:12:10:12:10 | smart_pointer.cpp:11:52:11:57 | AST only | -| smart_pointer.cpp:24:10:24:10 | smart_pointer.cpp:23:52:23:57 | AST only | -| standalone_iterators.cpp:41:10:41:10 | standalone_iterators.cpp:39:45:39:51 | AST only | -| standalone_iterators.cpp:42:10:42:10 | standalone_iterators.cpp:39:45:39:51 | AST only | -| standalone_iterators.cpp:47:10:47:10 | standalone_iterators.cpp:45:39:45:45 | AST only | -| standalone_iterators.cpp:48:10:48:10 | standalone_iterators.cpp:45:39:45:45 | AST only | -| standalone_iterators.cpp:87:10:87:11 | standalone_iterators.cpp:86:13:86:18 | AST only | -| string.cpp:33:9:33:13 | string.cpp:27:16:27:21 | AST only | -| string.cpp:39:13:39:17 | string.cpp:14:10:14:15 | AST only | -| string.cpp:43:13:43:17 | string.cpp:14:10:14:15 | AST only | -| string.cpp:46:13:46:17 | string.cpp:14:10:14:15 | AST only | -| string.cpp:70:7:70:8 | string.cpp:62:19:62:24 | AST only | -| string.cpp:126:8:126:11 | string.cpp:120:16:120:21 | IR only | -| string.cpp:145:8:145:14 | string.cpp:142:18:142:23 | IR only | -| string.cpp:146:8:146:14 | string.cpp:142:18:142:23 | IR only | -| string.cpp:147:8:147:14 | string.cpp:142:18:142:23 | IR only | -| string.cpp:150:8:150:20 | string.cpp:150:13:150:18 | IR only | -| string.cpp:162:11:162:11 | string.cpp:155:18:155:23 | AST only | -| string.cpp:166:11:166:11 | string.cpp:166:14:166:19 | AST only | -| string.cpp:167:11:167:11 | string.cpp:166:14:166:19 | AST only | -| string.cpp:199:10:199:15 | string.cpp:191:17:191:22 | AST only | -| string.cpp:202:10:202:15 | string.cpp:192:11:192:25 | AST only | -| string.cpp:220:10:220:15 | string.cpp:211:17:211:22 | AST only | -| string.cpp:224:10:224:15 | string.cpp:211:17:211:22 | AST only | -| string.cpp:228:10:228:15 | string.cpp:212:11:212:25 | AST only | -| string.cpp:243:10:243:16 | string.cpp:234:17:234:22 | AST only | -| string.cpp:247:10:247:16 | string.cpp:234:17:234:22 | AST only | -| string.cpp:251:10:251:16 | string.cpp:235:11:235:25 | AST only | -| string.cpp:312:9:312:12 | string.cpp:309:16:309:21 | AST only | -| string.cpp:323:7:323:29 | string.cpp:320:16:320:21 | IR only | -| string.cpp:340:7:340:7 | string.cpp:336:9:336:23 | AST only | -| string.cpp:341:7:341:7 | string.cpp:337:12:337:26 | AST only | -| string.cpp:342:7:342:7 | string.cpp:336:9:336:23 | AST only | -| string.cpp:350:7:350:9 | string.cpp:349:18:349:32 | AST only | -| string.cpp:351:11:351:14 | string.cpp:349:18:349:32 | AST only | -| string.cpp:363:11:363:16 | string.cpp:358:18:358:23 | AST only | -| string.cpp:382:8:382:14 | string.cpp:374:18:374:23 | IR only | -| string.cpp:383:13:383:15 | string.cpp:374:18:374:23 | IR only | -| string.cpp:396:8:396:15 | string.cpp:389:18:389:23 | IR only | -| string.cpp:397:8:397:15 | string.cpp:389:18:389:23 | IR only | -| string.cpp:399:8:399:8 | string.cpp:389:18:389:23 | AST only | -| string.cpp:401:8:401:8 | string.cpp:389:18:389:23 | AST only | -| string.cpp:404:8:404:11 | string.cpp:389:18:389:23 | IR only | -| string.cpp:407:8:407:11 | string.cpp:389:18:389:23 | IR only | -| string.cpp:409:8:409:8 | string.cpp:389:18:389:23 | AST only | -| string.cpp:411:8:411:8 | string.cpp:389:18:389:23 | AST only | -| string.cpp:415:8:415:11 | string.cpp:389:18:389:23 | IR only | -| string.cpp:418:8:418:8 | string.cpp:389:18:389:23 | AST only | -| string.cpp:421:8:421:8 | string.cpp:389:18:389:23 | AST only | -| string.cpp:436:10:436:15 | string.cpp:431:14:431:19 | AST only | -| string.cpp:449:10:449:15 | string.cpp:449:32:449:46 | AST only | -| string.cpp:462:10:462:15 | string.cpp:457:18:457:23 | AST only | -| string.cpp:465:11:465:16 | string.cpp:457:18:457:23 | AST only | -| string.cpp:478:10:478:15 | string.cpp:473:18:473:23 | AST only | -| string.cpp:481:11:481:16 | string.cpp:473:18:473:23 | AST only | -| string.cpp:494:10:494:15 | string.cpp:489:18:489:23 | AST only | -| string.cpp:522:9:522:13 | string.cpp:521:14:521:28 | AST only | -| string.cpp:523:9:523:12 | string.cpp:521:14:521:28 | AST only | -| string.cpp:536:11:536:11 | string.cpp:536:20:536:25 | AST only | -| string.cpp:537:21:537:21 | string.cpp:537:24:537:29 | AST only | -| string.cpp:538:25:538:25 | string.cpp:538:15:538:20 | AST only | -| string.cpp:541:8:541:8 | string.cpp:536:20:536:25 | AST only | -| string.cpp:543:8:543:8 | string.cpp:537:24:537:29 | AST only | -| string.cpp:556:11:556:16 | string.cpp:556:27:556:32 | AST only | -| string.cpp:557:24:557:29 | string.cpp:557:31:557:36 | AST only | -| string.cpp:561:8:561:8 | string.cpp:556:27:556:32 | AST only | -| string.cpp:563:8:563:8 | string.cpp:557:31:557:36 | AST only | -| stringstream.cpp:32:11:32:22 | stringstream.cpp:32:14:32:19 | IR only | -| stringstream.cpp:33:20:33:31 | stringstream.cpp:33:23:33:28 | IR only | -| stringstream.cpp:34:23:34:31 | stringstream.cpp:34:14:34:19 | IR only | -| stringstream.cpp:35:11:35:11 | stringstream.cpp:29:16:29:21 | AST only | -| stringstream.cpp:39:7:39:9 | stringstream.cpp:33:23:33:28 | AST only | -| stringstream.cpp:41:7:41:9 | stringstream.cpp:29:16:29:21 | AST only | -| stringstream.cpp:43:7:43:15 | stringstream.cpp:32:14:32:19 | IR only | -| stringstream.cpp:44:11:44:13 | stringstream.cpp:33:23:33:28 | AST only | -| stringstream.cpp:45:7:45:15 | stringstream.cpp:34:14:34:19 | IR only | -| stringstream.cpp:46:11:46:13 | stringstream.cpp:29:16:29:21 | AST only | -| stringstream.cpp:56:11:56:13 | stringstream.cpp:56:15:56:29 | AST only | -| stringstream.cpp:57:44:57:46 | stringstream.cpp:57:25:57:39 | AST only | -| stringstream.cpp:60:7:60:10 | stringstream.cpp:57:25:57:39 | AST only | -| stringstream.cpp:63:12:63:16 | stringstream.cpp:63:18:63:23 | AST only | -| stringstream.cpp:64:54:64:58 | stringstream.cpp:64:36:64:41 | AST only | -| stringstream.cpp:67:7:67:10 | stringstream.cpp:64:36:64:41 | AST only | -| stringstream.cpp:76:11:76:11 | stringstream.cpp:70:32:70:37 | AST only | -| stringstream.cpp:78:11:78:11 | stringstream.cpp:70:32:70:37 | AST only | -| stringstream.cpp:83:7:83:15 | stringstream.cpp:70:32:70:37 | IR only | -| stringstream.cpp:100:11:100:11 | stringstream.cpp:100:31:100:36 | AST only | -| stringstream.cpp:143:11:143:22 | stringstream.cpp:143:14:143:19 | IR only | -| stringstream.cpp:146:11:146:11 | stringstream.cpp:143:14:143:19 | AST only | -| stringstream.cpp:147:17:147:17 | stringstream.cpp:143:14:143:19 | AST only | -| stringstream.cpp:151:7:151:8 | stringstream.cpp:143:14:143:19 | AST only | -| stringstream.cpp:154:11:154:11 | stringstream.cpp:143:14:143:19 | AST only | -| stringstream.cpp:155:17:155:17 | stringstream.cpp:143:14:143:19 | AST only | -| stringstream.cpp:159:7:159:8 | stringstream.cpp:143:14:143:19 | AST only | -| stringstream.cpp:162:11:162:14 | stringstream.cpp:143:14:143:19 | AST only | -| stringstream.cpp:166:11:166:13 | stringstream.cpp:143:14:143:19 | AST only | -| stringstream.cpp:179:11:179:13 | stringstream.cpp:143:14:143:19 | AST only | -| stringstream.cpp:196:10:196:16 | stringstream.cpp:196:18:196:32 | AST only | -| stringstream.cpp:215:11:215:17 | stringstream.cpp:203:24:203:29 | AST only | -| stringstream.cpp:216:11:216:17 | stringstream.cpp:203:24:203:29 | AST only | -| stringstream.cpp:223:11:223:17 | stringstream.cpp:203:24:203:29 | AST only | -| stringstream.cpp:224:11:224:17 | stringstream.cpp:203:24:203:29 | AST only | -| stringstream.cpp:230:29:230:35 | stringstream.cpp:203:24:203:29 | AST only | -| stringstream.cpp:232:7:232:8 | stringstream.cpp:203:24:203:29 | AST only | -| stringstream.cpp:235:7:235:13 | stringstream.cpp:203:24:203:29 | AST only | -| stringstream.cpp:236:7:236:13 | stringstream.cpp:203:24:203:29 | AST only | -| stringstream.cpp:243:7:243:13 | stringstream.cpp:203:24:203:29 | AST only | -| stringstream.cpp:244:7:244:13 | stringstream.cpp:203:24:203:29 | AST only | -| stringstream.cpp:250:7:250:13 | stringstream.cpp:203:24:203:29 | AST only | -| stringstream.cpp:252:7:252:8 | stringstream.cpp:203:24:203:29 | AST only | -| stringstream.cpp:262:32:262:34 | stringstream.cpp:257:24:257:29 | AST only | -| stringstream.cpp:264:7:264:8 | stringstream.cpp:257:24:257:29 | AST only | -| stringstream.cpp:266:62:266:66 | stringstream.cpp:266:41:266:46 | AST only | -| stringstream.cpp:267:7:267:9 | stringstream.cpp:266:41:266:46 | AST only | -| swap1.cpp:78:12:78:16 | swap1.cpp:69:23:69:23 | AST only | -| swap1.cpp:88:13:88:17 | swap1.cpp:81:27:81:28 | AST only | -| swap1.cpp:102:12:102:16 | swap1.cpp:93:23:93:23 | AST only | -| swap1.cpp:115:18:115:22 | swap1.cpp:108:23:108:31 | AST only | -| swap1.cpp:129:12:129:16 | swap1.cpp:120:23:120:23 | AST only | -| swap1.cpp:144:12:144:16 | swap1.cpp:135:23:135:23 | AST only | -| swap2.cpp:78:12:78:16 | swap2.cpp:69:23:69:23 | AST only | -| swap2.cpp:87:13:87:17 | swap2.cpp:82:16:82:21 | IR only | -| swap2.cpp:88:13:88:17 | swap2.cpp:81:27:81:28 | AST only | -| swap2.cpp:102:12:102:16 | swap2.cpp:93:23:93:23 | AST only | -| swap2.cpp:115:18:115:22 | swap2.cpp:108:23:108:31 | AST only | -| swap2.cpp:129:12:129:16 | swap2.cpp:120:23:120:23 | AST only | -| swap2.cpp:144:12:144:16 | swap2.cpp:135:23:135:23 | AST only | -| taint.cpp:41:7:41:13 | taint.cpp:35:12:35:17 | AST only | -| taint.cpp:42:7:42:13 | taint.cpp:35:12:35:17 | AST only | -| taint.cpp:43:7:43:13 | taint.cpp:37:22:37:27 | AST only | -| taint.cpp:137:7:137:9 | taint.cpp:120:11:120:16 | AST only | -| taint.cpp:195:7:195:7 | taint.cpp:193:6:193:6 | AST only | -| taint.cpp:236:3:236:6 | taint.cpp:223:10:223:15 | AST only | -| taint.cpp:372:7:372:7 | taint.cpp:365:24:365:29 | AST only | -| taint.cpp:374:7:374:7 | taint.cpp:365:24:365:29 | AST only | -| taint.cpp:391:7:391:7 | taint.cpp:385:27:385:32 | AST only | -| taint.cpp:429:7:429:7 | taint.cpp:428:13:428:18 | IR only | -| taint.cpp:431:9:431:17 | taint.cpp:428:13:428:18 | IR only | -| taint.cpp:447:9:447:17 | taint.cpp:445:14:445:28 | AST only | -| vector.cpp:24:8:24:11 | vector.cpp:16:43:16:49 | IR only | -| vector.cpp:52:7:52:8 | vector.cpp:51:10:51:15 | AST only | -| vector.cpp:53:9:53:9 | vector.cpp:51:10:51:15 | AST only | -| vector.cpp:54:9:54:9 | vector.cpp:51:10:51:15 | AST only | -| vector.cpp:55:9:55:9 | vector.cpp:51:10:51:15 | AST only | -| vector.cpp:58:7:58:8 | vector.cpp:51:10:51:15 | AST only | -| vector.cpp:59:9:59:9 | vector.cpp:51:10:51:15 | AST only | -| vector.cpp:60:9:60:9 | vector.cpp:51:10:51:15 | AST only | -| vector.cpp:61:9:61:9 | vector.cpp:51:10:51:15 | AST only | -| vector.cpp:64:7:64:8 | vector.cpp:63:10:63:15 | AST only | -| vector.cpp:65:9:65:9 | vector.cpp:63:10:63:15 | AST only | -| vector.cpp:66:9:66:9 | vector.cpp:63:10:63:15 | AST only | -| vector.cpp:67:9:67:9 | vector.cpp:63:10:63:15 | AST only | -| vector.cpp:71:10:71:14 | vector.cpp:69:15:69:20 | AST only | -| vector.cpp:72:10:72:13 | vector.cpp:69:15:69:20 | AST only | -| vector.cpp:75:7:75:8 | vector.cpp:74:17:74:22 | AST only | -| vector.cpp:76:7:76:18 | vector.cpp:74:17:74:22 | AST only | -| vector.cpp:84:10:84:14 | vector.cpp:81:17:81:22 | AST only | -| vector.cpp:85:10:85:13 | vector.cpp:81:17:81:22 | AST only | -| vector.cpp:97:7:97:8 | vector.cpp:96:13:96:18 | AST only | -| vector.cpp:98:10:98:11 | vector.cpp:96:13:96:18 | AST only | -| vector.cpp:99:10:99:11 | vector.cpp:96:13:96:18 | AST only | -| vector.cpp:100:10:100:11 | vector.cpp:96:13:96:18 | AST only | -| vector.cpp:171:13:171:13 | vector.cpp:170:14:170:19 | AST only | -| vector.cpp:180:13:180:13 | vector.cpp:179:14:179:19 | AST only | -| vector.cpp:201:13:201:13 | vector.cpp:200:14:200:19 | AST only | -| vector.cpp:286:10:286:13 | vector.cpp:284:15:284:20 | AST only | -| vector.cpp:287:7:287:18 | vector.cpp:284:15:284:20 | AST only | -| vector.cpp:290:7:290:8 | vector.cpp:289:17:289:30 | AST only | -| vector.cpp:291:10:291:13 | vector.cpp:289:17:289:30 | AST only | -| vector.cpp:292:7:292:18 | vector.cpp:289:17:289:30 | AST only | -| vector.cpp:308:9:308:14 | vector.cpp:303:14:303:19 | AST only | -| vector.cpp:311:9:311:14 | vector.cpp:303:14:303:19 | AST only | -| vector.cpp:342:7:342:8 | vector.cpp:341:8:341:13 | AST only | -| vector.cpp:347:7:347:8 | vector.cpp:345:9:345:14 | AST only | -| vector.cpp:357:7:357:8 | vector.cpp:330:10:330:15 | AST only | -| vector.cpp:361:7:361:8 | vector.cpp:360:8:360:13 | AST only | -| vector.cpp:363:7:363:8 | vector.cpp:360:8:360:13 | AST only | -| vector.cpp:367:7:367:8 | vector.cpp:366:8:366:13 | AST only | -| vector.cpp:369:7:369:8 | vector.cpp:366:8:366:13 | AST only | -| vector.cpp:374:8:374:9 | vector.cpp:373:9:373:14 | AST only | -| vector.cpp:379:7:379:8 | vector.cpp:373:9:373:14 | AST only | -| vector.cpp:383:7:383:8 | vector.cpp:382:8:382:13 | AST only | -| vector.cpp:385:7:385:8 | vector.cpp:382:8:382:13 | AST only | -| vector.cpp:392:7:392:8 | vector.cpp:330:10:330:15 | AST only | -| vector.cpp:392:7:392:8 | vector.cpp:389:8:389:13 | AST only | -| vector.cpp:400:7:400:9 | vector.cpp:399:38:399:43 | AST only | -| vector.cpp:405:7:405:9 | vector.cpp:404:9:404:14 | AST only | -| vector.cpp:409:7:409:9 | vector.cpp:408:11:408:16 | AST only | -| vector.cpp:414:7:414:9 | vector.cpp:413:11:413:16 | AST only | -| vector.cpp:422:8:422:10 | vector.cpp:417:33:417:45 | AST only | -| vector.cpp:429:8:429:10 | vector.cpp:417:33:417:45 | AST only | -| vector.cpp:436:8:436:10 | vector.cpp:435:11:435:16 | AST only | -| vector.cpp:443:8:443:10 | vector.cpp:417:33:417:45 | AST only | -| vector.cpp:450:8:450:10 | vector.cpp:449:11:449:16 | AST only | -| vector.cpp:473:8:473:8 | vector.cpp:468:11:468:16 | AST only | -| vector.cpp:486:8:486:9 | vector.cpp:478:21:478:37 | AST only | -| vector.cpp:494:7:494:8 | vector.cpp:493:18:493:23 | AST only | -| vector.cpp:497:7:497:8 | vector.cpp:496:25:496:30 | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected deleted file mode 100644 index e84ce0d4c2e..00000000000 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected +++ /dev/null @@ -1,580 +0,0 @@ -| arrayassignment.cpp:16:7:16:7 | x | arrayassignment.cpp:14:9:14:14 | call to source | -| arrayassignment.cpp:17:7:17:10 | * ... | arrayassignment.cpp:14:9:14:14 | call to source | -| arrayassignment.cpp:18:7:18:11 | * ... | arrayassignment.cpp:14:9:14:14 | call to source | -| arrayassignment.cpp:19:7:19:9 | (reference dereference) | arrayassignment.cpp:14:9:14:14 | call to source | -| arrayassignment.cpp:31:7:31:7 | x | arrayassignment.cpp:29:8:29:13 | call to source | -| arrayassignment.cpp:32:7:32:10 | * ... | arrayassignment.cpp:29:8:29:13 | call to source | -| arrayassignment.cpp:33:7:33:9 | (reference dereference) | arrayassignment.cpp:29:8:29:13 | call to source | -| arrayassignment.cpp:34:7:34:10 | (reference dereference) | arrayassignment.cpp:29:8:29:13 | call to source | -| arrayassignment.cpp:56:7:56:8 | mi | arrayassignment.cpp:54:9:54:14 | call to source | -| arrayassignment.cpp:57:10:57:15 | (reference dereference) | arrayassignment.cpp:54:9:54:14 | call to source | -| arrayassignment.cpp:66:7:66:8 | mi | arrayassignment.cpp:64:13:64:18 | call to source | -| arrayassignment.cpp:67:10:67:15 | (reference dereference) | arrayassignment.cpp:64:13:64:18 | call to source | -| arrayassignment.cpp:101:7:101:18 | access to array | arrayassignment.cpp:99:17:99:22 | call to source | -| arrayassignment.cpp:135:7:135:10 | (reference dereference) | arrayassignment.cpp:134:9:134:14 | call to source | -| arrayassignment.cpp:136:7:136:13 | access to array | arrayassignment.cpp:134:9:134:14 | call to source | -| arrayassignment.cpp:140:7:140:11 | * ... | arrayassignment.cpp:139:10:139:15 | call to source | -| arrayassignment.cpp:141:7:141:13 | access to array | arrayassignment.cpp:139:10:139:15 | call to source | -| arrayassignment.cpp:145:7:145:13 | access to array | arrayassignment.cpp:144:12:144:17 | call to source | -| arrayassignment.cpp:146:7:146:13 | access to array | arrayassignment.cpp:144:12:144:17 | call to source | -| copyableclass.cpp:40:8:40:9 | s1 | copyableclass.cpp:34:22:34:27 | call to source | -| copyableclass.cpp:41:8:41:9 | s2 | copyableclass.cpp:35:24:35:29 | call to source | -| copyableclass.cpp:42:8:42:9 | s3 | copyableclass.cpp:34:22:34:27 | call to source | -| copyableclass.cpp:43:8:43:9 | s4 | copyableclass.cpp:38:8:38:13 | call to source | -| copyableclass.cpp:65:8:65:9 | s1 | copyableclass.cpp:60:40:60:45 | call to source | -| copyableclass.cpp:66:8:66:9 | s2 | copyableclass.cpp:63:24:63:29 | call to source | -| copyableclass.cpp:67:11:67:21 | (reference dereference) | copyableclass.cpp:67:13:67:18 | call to source | -| copyableclass_declonly.cpp:40:8:40:9 | s1 | copyableclass_declonly.cpp:34:30:34:35 | call to source | -| copyableclass_declonly.cpp:41:8:41:9 | s2 | copyableclass_declonly.cpp:35:32:35:37 | call to source | -| copyableclass_declonly.cpp:42:8:42:9 | s3 | copyableclass_declonly.cpp:34:30:34:35 | call to source | -| copyableclass_declonly.cpp:43:8:43:9 | s4 | copyableclass_declonly.cpp:38:8:38:13 | call to source | -| copyableclass_declonly.cpp:65:8:65:9 | s1 | copyableclass_declonly.cpp:60:56:60:61 | call to source | -| copyableclass_declonly.cpp:66:8:66:9 | s2 | copyableclass_declonly.cpp:63:32:63:37 | call to source | -| format.cpp:57:8:57:13 | Argument 0 indirection | format.cpp:56:36:56:49 | call to source | -| format.cpp:62:8:62:13 | Argument 0 indirection | format.cpp:61:30:61:43 | call to source | -| format.cpp:67:8:67:13 | Argument 0 indirection | format.cpp:66:52:66:65 | call to source | -| format.cpp:72:8:72:13 | Argument 0 indirection | format.cpp:71:42:71:55 | call to source | -| format.cpp:83:8:83:13 | Argument 0 indirection | format.cpp:82:36:82:41 | call to source | -| format.cpp:88:8:88:13 | Argument 0 indirection | format.cpp:87:38:87:43 | call to source | -| format.cpp:94:8:94:13 | Argument 0 indirection | format.cpp:93:36:93:49 | call to source | -| format.cpp:100:8:100:13 | Argument 0 indirection | format.cpp:99:30:99:43 | call to source | -| format.cpp:105:8:105:13 | Argument 0 indirection | format.cpp:104:31:104:45 | call to source | -| format.cpp:110:8:110:14 | Argument 0 indirection | format.cpp:109:38:109:52 | call to source | -| format.cpp:115:8:115:13 | Argument 0 indirection | format.cpp:114:37:114:50 | call to source | -| format.cpp:157:7:157:22 | access to array | format.cpp:147:12:147:25 | call to source | -| format.cpp:158:7:158:27 | ... + ... | format.cpp:148:16:148:30 | call to source | -| map.cpp:29:9:29:13 | first | map.cpp:28:12:28:17 | call to source | -| map.cpp:35:9:35:14 | second | map.cpp:33:13:33:18 | call to source | -| map.cpp:44:9:44:13 | first | map.cpp:43:30:43:35 | call to source | -| map.cpp:49:9:49:13 | first | map.cpp:48:37:48:42 | call to source | -| map.cpp:50:9:50:14 | second | map.cpp:48:37:48:42 | call to source | -| map.cpp:51:7:51:7 | f | map.cpp:48:37:48:42 | call to source | -| map.cpp:54:9:54:13 | first | map.cpp:48:37:48:42 | call to source | -| map.cpp:55:9:55:14 | second | map.cpp:48:37:48:42 | call to source | -| map.cpp:56:7:56:7 | g | map.cpp:48:37:48:42 | call to source | -| map.cpp:60:9:60:13 | first | map.cpp:48:37:48:42 | call to source | -| map.cpp:61:9:61:14 | second | map.cpp:48:37:48:42 | call to source | -| map.cpp:62:7:62:7 | h | map.cpp:48:37:48:42 | call to source | -| map.cpp:70:9:70:13 | first | map.cpp:65:37:65:42 | call to source | -| map.cpp:71:9:71:14 | second | map.cpp:65:37:65:42 | call to source | -| map.cpp:72:7:72:7 | i | map.cpp:65:37:65:42 | call to source | -| map.cpp:73:9:73:13 | first | map.cpp:65:37:65:42 | call to source | -| map.cpp:74:9:74:14 | second | map.cpp:65:37:65:42 | call to source | -| map.cpp:75:7:75:7 | j | map.cpp:65:37:65:42 | call to source | -| map.cpp:76:9:76:13 | first | map.cpp:66:37:66:42 | call to source | -| map.cpp:77:9:77:14 | second | map.cpp:66:37:66:42 | call to source | -| map.cpp:78:7:78:7 | k | map.cpp:66:37:66:42 | call to source | -| map.cpp:79:9:79:13 | first | map.cpp:66:37:66:42 | call to source | -| map.cpp:80:9:80:14 | second | map.cpp:66:37:66:42 | call to source | -| map.cpp:81:7:81:7 | l | map.cpp:66:37:66:42 | call to source | -| map.cpp:87:34:87:38 | first | map.cpp:87:17:87:22 | call to source | -| map.cpp:89:7:89:32 | call to pair | map.cpp:89:24:89:29 | call to source | -| map.cpp:90:34:90:38 | first | map.cpp:90:24:90:29 | call to source | -| map.cpp:91:34:91:39 | second | map.cpp:91:24:91:29 | call to source | -| map.cpp:108:7:108:54 | call to iterator | map.cpp:108:39:108:44 | call to source | -| map.cpp:110:10:110:15 | call to insert | map.cpp:110:62:110:67 | call to source | -| map.cpp:111:7:111:48 | call to iterator | map.cpp:111:34:111:39 | call to source | -| map.cpp:112:10:112:25 | call to insert_or_assign | map.cpp:112:46:112:51 | call to source | -| map.cpp:114:7:114:8 | call to map | map.cpp:108:39:108:44 | call to source | -| map.cpp:116:7:116:8 | call to map | map.cpp:110:62:110:67 | call to source | -| map.cpp:117:7:117:8 | call to map | map.cpp:111:34:111:39 | call to source | -| map.cpp:118:7:118:8 | call to map | map.cpp:112:46:112:51 | call to source | -| map.cpp:120:10:120:13 | call to find | map.cpp:108:39:108:44 | call to source | -| map.cpp:122:10:122:13 | call to find | map.cpp:110:62:110:67 | call to source | -| map.cpp:123:10:123:13 | call to find | map.cpp:111:34:111:39 | call to source | -| map.cpp:124:10:124:13 | call to find | map.cpp:112:46:112:51 | call to source | -| map.cpp:126:10:126:13 | call to find | map.cpp:108:39:108:44 | call to source | -| map.cpp:128:10:128:13 | call to find | map.cpp:110:62:110:67 | call to source | -| map.cpp:129:10:129:13 | call to find | map.cpp:111:34:111:39 | call to source | -| map.cpp:130:10:130:13 | call to find | map.cpp:112:46:112:51 | call to source | -| map.cpp:137:7:137:8 | call to map | map.cpp:108:39:108:44 | call to source | -| map.cpp:138:7:138:8 | call to map | map.cpp:108:39:108:44 | call to source | -| map.cpp:139:7:139:8 | call to map | map.cpp:108:39:108:44 | call to source | -| map.cpp:140:10:140:13 | call to find | map.cpp:108:39:108:44 | call to source | -| map.cpp:141:10:141:13 | call to find | map.cpp:108:39:108:44 | call to source | -| map.cpp:142:10:142:13 | call to find | map.cpp:108:39:108:44 | call to source | -| map.cpp:154:8:154:10 | call to pair | map.cpp:108:39:108:44 | call to source | -| map.cpp:155:12:155:16 | first | map.cpp:108:39:108:44 | call to source | -| map.cpp:156:12:156:17 | second | map.cpp:108:39:108:44 | call to source | -| map.cpp:161:12:161:16 | first | map.cpp:108:39:108:44 | call to source | -| map.cpp:162:12:162:17 | second | map.cpp:108:39:108:44 | call to source | -| map.cpp:168:7:168:27 | ... = ... | map.cpp:168:20:168:25 | call to source | -| map.cpp:170:7:170:30 | ... = ... | map.cpp:170:23:170:28 | call to source | -| map.cpp:182:10:182:20 | call to lower_bound | map.cpp:108:39:108:44 | call to source | -| map.cpp:183:10:183:20 | call to upper_bound | map.cpp:108:39:108:44 | call to source | -| map.cpp:184:7:184:31 | call to iterator | map.cpp:108:39:108:44 | call to source | -| map.cpp:185:7:185:32 | call to iterator | map.cpp:108:39:108:44 | call to source | -| map.cpp:186:10:186:20 | call to upper_bound | map.cpp:108:39:108:44 | call to source | -| map.cpp:187:7:187:32 | call to iterator | map.cpp:108:39:108:44 | call to source | -| map.cpp:193:7:193:9 | call to map | map.cpp:191:49:191:54 | call to source | -| map.cpp:196:7:196:9 | call to map | map.cpp:192:49:192:54 | call to source | -| map.cpp:199:7:199:9 | call to map | map.cpp:191:49:191:54 | call to source | -| map.cpp:200:7:200:9 | call to map | map.cpp:191:49:191:54 | call to source | -| map.cpp:201:7:201:9 | call to map | map.cpp:192:49:192:54 | call to source | -| map.cpp:202:7:202:9 | call to map | map.cpp:192:49:192:54 | call to source | -| map.cpp:210:7:210:9 | call to map | map.cpp:206:49:206:54 | call to source | -| map.cpp:213:7:213:9 | call to map | map.cpp:209:49:209:54 | call to source | -| map.cpp:216:7:216:9 | call to map | map.cpp:206:49:206:54 | call to source | -| map.cpp:218:7:218:9 | call to map | map.cpp:209:49:209:54 | call to source | -| map.cpp:219:7:219:9 | call to map | map.cpp:209:49:209:54 | call to source | -| map.cpp:225:7:225:9 | call to map | map.cpp:223:49:223:54 | call to source | -| map.cpp:225:7:225:9 | call to map | map.cpp:224:49:224:54 | call to source | -| map.cpp:226:11:226:15 | call to erase | map.cpp:223:49:223:54 | call to source | -| map.cpp:226:11:226:15 | call to erase | map.cpp:224:49:224:54 | call to source | -| map.cpp:227:7:227:9 | call to map | map.cpp:223:49:223:54 | call to source | -| map.cpp:227:7:227:9 | call to map | map.cpp:224:49:224:54 | call to source | -| map.cpp:229:7:229:9 | call to map | map.cpp:223:49:223:54 | call to source | -| map.cpp:229:7:229:9 | call to map | map.cpp:224:49:224:54 | call to source | -| map.cpp:235:7:235:40 | call to iterator | map.cpp:235:26:235:31 | call to source | -| map.cpp:236:7:236:9 | call to map | map.cpp:235:26:235:31 | call to source | -| map.cpp:239:11:239:22 | call to emplace_hint | map.cpp:239:44:239:49 | call to source | -| map.cpp:240:7:240:9 | call to map | map.cpp:239:44:239:49 | call to source | -| map.cpp:246:7:246:44 | call to iterator | map.cpp:246:30:246:35 | call to source | -| map.cpp:247:7:247:9 | call to map | map.cpp:246:30:246:35 | call to source | -| map.cpp:250:11:250:21 | call to try_emplace | map.cpp:250:43:250:48 | call to source | -| map.cpp:251:7:251:9 | call to map | map.cpp:250:43:250:48 | call to source | -| map.cpp:260:7:260:54 | call to iterator | map.cpp:260:39:260:44 | call to source | -| map.cpp:262:10:262:15 | call to insert | map.cpp:262:62:262:67 | call to source | -| map.cpp:263:7:263:48 | call to iterator | map.cpp:263:34:263:39 | call to source | -| map.cpp:264:10:264:25 | call to insert_or_assign | map.cpp:264:46:264:51 | call to source | -| map.cpp:266:7:266:8 | call to unordered_map | map.cpp:260:39:260:44 | call to source | -| map.cpp:268:7:268:8 | call to unordered_map | map.cpp:262:62:262:67 | call to source | -| map.cpp:269:7:269:8 | call to unordered_map | map.cpp:263:34:263:39 | call to source | -| map.cpp:270:7:270:8 | call to unordered_map | map.cpp:264:46:264:51 | call to source | -| map.cpp:272:10:272:13 | call to find | map.cpp:260:39:260:44 | call to source | -| map.cpp:274:10:274:13 | call to find | map.cpp:262:62:262:67 | call to source | -| map.cpp:275:10:275:13 | call to find | map.cpp:263:34:263:39 | call to source | -| map.cpp:276:10:276:13 | call to find | map.cpp:264:46:264:51 | call to source | -| map.cpp:278:10:278:13 | call to find | map.cpp:260:39:260:44 | call to source | -| map.cpp:280:10:280:13 | call to find | map.cpp:262:62:262:67 | call to source | -| map.cpp:281:10:281:13 | call to find | map.cpp:263:34:263:39 | call to source | -| map.cpp:282:10:282:13 | call to find | map.cpp:264:46:264:51 | call to source | -| map.cpp:289:7:289:8 | call to unordered_map | map.cpp:260:39:260:44 | call to source | -| map.cpp:290:7:290:8 | call to unordered_map | map.cpp:260:39:260:44 | call to source | -| map.cpp:291:7:291:8 | call to unordered_map | map.cpp:260:39:260:44 | call to source | -| map.cpp:292:10:292:13 | call to find | map.cpp:260:39:260:44 | call to source | -| map.cpp:293:10:293:13 | call to find | map.cpp:260:39:260:44 | call to source | -| map.cpp:294:10:294:13 | call to find | map.cpp:260:39:260:44 | call to source | -| map.cpp:306:8:306:10 | call to pair | map.cpp:260:39:260:44 | call to source | -| map.cpp:307:12:307:16 | first | map.cpp:260:39:260:44 | call to source | -| map.cpp:308:12:308:17 | second | map.cpp:260:39:260:44 | call to source | -| map.cpp:313:12:313:16 | first | map.cpp:260:39:260:44 | call to source | -| map.cpp:314:12:314:17 | second | map.cpp:260:39:260:44 | call to source | -| map.cpp:320:7:320:27 | ... = ... | map.cpp:320:20:320:25 | call to source | -| map.cpp:322:7:322:30 | ... = ... | map.cpp:322:23:322:28 | call to source | -| map.cpp:334:7:334:31 | call to iterator | map.cpp:260:39:260:44 | call to source | -| map.cpp:335:7:335:32 | call to iterator | map.cpp:260:39:260:44 | call to source | -| map.cpp:336:7:336:32 | call to iterator | map.cpp:260:39:260:44 | call to source | -| map.cpp:342:7:342:9 | call to unordered_map | map.cpp:340:49:340:54 | call to source | -| map.cpp:345:7:345:9 | call to unordered_map | map.cpp:341:49:341:54 | call to source | -| map.cpp:348:7:348:9 | call to unordered_map | map.cpp:340:49:340:54 | call to source | -| map.cpp:349:7:349:9 | call to unordered_map | map.cpp:340:49:340:54 | call to source | -| map.cpp:350:7:350:9 | call to unordered_map | map.cpp:341:49:341:54 | call to source | -| map.cpp:351:7:351:9 | call to unordered_map | map.cpp:341:49:341:54 | call to source | -| map.cpp:359:7:359:9 | call to unordered_map | map.cpp:355:49:355:54 | call to source | -| map.cpp:362:7:362:9 | call to unordered_map | map.cpp:358:49:358:54 | call to source | -| map.cpp:365:7:365:9 | call to unordered_map | map.cpp:355:49:355:54 | call to source | -| map.cpp:367:7:367:9 | call to unordered_map | map.cpp:358:49:358:54 | call to source | -| map.cpp:368:7:368:9 | call to unordered_map | map.cpp:358:49:358:54 | call to source | -| map.cpp:374:7:374:9 | call to unordered_map | map.cpp:372:49:372:54 | call to source | -| map.cpp:374:7:374:9 | call to unordered_map | map.cpp:373:49:373:54 | call to source | -| map.cpp:375:11:375:15 | call to erase | map.cpp:372:49:372:54 | call to source | -| map.cpp:375:11:375:15 | call to erase | map.cpp:373:49:373:54 | call to source | -| map.cpp:376:7:376:9 | call to unordered_map | map.cpp:372:49:372:54 | call to source | -| map.cpp:376:7:376:9 | call to unordered_map | map.cpp:373:49:373:54 | call to source | -| map.cpp:378:7:378:9 | call to unordered_map | map.cpp:372:49:372:54 | call to source | -| map.cpp:378:7:378:9 | call to unordered_map | map.cpp:373:49:373:54 | call to source | -| map.cpp:384:7:384:40 | call to iterator | map.cpp:384:26:384:31 | call to source | -| map.cpp:385:7:385:9 | call to unordered_map | map.cpp:384:26:384:31 | call to source | -| map.cpp:388:11:388:22 | call to emplace_hint | map.cpp:388:44:388:49 | call to source | -| map.cpp:389:7:389:9 | call to unordered_map | map.cpp:388:44:388:49 | call to source | -| map.cpp:396:7:396:44 | call to iterator | map.cpp:396:30:396:35 | call to source | -| map.cpp:397:40:397:45 | second | map.cpp:396:30:396:35 | call to source | -| map.cpp:397:40:397:45 | second | map.cpp:397:30:397:35 | call to source | -| map.cpp:398:7:398:9 | call to unordered_map | map.cpp:396:30:396:35 | call to source | -| map.cpp:398:7:398:9 | call to unordered_map | map.cpp:397:30:397:35 | call to source | -| map.cpp:401:11:401:21 | call to try_emplace | map.cpp:401:43:401:48 | call to source | -| map.cpp:402:7:402:9 | call to unordered_map | map.cpp:401:43:401:48 | call to source | -| map.cpp:416:7:416:41 | call to pair | map.cpp:416:30:416:35 | call to source | -| map.cpp:417:7:417:9 | call to unordered_map | map.cpp:416:30:416:35 | call to source | -| map.cpp:419:7:419:41 | call to pair | map.cpp:419:33:419:38 | call to source | -| map.cpp:420:7:420:9 | call to unordered_map | map.cpp:419:33:419:38 | call to source | -| map.cpp:431:7:431:67 | call to iterator | map.cpp:431:52:431:57 | call to source | -| map.cpp:432:7:432:9 | call to unordered_map | map.cpp:431:52:431:57 | call to source | -| map.cpp:433:11:433:22 | call to emplace_hint | map.cpp:431:52:431:57 | call to source | -| movableclass.cpp:44:8:44:9 | s1 | movableclass.cpp:39:21:39:26 | call to source | -| movableclass.cpp:45:8:45:9 | s2 | movableclass.cpp:40:23:40:28 | call to source | -| movableclass.cpp:46:8:46:9 | s3 | movableclass.cpp:42:8:42:13 | call to source | -| movableclass.cpp:54:8:54:9 | s1 | movableclass.cpp:50:38:50:43 | call to source | -| movableclass.cpp:55:8:55:9 | s2 | movableclass.cpp:52:23:52:28 | call to source | -| movableclass.cpp:64:8:64:9 | s2 | movableclass.cpp:23:55:23:60 | call to source | -| movableclass.cpp:65:11:65:21 | (reference dereference) | movableclass.cpp:65:13:65:18 | call to source | -| set.cpp:20:7:20:31 | call to iterator | set.cpp:20:17:20:22 | call to source | -| set.cpp:22:10:22:15 | call to insert | set.cpp:22:29:22:34 | call to source | -| set.cpp:26:7:26:8 | call to set | set.cpp:20:17:20:22 | call to source | -| set.cpp:28:7:28:8 | call to set | set.cpp:22:29:22:34 | call to source | -| set.cpp:30:7:30:8 | call to set | set.cpp:20:17:20:22 | call to source | -| set.cpp:32:10:32:13 | call to find | set.cpp:20:17:20:22 | call to source | -| set.cpp:34:10:34:13 | call to find | set.cpp:22:29:22:34 | call to source | -| set.cpp:36:10:36:13 | call to find | set.cpp:20:17:20:22 | call to source | -| set.cpp:44:7:44:8 | call to set | set.cpp:20:17:20:22 | call to source | -| set.cpp:45:7:45:8 | call to set | set.cpp:20:17:20:22 | call to source | -| set.cpp:46:7:46:8 | call to set | set.cpp:20:17:20:22 | call to source | -| set.cpp:47:7:47:9 | call to set | set.cpp:20:17:20:22 | call to source | -| set.cpp:48:10:48:13 | call to find | set.cpp:20:17:20:22 | call to source | -| set.cpp:49:10:49:13 | call to find | set.cpp:20:17:20:22 | call to source | -| set.cpp:50:10:50:13 | call to find | set.cpp:20:17:20:22 | call to source | -| set.cpp:51:11:51:14 | call to find | set.cpp:20:17:20:22 | call to source | -| set.cpp:61:8:61:8 | call to operator* | set.cpp:20:17:20:22 | call to source | -| set.cpp:61:8:61:11 | (reference dereference) | set.cpp:20:17:20:22 | call to source | -| set.cpp:69:11:69:21 | call to lower_bound | set.cpp:67:13:67:18 | call to source | -| set.cpp:70:11:70:21 | call to upper_bound | set.cpp:67:13:67:18 | call to source | -| set.cpp:71:7:71:32 | call to iterator | set.cpp:67:13:67:18 | call to source | -| set.cpp:72:7:72:33 | call to iterator | set.cpp:67:13:67:18 | call to source | -| set.cpp:78:7:78:9 | call to set | set.cpp:76:13:76:18 | call to source | -| set.cpp:81:7:81:9 | call to set | set.cpp:77:13:77:18 | call to source | -| set.cpp:84:7:84:9 | call to set | set.cpp:76:13:76:18 | call to source | -| set.cpp:85:7:85:9 | call to set | set.cpp:76:13:76:18 | call to source | -| set.cpp:86:7:86:9 | call to set | set.cpp:77:13:77:18 | call to source | -| set.cpp:87:7:87:9 | call to set | set.cpp:77:13:77:18 | call to source | -| set.cpp:95:7:95:9 | call to set | set.cpp:91:13:91:18 | call to source | -| set.cpp:98:7:98:9 | call to set | set.cpp:94:13:94:18 | call to source | -| set.cpp:101:7:101:9 | call to set | set.cpp:91:13:91:18 | call to source | -| set.cpp:103:7:103:9 | call to set | set.cpp:94:13:94:18 | call to source | -| set.cpp:104:7:104:9 | call to set | set.cpp:94:13:94:18 | call to source | -| set.cpp:110:7:110:9 | call to set | set.cpp:108:13:108:18 | call to source | -| set.cpp:110:7:110:9 | call to set | set.cpp:109:13:109:18 | call to source | -| set.cpp:111:11:111:15 | call to erase | set.cpp:108:13:108:18 | call to source | -| set.cpp:111:11:111:15 | call to erase | set.cpp:109:13:109:18 | call to source | -| set.cpp:112:7:112:9 | call to set | set.cpp:108:13:108:18 | call to source | -| set.cpp:112:7:112:9 | call to set | set.cpp:109:13:109:18 | call to source | -| set.cpp:114:7:114:9 | call to set | set.cpp:108:13:108:18 | call to source | -| set.cpp:114:7:114:9 | call to set | set.cpp:109:13:109:18 | call to source | -| set.cpp:120:7:120:33 | call to iterator | set.cpp:120:19:120:24 | call to source | -| set.cpp:121:7:121:9 | call to set | set.cpp:120:19:120:24 | call to source | -| set.cpp:124:11:124:22 | call to emplace_hint | set.cpp:124:37:124:42 | call to source | -| set.cpp:125:7:125:9 | call to set | set.cpp:124:37:124:42 | call to source | -| set.cpp:134:7:134:31 | call to iterator | set.cpp:134:17:134:22 | call to source | -| set.cpp:136:10:136:15 | call to insert | set.cpp:136:29:136:34 | call to source | -| set.cpp:140:7:140:8 | call to unordered_set | set.cpp:134:17:134:22 | call to source | -| set.cpp:142:7:142:8 | call to unordered_set | set.cpp:136:29:136:34 | call to source | -| set.cpp:144:7:144:8 | call to unordered_set | set.cpp:134:17:134:22 | call to source | -| set.cpp:146:10:146:13 | call to find | set.cpp:134:17:134:22 | call to source | -| set.cpp:148:10:148:13 | call to find | set.cpp:136:29:136:34 | call to source | -| set.cpp:150:10:150:13 | call to find | set.cpp:134:17:134:22 | call to source | -| set.cpp:158:7:158:8 | call to unordered_set | set.cpp:134:17:134:22 | call to source | -| set.cpp:159:7:159:8 | call to unordered_set | set.cpp:134:17:134:22 | call to source | -| set.cpp:160:7:160:8 | call to unordered_set | set.cpp:134:17:134:22 | call to source | -| set.cpp:161:7:161:9 | call to unordered_set | set.cpp:134:17:134:22 | call to source | -| set.cpp:162:10:162:13 | call to find | set.cpp:134:17:134:22 | call to source | -| set.cpp:163:10:163:13 | call to find | set.cpp:134:17:134:22 | call to source | -| set.cpp:164:10:164:13 | call to find | set.cpp:134:17:134:22 | call to source | -| set.cpp:165:11:165:14 | call to find | set.cpp:134:17:134:22 | call to source | -| set.cpp:175:8:175:8 | call to operator* | set.cpp:134:17:134:22 | call to source | -| set.cpp:175:8:175:11 | (reference dereference) | set.cpp:134:17:134:22 | call to source | -| set.cpp:183:7:183:32 | call to iterator | set.cpp:181:13:181:18 | call to source | -| set.cpp:184:7:184:33 | call to iterator | set.cpp:181:13:181:18 | call to source | -| set.cpp:190:7:190:9 | call to unordered_set | set.cpp:188:13:188:18 | call to source | -| set.cpp:193:7:193:9 | call to unordered_set | set.cpp:189:13:189:18 | call to source | -| set.cpp:196:7:196:9 | call to unordered_set | set.cpp:188:13:188:18 | call to source | -| set.cpp:197:7:197:9 | call to unordered_set | set.cpp:188:13:188:18 | call to source | -| set.cpp:198:7:198:9 | call to unordered_set | set.cpp:189:13:189:18 | call to source | -| set.cpp:199:7:199:9 | call to unordered_set | set.cpp:189:13:189:18 | call to source | -| set.cpp:207:7:207:9 | call to unordered_set | set.cpp:203:13:203:18 | call to source | -| set.cpp:210:7:210:9 | call to unordered_set | set.cpp:206:13:206:18 | call to source | -| set.cpp:213:7:213:9 | call to unordered_set | set.cpp:203:13:203:18 | call to source | -| set.cpp:215:7:215:9 | call to unordered_set | set.cpp:206:13:206:18 | call to source | -| set.cpp:216:7:216:9 | call to unordered_set | set.cpp:206:13:206:18 | call to source | -| set.cpp:222:7:222:9 | call to unordered_set | set.cpp:220:13:220:18 | call to source | -| set.cpp:222:7:222:9 | call to unordered_set | set.cpp:221:13:221:18 | call to source | -| set.cpp:223:11:223:15 | call to erase | set.cpp:220:13:220:18 | call to source | -| set.cpp:223:11:223:15 | call to erase | set.cpp:221:13:221:18 | call to source | -| set.cpp:224:7:224:9 | call to unordered_set | set.cpp:220:13:220:18 | call to source | -| set.cpp:224:7:224:9 | call to unordered_set | set.cpp:221:13:221:18 | call to source | -| set.cpp:226:7:226:9 | call to unordered_set | set.cpp:220:13:220:18 | call to source | -| set.cpp:226:7:226:9 | call to unordered_set | set.cpp:221:13:221:18 | call to source | -| set.cpp:232:7:232:33 | call to iterator | set.cpp:232:19:232:24 | call to source | -| set.cpp:233:7:233:9 | call to unordered_set | set.cpp:232:19:232:24 | call to source | -| set.cpp:236:11:236:22 | call to emplace_hint | set.cpp:236:37:236:42 | call to source | -| set.cpp:237:7:237:9 | call to unordered_set | set.cpp:236:37:236:42 | call to source | -| smart_pointer.cpp:13:10:13:10 | Argument 0 indirection | smart_pointer.cpp:11:52:11:57 | call to source | -| smart_pointer.cpp:25:10:25:10 | Argument 0 indirection | smart_pointer.cpp:23:52:23:57 | call to source | -| smart_pointer.cpp:52:12:52:14 | call to get | smart_pointer.cpp:51:52:51:57 | call to source | -| smart_pointer.cpp:57:12:57:14 | call to get | smart_pointer.cpp:56:52:56:57 | call to source | -| standalone_iterators.cpp:40:10:40:10 | call to operator* | standalone_iterators.cpp:39:45:39:51 | source1 | -| standalone_iterators.cpp:46:10:46:10 | call to operator* | standalone_iterators.cpp:45:39:45:45 | source1 | -| string.cpp:29:7:29:7 | a | string.cpp:25:12:25:17 | call to source | -| string.cpp:31:7:31:7 | Argument 0 indirection | string.cpp:27:16:27:21 | call to source | -| string.cpp:56:7:56:8 | cs | string.cpp:51:19:51:24 | call to source | -| string.cpp:57:7:57:8 | Argument 0 indirection | string.cpp:51:19:51:24 | call to source | -| string.cpp:71:7:71:8 | Argument 0 indirection | string.cpp:62:19:62:24 | call to source | -| string.cpp:93:8:93:9 | Argument 0 indirection | string.cpp:88:18:88:23 | call to source | -| string.cpp:94:8:94:9 | Argument 0 indirection | string.cpp:89:20:89:25 | call to source | -| string.cpp:95:8:95:9 | Argument 0 indirection | string.cpp:91:8:91:13 | call to source | -| string.cpp:114:8:114:9 | Argument 0 indirection | string.cpp:110:32:110:37 | call to source | -| string.cpp:115:8:115:9 | Argument 0 indirection | string.cpp:112:20:112:25 | call to source | -| string.cpp:122:8:122:8 | c | string.cpp:120:16:120:21 | call to source | -| string.cpp:126:8:126:8 | call to operator* | string.cpp:120:16:120:21 | call to source | -| string.cpp:126:8:126:11 | (reference dereference) | string.cpp:120:16:120:21 | call to source | -| string.cpp:130:8:130:8 | (reference dereference) | string.cpp:120:16:120:21 | call to source | -| string.cpp:130:8:130:8 | c | string.cpp:120:16:120:21 | call to source | -| string.cpp:135:8:135:8 | (reference dereference) | string.cpp:133:28:133:33 | call to source | -| string.cpp:135:8:135:8 | c | string.cpp:133:28:133:33 | call to source | -| string.cpp:145:8:145:14 | Argument 0 indirection | string.cpp:142:18:142:23 | call to source | -| string.cpp:145:11:145:11 | call to operator+ | string.cpp:142:18:142:23 | call to source | -| string.cpp:146:8:146:14 | Argument 0 indirection | string.cpp:142:18:142:23 | call to source | -| string.cpp:146:11:146:11 | call to operator+ | string.cpp:142:18:142:23 | call to source | -| string.cpp:147:8:147:14 | Argument 0 indirection | string.cpp:142:18:142:23 | call to source | -| string.cpp:147:11:147:11 | call to operator+ | string.cpp:142:18:142:23 | call to source | -| string.cpp:150:8:150:20 | Argument 0 indirection | string.cpp:150:13:150:18 | call to source | -| string.cpp:150:11:150:11 | call to operator+ | string.cpp:150:13:150:18 | call to source | -| string.cpp:159:8:159:9 | Argument 0 indirection | string.cpp:155:18:155:23 | call to source | -| string.cpp:163:8:163:9 | Argument 0 indirection | string.cpp:155:18:155:23 | call to source | -| string.cpp:168:8:168:9 | Argument 0 indirection | string.cpp:166:14:166:19 | call to source | -| string.cpp:172:8:172:9 | Argument 0 indirection | string.cpp:155:18:155:23 | call to source | -| string.cpp:177:8:177:9 | Argument 0 indirection | string.cpp:175:13:175:18 | call to source | -| string.cpp:185:8:185:10 | Argument 0 indirection | string.cpp:182:12:182:26 | call to source | -| string.cpp:200:7:200:8 | Argument 0 indirection | string.cpp:191:17:191:22 | call to source | -| string.cpp:203:7:203:8 | Argument 0 indirection | string.cpp:192:11:192:25 | call to source | -| string.cpp:206:7:206:8 | Argument 0 indirection | string.cpp:194:17:194:22 | call to source | -| string.cpp:221:7:221:8 | Argument 0 indirection | string.cpp:211:17:211:22 | call to source | -| string.cpp:225:7:225:8 | Argument 0 indirection | string.cpp:211:17:211:22 | call to source | -| string.cpp:229:7:229:8 | Argument 0 indirection | string.cpp:212:11:212:25 | call to source | -| string.cpp:244:7:244:8 | Argument 0 indirection | string.cpp:234:17:234:22 | call to source | -| string.cpp:248:7:248:8 | Argument 0 indirection | string.cpp:234:17:234:22 | call to source | -| string.cpp:252:7:252:8 | Argument 0 indirection | string.cpp:235:11:235:25 | call to source | -| string.cpp:265:7:265:8 | Argument 0 indirection | string.cpp:259:17:259:22 | call to source | -| string.cpp:275:7:275:8 | Argument 0 indirection | string.cpp:270:17:270:22 | call to source | -| string.cpp:277:7:277:8 | Argument 0 indirection | string.cpp:272:17:272:22 | call to source | -| string.cpp:282:7:282:8 | Argument 0 indirection | string.cpp:270:17:270:22 | call to source | -| string.cpp:283:7:283:8 | Argument 0 indirection | string.cpp:270:17:270:22 | call to source | -| string.cpp:284:7:284:8 | Argument 0 indirection | string.cpp:272:17:272:22 | call to source | -| string.cpp:285:7:285:8 | Argument 0 indirection | string.cpp:272:17:272:22 | call to source | -| string.cpp:293:7:293:8 | Argument 0 indirection | string.cpp:289:17:289:22 | call to source | -| string.cpp:294:7:294:8 | Argument 0 indirection | string.cpp:290:17:290:22 | call to source | -| string.cpp:295:7:295:8 | Argument 0 indirection | string.cpp:291:17:291:22 | call to source | -| string.cpp:301:7:301:8 | Argument 0 indirection | string.cpp:289:17:289:22 | call to source | -| string.cpp:303:7:303:8 | Argument 0 indirection | string.cpp:291:17:291:22 | call to source | -| string.cpp:323:7:323:29 | Argument 0 indirection | string.cpp:320:16:320:21 | call to source | -| string.cpp:323:9:323:14 | call to substr | string.cpp:320:16:320:21 | call to source | -| string.cpp:364:8:364:9 | Argument 0 indirection | string.cpp:358:18:358:23 | call to source | -| string.cpp:382:8:382:8 | call to operator* | string.cpp:374:18:374:23 | call to source | -| string.cpp:382:8:382:14 | (reference dereference) | string.cpp:374:18:374:23 | call to source | -| string.cpp:383:13:383:13 | call to operator[] | string.cpp:374:18:374:23 | call to source | -| string.cpp:383:13:383:15 | (reference dereference) | string.cpp:374:18:374:23 | call to source | -| string.cpp:396:8:396:8 | call to operator* | string.cpp:389:18:389:23 | call to source | -| string.cpp:396:8:396:15 | (reference dereference) | string.cpp:389:18:389:23 | call to source | -| string.cpp:397:8:397:8 | call to operator* | string.cpp:389:18:389:23 | call to source | -| string.cpp:397:8:397:15 | (reference dereference) | string.cpp:389:18:389:23 | call to source | -| string.cpp:404:8:404:8 | call to operator* | string.cpp:389:18:389:23 | call to source | -| string.cpp:404:8:404:11 | (reference dereference) | string.cpp:389:18:389:23 | call to source | -| string.cpp:407:8:407:8 | call to operator* | string.cpp:389:18:389:23 | call to source | -| string.cpp:407:8:407:11 | (reference dereference) | string.cpp:389:18:389:23 | call to source | -| string.cpp:415:8:415:8 | call to operator* | string.cpp:389:18:389:23 | call to source | -| string.cpp:415:8:415:11 | (reference dereference) | string.cpp:389:18:389:23 | call to source | -| string.cpp:419:8:419:10 | call to iterator | string.cpp:389:18:389:23 | call to source | -| string.cpp:422:8:422:10 | call to iterator | string.cpp:389:18:389:23 | call to source | -| string.cpp:437:7:437:8 | Argument 0 indirection | string.cpp:431:14:431:19 | call to source | -| string.cpp:450:8:450:8 | Argument 0 indirection | string.cpp:449:32:449:46 | call to source | -| string.cpp:463:8:463:8 | Argument 0 indirection | string.cpp:457:18:457:23 | call to source | -| string.cpp:466:8:466:9 | Argument 0 indirection | string.cpp:457:18:457:23 | call to source | -| string.cpp:479:8:479:8 | Argument 0 indirection | string.cpp:473:18:473:23 | call to source | -| string.cpp:482:8:482:9 | Argument 0 indirection | string.cpp:473:18:473:23 | call to source | -| string.cpp:495:8:495:8 | Argument 0 indirection | string.cpp:489:18:489:23 | call to source | -| string.cpp:498:8:498:9 | Argument 0 indirection | string.cpp:489:18:489:23 | call to source | -| string.cpp:511:7:511:8 | Argument 0 indirection | string.cpp:504:14:504:19 | call to source | -| string.cpp:513:7:513:8 | Argument 0 indirection | string.cpp:504:14:504:19 | call to source | -| string.cpp:542:8:542:8 | Argument 0 indirection | string.cpp:536:20:536:25 | call to source | -| string.cpp:544:8:544:8 | Argument 0 indirection | string.cpp:538:15:538:20 | call to source | -| string.cpp:562:8:562:8 | Argument 0 indirection | string.cpp:556:27:556:32 | call to source | -| string.cpp:564:8:564:8 | Argument 0 indirection | string.cpp:558:18:558:23 | call to source | -| stringstream.cpp:32:11:32:11 | call to operator<< | stringstream.cpp:32:14:32:19 | call to source | -| stringstream.cpp:32:11:32:22 | (reference dereference) | stringstream.cpp:32:14:32:19 | call to source | -| stringstream.cpp:33:20:33:20 | call to operator<< | stringstream.cpp:33:23:33:28 | call to source | -| stringstream.cpp:33:20:33:31 | (reference dereference) | stringstream.cpp:33:23:33:28 | call to source | -| stringstream.cpp:34:23:34:23 | call to operator<< | stringstream.cpp:34:14:34:19 | call to source | -| stringstream.cpp:34:23:34:31 | (reference dereference) | stringstream.cpp:34:14:34:19 | call to source | -| stringstream.cpp:38:7:38:9 | Argument 0 indirection | stringstream.cpp:32:14:32:19 | call to source | -| stringstream.cpp:40:7:40:9 | Argument 0 indirection | stringstream.cpp:34:14:34:19 | call to source | -| stringstream.cpp:43:7:43:15 | Argument 0 indirection | stringstream.cpp:32:14:32:19 | call to source | -| stringstream.cpp:43:11:43:13 | call to str | stringstream.cpp:32:14:32:19 | call to source | -| stringstream.cpp:45:7:45:15 | Argument 0 indirection | stringstream.cpp:34:14:34:19 | call to source | -| stringstream.cpp:45:11:45:13 | call to str | stringstream.cpp:34:14:34:19 | call to source | -| stringstream.cpp:52:7:52:9 | Argument 0 indirection | stringstream.cpp:49:10:49:15 | call to source | -| stringstream.cpp:53:7:53:9 | Argument 0 indirection | stringstream.cpp:50:10:50:15 | call to source | -| stringstream.cpp:59:7:59:9 | Argument 0 indirection | stringstream.cpp:56:15:56:29 | call to source | -| stringstream.cpp:66:7:66:10 | Argument 0 indirection | stringstream.cpp:63:18:63:23 | call to source | -| stringstream.cpp:81:7:81:9 | Argument 0 indirection | stringstream.cpp:70:32:70:37 | source | -| stringstream.cpp:83:7:83:15 | Argument 0 indirection | stringstream.cpp:70:32:70:37 | source | -| stringstream.cpp:83:11:83:13 | call to str | stringstream.cpp:70:32:70:37 | source | -| stringstream.cpp:85:7:85:8 | v2 | stringstream.cpp:70:32:70:37 | source | -| stringstream.cpp:103:7:103:9 | Argument 0 indirection | stringstream.cpp:91:19:91:24 | call to source | -| stringstream.cpp:105:7:105:9 | Argument 0 indirection | stringstream.cpp:95:44:95:49 | call to source | -| stringstream.cpp:107:7:107:9 | Argument 0 indirection | stringstream.cpp:100:31:100:36 | call to source | -| stringstream.cpp:120:7:120:9 | Argument 0 indirection | stringstream.cpp:113:24:113:29 | call to source | -| stringstream.cpp:121:7:121:9 | Argument 0 indirection | stringstream.cpp:113:24:113:29 | call to source | -| stringstream.cpp:122:7:122:9 | Argument 0 indirection | stringstream.cpp:115:24:115:29 | call to source | -| stringstream.cpp:123:7:123:9 | Argument 0 indirection | stringstream.cpp:115:24:115:29 | call to source | -| stringstream.cpp:143:11:143:11 | call to operator<< | stringstream.cpp:143:14:143:19 | call to source | -| stringstream.cpp:143:11:143:22 | (reference dereference) | stringstream.cpp:143:14:143:19 | call to source | -| stringstream.cpp:149:7:149:8 | Argument 0 indirection | stringstream.cpp:143:14:143:19 | call to source | -| stringstream.cpp:150:7:150:8 | Argument 0 indirection | stringstream.cpp:143:14:143:19 | call to source | -| stringstream.cpp:157:7:157:8 | Argument 0 indirection | stringstream.cpp:143:14:143:19 | call to source | -| stringstream.cpp:157:7:157:8 | call to basic_string | stringstream.cpp:143:14:143:19 | call to source | -| stringstream.cpp:158:7:158:8 | Argument 0 indirection | stringstream.cpp:143:14:143:19 | call to source | -| stringstream.cpp:158:7:158:8 | call to basic_string | stringstream.cpp:143:14:143:19 | call to source | -| stringstream.cpp:168:7:168:8 | Argument 0 indirection | stringstream.cpp:143:14:143:19 | call to source | -| stringstream.cpp:168:7:168:8 | call to basic_string | stringstream.cpp:143:14:143:19 | call to source | -| stringstream.cpp:170:7:170:8 | Argument 0 indirection | stringstream.cpp:143:14:143:19 | call to source | -| stringstream.cpp:170:7:170:8 | call to basic_string | stringstream.cpp:143:14:143:19 | call to source | -| stringstream.cpp:172:7:172:9 | Argument 0 indirection | stringstream.cpp:143:14:143:19 | call to source | -| stringstream.cpp:172:7:172:9 | call to basic_string | stringstream.cpp:143:14:143:19 | call to source | -| stringstream.cpp:175:7:175:20 | ... = ... | stringstream.cpp:143:14:143:19 | call to source | -| stringstream.cpp:177:7:177:21 | ... = ... | stringstream.cpp:143:14:143:19 | call to source | -| stringstream.cpp:181:7:181:8 | c2 | stringstream.cpp:143:14:143:19 | call to source | -| stringstream.cpp:183:7:183:8 | c4 | stringstream.cpp:143:14:143:19 | call to source | -| stringstream.cpp:185:7:185:8 | c6 | stringstream.cpp:143:14:143:19 | call to source | -| stringstream.cpp:197:10:197:12 | call to get | stringstream.cpp:196:18:196:32 | call to source | -| stringstream.cpp:219:7:219:8 | Argument 0 indirection | stringstream.cpp:203:24:203:29 | call to source | -| stringstream.cpp:219:7:219:8 | call to basic_string | stringstream.cpp:203:24:203:29 | call to source | -| stringstream.cpp:220:7:220:8 | Argument 0 indirection | stringstream.cpp:203:24:203:29 | call to source | -| stringstream.cpp:220:7:220:8 | call to basic_string | stringstream.cpp:203:24:203:29 | call to source | -| stringstream.cpp:227:7:227:8 | Argument 0 indirection | stringstream.cpp:203:24:203:29 | call to source | -| stringstream.cpp:227:7:227:8 | call to basic_string | stringstream.cpp:203:24:203:29 | call to source | -| stringstream.cpp:228:7:228:8 | Argument 0 indirection | stringstream.cpp:203:24:203:29 | call to source | -| stringstream.cpp:228:7:228:8 | call to basic_string | stringstream.cpp:203:24:203:29 | call to source | -| stringstream.cpp:231:7:231:8 | Argument 0 indirection | stringstream.cpp:203:24:203:29 | call to source | -| stringstream.cpp:231:7:231:8 | call to basic_string | stringstream.cpp:203:24:203:29 | call to source | -| stringstream.cpp:239:7:239:8 | Argument 0 indirection | stringstream.cpp:203:24:203:29 | call to source | -| stringstream.cpp:240:7:240:8 | Argument 0 indirection | stringstream.cpp:203:24:203:29 | call to source | -| stringstream.cpp:247:7:247:8 | Argument 0 indirection | stringstream.cpp:203:24:203:29 | call to source | -| stringstream.cpp:248:7:248:8 | Argument 0 indirection | stringstream.cpp:203:24:203:29 | call to source | -| stringstream.cpp:251:7:251:8 | Argument 0 indirection | stringstream.cpp:203:24:203:29 | call to source | -| stringstream.cpp:263:7:263:8 | Argument 0 indirection | stringstream.cpp:257:24:257:29 | call to source | -| stringstream.cpp:263:7:263:8 | call to basic_string | stringstream.cpp:257:24:257:29 | call to source | -| structlikeclass.cpp:35:8:35:9 | s1 | structlikeclass.cpp:29:22:29:27 | call to source | -| structlikeclass.cpp:36:8:36:9 | s2 | structlikeclass.cpp:30:24:30:29 | call to source | -| structlikeclass.cpp:37:8:37:9 | s3 | structlikeclass.cpp:29:22:29:27 | call to source | -| structlikeclass.cpp:38:8:38:9 | s4 | structlikeclass.cpp:33:8:33:13 | call to source | -| structlikeclass.cpp:60:8:60:9 | s1 | structlikeclass.cpp:55:40:55:45 | call to source | -| structlikeclass.cpp:61:8:61:9 | s2 | structlikeclass.cpp:58:24:58:29 | call to source | -| structlikeclass.cpp:62:8:62:20 | ... = ... | structlikeclass.cpp:62:13:62:18 | call to source | -| swap1.cpp:73:12:73:16 | data1 | swap1.cpp:71:15:71:20 | call to source | -| swap1.cpp:78:12:78:16 | data1 | swap1.cpp:71:15:71:20 | call to source | -| swap1.cpp:79:12:79:16 | data1 | swap1.cpp:71:15:71:20 | call to source | -| swap1.cpp:83:13:83:17 | data1 | swap1.cpp:82:16:82:21 | call to source | -| swap1.cpp:87:13:87:17 | data1 | swap1.cpp:82:16:82:21 | call to source | -| swap1.cpp:88:13:88:17 | data1 | swap1.cpp:82:16:82:21 | call to source | -| swap1.cpp:97:12:97:16 | data1 | swap1.cpp:95:15:95:20 | call to source | -| swap1.cpp:102:12:102:16 | data1 | swap1.cpp:95:15:95:20 | call to source | -| swap1.cpp:103:12:103:16 | data1 | swap1.cpp:95:15:95:20 | call to source | -| swap1.cpp:111:20:111:24 | data1 | swap1.cpp:109:23:109:28 | call to source | -| swap1.cpp:115:18:115:22 | data1 | swap1.cpp:109:23:109:28 | call to source | -| swap1.cpp:124:12:124:16 | data1 | swap1.cpp:122:15:122:20 | call to source | -| swap1.cpp:129:12:129:16 | data1 | swap1.cpp:122:15:122:20 | call to source | -| swap1.cpp:130:12:130:16 | data1 | swap1.cpp:122:15:122:20 | call to source | -| swap1.cpp:139:12:139:16 | data1 | swap1.cpp:137:15:137:20 | call to source | -| swap1.cpp:144:12:144:16 | data1 | swap1.cpp:137:15:137:20 | call to source | -| swap1.cpp:145:12:145:16 | data1 | swap1.cpp:137:15:137:20 | call to source | -| swap2.cpp:73:12:73:16 | data1 | swap2.cpp:71:15:71:20 | call to source | -| swap2.cpp:78:12:78:16 | data1 | swap2.cpp:71:15:71:20 | call to source | -| swap2.cpp:79:12:79:16 | data1 | swap2.cpp:71:15:71:20 | call to source | -| swap2.cpp:83:13:83:17 | data1 | swap2.cpp:82:16:82:21 | call to source | -| swap2.cpp:87:13:87:17 | data1 | swap2.cpp:82:16:82:21 | call to source | -| swap2.cpp:88:13:88:17 | data1 | swap2.cpp:82:16:82:21 | call to source | -| swap2.cpp:97:12:97:16 | data1 | swap2.cpp:95:15:95:20 | call to source | -| swap2.cpp:102:12:102:16 | data1 | swap2.cpp:95:15:95:20 | call to source | -| swap2.cpp:103:12:103:16 | data1 | swap2.cpp:95:15:95:20 | call to source | -| swap2.cpp:111:20:111:24 | data1 | swap2.cpp:109:23:109:28 | call to source | -| swap2.cpp:115:18:115:22 | data1 | swap2.cpp:109:23:109:28 | call to source | -| swap2.cpp:124:12:124:16 | data1 | swap2.cpp:122:15:122:20 | call to source | -| swap2.cpp:129:12:129:16 | data1 | swap2.cpp:122:15:122:20 | call to source | -| swap2.cpp:130:12:130:16 | data1 | swap2.cpp:122:15:122:20 | call to source | -| swap2.cpp:139:12:139:16 | data1 | swap2.cpp:137:15:137:20 | call to source | -| swap2.cpp:144:12:144:16 | data1 | swap2.cpp:137:15:137:20 | call to source | -| swap2.cpp:145:12:145:16 | data1 | swap2.cpp:137:15:137:20 | call to source | -| taint.cpp:8:8:8:13 | clean1 | taint.cpp:4:27:4:33 | source1 | -| taint.cpp:16:8:16:14 | source1 | taint.cpp:12:22:12:27 | call to source | -| taint.cpp:17:8:17:16 | ++ ... | taint.cpp:12:22:12:27 | call to source | -| taint.cpp:89:11:89:11 | b | taint.cpp:71:22:71:27 | call to source | -| taint.cpp:90:11:90:11 | c | taint.cpp:72:7:72:12 | call to source | -| taint.cpp:91:11:91:11 | d | taint.cpp:77:7:77:12 | call to source | -| taint.cpp:93:11:93:11 | b | taint.cpp:71:22:71:27 | call to source | -| taint.cpp:94:11:94:11 | c | taint.cpp:72:7:72:12 | call to source | -| taint.cpp:109:7:109:13 | access to array | taint.cpp:105:12:105:17 | call to source | -| taint.cpp:110:7:110:13 | access to array | taint.cpp:105:12:105:17 | call to source | -| taint.cpp:111:7:111:13 | access to array | taint.cpp:106:12:106:17 | call to source | -| taint.cpp:112:7:112:13 | access to array | taint.cpp:106:12:106:17 | call to source | -| taint.cpp:129:7:129:9 | * ... | taint.cpp:120:11:120:16 | call to source | -| taint.cpp:130:7:130:9 | * ... | taint.cpp:127:8:127:13 | call to source | -| taint.cpp:134:7:134:9 | * ... | taint.cpp:120:11:120:16 | call to source | -| taint.cpp:151:7:151:12 | call to select | taint.cpp:151:20:151:25 | call to source | -| taint.cpp:167:8:167:13 | call to source | taint.cpp:167:8:167:13 | call to source | -| taint.cpp:168:8:168:14 | tainted | taint.cpp:164:19:164:24 | call to source | -| taint.cpp:173:8:173:13 | Argument 0 indirection | taint.cpp:164:19:164:24 | call to source | -| taint.cpp:181:8:181:9 | * ... | taint.cpp:185:11:185:16 | call to source | -| taint.cpp:195:7:195:7 | x | taint.cpp:192:23:192:28 | source | -| taint.cpp:210:7:210:7 | x | taint.cpp:207:6:207:11 | call to source | -| taint.cpp:215:7:215:7 | x | taint.cpp:207:6:207:11 | call to source | -| taint.cpp:216:7:216:7 | y | taint.cpp:207:6:207:11 | call to source | -| taint.cpp:229:3:229:6 | t | taint.cpp:223:10:223:15 | call to source | -| taint.cpp:233:8:233:8 | call to operator() | taint.cpp:223:10:223:15 | call to source | -| taint.cpp:244:3:244:6 | t | taint.cpp:223:10:223:15 | call to source | -| taint.cpp:250:8:250:8 | a | taint.cpp:223:10:223:15 | call to source | -| taint.cpp:256:8:256:8 | (reference dereference) | taint.cpp:223:10:223:15 | call to source | -| taint.cpp:261:7:261:7 | w | taint.cpp:258:7:258:12 | call to source | -| taint.cpp:280:7:280:7 | t | taint.cpp:275:6:275:11 | call to source | -| taint.cpp:289:7:289:7 | t | taint.cpp:275:6:275:11 | call to source | -| taint.cpp:290:7:290:7 | x | taint.cpp:275:6:275:11 | call to source | -| taint.cpp:291:7:291:7 | y | taint.cpp:275:6:275:11 | call to source | -| taint.cpp:337:7:337:7 | t | taint.cpp:330:6:330:11 | call to source | -| taint.cpp:350:7:350:7 | t | taint.cpp:330:6:330:11 | call to source | -| taint.cpp:351:7:351:7 | a | taint.cpp:330:6:330:11 | call to source | -| taint.cpp:352:7:352:7 | b | taint.cpp:330:6:330:11 | call to source | -| taint.cpp:353:7:353:7 | c | taint.cpp:330:6:330:11 | call to source | -| taint.cpp:354:7:354:7 | d | taint.cpp:330:6:330:11 | call to source | -| taint.cpp:382:7:382:7 | a | taint.cpp:377:23:377:28 | source | -| taint.cpp:429:7:429:7 | b | taint.cpp:428:13:428:18 | call to source | -| taint.cpp:430:9:430:14 | member | taint.cpp:428:13:428:18 | call to source | -| taint.cpp:465:7:465:7 | x | taint.cpp:462:6:462:11 | call to source | -| taint.cpp:470:7:470:7 | x | taint.cpp:462:6:462:11 | call to source | -| taint.cpp:471:7:471:7 | y | taint.cpp:462:6:462:11 | call to source | -| taint.cpp:485:7:485:10 | line | taint.cpp:480:26:480:32 | source1 | -| vector.cpp:20:8:20:8 | x | vector.cpp:16:43:16:49 | source1 | -| vector.cpp:24:8:24:8 | call to operator* | vector.cpp:16:43:16:49 | source1 | -| vector.cpp:24:8:24:11 | (reference dereference) | vector.cpp:16:43:16:49 | source1 | -| vector.cpp:28:8:28:8 | (reference dereference) | vector.cpp:16:43:16:49 | source1 | -| vector.cpp:28:8:28:8 | x | vector.cpp:16:43:16:49 | source1 | -| vector.cpp:33:8:33:8 | (reference dereference) | vector.cpp:16:43:16:49 | source1 | -| vector.cpp:33:8:33:8 | x | vector.cpp:16:43:16:49 | source1 | -| vector.cpp:70:7:70:8 | Argument 0 indirection | vector.cpp:69:15:69:20 | call to source | -| vector.cpp:83:7:83:8 | Argument 0 indirection | vector.cpp:81:17:81:22 | call to source | -| vector.cpp:109:7:109:8 | Argument 0 indirection | vector.cpp:106:15:106:20 | call to source | -| vector.cpp:112:7:112:8 | Argument 0 indirection | vector.cpp:107:15:107:20 | call to source | -| vector.cpp:117:7:117:8 | Argument 0 indirection | vector.cpp:106:15:106:20 | call to source | -| vector.cpp:118:7:118:8 | Argument 0 indirection | vector.cpp:106:15:106:20 | call to source | -| vector.cpp:119:7:119:8 | Argument 0 indirection | vector.cpp:107:15:107:20 | call to source | -| vector.cpp:120:7:120:8 | Argument 0 indirection | vector.cpp:107:15:107:20 | call to source | -| vector.cpp:130:7:130:8 | Argument 0 indirection | vector.cpp:126:15:126:20 | call to source | -| vector.cpp:131:7:131:8 | Argument 0 indirection | vector.cpp:127:15:127:20 | call to source | -| vector.cpp:132:7:132:8 | Argument 0 indirection | vector.cpp:128:15:128:20 | call to source | -| vector.cpp:139:7:139:8 | Argument 0 indirection | vector.cpp:126:15:126:20 | call to source | -| vector.cpp:140:7:140:8 | Argument 0 indirection | vector.cpp:127:15:127:20 | call to source | -| vector.cpp:141:7:141:8 | Argument 0 indirection | vector.cpp:128:15:128:20 | call to source | -| vector.cpp:162:8:162:15 | access to array | vector.cpp:161:14:161:19 | call to source | -| vector.cpp:242:7:242:8 | Argument 0 indirection | vector.cpp:238:17:238:30 | call to source | -| vector.cpp:243:7:243:8 | Argument 0 indirection | vector.cpp:239:15:239:20 | call to source | -| vector.cpp:258:8:258:9 | Argument 0 indirection | vector.cpp:239:15:239:20 | call to source | -| vector.cpp:259:8:259:9 | Argument 0 indirection | vector.cpp:239:15:239:20 | call to source | -| vector.cpp:260:8:260:9 | Argument 0 indirection | vector.cpp:239:15:239:20 | call to source | -| vector.cpp:261:8:261:9 | Argument 0 indirection | vector.cpp:239:15:239:20 | call to source | -| vector.cpp:273:8:273:9 | Argument 0 indirection | vector.cpp:269:18:269:31 | call to source | -| vector.cpp:274:8:274:9 | Argument 0 indirection | vector.cpp:270:18:270:35 | call to source | -| vector.cpp:275:8:275:9 | Argument 0 indirection | vector.cpp:271:18:271:34 | call to source | -| vector.cpp:285:7:285:8 | Argument 0 indirection | vector.cpp:284:15:284:20 | call to source | -| vector.cpp:309:7:309:7 | Argument 0 indirection | vector.cpp:303:14:303:19 | call to source | -| vector.cpp:312:7:312:7 | Argument 0 indirection | vector.cpp:303:14:303:19 | call to source | -| vector.cpp:324:7:324:8 | Argument 0 indirection | vector.cpp:318:15:318:20 | call to source | -| vector.cpp:326:7:326:8 | Argument 0 indirection | vector.cpp:318:15:318:20 | call to source | -| vector.cpp:482:8:482:10 | Argument 0 indirection | vector.cpp:478:21:478:37 | call to source | -| vector.cpp:485:8:485:10 | Argument 0 indirection | vector.cpp:478:21:478:37 | call to source | From 6ba35f4aac18f6debb29fff0355d03f32ea67fc1 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 2 Mar 2021 11:25:22 +0100 Subject: [PATCH 070/725] C++: Fix function renaming and accept test change. --- .../annotate_sinks_only/defaulttainttracking.cpp | 4 ++-- .../DefaultTaintTracking/annotate_sinks_only/tainted.expected | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/defaulttainttracking.cpp b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/defaulttainttracking.cpp index c676b590da2..47d95297e6f 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/defaulttainttracking.cpp +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/defaulttainttracking.cpp @@ -9,7 +9,7 @@ -int test() { +int main() { @@ -19,7 +19,7 @@ int test() { char untainted_buf[100] = ""; char buf[100] = "VAR = "; - sink(strcat(buf, getenv("VAR"))); // $ ast,ir + sink(strcat(buf, getenv("VAR"))); // $ ast MISSING: ir sink(buf); // $ ast,ir sink(untainted_buf); // the two buffers would be conflated if we added flow through all partial chi inputs diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/tainted.expected b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/tainted.expected index f1db2289108..e69de29bb2d 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/tainted.expected +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/tainted.expected @@ -1 +0,0 @@ -| defaulttainttracking.cpp:22:37:22:47 | // $ ast,ir | Missing result:ir= | From 23d31090715ada19830c2a34cc081bb79991aba9 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 2 Mar 2021 13:40:39 +0100 Subject: [PATCH 071/725] C++: Use taintedWithPath in more tests. This is the predicate that's currently hooked up to the new IR taint tracking library. --- .../annotate_path_to_sink/tainted.ql | 9 ++++++++- .../annotate_sinks_only/defaulttainttracking.cpp | 12 ++++++------ .../annotate_sinks_only/stl.cpp | 16 ++++++++-------- .../annotate_sinks_only/tainted.ql | 11 ++++++++--- 4 files changed, 30 insertions(+), 18 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_path_to_sink/tainted.ql b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_path_to_sink/tainted.ql index 89a7622c49a..27f45cf64ef 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_path_to_sink/tainted.ql +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_path_to_sink/tainted.ql @@ -6,6 +6,7 @@ import cpp import semmle.code.cpp.security.TaintTrackingImpl as ASTTaintTracking import semmle.code.cpp.ir.dataflow.DefaultTaintTracking as IRDefaultTaintTracking +import IRDefaultTaintTracking::TaintedWithPath as TaintedWithPath import TestUtilities.InlineExpectationsTest predicate isSink(Element sink) { @@ -17,7 +18,13 @@ predicate isSink(Element sink) { predicate astTaint(Expr source, Element sink) { ASTTaintTracking::tainted(source, sink) } -predicate irTaint(Expr source, Element sink) { IRDefaultTaintTracking::tainted(source, sink) } +class SourceConfiguration extends TaintedWithPath::TaintTrackingConfiguration { + override predicate isSink(Element e) { any() } +} + +predicate irTaint(Expr source, Element sink) { + TaintedWithPath::taintedWithPath(source, sink, _, _) +} class IRDefaultTaintTrackingTest extends InlineExpectationsTest { IRDefaultTaintTrackingTest() { this = "IRDefaultTaintTrackingTest" } diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/defaulttainttracking.cpp b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/defaulttainttracking.cpp index 47d95297e6f..6895ef4d6bb 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/defaulttainttracking.cpp +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/defaulttainttracking.cpp @@ -13,8 +13,8 @@ int main() { - sink(_strdup(getenv("VAR"))); // $ ir MISSING: ast - sink(strdup(getenv("VAR"))); // $ ast,ir + sink(_strdup(getenv("VAR"))); // $ MISSING: ast,ir + sink(strdup(getenv("VAR"))); // $ ast MISSING: ir sink(unmodeled_function(getenv("VAR"))); // clean by assumption char untainted_buf[100] = ""; @@ -250,12 +250,12 @@ void sink(iovec); int test_readv_and_writev(iovec* iovs) { readv(0, iovs, 16); sink(iovs); // $ast,ir - sink(iovs[0]); // $ast MISSING: ir - sink(*iovs); // $ast MISSING: ir + sink(iovs[0]); // $ast,ir + sink(*iovs); // $ast,ir char* p = (char*)iovs[1].iov_base; - sink(p); // $ MISSING: ast,ir - sink(*p); // $ MISSING: ast,ir + sink(p); // $ ir MISSING: ast + sink(*p); // $ ir MISSING: ast writev(0, iovs, 16); // $ remote } diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/stl.cpp b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/stl.cpp index e2f5d3b16bd..0264f29f4af 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/stl.cpp +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/stl.cpp @@ -73,7 +73,7 @@ void test_string() sink(b); // clean sink(c); // $ ir MISSING: ast sink(b.c_str()); // clean - sink(c.c_str()); // $ MISSING: ast,ir + sink(c.c_str()); // $ ir MISSING: ast } void test_stringstream() @@ -91,11 +91,11 @@ void test_stringstream() sink(ss2); // $ ir MISSING: ast sink(ss3); // $ MISSING: ast,ir sink(ss4); // $ ir MISSING: ast - sink(ss5); // $ ir MISSING: ast + sink(ss5); // $ MISSING: ast,ir sink(ss1.str()); - sink(ss2.str()); // $ MISSING: ast,ir + sink(ss2.str()); // $ ir MISSING: ast sink(ss3.str()); // $ MISSING: ast,ir - sink(ss4.str()); // $ MISSING: ast,ir + sink(ss4.str()); // $ ir MISSING: ast sink(ss5.str()); // $ MISSING: ast,ir } @@ -123,14 +123,14 @@ void sink(const char *filename, const char *mode); void test_strings2() { string path1 = user_input(); - sink(path1.c_str(), "r"); // $ MISSING: ast,ir + sink(path1.c_str(), "r"); // $ ir MISSING: ast string path2; path2 = user_input(); - sink(path2.c_str(), "r"); // $ MISSING: ast,ir + sink(path2.c_str(), "r"); // $ ir MISSING: ast string path3(user_input()); - sink(path3.c_str(), "r"); // $ MISSING: ast,ir + sink(path3.c_str(), "r"); // $ ir MISSING: ast } void test_string3() @@ -154,6 +154,6 @@ void test_string4() // convert back std::string -> char * cs = ss.c_str(); - sink(cs); // $ ast MISSING: ir + sink(cs); // $ ast,ir sink(ss); // $ ir MISSING: ast } diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/tainted.ql b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/tainted.ql index d6ddf93bf49..5784906862b 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/tainted.ql +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/tainted.ql @@ -7,9 +7,10 @@ import cpp import semmle.code.cpp.security.TaintTrackingImpl as ASTTaintTracking import semmle.code.cpp.ir.dataflow.DefaultTaintTracking as IRDefaultTaintTracking +import IRDefaultTaintTracking::TaintedWithPath as TaintedWithPath import TestUtilities.InlineExpectationsTest -predicate isSink(Element sink) { +predicate argToSinkCall(Element sink) { exists(FunctionCall call | call.getTarget().getName() = "sink" and sink = call.getAnArgument() @@ -17,11 +18,15 @@ predicate isSink(Element sink) { } predicate astTaint(Expr source, Element sink) { - ASTTaintTracking::tainted(source, sink) and isSink(sink) + ASTTaintTracking::tainted(source, sink) and argToSinkCall(sink) +} + +class SourceConfiguration extends TaintedWithPath::TaintTrackingConfiguration { + override predicate isSink(Element e) { argToSinkCall(e) } } predicate irTaint(Expr source, Element sink) { - IRDefaultTaintTracking::tainted(source, sink) and isSink(sink) + TaintedWithPath::taintedWithPath(source, sink, _, _) } class IRDefaultTaintTrackingTest extends InlineExpectationsTest { From eb4f1e1ba03cdbda41df975295dbf8e5e4dcd0f7 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 2 Mar 2021 15:45:40 +0100 Subject: [PATCH 072/725] C++: Restore some of the lost test results by doing operand -> instruction taint steps in IR TaintTracking. --- .../cpp/ir/dataflow/DefaultTaintTracking.qll | 2 +- .../cpp/ir/dataflow/internal/ModelUtil.qll | 38 +++------- .../dataflow/internal/TaintTrackingUtil.qll | 76 ++++++++++++------- .../defaulttainttracking.cpp | 4 +- .../dataflow/taint-tests/taint.cpp | 6 +- 5 files changed, 62 insertions(+), 64 deletions(-) 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 428ec5a13f0..7a4581cf31f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll @@ -613,7 +613,7 @@ module TaintedWithPath { // Step to return value of a modeled function when an input taints the // dereference of the return value exists(CallInstruction call, Function func, FunctionInput modelIn, FunctionOutput modelOut | - n1 = callInput(call, modelIn) and + n1.asOperand() = callInput(call, modelIn) and ( func.(TaintFunction).hasTaintFlow(modelIn, modelOut) or diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/ModelUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/ModelUtil.qll index 93d74519ca5..2f4037d4ec8 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/ModelUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/ModelUtil.qll @@ -9,30 +9,18 @@ private import semmle.code.cpp.ir.dataflow.DataFlow /** * Gets the instruction that goes into `input` for `call`. */ -DataFlow::Node callInput(CallInstruction call, FunctionInput input) { - // A positional argument +Operand callInput(CallInstruction call, FunctionInput input) { + // An argument or qualifier exists(int index | - result.asInstruction() = call.getPositionalArgument(index) and - input.isParameter(index) + result = call.getArgumentOperand(index) and + input.isParameterOrQualifierAddress(index) ) or - // A value pointed to by a positional argument + // A value pointed to by an argument or qualifier exists(ReadSideEffectInstruction read | - result.asOperand() = read.getSideEffectOperand() and + result = read.getSideEffectOperand() and read.getPrimaryInstruction() = call and - input.isParameterDeref(read.getIndex()) - ) - or - // The qualifier pointer - result.asInstruction() = call.getThisArgument() and - input.isQualifierAddress() - or - // The qualifier object - exists(ReadSideEffectInstruction read | - result.asOperand() = read.getSideEffectOperand() and - read.getPrimaryInstruction() = call and - read.getIndex() = -1 and - input.isQualifierObject() + input.isParameterDerefOrQualifierObject(read.getIndex()) ) } @@ -44,19 +32,11 @@ Instruction callOutput(CallInstruction call, FunctionOutput output) { result = call and output.isReturnValue() or - // The side effect of a call on the value pointed to by a positional argument + // The side effect of a call on the value pointed to by an argument or qualifier exists(WriteSideEffectInstruction effect | result = effect and effect.getPrimaryInstruction() = call and - output.isParameterDeref(effect.getIndex()) - ) - or - // The side effect of a call on the qualifier object - exists(WriteSideEffectInstruction effect | - result = effect and - effect.getPrimaryInstruction() = call and - effect.getIndex() = -1 and - output.isQualifierObject() + output.isParameterDerefOrQualifierObject(effect.getIndex()) ) // TODO: return value dereference } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll index 0ea24dc7862..c5c168efb0d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll @@ -21,53 +21,69 @@ predicate localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { */ cached predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { - localInstructionTaintStep(nodeFrom.asInstruction(), nodeTo.asInstruction()) + operandToInstructionTaintStep(nodeFrom.asOperand(), nodeTo.asInstruction()) or - modeledTaintStep(nodeFrom, nodeTo) + instructionToOperandTaintStep(nodeFrom.asInstruction(), nodeTo.asOperand()) +} + +private predicate instructionToOperandTaintStep(Instruction fromInstr, Operand toOperand) { + // Propagate flow from the definition of an operand to the operand, even when the overlap is inexact. + // We only do this in certain cases: + // 1. The instruction's result must not be conflated, and + // 2. The instruction's result type is one the types where we expect element-to-object flow. Currently + // this is array types and union types. This matches the other two cases of element-to-object flow in + // `DefaultTaintTracking`. + toOperand.getAnyDef() = fromInstr and + not fromInstr.isResultConflated() and + ( + fromInstr.getResultType() instanceof ArrayType or + fromInstr.getResultType() instanceof Union + ) + or + exists(ReadSideEffectInstruction readInstr | + fromInstr = readInstr.getArgumentDef() and + toOperand = readInstr.getSideEffectOperand() + ) + or + toOperand.(LoadOperand).getAnyDef() = fromInstr } /** * Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local * (intra-procedural) step. */ -private predicate localInstructionTaintStep(Instruction nodeFrom, Instruction nodeTo) { +private predicate operandToInstructionTaintStep(Operand opFrom, Instruction instrTo) { // Taint can flow through expressions that alter the value but preserve // more than one bit of it _or_ expressions that follow data through // pointer indirections. - nodeTo.getAnOperand().getAnyDef() = nodeFrom and + instrTo.getAnOperand() = opFrom and ( - nodeTo instanceof ArithmeticInstruction + instrTo instanceof ArithmeticInstruction or - nodeTo instanceof BitwiseInstruction + instrTo instanceof BitwiseInstruction or - nodeTo instanceof PointerArithmeticInstruction + instrTo instanceof PointerArithmeticInstruction or - nodeTo instanceof FieldAddressInstruction + instrTo instanceof FieldAddressInstruction or // The `CopyInstruction` case is also present in non-taint data flow, but // that uses `getDef` rather than `getAnyDef`. For taint, we want flow // from a definition of `myStruct` to a `myStruct.myField` expression. - nodeTo instanceof CopyInstruction + instrTo instanceof CopyInstruction ) or - nodeTo.(LoadInstruction).getSourceAddress() = nodeFrom - or - // Flow through partial reads of arrays and unions - nodeTo.(LoadInstruction).getSourceValueOperand().getAnyDef() = nodeFrom and - not nodeFrom.isResultConflated() and - ( - nodeFrom.getResultType() instanceof ArrayType or - nodeFrom.getResultType() instanceof Union - ) + instrTo.(LoadInstruction).getSourceAddressOperand() = opFrom or // Flow from an element to an array or union that contains it. - nodeTo.(ChiInstruction).getPartial() = nodeFrom and - not nodeTo.isResultConflated() and - exists(Type t | nodeTo.getResultLanguageType().hasType(t, false) | + instrTo.(ChiInstruction).getPartialOperand() = opFrom and + not instrTo.isResultConflated() and + exists(Type t | instrTo.getResultLanguageType().hasType(t, false) | t instanceof Union or t instanceof ArrayType ) + or + modeledTaintStep(opFrom, instrTo) } /** @@ -110,17 +126,19 @@ predicate defaultTaintSanitizer(DataFlow::Node node) { none() } * Holds if taint can flow from `instrIn` to `instrOut` through a call to a * modeled function. */ -predicate modeledTaintStep(DataFlow::Node nodeIn, DataFlow::Node nodeOut) { +predicate modeledTaintStep(Operand nodeIn, Instruction nodeOut) { exists(CallInstruction call, TaintFunction func, FunctionInput modelIn, FunctionOutput modelOut | ( nodeIn = callInput(call, modelIn) or exists(int n | - modelIn.isParameterDeref(n) and - nodeIn = callInput(call, any(InParameter inParam | inParam.getIndex() = n)) + modelIn.isParameterDerefOrQualifierObject(n) and + if n = -1 + then nodeIn = callInput(call, any(InQualifierObject inQualifier)) + else nodeIn = callInput(call, any(InParameter inParam | inParam.getIndex() = n)) ) ) and - nodeOut.asInstruction() = callOutput(call, modelOut) and + nodeOut = callOutput(call, modelOut) and call.getStaticCallTarget() = func and func.hasTaintFlow(modelIn, modelOut) ) @@ -135,7 +153,7 @@ predicate modeledTaintStep(DataFlow::Node nodeIn, DataFlow::Node nodeOut) { int indexMid, InParameter modelMidIn, OutReturnValue modelOut | nodeIn = callInput(call, modelIn) and - nodeOut.asInstruction() = callOutput(call, modelOut) and + nodeOut = callOutput(call, modelOut) and call.getStaticCallTarget() = func and func.(TaintFunction).hasTaintFlow(modelIn, modelMidOut) and func.(DataFlowFunction).hasDataFlow(modelMidIn, modelOut) and @@ -149,8 +167,8 @@ predicate modeledTaintStep(DataFlow::Node nodeIn, DataFlow::Node nodeOut) { CallInstruction call, ReadSideEffectInstruction read, Function func, FunctionInput modelIn, FunctionOutput modelOut | - read.getSideEffectOperand() = callInput(call, modelIn).asOperand() and - read.getArgumentDef() = nodeIn.asInstruction() and + read.getSideEffectOperand() = callInput(call, modelIn) and + read.getArgumentDef() = nodeIn.getDef() and not read.getSideEffect().isResultModeled() and call.getStaticCallTarget() = func and ( @@ -158,6 +176,6 @@ predicate modeledTaintStep(DataFlow::Node nodeIn, DataFlow::Node nodeOut) { or func.(TaintFunction).hasTaintFlow(modelIn, modelOut) ) and - nodeOut.asInstruction() = callOutput(call, modelOut) + nodeOut = callOutput(call, modelOut) ) } diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/defaulttainttracking.cpp b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/defaulttainttracking.cpp index 6895ef4d6bb..d64f1966b49 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/defaulttainttracking.cpp +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/defaulttainttracking.cpp @@ -13,8 +13,8 @@ int main() { - sink(_strdup(getenv("VAR"))); // $ MISSING: ast,ir - sink(strdup(getenv("VAR"))); // $ ast MISSING: ir + sink(_strdup(getenv("VAR"))); // $ ir MISSING: ast + sink(strdup(getenv("VAR"))); // $ ast,ir sink(unmodeled_function(getenv("VAR"))); // clean by assumption char untainted_buf[100] = ""; diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp index baf26ee9af4..7797d905f29 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp @@ -369,9 +369,9 @@ void test_strdup(char *source) a = strdup(source); b = strdup("hello, world"); c = strndup(source, 100); - sink(a); // $ ast MISSING: ir + sink(a); // $ ast,ir sink(b); - sink(c); // $ ast MISSING: ir + sink(c); // $ ast,ir } void test_strndup(int source) @@ -388,7 +388,7 @@ void test_wcsdup(wchar_t *source) a = wcsdup(source); b = wcsdup(L"hello, world"); - sink(a); // $ ast MISSING: ir + sink(a); // $ ast,ir sink(b); } From 617ba65ef5994e285a26bc4ac0a799d37b3fdb60 Mon Sep 17 00:00:00 2001 From: Artem Smotrakov Date: Tue, 2 Mar 2021 21:36:14 +0100 Subject: [PATCH 073/725] Improved docs for SpringHttpInvokerUnsafeDeserialization.ql --- .../CWE-502/SpringHttpInvokerUnsafeDeserialization.qhelp | 8 ++++---- .../CWE/CWE-502/SpringHttpInvokerUnsafeDeserialization.ql | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-502/SpringHttpInvokerUnsafeDeserialization.qhelp b/java/ql/src/experimental/Security/CWE/CWE-502/SpringHttpInvokerUnsafeDeserialization.qhelp index 49237a8500e..ffb8dddae56 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-502/SpringHttpInvokerUnsafeDeserialization.qhelp +++ b/java/ql/src/experimental/Security/CWE/CWE-502/SpringHttpInvokerUnsafeDeserialization.qhelp @@ -3,14 +3,14 @@

    -Spring Framework provides an abstract base class RemoteInvocationSerializingExporter +The Spring Framework provides an abstract base class RemoteInvocationSerializingExporter for defining remote service exporters. A Spring exporter, which is based on this class, deserializes incoming data using ObjectInputStream. Deserializing untrusted data is easily exploitable and in many cases allows an attacker to execute arbitrary code.

    -Spring Framework also provides two classes that extend RemoteInvocationSerializingExporter: +The Spring Framework also provides two classes that extend RemoteInvocationSerializingExporter:

  • HttpInvokerServiceExporter
  • @@ -24,7 +24,7 @@ using unsafe ObjectInputStream. If a remote attacker can reach such it results in remote code execution in the worst case.

    -CVE-2016-1000027 has been assigned to this issue in Spring Framework. There is no fix for that. +CVE-2016-1000027 has been assigned to this issue in the Spring Framework. It is regarded as a design limitation, and can be mitigated but not fixed outright.

    @@ -36,7 +36,7 @@ Instead, use other message formats for API endpoints (for example, JSON), but make sure that the underlying deserialization mechanism is properly configured so that deserialization attacks are not possible. If the vulnerable exporters can not be replaced, consider using global deserialization filters introduced by JEP 290. -In general, avoid deserialization of untrusted data. +In general, avoid using Java's built-in deserialization methods on untrusted data.

    diff --git a/java/ql/src/experimental/Security/CWE/CWE-502/SpringHttpInvokerUnsafeDeserialization.ql b/java/ql/src/experimental/Security/CWE/CWE-502/SpringHttpInvokerUnsafeDeserialization.ql index df01ae478cc..54e8272575b 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-502/SpringHttpInvokerUnsafeDeserialization.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-502/SpringHttpInvokerUnsafeDeserialization.ql @@ -52,4 +52,4 @@ private predicate createsRemoteInvocationSerializingExporterBean(Method method) from Method method where createsRemoteInvocationSerializingExporterBean(method) select method, - "Unasafe deserialization in a remote service exporter in '" + method.getName() + "' method" + "Unsafe deserialization in a remote service exporter in '" + method.getName() + "' method" From b366ffa69e98e21ac8998bb08a8815fc4cae6b4f Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Wed, 3 Mar 2021 13:38:18 +0000 Subject: [PATCH 074/725] Revamp source of the query --- .../CWE-1004/SensitiveCookieNotHttpOnly.qhelp | 2 +- .../CWE-1004/SensitiveCookieNotHttpOnly.ql | 116 +++++++++--------- .../SensitiveCookieNotHttpOnly.expected | 12 +- .../javax/ws/rs/core/Cookie.java | 59 +++------ .../javax/ws/rs/core/NewCookie.java | 36 ------ 5 files changed, 82 insertions(+), 143 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.qhelp b/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.qhelp index 880ed767be9..ee3e8a4181a 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.qhelp +++ b/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.qhelp @@ -2,7 +2,7 @@ -

    Cross-Site Scripting (XSS) is categorized as one of the OWASP Top 10 Security Vulnerabilities. The HttpOnly flag directs compatible browsers to prevent client-side script from accessing cookies. Including the HttpOnly flag in the Set-Cookie HTTP response header for a sensitive cookie helps mitigate the risk associated with XSS where an attacker's script code attempts to read the contents of a cookie and exfiltrate information obtained.

    +

    Cross-Site Scripting (XSS) is categorized as one of the OWASP Top 10 Security Vulnerabilities. The HttpOnly flag directs compatible browsers to prevent client-side script from accessing cookies. Including the HttpOnly flag in the Set-Cookie HTTP response header for a sensitive cookie helps mitigate the risk associated with XSS where an attacker's script code attempts to read the contents of a cookie and exfiltrate information obtained.

    diff --git a/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql b/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql index bf4e60134c9..842e8b7eabb 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql @@ -9,7 +9,6 @@ import java import semmle.code.java.frameworks.Servlets -import semmle.code.java.dataflow.FlowSources import semmle.code.java.dataflow.TaintTracking import DataFlow::PathGraph @@ -18,8 +17,8 @@ string getSensitiveCookieNameRegex() { result = "(?i).*(auth|session|token|key|c /** Holds if a string is concatenated with the name of a sensitive cookie. */ predicate isSensitiveCookieNameExpr(Expr expr) { - expr.(StringLiteral) - .getRepresentedString() + expr.(CompileTimeConstantExpr) + .getStringValue() .toLowerCase() .regexpMatch(getSensitiveCookieNameRegex()) or isSensitiveCookieNameExpr(expr.(AddExpr).getAnOperand()) @@ -27,7 +26,7 @@ predicate isSensitiveCookieNameExpr(Expr expr) { /** Holds if a string is concatenated with the `HttpOnly` flag. */ predicate hasHttpOnlyExpr(Expr expr) { - expr.(StringLiteral).getRepresentedString().toLowerCase().matches("%httponly%") or + expr.(CompileTimeConstantExpr).getStringValue().toLowerCase().matches("%httponly%") or hasHttpOnlyExpr(expr.(AddExpr).getAnOperand()) } @@ -38,37 +37,34 @@ class SetCookieMethodAccess extends MethodAccess { this.getMethod() instanceof ResponseAddHeaderMethod or this.getMethod() instanceof ResponseSetHeaderMethod ) and - this.getArgument(0).(StringLiteral).getRepresentedString().toLowerCase() = "set-cookie" + this.getArgument(0).(CompileTimeConstantExpr).getStringValue().toLowerCase() = "set-cookie" } } /** Sensitive cookie name used in a `Cookie` constructor or a `Set-Cookie` call. */ class SensitiveCookieNameExpr extends Expr { SensitiveCookieNameExpr() { - isSensitiveCookieNameExpr(this) and - ( - exists( - ClassInstanceExpr cie // new Cookie("jwt_token", token) - | - ( - cie.getConstructor().getDeclaringType().hasQualifiedName("javax.servlet.http", "Cookie") or - cie.getConstructor() - .getDeclaringType() - .getASupertype*() - .hasQualifiedName("javax.ws.rs.core", "Cookie") or - cie.getConstructor() - .getDeclaringType() - .getASupertype*() - .hasQualifiedName("jakarta.ws.rs.core", "Cookie") - ) and - DataFlow::localExprFlow(this, cie.getArgument(0)) - ) - or - exists( - SetCookieMethodAccess ma // response.addHeader("Set-Cookie: token=" +authId + ";HttpOnly;Secure") - | - DataFlow::localExprFlow(this, ma.getArgument(1)) - ) + exists( + ClassInstanceExpr cie, Expr e // new Cookie("jwt_token", token) + | + ( + cie.getConstructor().getDeclaringType().hasQualifiedName("javax.servlet.http", "Cookie") or + cie.getConstructor() + .getDeclaringType() + .getASupertype*() + .hasQualifiedName(["javax.ws.rs.core", "jakarta.ws.rs.core"], "Cookie") + ) and + this = cie and + isSensitiveCookieNameExpr(e) and + DataFlow::localExprFlow(e, cie.getArgument(0)) + ) + or + exists( + SetCookieMethodAccess ma, Expr e // response.addHeader("Set-Cookie: token=" +authId + ";HttpOnly;Secure") + | + this = ma.getArgument(1) and + isSensitiveCookieNameExpr(e) and + DataFlow::localExprFlow(e, ma.getArgument(1)) ) } } @@ -78,15 +74,20 @@ class CookieResponseSink extends DataFlow::ExprNode { CookieResponseSink() { exists(MethodAccess ma | ( - ma.getMethod() instanceof ResponseAddCookieMethod or - ma instanceof SetCookieMethodAccess - ) and - ma.getAnArgument() = this.getExpr() + ma.getMethod() instanceof ResponseAddCookieMethod and + this.getExpr() = ma.getArgument(0) + or + ma instanceof SetCookieMethodAccess and + this.getExpr() = ma.getArgument(1) + ) ) } } -/** Holds if the `node` is a method call of `setHttpOnly(true)` on a cookie. */ +/** + * Holds if `node` is an access to a variable which has `setHttpOnly(true)` called on it and is also + * the first argument to a call to the method `addCookie` of `javax.servlet.http.HttpServletResponse`. + */ predicate setHttpOnlyMethodAccess(DataFlow::Node node) { exists( MethodAccess addCookie, Variable cookie, MethodAccess m // jwtCookie.setHttpOnly(true) @@ -100,7 +101,10 @@ predicate setHttpOnlyMethodAccess(DataFlow::Node node) { ) } -/** Holds if the `node` is a method call of `Set-Cookie` header with the `HttpOnly` flag whose cookie name is sensitive. */ +/** + * Holds if `node` is a string that contains `httponly` and which flows to the second argument + * of a method to set a cookie. + */ predicate setHttpOnlyInSetCookie(DataFlow::Node node) { exists(SetCookieMethodAccess sa | hasHttpOnlyExpr(node.asExpr()) and @@ -108,20 +112,17 @@ predicate setHttpOnlyInSetCookie(DataFlow::Node node) { ) } -/** Holds if the `node` is an invocation of a JAX-RS `NewCookie` constructor that sets `HttpOnly` to true. */ -predicate setHttpOnlyInNewCookie(DataFlow::Node node) { - exists(ClassInstanceExpr cie | - cie.getConstructor().getDeclaringType().hasName("NewCookie") and - DataFlow::localExprFlow(node.asExpr(), cie.getArgument(0)) and - ( - cie.getNumArgument() = 6 and cie.getArgument(5).(BooleanLiteral).getBooleanValue() = true // NewCookie(Cookie cookie, String comment, int maxAge, Date expiry, boolean secure, boolean httpOnly) - or - cie.getNumArgument() = 8 and - cie.getArgument(6).getType() instanceof BooleanType and - cie.getArgument(7).(BooleanLiteral).getBooleanValue() = true // NewCookie(String name, String value, String path, String domain, String comment, int maxAge, boolean secure, boolean httpOnly) - or - cie.getNumArgument() = 10 and cie.getArgument(9).(BooleanLiteral).getBooleanValue() = true // NewCookie(String name, String value, String path, String domain, int version, String comment, int maxAge, Date expiry, boolean secure, boolean httpOnly) - ) +/** Holds if `cie` is an invocation of a JAX-RS `NewCookie` constructor that sets `HttpOnly` to true. */ +predicate setHttpOnlyInNewCookie(ClassInstanceExpr cie) { + cie.getConstructedType().hasQualifiedName(["javax.ws.rs.core", "jakarta.ws.rs.core"], "NewCookie") and + ( + cie.getNumArgument() = 6 and cie.getArgument(5).(BooleanLiteral).getBooleanValue() = true // NewCookie(Cookie cookie, String comment, int maxAge, Date expiry, boolean secure, boolean httpOnly) + or + cie.getNumArgument() = 8 and + cie.getArgument(6).getType() instanceof BooleanType and + cie.getArgument(7).(BooleanLiteral).getBooleanValue() = true // NewCookie(String name, String value, String path, String domain, String comment, int maxAge, boolean secure, boolean httpOnly) + or + cie.getNumArgument() = 10 and cie.getArgument(9).(BooleanLiteral).getBooleanValue() = true // NewCookie(String name, String value, String path, String domain, int version, String comment, int maxAge, Date expiry, boolean secure, boolean httpOnly) ) } @@ -145,7 +146,10 @@ predicate isTestMethod(DataFlow::Node node) { ) } -/** A taint configuration tracking flow from a sensitive cookie without HttpOnly flag set to its HTTP response. */ +/** + * A taint configuration tracking flow from a sensitive cookie without the `HttpOnly` flag + * set to its HTTP response. + */ class MissingHttpOnlyConfiguration extends TaintTracking::Configuration { MissingHttpOnlyConfiguration() { this = "MissingHttpOnlyConfiguration" } @@ -159,25 +163,17 @@ class MissingHttpOnlyConfiguration extends TaintTracking::Configuration { // cookie.setHttpOnly(true) setHttpOnlyMethodAccess(node) or - // response.addHeader("Set-Cookie: token=" +authId + ";HttpOnly;Secure") + // response.addHeader("Set-Cookie", "token=" +authId + ";HttpOnly;Secure") setHttpOnlyInSetCookie(node) or // new NewCookie("session-access-key", accessKey, "/", null, null, 0, true, true) - setHttpOnlyInNewCookie(node) + setHttpOnlyInNewCookie(node.asExpr()) or // Test class or method isTestMethod(node) } override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { - exists( - ClassInstanceExpr cie // `NewCookie` constructor - | - cie.getAnArgument() = pred.asExpr() and - cie = succ.asExpr() and - cie.getConstructor().getDeclaringType().hasName("NewCookie") - ) - or exists( MethodAccess ma // `toString` call on a cookie object | diff --git a/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.expected b/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.expected index 84d6be3863a..e2d05a9b24d 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.expected @@ -1,13 +1,13 @@ edges -| SensitiveCookieNotHttpOnly.java:22:38:22:48 | "jwt_token" : String | SensitiveCookieNotHttpOnly.java:28:28:28:36 | jwtCookie | -| SensitiveCookieNotHttpOnly.java:49:56:49:75 | "session-access-key" : String | SensitiveCookieNotHttpOnly.java:49:42:49:124 | toString(...) | +| SensitiveCookieNotHttpOnly.java:22:27:22:60 | new Cookie(...) : Cookie | SensitiveCookieNotHttpOnly.java:28:28:28:36 | jwtCookie | +| SensitiveCookieNotHttpOnly.java:49:42:49:113 | new NewCookie(...) : NewCookie | SensitiveCookieNotHttpOnly.java:49:42:49:124 | toString(...) | nodes -| SensitiveCookieNotHttpOnly.java:22:38:22:48 | "jwt_token" : String | semmle.label | "jwt_token" : String | +| SensitiveCookieNotHttpOnly.java:22:27:22:60 | new Cookie(...) : Cookie | semmle.label | new Cookie(...) : Cookie | | SensitiveCookieNotHttpOnly.java:28:28:28:36 | jwtCookie | semmle.label | jwtCookie | | SensitiveCookieNotHttpOnly.java:39:42:39:69 | ... + ... | semmle.label | ... + ... | +| SensitiveCookieNotHttpOnly.java:49:42:49:113 | new NewCookie(...) : NewCookie | semmle.label | new NewCookie(...) : NewCookie | | SensitiveCookieNotHttpOnly.java:49:42:49:124 | toString(...) | semmle.label | toString(...) | -| SensitiveCookieNotHttpOnly.java:49:56:49:75 | "session-access-key" : String | semmle.label | "session-access-key" : String | #select -| SensitiveCookieNotHttpOnly.java:28:28:28:36 | jwtCookie | SensitiveCookieNotHttpOnly.java:22:38:22:48 | "jwt_token" : String | SensitiveCookieNotHttpOnly.java:28:28:28:36 | jwtCookie | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:22:38:22:48 | "jwt_token" | This sensitive cookie | +| SensitiveCookieNotHttpOnly.java:28:28:28:36 | jwtCookie | SensitiveCookieNotHttpOnly.java:22:27:22:60 | new Cookie(...) : Cookie | SensitiveCookieNotHttpOnly.java:28:28:28:36 | jwtCookie | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:22:27:22:60 | new Cookie(...) | This sensitive cookie | | SensitiveCookieNotHttpOnly.java:39:42:39:69 | ... + ... | SensitiveCookieNotHttpOnly.java:39:42:39:69 | ... + ... | SensitiveCookieNotHttpOnly.java:39:42:39:69 | ... + ... | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:39:42:39:69 | ... + ... | This sensitive cookie | -| SensitiveCookieNotHttpOnly.java:49:42:49:124 | toString(...) | SensitiveCookieNotHttpOnly.java:49:56:49:75 | "session-access-key" : String | SensitiveCookieNotHttpOnly.java:49:42:49:124 | toString(...) | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:49:56:49:75 | "session-access-key" | This sensitive cookie | +| SensitiveCookieNotHttpOnly.java:49:42:49:124 | toString(...) | SensitiveCookieNotHttpOnly.java:49:42:49:113 | new NewCookie(...) : NewCookie | SensitiveCookieNotHttpOnly.java:49:42:49:124 | toString(...) | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:49:42:49:113 | new NewCookie(...) | This sensitive cookie | diff --git a/java/ql/test/stubs/jsr311-api-1.1.1/javax/ws/rs/core/Cookie.java b/java/ql/test/stubs/jsr311-api-1.1.1/javax/ws/rs/core/Cookie.java index 4e4c7585c35..f810600a766 100644 --- a/java/ql/test/stubs/jsr311-api-1.1.1/javax/ws/rs/core/Cookie.java +++ b/java/ql/test/stubs/jsr311-api-1.1.1/javax/ws/rs/core/Cookie.java @@ -51,10 +51,16 @@ package javax.ws.rs.core; * @since 1.0 */ public class Cookie { + /** * Cookies using the default version correspond to RFC 2109. */ public static final int DEFAULT_VERSION = 1; + private final String name; + private final String value; + private final int version; + private final String path; + private final String domain; /** * Create a new instance. @@ -68,6 +74,11 @@ public class Cookie { */ public Cookie(final String name, final String value, final String path, final String domain, final int version) throws IllegalArgumentException { + this.name = name; + this.value = value; + this.version = version; + this.domain = domain; + this.path = path; } /** @@ -81,6 +92,7 @@ public class Cookie { */ public Cookie(final String name, final String value, final String path, final String domain) throws IllegalArgumentException { + this(name, value, path, domain, DEFAULT_VERSION); } /** @@ -92,6 +104,7 @@ public class Cookie { */ public Cookie(final String name, final String value) throws IllegalArgumentException { + this(name, value, null, null); } /** @@ -112,7 +125,7 @@ public class Cookie { * @return the cookie name. */ public String getName() { - return null; + return name; } /** @@ -121,7 +134,7 @@ public class Cookie { * @return the cookie value. */ public String getValue() { - return null; + return value; } /** @@ -130,7 +143,7 @@ public class Cookie { * @return the cookie version. */ public int getVersion() { - return -1; + return version; } /** @@ -139,7 +152,7 @@ public class Cookie { * @return the cookie domain. */ public String getDomain() { - return null; + return domain; } /** @@ -148,40 +161,6 @@ public class Cookie { * @return the cookie path. */ public String getPath() { - return null; + return path; } - - /** - * Convert the cookie to a string suitable for use as the value of the - * corresponding HTTP header. - * - * @return a stringified cookie. - */ - @Override - public String toString() { - return null; - } - - /** - * Generate a hash code by hashing all of the cookies properties. - * - * @return the cookie hash code. - */ - @Override - public int hashCode() { - return -1; - } - - /** - * Compare for equality. - * - * @param obj the object to compare to. - * @return {@code true}, if the object is a {@code Cookie} with the same - * value for all properties, {@code false} otherwise. - */ - @SuppressWarnings({"StringEquality", "RedundantIfStatement"}) - @Override - public boolean equals(final Object obj) { - return true; - } -} \ No newline at end of file +} diff --git a/java/ql/test/stubs/jsr311-api-1.1.1/javax/ws/rs/core/NewCookie.java b/java/ql/test/stubs/jsr311-api-1.1.1/javax/ws/rs/core/NewCookie.java index 43a4899e0ca..7f2e3ec0535 100644 --- a/java/ql/test/stubs/jsr311-api-1.1.1/javax/ws/rs/core/NewCookie.java +++ b/java/ql/test/stubs/jsr311-api-1.1.1/javax/ws/rs/core/NewCookie.java @@ -320,40 +320,4 @@ public class NewCookie extends Cookie { public Cookie toCookie() { return null; } - - /** - * Convert the cookie to a string suitable for use as the value of the - * corresponding HTTP header. - * - * @return a stringified cookie. - */ - @Override - public String toString() { - return null; - } - - /** - * Generate a hash code by hashing all of the properties. - * - * @return the hash code. - */ - @Override - public int hashCode() { - return -1; - } - - /** - * Compare for equality. Use {@link #toCookie()} to compare a - * {@code NewCookie} to a {@code Cookie} considering only the common - * properties. - * - * @param obj the object to compare to - * @return true if the object is a {@code NewCookie} with the same value for - * all properties, false otherwise. - */ - @SuppressWarnings({"StringEquality", "RedundantIfStatement"}) - @Override - public boolean equals(Object obj) { - return true; - } } \ No newline at end of file From 1b1c3f953b9ebb828e161e4b36d67075a7bca510 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Wed, 3 Mar 2021 13:54:26 +0000 Subject: [PATCH 075/725] Remove localflow from the source --- .../CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql b/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql index 842e8b7eabb..258b2545b27 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql @@ -45,7 +45,7 @@ class SetCookieMethodAccess extends MethodAccess { class SensitiveCookieNameExpr extends Expr { SensitiveCookieNameExpr() { exists( - ClassInstanceExpr cie, Expr e // new Cookie("jwt_token", token) + ClassInstanceExpr cie // new Cookie("jwt_token", token) | ( cie.getConstructor().getDeclaringType().hasQualifiedName("javax.servlet.http", "Cookie") or @@ -55,16 +55,14 @@ class SensitiveCookieNameExpr extends Expr { .hasQualifiedName(["javax.ws.rs.core", "jakarta.ws.rs.core"], "Cookie") ) and this = cie and - isSensitiveCookieNameExpr(e) and - DataFlow::localExprFlow(e, cie.getArgument(0)) + isSensitiveCookieNameExpr(cie.getArgument(0)) ) or exists( - SetCookieMethodAccess ma, Expr e // response.addHeader("Set-Cookie: token=" +authId + ";HttpOnly;Secure") + SetCookieMethodAccess ma // response.addHeader("Set-Cookie: token=" +authId + ";HttpOnly;Secure") | this = ma.getArgument(1) and - isSensitiveCookieNameExpr(e) and - DataFlow::localExprFlow(e, ma.getArgument(1)) + isSensitiveCookieNameExpr(this) ) } } From 502cf38fccef4c0b2a1120f2fe175571ec1b9cb5 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Wed, 3 Mar 2021 14:07:43 +0000 Subject: [PATCH 076/725] Use concise API --- .../Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql b/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql index 258b2545b27..d9104cbad97 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql @@ -48,9 +48,8 @@ class SensitiveCookieNameExpr extends Expr { ClassInstanceExpr cie // new Cookie("jwt_token", token) | ( - cie.getConstructor().getDeclaringType().hasQualifiedName("javax.servlet.http", "Cookie") or - cie.getConstructor() - .getDeclaringType() + cie.getConstructedType().hasQualifiedName("javax.servlet.http", "Cookie") or + cie.getConstructedType() .getASupertype*() .hasQualifiedName(["javax.ws.rs.core", "jakarta.ws.rs.core"], "Cookie") ) and From 1784c202a7ad4b06932ee33c8e0609aed5181ffc Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Wed, 3 Mar 2021 17:03:37 +0000 Subject: [PATCH 077/725] Clean up the query --- .../Security/CWE/CWE-759/HashWithoutSalt.ql | 40 +++++++------------ .../security/CWE-759/HashWithoutSalt.java | 27 +++++-------- 2 files changed, 26 insertions(+), 41 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql b/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql index e1ac21e9200..7ea8c7598d2 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql @@ -17,6 +17,7 @@ class MessageDigest extends RefType { MessageDigest() { this.hasQualifiedName("java.security", "MessageDigest") } } +/** The method call `MessageDigest.getInstance(...)` */ class MDConstructor extends StaticMethodAccess { MDConstructor() { exists(Method m | m = this.getMethod() | @@ -57,26 +58,22 @@ class MDHashMethodAccess extends MethodAccess { string getPasswordRegex() { result = "(?i).*pass(wd|word|code|phrase).*" } /** Finds variables that hold password information judging by their names. */ -class PasswordVarExpr extends Expr { +class PasswordVarExpr extends VarAccess { PasswordVarExpr() { - this.(VarAccess).getVariable().getName().toLowerCase().regexpMatch(getPasswordRegex()) and - not this.(VarAccess).getVariable().getName().toLowerCase().matches("%hash%") // Exclude variable names such as `passwordHash` since their values were already hashed + exists(string name | name = this.getVariable().getName().toLowerCase() | + name.regexpMatch(getPasswordRegex()) and not name.matches("%hash%") // Exclude variable names such as `passwordHash` since their values were already hashed + ) } } /** Holds if `Expr` e is a direct or indirect operand of `ae`. */ -predicate hasAddExpr(AddExpr ae, Expr e) { ae.getAnOperand+() = e } +predicate hasAddExprAncestor(AddExpr ae, Expr e) { ae.getAnOperand+() = e } -/** Holds if `MethodAccess` ma has a flow to another `MDHashMethodAccess` call. */ -predicate hasAnotherHashCall(MethodAccess ma) { - exists(MDHashMethodAccess ma2, DataFlow::Node node1, DataFlow::Node node2 | +/** Holds if `MDHashMethodAccess ma` is a second `MDHashMethodAccess` call by the same object. */ +predicate hasAnotherHashCall(MDHashMethodAccess ma) { + exists(MDHashMethodAccess ma2 | ma2 != ma and - node1.asExpr() = ma.getAChildExpr() and - node2.asExpr() = ma2.getAChildExpr() and - ( - TaintTracking2::localTaint(node1, node2) or - TaintTracking2::localTaint(node2, node1) - ) + ma2.getQualifier() = ma.getQualifier().(VarAccess).getVariable().getAnAccess() ) } @@ -84,19 +81,12 @@ predicate hasAnotherHashCall(MethodAccess ma) { predicate isSingleHashMethodCall(MDHashMethodAccess ma) { not hasAnotherHashCall(ma) } /** Holds if `MethodAccess` ma is invoked by `MethodAccess` ma2 either directly or indirectly. */ -predicate hasParentCall(MethodAccess ma2, MethodAccess ma) { - ma.getCaller() = ma2.getMethod() - or - exists(MethodAccess ma3 | - ma.getCaller() = ma3.getMethod() and - hasParentCall(ma2, ma3) - ) -} +predicate hasParentCall(MethodAccess ma2, MethodAccess ma) { ma.getCaller() = ma2.getMethod() } /** Holds if `MethodAccess` is a single hashing call that is not invoked by a wrapper method. */ predicate isSink(MethodAccess ma) { isSingleHashMethodCall(ma) and - not exists(MethodAccess ma2 | hasParentCall(ma2, ma)) // Not invoked by a wrapper method which could invoke MDHashMethod in another call stack to reduce FPs + not hasParentCall(_, ma) // Not invoked by a wrapper method which could invoke MDHashMethod in another call stack. This reduces FPs. } /** Sink of hashing calls. */ @@ -131,9 +121,9 @@ class HashWithoutSaltConfiguration extends TaintTracking::Configuration { ma.getArgument(0) = node.asExpr() ) // System.arraycopy(password.getBytes(), ...) or - exists(AddExpr e | hasAddExpr(e, node.asExpr())) // password+salt + exists(AddExpr e | hasAddExprAncestor(e, node.asExpr())) // password+salt or - exists(ConditionalExpr ce | ce = node.asExpr()) // useSalt?password+":"+salt:password + exists(ConditionalExpr ce | ce.getAChildExpr() = node.asExpr()) // useSalt?password+":"+salt:password or exists(MethodAccess ma | ma.getMethod().getDeclaringType().hasQualifiedName("java.lang", "StringBuilder") and @@ -143,7 +133,7 @@ class HashWithoutSaltConfiguration extends TaintTracking::Configuration { or exists(MethodAccess ma | ma.getQualifier().(VarAccess).getVariable().getType() instanceof Interface and - ma.getAnArgument() = node.asExpr() // Method access of interface type variables requires runtime determination + ma.getAnArgument() = node.asExpr() // Method access of interface type variables requires runtime determination thus not handled ) } } diff --git a/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.java b/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.java index ef2fef8dd9c..026ccfa70be 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.java +++ b/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.java @@ -54,12 +54,16 @@ public class HashWithoutSalt { // GOOD - Hash with a given salt stored somewhere else. public String getSHA256Hash(String password, String salt) throws NoSuchAlgorithmException { - return hash(password+":"+salt); + MessageDigest alg = MessageDigest.getInstance("SHA-256"); + String payload = password+":"+salt; + return Base64.getEncoder().encodeToString(alg.digest(payload.getBytes(java.nio.charset.StandardCharsets.UTF_8))); } // GOOD - Hash with a given salt stored somewhere else. public String getSHA256Hash2(String password, String salt, boolean useSalt) throws NoSuchAlgorithmException { - return hash(useSalt?password+":"+salt:password); + MessageDigest alg = MessageDigest.getInstance("SHA-256"); + String payload = useSalt?password+":"+salt:password; + return Base64.getEncoder().encodeToString(alg.digest(payload.getBytes(java.nio.charset.StandardCharsets.UTF_8))); } // GOOD - Hash with a salt for a variable named passwordHash, whose value is a hash used as an input for a hashing function. @@ -73,10 +77,6 @@ public class HashWithoutSalt { sha256.update(foo, start, len); } - public void update2(SHA256 sha256, byte[] foo, int start, int len) throws NoSuchAlgorithmException { - sha256.update(foo, start, len); - } - // BAD - Invoking a wrapper implementation without a salt is not detected. public String getSHA256Hash4(String password) throws NoSuchAlgorithmException, ClassNotFoundException, IllegalAccessException, InstantiationException { SHA256 sha256 = new SHA256(); @@ -98,15 +98,15 @@ public class HashWithoutSalt { } // BAD - Invoking a wrapper implementation without a salt is not detected. - public String getSHA256Hash6(String password) throws NoSuchAlgorithmException { - SHA256 sha256 = new SHA256(); + public String getSHA512Hash6(String password) throws NoSuchAlgorithmException { + SHA512 sha512 = new SHA512(); byte[] passBytes = password.getBytes(); - sha256.update(passBytes, 0, passBytes.length); - return Base64.getEncoder().encodeToString(sha256.digest()); + sha512.update(passBytes, 0, passBytes.length); + return Base64.getEncoder().encodeToString(sha512.digest()); } // BAD - Invoke a wrapper implementation with a salt, which is not detected with an interface type variable. - public String getSHA256Hash7(byte[] passphrase) throws NoSuchAlgorithmException, ClassNotFoundException, IllegalAccessException, InstantiationException { + public String getSHA512Hash7(byte[] passphrase) throws NoSuchAlgorithmException, ClassNotFoundException, IllegalAccessException, InstantiationException { Class c = Class.forName("SHA512"); HASH sha512 = (HASH) (c.newInstance()); byte[] tmp = new byte[4]; @@ -120,11 +120,6 @@ public class HashWithoutSalt { return Base64.getEncoder().encodeToString(key); } - private String hash(String payload) throws NoSuchAlgorithmException { - MessageDigest alg = MessageDigest.getInstance("SHA-256"); - return Base64.getEncoder().encodeToString(alg.digest(payload.getBytes(java.nio.charset.StandardCharsets.UTF_8))); - } - public static byte[] getSalt() throws NoSuchAlgorithmException { SecureRandom sr = SecureRandom.getInstance("SHA1PRNG"); byte[] salt = new byte[16]; From c5577cb09a073c2fb4f6feeca887c437d5fbe2fb Mon Sep 17 00:00:00 2001 From: haby0 Date: Thu, 4 Mar 2021 19:54:49 +0800 Subject: [PATCH 078/725] Fix the problem --- .../Security/CWE/CWE-352/JsonpInjection.ql | 68 -------- .../CWE/CWE-352/JsonpInjectionFilterLib.qll | 77 --------- .../CWE/CWE-352/JsonpInjectionLib.qll | 155 ------------------ .../Security/CWE/CWE-352/JsonStringLib.qll | 0 .../CWE/CWE-352/JsonpController.java} | 48 +----- .../Security/CWE/CWE-352/JsonpInjection.java | 0 .../Security/CWE/CWE-352/JsonpInjection.qhelp | 2 +- .../Security/CWE/CWE-352/JsonpInjection.ql | 64 ++++++++ .../CWE/CWE-352/JsonpInjectionLib.qll | 130 +++++++++++++++ .../CWE/CWE-352/JsonpInjectionServlet1.java | 0 .../CWE/CWE-352/JsonpInjectionServlet2.java | 0 .../Security/CWE/CWE-352/RefererFilter.java | 43 +++++ .../semmle/code/java/frameworks/Servlets.qll | 12 +- .../security/CWE-352/JsonpController.java | 128 +++++++++++++++ .../security/CWE-352/JsonpInjection.expected | 60 ------- .../CWE-352/JsonpInjectionServlet1.java | 64 ++++++++ .../CWE-352/JsonpInjectionServlet2.java} | 16 +- .../CWE-352/JsonpInjection_1.expected | 60 +++++++ .../CWE-352/JsonpInjection_2.expected | 78 +++++++++ .../CWE-352/JsonpInjection_3.expected | 66 ++++++++ .../query-tests/security/CWE-352/Readme | 3 + .../security/CWE-352/RefererFilter.java | 43 +++++ .../gson-2.8.6/com/google/gson/Gson.java | 7 + .../org/springframework/util/StringUtils.java | 8 + .../javax/servlet/Filter.java | 13 ++ .../javax/servlet/FilterChain.java | 8 + .../javax/servlet/FilterConfig.java | 3 + .../javax/servlet/ServletException.java | 8 + .../javax/servlet/ServletRequest.java | 87 ++++++++++ .../javax/servlet/ServletResponse.java | 39 +++++ .../servlet/http/HttpServletRequest.java | 116 +++++++++++++ .../servlet/http/HttpServletResponse.java | 106 ++++++++++++ 32 files changed, 1084 insertions(+), 428 deletions(-) delete mode 100644 java/ql/src/Security/CWE/CWE-352/JsonpInjection.ql delete mode 100644 java/ql/src/Security/CWE/CWE-352/JsonpInjectionFilterLib.qll delete mode 100644 java/ql/src/Security/CWE/CWE-352/JsonpInjectionLib.qll rename java/ql/src/{ => experimental}/Security/CWE/CWE-352/JsonStringLib.qll (100%) rename java/ql/{test/experimental/query-tests/security/CWE-352/JsonpInjection.java => src/experimental/Security/CWE/CWE-352/JsonpController.java} (72%) rename java/ql/src/{ => experimental}/Security/CWE/CWE-352/JsonpInjection.java (100%) rename java/ql/src/{ => experimental}/Security/CWE/CWE-352/JsonpInjection.qhelp (96%) create mode 100644 java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.ql create mode 100644 java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjectionLib.qll rename java/ql/src/{ => experimental}/Security/CWE/CWE-352/JsonpInjectionServlet1.java (100%) rename java/ql/src/{ => experimental}/Security/CWE/CWE-352/JsonpInjectionServlet2.java (100%) create mode 100644 java/ql/src/experimental/Security/CWE/CWE-352/RefererFilter.java create mode 100644 java/ql/test/experimental/query-tests/security/CWE-352/JsonpController.java delete mode 100644 java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionServlet1.java rename java/ql/{src/Security/CWE/CWE-352/JsonpInjectionServlet.java => test/experimental/query-tests/security/CWE-352/JsonpInjectionServlet2.java} (75%) create mode 100644 java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection_1.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection_2.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection_3.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-352/Readme create mode 100644 java/ql/test/experimental/query-tests/security/CWE-352/RefererFilter.java create mode 100644 java/ql/test/stubs/gson-2.8.6/com/google/gson/Gson.java create mode 100644 java/ql/test/stubs/spring-core-5.3.2/org/springframework/util/StringUtils.java create mode 100644 java/ql/test/stubs/tomcat-embed-core-9.0.41/javax/servlet/Filter.java create mode 100644 java/ql/test/stubs/tomcat-embed-core-9.0.41/javax/servlet/FilterChain.java create mode 100644 java/ql/test/stubs/tomcat-embed-core-9.0.41/javax/servlet/FilterConfig.java create mode 100644 java/ql/test/stubs/tomcat-embed-core-9.0.41/javax/servlet/ServletException.java create mode 100644 java/ql/test/stubs/tomcat-embed-core-9.0.41/javax/servlet/ServletRequest.java create mode 100644 java/ql/test/stubs/tomcat-embed-core-9.0.41/javax/servlet/ServletResponse.java create mode 100644 java/ql/test/stubs/tomcat-embed-core-9.0.41/javax/servlet/http/HttpServletRequest.java create mode 100644 java/ql/test/stubs/tomcat-embed-core-9.0.41/javax/servlet/http/HttpServletResponse.java diff --git a/java/ql/src/Security/CWE/CWE-352/JsonpInjection.ql b/java/ql/src/Security/CWE/CWE-352/JsonpInjection.ql deleted file mode 100644 index 53ee6182511..00000000000 --- a/java/ql/src/Security/CWE/CWE-352/JsonpInjection.ql +++ /dev/null @@ -1,68 +0,0 @@ -/** - * @name JSONP Injection - * @description User-controlled callback function names that are not verified are vulnerable - * to jsonp injection attacks. - * @kind path-problem - * @problem.severity error - * @precision high - * @id java/JSONP-Injection - * @tags security - * external/cwe/cwe-352 - */ - -import java -import JsonpInjectionLib -import JsonpInjectionFilterLib -import semmle.code.java.dataflow.FlowSources -import semmle.code.java.deadcode.WebEntryPoints -import DataFlow::PathGraph - - -/** If there is a method to verify `token`, `auth`, `referer`, and `origin`, it will not pass. */ -class ServletVerifAuth extends DataFlow::BarrierGuard { - ServletVerifAuth() { - exists(MethodAccess ma, Node prod, Node succ | - ma.getMethod().getName().regexpMatch("(?i).*(token|auth|referer|origin).*") and - prod instanceof RemoteFlowSource and - succ.asExpr() = ma.getAnArgument() and - ma.getMethod().getAParameter().getName().regexpMatch("(?i).*(token|auth|referer|origin).*") and - localFlowStep*(prod, succ) and - this = ma - ) - } - - override predicate checks(Expr e, boolean branch) { - exists(Node node | - node instanceof JsonpInjectionSink and - e = node.asExpr() and - branch = true - ) - } -} - -/** Taint-tracking configuration tracing flow from get method request sources to output jsonp data. */ -class JsonpInjectionConfig extends TaintTracking::Configuration { - JsonpInjectionConfig() { this = "JsonpInjectionConfig" } - - override predicate isSource(DataFlow::Node source) { source instanceof GetHttpRequestSource } - - override predicate isSink(DataFlow::Node sink) { sink instanceof JsonpInjectionSink } - - override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { - guard instanceof ServletVerifAuth - } - - override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { - exists(MethodAccess ma | - isRequestGetParamMethod(ma) and pred.asExpr() = ma.getQualifier() and succ.asExpr() = ma - ) - } -} - -from DataFlow::PathNode source, DataFlow::PathNode sink, JsonpInjectionConfig conf -where - not checks() = false and - conf.hasFlowPath(source, sink) and - exists(JsonpInjectionFlowConfig jhfc | jhfc.hasFlowTo(sink.getNode())) -select sink.getNode(), source, sink, "Jsonp Injection query might include code from $@.", - source.getNode(), "this user input" diff --git a/java/ql/src/Security/CWE/CWE-352/JsonpInjectionFilterLib.qll b/java/ql/src/Security/CWE/CWE-352/JsonpInjectionFilterLib.qll deleted file mode 100644 index b349bed2641..00000000000 --- a/java/ql/src/Security/CWE/CWE-352/JsonpInjectionFilterLib.qll +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @name JSONP Injection - * @description User-controlled callback function names that are not verified are vulnerable - * to json hijacking attacks. - * @kind path-problem - */ - -import java -import DataFlow -import semmle.code.java.dataflow.FlowSources -import semmle.code.java.dataflow.TaintTracking2 -import DataFlow::PathGraph - -class FilterVerifAuth extends DataFlow::BarrierGuard { - FilterVerifAuth() { - exists(MethodAccess ma, Node prod, Node succ | - ma.getMethod().getName().regexpMatch("(?i).*(token|auth|referer|origin).*") and - prod instanceof RemoteFlowSource and - succ.asExpr() = ma.getAnArgument() and - ma.getMethod().getAParameter().getName().regexpMatch("(?i).*(token|auth|referer|origin).*") and - localFlowStep*(prod, succ) and - this = ma - ) - } - - override predicate checks(Expr e, boolean branch) { - exists(Node node | - node instanceof DoFilterMethodSink and - e = node.asExpr() and - branch = true - ) - } -} - -/** A data flow source for `Filter.doFilter` method paramters. */ -private class DoFilterMethodSource extends DataFlow::Node { - DoFilterMethodSource() { - exists(Method m | - isDoFilterMethod(m) and - m.getAParameter().getAnAccess() = this.asExpr() - ) - } -} - -/** A data flow sink for `FilterChain.doFilter` method qualifying expression. */ -private class DoFilterMethodSink extends DataFlow::Node { - DoFilterMethodSink() { - exists(MethodAccess ma, Method m | ma.getMethod() = m | - m.hasName("doFilter") and - m.getDeclaringType*().hasQualifiedName("javax.servlet", "FilterChain") and - ma.getQualifier() = this.asExpr() - ) - } -} - -/** Taint-tracking configuration tracing flow from `doFilter` method paramter source to output - * `FilterChain.doFilter` method qualifying expression. - * */ -class DoFilterMethodConfig extends TaintTracking::Configuration { - DoFilterMethodConfig() { this = "DoFilterMethodConfig" } - - override predicate isSource(DataFlow::Node source) { source instanceof DoFilterMethodSource } - - override predicate isSink(DataFlow::Node sink) { sink instanceof DoFilterMethodSink } - - override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { - guard instanceof FilterVerifAuth - } -} - -/** Implement class modeling verification for `Filter.doFilter`, return false if it fails. */ -boolean checks() { - exists(DataFlow::PathNode source, DataFlow::PathNode sink, DoFilterMethodConfig conf | - conf.hasFlowPath(source, sink) and - result = false - ) -} diff --git a/java/ql/src/Security/CWE/CWE-352/JsonpInjectionLib.qll b/java/ql/src/Security/CWE/CWE-352/JsonpInjectionLib.qll deleted file mode 100644 index 3f730425823..00000000000 --- a/java/ql/src/Security/CWE/CWE-352/JsonpInjectionLib.qll +++ /dev/null @@ -1,155 +0,0 @@ -import java -import DataFlow -import JsonStringLib -import semmle.code.java.dataflow.DataFlow -import semmle.code.java.dataflow.FlowSources -import semmle.code.java.frameworks.spring.SpringController - -/** Holds if `m` is a method of some override of `HttpServlet.doGet`. */ -private predicate isGetServletMethod(Method m) { - isServletRequestMethod(m) and m.getName() = "doGet" -} - -/** Holds if `m` is a method of some override of `HttpServlet.doGet`. */ -private predicate isGetSpringControllerMethod(Method m) { - exists(Annotation a | - a = m.getAnAnnotation() and - a.getType().hasQualifiedName("org.springframework.web.bind.annotation", "GetMapping") - ) - or - exists(Annotation a | - a = m.getAnAnnotation() and - a.getType().hasQualifiedName("org.springframework.web.bind.annotation", "RequestMapping") and - a.getValue("method").toString().regexpMatch("RequestMethod.GET|\\{...\\}") - ) -} - -/** Method parameters use the annotation `@RequestParam` or the parameter type is `ServletRequest`, `String`, `Object` */ -predicate checkSpringMethodParameterType(Method m, int i) { - m.getParameter(i).getType() instanceof ServletRequest - or - exists(Parameter p | - p = m.getParameter(i) and - p.hasAnnotation() and - p.getAnAnnotation() - .getType() - .hasQualifiedName("org.springframework.web.bind.annotation", "RequestParam") and - p.getType().getName().regexpMatch("String|Object") - ) - or - exists(Parameter p | - p = m.getParameter(i) and - not p.hasAnnotation() and - p.getType().getName().regexpMatch("String|Object") - ) -} - -/** A data flow source for get method request parameters. */ -abstract class GetHttpRequestSource extends DataFlow::Node { } - -/** A data flow source for servlet get method request parameters. */ -private class ServletGetHttpRequestSource extends GetHttpRequestSource { - ServletGetHttpRequestSource() { - exists(Method m | - isGetServletMethod(m) and - m.getParameter(0).getAnAccess() = this.asExpr() - ) - } -} - -/** A data flow source for spring controller get method request parameters. */ -private class SpringGetHttpRequestSource extends GetHttpRequestSource { - SpringGetHttpRequestSource() { - exists(SpringControllerMethod scm, int i | - isGetSpringControllerMethod(scm) and - checkSpringMethodParameterType(scm, i) and - scm.getParameter(i).getAnAccess() = this.asExpr() - ) - } -} - -/** A data flow sink for unvalidated user input that is used to jsonp. */ -abstract class JsonpInjectionSink extends DataFlow::Node { } - -/** Use ```print```, ```println```, ```write``` to output result. */ -private class WriterPrintln extends JsonpInjectionSink { - WriterPrintln() { - exists(MethodAccess ma | - ma.getMethod().getName().regexpMatch("print|println|write") and - ma.getMethod() - .getDeclaringType() - .getASourceSupertype*() - .hasQualifiedName("java.io", "PrintWriter") and - ma.getArgument(0) = this.asExpr() - ) - } -} - -/** Spring Request Method return result. */ -private class SpringReturn extends JsonpInjectionSink { - SpringReturn() { - exists(ReturnStmt rs, Method m | m = rs.getEnclosingCallable() | - isGetSpringControllerMethod(m) and - rs.getResult() = this.asExpr() - ) - } -} - -/** A concatenate expression using `(` and `)` or `);`. */ -class JsonpInjectionExpr extends AddExpr { - JsonpInjectionExpr() { - getRightOperand().toString().regexpMatch("\"\\)\"|\"\\);\"") and - getLeftOperand() - .(AddExpr) - .getLeftOperand() - .(AddExpr) - .getRightOperand() - .toString() - .regexpMatch("\"\\(\"") - } - - /** Get the jsonp function name of this expression */ - Expr getFunctionName() { - result = getLeftOperand().(AddExpr).getLeftOperand().(AddExpr).getLeftOperand() - } - - /** Get the json data of this expression */ - Expr getJsonExpr() { result = getLeftOperand().(AddExpr).getRightOperand() } -} - -/** A data flow configuration tracing flow from remote sources to jsonp function name. */ -class RemoteFlowConfig extends DataFlow2::Configuration { - RemoteFlowConfig() { this = "RemoteFlowConfig" } - - override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource } - - override predicate isSink(DataFlow::Node sink) { - exists(JsonpInjectionExpr jhe | jhe.getFunctionName() = sink.asExpr()) - } -} - -/** A data flow configuration tracing flow from json data to splicing jsonp data. */ -class JsonDataFlowConfig extends DataFlow2::Configuration { - JsonDataFlowConfig() { this = "JsonDataFlowConfig" } - - override predicate isSource(DataFlow::Node src) { src instanceof JsonpStringSource } - - override predicate isSink(DataFlow::Node sink) { - exists(JsonpInjectionExpr jhe | jhe.getJsonExpr() = sink.asExpr()) - } -} - -/** Taint-tracking configuration tracing flow from user-controllable function name jsonp data to output jsonp data. */ -class JsonpInjectionFlowConfig extends DataFlow::Configuration { - JsonpInjectionFlowConfig() { this = "JsonpInjectionFlowConfig" } - - override predicate isSource(DataFlow::Node src) { - exists(JsonpInjectionExpr jhe, JsonDataFlowConfig jdfc, RemoteFlowConfig rfc | - jhe = src.asExpr() and - jdfc.hasFlowTo(DataFlow::exprNode(jhe.getJsonExpr())) and - rfc.hasFlowTo(DataFlow::exprNode(jhe.getFunctionName())) - ) - } - - override predicate isSink(DataFlow::Node sink) { sink instanceof JsonpInjectionSink } -} diff --git a/java/ql/src/Security/CWE/CWE-352/JsonStringLib.qll b/java/ql/src/experimental/Security/CWE/CWE-352/JsonStringLib.qll similarity index 100% rename from java/ql/src/Security/CWE/CWE-352/JsonStringLib.qll rename to java/ql/src/experimental/Security/CWE/CWE-352/JsonStringLib.qll diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection.java b/java/ql/src/experimental/Security/CWE/CWE-352/JsonpController.java similarity index 72% rename from java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection.java rename to java/ql/src/experimental/Security/CWE/CWE-352/JsonpController.java index 9f079513a8b..84a172a7aeb 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection.java +++ b/java/ql/src/experimental/Security/CWE/CWE-352/JsonpController.java @@ -3,17 +3,14 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.Gson; import java.io.PrintWriter; import java.util.HashMap; -import java.util.Random; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; @Controller -public class JsonpInjection { +public class JsonpController { private static HashMap hashMap = new HashMap(); static { @@ -96,54 +93,13 @@ public class JsonpInjection { @GetMapping(value = "jsonp7") @ResponseBody - public String good(HttpServletRequest request) { - String resultStr = null; - String jsonpCallback = request.getParameter("jsonpCallback"); - - String val = ""; - Random random = new Random(); - for (int i = 0; i < 10; i++) { - val += String.valueOf(random.nextInt(10)); - } - // good - jsonpCallback = jsonpCallback + "_" + val; - String jsonStr = getJsonStr(hashMap); - resultStr = jsonpCallback + "(" + jsonStr + ")"; - return resultStr; - } - - @GetMapping(value = "jsonp8") - @ResponseBody public String good1(HttpServletRequest request) { String resultStr = null; - String jsonpCallback = request.getParameter("jsonpCallback"); String token = request.getParameter("token"); - // good if (verifToken(token)){ - System.out.println(token); - String jsonStr = getJsonStr(hashMap); - resultStr = jsonpCallback + "(" + jsonStr + ")"; - return resultStr; - } - - return "error"; - } - - @GetMapping(value = "jsonp9") - @ResponseBody - public String good2(HttpServletRequest request) { - String resultStr = null; - String jsonpCallback = request.getParameter("jsonpCallback"); - - String referer = request.getHeader("Referer"); - - boolean result = verifReferer(referer); - - boolean test = result; - // good - if (test){ + String jsonpCallback = request.getParameter("jsonpCallback"); String jsonStr = getJsonStr(hashMap); resultStr = jsonpCallback + "(" + jsonStr + ")"; return resultStr; diff --git a/java/ql/src/Security/CWE/CWE-352/JsonpInjection.java b/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.java similarity index 100% rename from java/ql/src/Security/CWE/CWE-352/JsonpInjection.java rename to java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.java diff --git a/java/ql/src/Security/CWE/CWE-352/JsonpInjection.qhelp b/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.qhelp similarity index 96% rename from java/ql/src/Security/CWE/CWE-352/JsonpInjection.qhelp rename to java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.qhelp index b063b409d3a..bb5d628ac0b 100644 --- a/java/ql/src/Security/CWE/CWE-352/JsonpInjection.qhelp +++ b/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.qhelp @@ -16,7 +16,7 @@ there is a problem of sensitive information leakage.

    The following example shows the case of no verification processing and verification processing for the external input function name.

    - + diff --git a/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.ql b/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.ql new file mode 100644 index 00000000000..f3ae25daa03 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.ql @@ -0,0 +1,64 @@ +/** + * @name JSONP Injection + * @description User-controlled callback function names that are not verified are vulnerable + * to jsonp injection attacks. + * @kind path-problem + * @problem.severity error + * @precision high + * @id java/JSONP-Injection + * @tags security + * external/cwe/cwe-352 + */ + +import java +import JsonpInjectionLib +import semmle.code.java.dataflow.FlowSources +import semmle.code.java.deadcode.WebEntryPoints +import semmle.code.java.security.XSS +import DataFlow::PathGraph + +/** Determine whether there is a verification method for the remote streaming source data flow path method. */ +predicate existsFilterVerificationMethod() { + exists(MethodAccess ma,Node existsNode, Method m| + ma.getMethod() instanceof VerificationMethodClass and + existsNode.asExpr() = ma and + m = getAnMethod(existsNode.getEnclosingCallable()) and + isDoFilterMethod(m) + ) +} + +/** Determine whether there is a verification method for the remote streaming source data flow path method. */ +predicate existsServletVerificationMethod(Node checkNode) { + exists(MethodAccess ma,Node existsNode| + ma.getMethod() instanceof VerificationMethodClass and + existsNode.asExpr() = ma and + getAnMethod(existsNode.getEnclosingCallable()) = getAnMethod(checkNode.getEnclosingCallable()) + ) +} + +/** Taint-tracking configuration tracing flow from get method request sources to output jsonp data. */ +class RequestResponseFlowConfig extends TaintTracking::Configuration { + RequestResponseFlowConfig() { this = "RequestResponseFlowConfig" } + + override predicate isSource(DataFlow::Node source) { + source instanceof RemoteFlowSource and + getAnMethod(source.getEnclosingCallable()) instanceof RequestGetMethod + } + + override predicate isSink(DataFlow::Node sink) { sink instanceof XssSink } + + override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { + exists(MethodAccess ma | + isRequestGetParamMethod(ma) and pred.asExpr() = ma.getQualifier() and succ.asExpr() = ma + ) + } +} + +from DataFlow::PathNode source, DataFlow::PathNode sink, RequestResponseFlowConfig conf +where + not existsServletVerificationMethod(source.getNode()) and + not existsFilterVerificationMethod() and + conf.hasFlowPath(source, sink) and + exists(JsonpInjectionFlowConfig jhfc | jhfc.hasFlowTo(sink.getNode())) +select sink.getNode(), source, sink, "Jsonp Injection query might include code from $@.", + source.getNode(), "this user input" \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjectionLib.qll new file mode 100644 index 00000000000..b8964524a9f --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjectionLib.qll @@ -0,0 +1,130 @@ +import java +import DataFlow +import JsonStringLib +import semmle.code.java.security.XSS +import semmle.code.java.dataflow.DataFlow +import semmle.code.java.dataflow.FlowSources +import semmle.code.java.frameworks.spring.SpringController + +/** Taint-tracking configuration tracing flow from user-controllable function name jsonp data to output jsonp data. */ +class VerificationMethodFlowConfig extends TaintTracking::Configuration { + VerificationMethodFlowConfig() { this = "VerificationMethodFlowConfig" } + + override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource } + + override predicate isSink(DataFlow::Node sink) { + exists(MethodAccess ma, BarrierGuard bg | + ma.getMethod().getAParameter().getName().regexpMatch("(?i).*(token|auth|referer|origin).*") and + bg = ma and + sink.asExpr() = ma.getAnArgument() + ) + } +} + +/** The parameter name of the method is `token`, `auth`, `referer`, `origin`. */ +class VerificationMethodClass extends Method { + VerificationMethodClass() { + exists(MethodAccess ma, BarrierGuard bg, VerificationMethodFlowConfig vmfc, Node node | + this = ma.getMethod() and + this.getAParameter().getName().regexpMatch("(?i).*(token|auth|referer|origin).*") and + bg = ma and + node.asExpr() = ma.getAnArgument() and + vmfc.hasFlowTo(node) + ) + } +} + +/** Get Callable by recursive method. */ +Callable getAnMethod(Callable call) { + result = call + or + result = getAnMethod(call.getAReference().getEnclosingCallable()) +} + +abstract class RequestGetMethod extends Method { } + +/** Holds if `m` is a method of some override of `HttpServlet.doGet`. */ +private class ServletGetMethod extends RequestGetMethod { + ServletGetMethod() { + exists(Method m | + m = this and + isServletRequestMethod(m) and + m.getName() = "doGet" + ) + } +} + +/** Holds if `m` is a method of some override of `HttpServlet.doGet`. */ +private class SpringControllerGetMethod extends RequestGetMethod { + SpringControllerGetMethod() { + exists(Annotation a | + a = this.getAnAnnotation() and + a.getType().hasQualifiedName("org.springframework.web.bind.annotation", "GetMapping") + ) + or + exists(Annotation a | + a = this.getAnAnnotation() and + a.getType().hasQualifiedName("org.springframework.web.bind.annotation", "RequestMapping") and + a.getValue("method").toString().regexpMatch("RequestMethod.GET|\\{...\\}") + ) + } +} + +/** A concatenate expression using `(` and `)` or `);`. */ +class JsonpInjectionExpr extends AddExpr { + JsonpInjectionExpr() { + getRightOperand().toString().regexpMatch("\"\\)\"|\"\\);\"") and + getLeftOperand() + .(AddExpr) + .getLeftOperand() + .(AddExpr) + .getRightOperand() + .toString() + .regexpMatch("\"\\(\"") + } + + /** Get the jsonp function name of this expression */ + Expr getFunctionName() { + result = getLeftOperand().(AddExpr).getLeftOperand().(AddExpr).getLeftOperand() + } + + /** Get the json data of this expression */ + Expr getJsonExpr() { result = getLeftOperand().(AddExpr).getRightOperand() } +} + +/** A data flow configuration tracing flow from remote sources to jsonp function name. */ +class RemoteFlowConfig extends DataFlow2::Configuration { + RemoteFlowConfig() { this = "RemoteFlowConfig" } + + override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource } + + override predicate isSink(DataFlow::Node sink) { + exists(JsonpInjectionExpr jhe | jhe.getFunctionName() = sink.asExpr()) + } +} + +/** A data flow configuration tracing flow from json data to splicing jsonp data. */ +class JsonDataFlowConfig extends DataFlow2::Configuration { + JsonDataFlowConfig() { this = "JsonDataFlowConfig" } + + override predicate isSource(DataFlow::Node src) { src instanceof JsonpStringSource } + + override predicate isSink(DataFlow::Node sink) { + exists(JsonpInjectionExpr jhe | jhe.getJsonExpr() = sink.asExpr()) + } +} + +/** Taint-tracking configuration tracing flow from user-controllable function name jsonp data to output jsonp data. */ +class JsonpInjectionFlowConfig extends TaintTracking::Configuration { + JsonpInjectionFlowConfig() { this = "JsonpInjectionFlowConfig" } + + override predicate isSource(DataFlow::Node src) { + exists(JsonpInjectionExpr jhe, JsonDataFlowConfig jdfc, RemoteFlowConfig rfc | + jhe = src.asExpr() and + jdfc.hasFlowTo(DataFlow::exprNode(jhe.getJsonExpr())) and + rfc.hasFlowTo(DataFlow::exprNode(jhe.getFunctionName())) + ) + } + + override predicate isSink(DataFlow::Node sink) { sink instanceof XssSink } +} diff --git a/java/ql/src/Security/CWE/CWE-352/JsonpInjectionServlet1.java b/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjectionServlet1.java similarity index 100% rename from java/ql/src/Security/CWE/CWE-352/JsonpInjectionServlet1.java rename to java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjectionServlet1.java diff --git a/java/ql/src/Security/CWE/CWE-352/JsonpInjectionServlet2.java b/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjectionServlet2.java similarity index 100% rename from java/ql/src/Security/CWE/CWE-352/JsonpInjectionServlet2.java rename to java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjectionServlet2.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-352/RefererFilter.java b/java/ql/src/experimental/Security/CWE/CWE-352/RefererFilter.java new file mode 100644 index 00000000000..97444932ae1 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-352/RefererFilter.java @@ -0,0 +1,43 @@ +import java.io.IOException; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.springframework.util.StringUtils; + +public class RefererFilter implements Filter { + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { + HttpServletRequest request = (HttpServletRequest) servletRequest; + HttpServletResponse response = (HttpServletResponse) servletResponse; + String refefer = request.getHeader("Referer"); + boolean result = verifReferer(refefer); + if (result){ + filterChain.doFilter(servletRequest, servletResponse); + } + response.sendError(444, "Referer xxx."); + } + + @Override + public void destroy() { + } + + public static boolean verifReferer(String referer){ + if (StringUtils.isEmpty(referer)){ + return false; + } + if (referer.startsWith("http://www.baidu.com/")){ + return true; + } + return false; + } +} diff --git a/java/ql/src/semmle/code/java/frameworks/Servlets.qll b/java/ql/src/semmle/code/java/frameworks/Servlets.qll index b2054dc30cb..5cccf62122f 100644 --- a/java/ql/src/semmle/code/java/frameworks/Servlets.qll +++ b/java/ql/src/semmle/code/java/frameworks/Servlets.qll @@ -338,7 +338,6 @@ predicate isRequestGetParamMethod(MethodAccess ma) { ma.getMethod() instanceof HttpServletRequestGetQueryStringMethod } - /** * A class that has `javax.servlet.Filter` as an ancestor. */ @@ -346,21 +345,18 @@ class FilterClass extends Class { FilterClass() { getAnAncestor().hasQualifiedName("javax.servlet", "Filter") } } - /** * The interface `javax.servlet.FilterChain` */ -class FilterChain extends RefType { - FilterChain() { - hasQualifiedName("javax.servlet", "FilterChain") - } +class FilterChain extends Interface { + FilterChain() { hasQualifiedName("javax.servlet", "FilterChain") } } -/** Holds if `m` is a request handler method (for example `doGet` or `doPost`). */ +/** Holds if `m` is a filter handler method (for example `doFilter`). */ predicate isDoFilterMethod(Method m) { m.getDeclaringType() instanceof FilterClass and m.getNumberOfParameters() = 3 and m.getParameter(0).getType() instanceof ServletRequest and m.getParameter(1).getType() instanceof ServletResponse and m.getParameter(2).getType() instanceof FilterChain -} \ No newline at end of file +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpController.java b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpController.java new file mode 100644 index 00000000000..cf860c75640 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpController.java @@ -0,0 +1,128 @@ +import com.alibaba.fastjson.JSONObject; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; +import java.io.PrintWriter; +import java.util.HashMap; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +@Controller +public class JsonpController { + private static HashMap hashMap = new HashMap(); + + static { + hashMap.put("username","admin"); + hashMap.put("password","123456"); + } + + + @GetMapping(value = "jsonp1", produces="text/javascript") + @ResponseBody + public String bad1(HttpServletRequest request) { + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + + Gson gson = new Gson(); + String result = gson.toJson(hashMap); + resultStr = jsonpCallback + "(" + result + ")"; + return resultStr; + } + + @GetMapping(value = "jsonp2") + @ResponseBody + public String bad2(HttpServletRequest request) { + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + + resultStr = jsonpCallback + "(" + JSONObject.toJSONString(hashMap) + ")"; + + return resultStr; + } + + @GetMapping(value = "jsonp3") + @ResponseBody + public String bad3(HttpServletRequest request) { + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + String jsonStr = getJsonStr(hashMap); + resultStr = jsonpCallback + "(" + jsonStr + ")"; + return resultStr; + } + + @GetMapping(value = "jsonp4") + @ResponseBody + public String bad4(HttpServletRequest request) { + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + String restr = JSONObject.toJSONString(hashMap); + resultStr = jsonpCallback + "(" + restr + ");"; + return resultStr; + } + + @GetMapping(value = "jsonp5") + @ResponseBody + public void bad5(HttpServletRequest request, + HttpServletResponse response) throws Exception { + String jsonpCallback = request.getParameter("jsonpCallback"); + PrintWriter pw = null; + Gson gson = new Gson(); + String result = gson.toJson(hashMap); + + String resultStr = null; + pw = response.getWriter(); + resultStr = jsonpCallback + "(" + result + ")"; + pw.println(resultStr); + } + + @GetMapping(value = "jsonp6") + @ResponseBody + public void bad6(HttpServletRequest request, + HttpServletResponse response) throws Exception { + String jsonpCallback = request.getParameter("jsonpCallback"); + PrintWriter pw = null; + ObjectMapper mapper = new ObjectMapper(); + String result = mapper.writeValueAsString(hashMap); + String resultStr = null; + pw = response.getWriter(); + resultStr = jsonpCallback + "(" + result + ")"; + pw.println(resultStr); + } + + @GetMapping(value = "jsonp7") + @ResponseBody + public String good1(HttpServletRequest request) { + String resultStr = null; + + String token = request.getParameter("token"); + + if (verifToken(token)){ + String jsonpCallback = request.getParameter("jsonpCallback"); + String jsonStr = getJsonStr(hashMap); + resultStr = jsonpCallback + "(" + jsonStr + ")"; + return resultStr; + } + + return "error"; + } + + public static String getJsonStr(Object result) { + return JSONObject.toJSONString(result); + } + + public static boolean verifToken(String token){ + if (token != "xxxx"){ + return false; + } + return true; + } + + public static boolean verifReferer(String referer){ + if (!referer.startsWith("http://test.com/")){ + return false; + } + return true; + } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection.expected b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection.expected deleted file mode 100644 index 7e3069cf1d9..00000000000 --- a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection.expected +++ /dev/null @@ -1,60 +0,0 @@ -edges -| JsonpInjection.java:29:32:29:38 | request : HttpServletRequest | JsonpInjection.java:34:16:34:24 | resultStr | -| JsonpInjection.java:33:21:33:54 | ... + ... : String | JsonpInjection.java:34:16:34:24 | resultStr | -| JsonpInjection.java:41:32:41:38 | request : HttpServletRequest | JsonpInjection.java:45:16:45:24 | resultStr | -| JsonpInjection.java:43:21:43:80 | ... + ... : String | JsonpInjection.java:45:16:45:24 | resultStr | -| JsonpInjection.java:52:32:52:38 | request : HttpServletRequest | JsonpInjection.java:55:16:55:24 | resultStr | -| JsonpInjection.java:54:21:54:55 | ... + ... : String | JsonpInjection.java:55:16:55:24 | resultStr | -| JsonpInjection.java:62:32:62:38 | request : HttpServletRequest | JsonpInjection.java:65:16:65:24 | resultStr | -| JsonpInjection.java:64:21:64:54 | ... + ... : String | JsonpInjection.java:65:16:65:24 | resultStr | -| JsonpInjection.java:72:32:72:38 | request : HttpServletRequest | JsonpInjection.java:80:20:80:28 | resultStr | -| JsonpInjection.java:79:21:79:54 | ... + ... : String | JsonpInjection.java:80:20:80:28 | resultStr | -| JsonpInjection.java:87:32:87:38 | request : HttpServletRequest | JsonpInjection.java:94:20:94:28 | resultStr | -| JsonpInjection.java:93:21:93:54 | ... + ... : String | JsonpInjection.java:94:20:94:28 | resultStr | -| JsonpInjection.java:101:32:101:38 | request : HttpServletRequest | JsonpInjection.java:112:16:112:24 | resultStr | -| JsonpInjection.java:127:25:127:59 | ... + ... : String | JsonpInjection.java:128:20:128:28 | resultStr | -| JsonpInjection.java:148:25:148:59 | ... + ... : String | JsonpInjection.java:149:20:149:28 | resultStr | -nodes -| JsonpInjection.java:29:32:29:38 | request : HttpServletRequest | semmle.label | request : HttpServletRequest | -| JsonpInjection.java:33:21:33:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpInjection.java:34:16:34:24 | resultStr | semmle.label | resultStr | -| JsonpInjection.java:34:16:34:24 | resultStr | semmle.label | resultStr | -| JsonpInjection.java:41:32:41:38 | request : HttpServletRequest | semmle.label | request : HttpServletRequest | -| JsonpInjection.java:43:21:43:80 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpInjection.java:45:16:45:24 | resultStr | semmle.label | resultStr | -| JsonpInjection.java:45:16:45:24 | resultStr | semmle.label | resultStr | -| JsonpInjection.java:52:32:52:38 | request : HttpServletRequest | semmle.label | request : HttpServletRequest | -| JsonpInjection.java:54:21:54:55 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpInjection.java:55:16:55:24 | resultStr | semmle.label | resultStr | -| JsonpInjection.java:55:16:55:24 | resultStr | semmle.label | resultStr | -| JsonpInjection.java:62:32:62:38 | request : HttpServletRequest | semmle.label | request : HttpServletRequest | -| JsonpInjection.java:64:21:64:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpInjection.java:65:16:65:24 | resultStr | semmle.label | resultStr | -| JsonpInjection.java:65:16:65:24 | resultStr | semmle.label | resultStr | -| JsonpInjection.java:72:32:72:38 | request : HttpServletRequest | semmle.label | request : HttpServletRequest | -| JsonpInjection.java:79:21:79:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpInjection.java:80:20:80:28 | resultStr | semmle.label | resultStr | -| JsonpInjection.java:80:20:80:28 | resultStr | semmle.label | resultStr | -| JsonpInjection.java:87:32:87:38 | request : HttpServletRequest | semmle.label | request : HttpServletRequest | -| JsonpInjection.java:93:21:93:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpInjection.java:94:20:94:28 | resultStr | semmle.label | resultStr | -| JsonpInjection.java:94:20:94:28 | resultStr | semmle.label | resultStr | -| JsonpInjection.java:101:32:101:38 | request : HttpServletRequest | semmle.label | request : HttpServletRequest | -| JsonpInjection.java:112:16:112:24 | resultStr | semmle.label | resultStr | -| JsonpInjection.java:127:25:127:59 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpInjection.java:128:20:128:28 | resultStr | semmle.label | resultStr | -| JsonpInjection.java:148:25:148:59 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpInjection.java:149:20:149:28 | resultStr | semmle.label | resultStr | -#select -| JsonpInjection.java:34:16:34:24 | resultStr | JsonpInjection.java:29:32:29:38 | request : HttpServletRequest | JsonpInjection.java:34:16:34:24 | -resultStr | Jsonp Injection query might include code from $@. | JsonpInjection.java:29:32:29:38 | request | this user input | -| JsonpInjection.java:45:16:45:24 | resultStr | JsonpInjection.java:41:32:41:38 | request : HttpServletRequest | JsonpInjection.java:45:16:45:24 | -resultStr | Jsonp Injection query might include code from $@. | JsonpInjection.java:41:32:41:38 | request | this user input | -| JsonpInjection.java:55:16:55:24 | resultStr | JsonpInjection.java:52:32:52:38 | request : HttpServletRequest | JsonpInjection.java:55:16:55:24 | -resultStr | Jsonp Injection query might include code from $@. | JsonpInjection.java:52:32:52:38 | request | this user input | -| JsonpInjection.java:65:16:65:24 | resultStr | JsonpInjection.java:62:32:62:38 | request : HttpServletRequest | JsonpInjection.java:65:16:65:24 | -resultStr | Jsonp Injection query might include code from $@. | JsonpInjection.java:62:32:62:38 | request | this user input | -| JsonpInjection.java:80:20:80:28 | resultStr | JsonpInjection.java:72:32:72:38 | request : HttpServletRequest | JsonpInjection.java:80:20:80:28 | -resultStr | Jsonp Injection query might include code from $@. | JsonpInjection.java:72:32:72:38 | request | this user input | -| JsonpInjection.java:94:20:94:28 | resultStr | JsonpInjection.java:87:32:87:38 | request : HttpServletRequest | JsonpInjection.java:94:20:94:28 | -resultStr | Jsonp Injection query might include code from $@. | JsonpInjection.java:87:32:87:38 | request | this user input | \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionServlet1.java b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionServlet1.java new file mode 100644 index 00000000000..14ef76275b1 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionServlet1.java @@ -0,0 +1,64 @@ +import com.google.gson.Gson; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashMap; +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class JsonpInjectionServlet1 extends HttpServlet { + + private static HashMap hashMap = new HashMap(); + + static { + hashMap.put("username","admin"); + hashMap.put("password","123456"); + } + + private static final long serialVersionUID = 1L; + + private String key = "test"; + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + doPost(req, resp); + } + + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + resp.setContentType("application/json"); + String jsonpCallback = req.getParameter("jsonpCallback"); + PrintWriter pw = null; + Gson gson = new Gson(); + String jsonResult = gson.toJson(hashMap); + + String referer = req.getHeader("Referer"); + + boolean result = verifReferer(referer); + + // good + if (result){ + String resultStr = null; + pw = resp.getWriter(); + resultStr = jsonpCallback + "(" + jsonResult + ")"; + pw.println(resultStr); + pw.flush(); + } + } + + public static boolean verifReferer(String referer){ + if (!referer.startsWith("http://test.com/")){ + return false; + } + return true; + } + + @Override + public void init(ServletConfig config) throws ServletException { + this.key = config.getInitParameter("key"); + System.out.println("初始化" + this.key); + super.init(config); + } + +} diff --git a/java/ql/src/Security/CWE/CWE-352/JsonpInjectionServlet.java b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionServlet2.java similarity index 75% rename from java/ql/src/Security/CWE/CWE-352/JsonpInjectionServlet.java rename to java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionServlet2.java index 916cd9bf676..bbfbc2dc436 100644 --- a/java/ql/src/Security/CWE/CWE-352/JsonpInjectionServlet.java +++ b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionServlet2.java @@ -4,12 +4,11 @@ import java.io.PrintWriter; import java.util.HashMap; import javax.servlet.ServletConfig; import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -public class JsonpInjectionServlet extends HttpServlet { +public class JsonpInjectionServlet2 extends HttpServlet { private static HashMap hashMap = new HashMap(); @@ -23,21 +22,12 @@ public class JsonpInjectionServlet extends HttpServlet { private String key = "test"; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - String jsonpCallback = req.getParameter("jsonpCallback"); - - PrintWriter pw = null; - Gson gson = new Gson(); - String result = gson.toJson(hashMap); - - String resultStr = null; - pw = resp.getWriter(); - resultStr = jsonpCallback + "(" + result + ")"; - pw.println(resultStr); - pw.flush(); + doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + resp.setContentType("application/json"); String jsonpCallback = req.getParameter("jsonpCallback"); PrintWriter pw = null; Gson gson = new Gson(); diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection_1.expected b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection_1.expected new file mode 100644 index 00000000000..a89d03b67a7 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection_1.expected @@ -0,0 +1,60 @@ +edges +| JsonpController.java:26:32:26:68 | getParameter(...) : String | JsonpController.java:31:16:31:24 | resultStr | +| JsonpController.java:30:21:30:54 | ... + ... : String | JsonpController.java:31:16:31:24 | resultStr | +| JsonpController.java:38:32:38:68 | getParameter(...) : String | JsonpController.java:42:16:42:24 | resultStr | +| JsonpController.java:40:21:40:80 | ... + ... : String | JsonpController.java:42:16:42:24 | resultStr | +| JsonpController.java:49:32:49:68 | getParameter(...) : String | JsonpController.java:52:16:52:24 | resultStr | +| JsonpController.java:51:21:51:55 | ... + ... : String | JsonpController.java:52:16:52:24 | resultStr | +| JsonpController.java:59:32:59:68 | getParameter(...) : String | JsonpController.java:62:16:62:24 | resultStr | +| JsonpController.java:61:21:61:54 | ... + ... : String | JsonpController.java:62:16:62:24 | resultStr | +| JsonpController.java:69:32:69:68 | getParameter(...) : String | JsonpController.java:77:20:77:28 | resultStr | +| JsonpController.java:76:21:76:54 | ... + ... : String | JsonpController.java:77:20:77:28 | resultStr | +| JsonpController.java:84:32:84:68 | getParameter(...) : String | JsonpController.java:91:20:91:28 | resultStr | +| JsonpController.java:90:21:90:54 | ... + ... : String | JsonpController.java:91:20:91:28 | resultStr | +| JsonpController.java:99:24:99:52 | getParameter(...) : String | JsonpController.java:101:24:101:28 | token | +| JsonpController.java:102:36:102:72 | getParameter(...) : String | JsonpController.java:105:20:105:28 | resultStr | +| JsonpController.java:104:25:104:59 | ... + ... : String | JsonpController.java:105:20:105:28 | resultStr | +nodes +| JsonpController.java:26:32:26:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:30:21:30:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:31:16:31:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:31:16:31:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:38:32:38:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:40:21:40:80 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:42:16:42:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:42:16:42:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:49:32:49:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:51:21:51:55 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:52:16:52:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:52:16:52:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:59:32:59:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:61:21:61:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:62:16:62:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:62:16:62:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:69:32:69:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:76:21:76:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:77:20:77:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:77:20:77:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:84:32:84:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:90:21:90:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:91:20:91:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:91:20:91:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:99:24:99:52 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:101:24:101:28 | token | semmle.label | token | +| JsonpController.java:102:36:102:72 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:104:25:104:59 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:105:20:105:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:105:20:105:28 | resultStr | semmle.label | resultStr | +#select +| JsonpController.java:31:16:31:24 | resultStr | JsonpController.java:26:32:26:68 | getParameter(...) : String | JsonpController.java:31:16:31:24 | + resultStr | Jsonp Injection query might include code from $@. | JsonpController.java:26:32:26:68 | getParameter(...) | this user input | +| JsonpController.java:42:16:42:24 | resultStr | JsonpController.java:38:32:38:68 | getParameter(...) : String | JsonpController.java:42:16:42:24 | + resultStr | Jsonp Injection query might include code from $@. | JsonpController.java:38:32:38:68 | getParameter(...) | this user input | +| JsonpController.java:52:16:52:24 | resultStr | JsonpController.java:49:32:49:68 | getParameter(...) : String | JsonpController.java:52:16:52:24 | + resultStr | Jsonp Injection query might include code from $@. | JsonpController.java:49:32:49:68 | getParameter(...) | this user input | +| JsonpController.java:62:16:62:24 | resultStr | JsonpController.java:59:32:59:68 | getParameter(...) : String | JsonpController.java:62:16:62:24 | + resultStr | Jsonp Injection query might include code from $@. | JsonpController.java:59:32:59:68 | getParameter(...) | this user input | +| JsonpController.java:77:20:77:28 | resultStr | JsonpController.java:69:32:69:68 | getParameter(...) : String | JsonpController.java:77:20:77:28 | + resultStr | Jsonp Injection query might include code from $@. | JsonpController.java:69:32:69:68 | getParameter(...) | this user input | +| JsonpController.java:91:20:91:28 | resultStr | JsonpController.java:84:32:84:68 | getParameter(...) : String | JsonpController.java:91:20:91:28 | + resultStr | Jsonp Injection query might include code from $@. | JsonpController.java:84:32:84:68 | getParameter(...) | this user input | \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection_2.expected b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection_2.expected new file mode 100644 index 00000000000..4b12308a212 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection_2.expected @@ -0,0 +1,78 @@ +edges +| JsonpController.java:26:32:26:68 | getParameter(...) : String | JsonpController.java:31:16:31:24 | resultStr | +| JsonpController.java:30:21:30:54 | ... + ... : String | JsonpController.java:31:16:31:24 | resultStr | +| JsonpController.java:38:32:38:68 | getParameter(...) : String | JsonpController.java:42:16:42:24 | resultStr | +| JsonpController.java:40:21:40:80 | ... + ... : String | JsonpController.java:42:16:42:24 | resultStr | +| JsonpController.java:49:32:49:68 | getParameter(...) : String | JsonpController.java:52:16:52:24 | resultStr | +| JsonpController.java:51:21:51:55 | ... + ... : String | JsonpController.java:52:16:52:24 | resultStr | +| JsonpController.java:59:32:59:68 | getParameter(...) : String | JsonpController.java:62:16:62:24 | resultStr | +| JsonpController.java:61:21:61:54 | ... + ... : String | JsonpController.java:62:16:62:24 | resultStr | +| JsonpController.java:69:32:69:68 | getParameter(...) : String | JsonpController.java:77:20:77:28 | resultStr | +| JsonpController.java:76:21:76:54 | ... + ... : String | JsonpController.java:77:20:77:28 | resultStr | +| JsonpController.java:84:32:84:68 | getParameter(...) : String | JsonpController.java:91:20:91:28 | resultStr | +| JsonpController.java:90:21:90:54 | ... + ... : String | JsonpController.java:91:20:91:28 | resultStr | +| JsonpController.java:99:24:99:52 | getParameter(...) : String | JsonpController.java:101:24:101:28 | token | +| JsonpController.java:102:36:102:72 | getParameter(...) : String | JsonpController.java:105:20:105:28 | resultStr | +| JsonpController.java:104:25:104:59 | ... + ... : String | JsonpController.java:105:20:105:28 | resultStr | +| JsonpInjectionServlet1.java:31:32:31:64 | getParameter(...) : String | JsonpInjectionServlet1.java:45:24:45:32 | resultStr | +| JsonpInjectionServlet1.java:36:26:36:49 | getHeader(...) : String | JsonpInjectionServlet1.java:38:39:38:45 | referer | +| JsonpInjectionServlet1.java:44:25:44:62 | ... + ... : String | JsonpInjectionServlet1.java:45:24:45:32 | resultStr | +| JsonpInjectionServlet2.java:31:32:31:64 | getParameter(...) : String | JsonpInjectionServlet2.java:39:20:39:28 | resultStr | +| JsonpInjectionServlet2.java:38:21:38:54 | ... + ... : String | JsonpInjectionServlet2.java:39:20:39:28 | resultStr | +nodes +| JsonpController.java:26:32:26:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:30:21:30:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:31:16:31:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:31:16:31:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:38:32:38:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:40:21:40:80 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:42:16:42:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:42:16:42:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:49:32:49:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:51:21:51:55 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:52:16:52:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:52:16:52:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:59:32:59:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:61:21:61:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:62:16:62:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:62:16:62:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:69:32:69:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:76:21:76:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:77:20:77:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:77:20:77:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:84:32:84:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:90:21:90:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:91:20:91:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:91:20:91:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:99:24:99:52 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:101:24:101:28 | token | semmle.label | token | +| JsonpController.java:102:36:102:72 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:104:25:104:59 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:105:20:105:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:105:20:105:28 | resultStr | semmle.label | resultStr | +| JsonpInjectionServlet1.java:31:32:31:64 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpInjectionServlet1.java:36:26:36:49 | getHeader(...) : String | semmle.label | getHeader(...) : String | +| JsonpInjectionServlet1.java:38:39:38:45 | referer | semmle.label | referer | +| JsonpInjectionServlet1.java:44:25:44:62 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpInjectionServlet1.java:45:24:45:32 | resultStr | semmle.label | resultStr | +| JsonpInjectionServlet1.java:45:24:45:32 | resultStr | semmle.label | resultStr | +| JsonpInjectionServlet2.java:31:32:31:64 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpInjectionServlet2.java:38:21:38:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpInjectionServlet2.java:39:20:39:28 | resultStr | semmle.label | resultStr | +| JsonpInjectionServlet2.java:39:20:39:28 | resultStr | semmle.label | resultStr | +#select +| JsonpController.java:31:16:31:24 | resultStr | JsonpController.java:26:32:26:68 | getParameter(...) : String | JsonpController.java:31:16:31:24 | + resultStr | Jsonp Injection query might include code from $@. | JsonpController.java:26:32:26:68 | getParameter(...) | this user input | +| JsonpController.java:42:16:42:24 | resultStr | JsonpController.java:38:32:38:68 | getParameter(...) : String | JsonpController.java:42:16:42:24 | + resultStr | Jsonp Injection query might include code from $@. | JsonpController.java:38:32:38:68 | getParameter(...) | this user input | +| JsonpController.java:52:16:52:24 | resultStr | JsonpController.java:49:32:49:68 | getParameter(...) : String | JsonpController.java:52:16:52:24 | + resultStr | Jsonp Injection query might include code from $@. | JsonpController.java:49:32:49:68 | getParameter(...) | this user input | +| JsonpController.java:62:16:62:24 | resultStr | JsonpController.java:59:32:59:68 | getParameter(...) : String | JsonpController.java:62:16:62:24 | + resultStr | Jsonp Injection query might include code from $@. | JsonpController.java:59:32:59:68 | getParameter(...) | this user input | +| JsonpController.java:77:20:77:28 | resultStr | JsonpController.java:69:32:69:68 | getParameter(...) : String | JsonpController.java:77:20:77:28 | + resultStr | Jsonp Injection query might include code from $@. | JsonpController.java:69:32:69:68 | getParameter(...) | this user input | +| JsonpController.java:91:20:91:28 | resultStr | JsonpController.java:84:32:84:68 | getParameter(...) : String | JsonpController.java:91:20:91:28 | + resultStr | Jsonp Injection query might include code from $@. | JsonpController.java:84:32:84:68 | getParameter(...) | this user input | +| JsonpInjectionServlet2.java:39:20:39:28 | resultStr | JsonpInjectionServlet2.java:31:32:31:64 | getParameter(...) : String | JsonpInjectionServle +t2.java:39:20:39:28 | resultStr | Jsonp Injection query might include code from $@. | JsonpInjectionServlet2.java:31:32:31:64 | getParameter(...) | + this user input | \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection_3.expected b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection_3.expected new file mode 100644 index 00000000000..8e33ca6984c --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection_3.expected @@ -0,0 +1,66 @@ +edges +| JsonpController.java:26:32:26:68 | getParameter(...) : String | JsonpController.java:31:16:31:24 | resultStr | +| JsonpController.java:30:21:30:54 | ... + ... : String | JsonpController.java:31:16:31:24 | resultStr | +| JsonpController.java:38:32:38:68 | getParameter(...) : String | JsonpController.java:42:16:42:24 | resultStr | +| JsonpController.java:40:21:40:80 | ... + ... : String | JsonpController.java:42:16:42:24 | resultStr | +| JsonpController.java:49:32:49:68 | getParameter(...) : String | JsonpController.java:52:16:52:24 | resultStr | +| JsonpController.java:51:21:51:55 | ... + ... : String | JsonpController.java:52:16:52:24 | resultStr | +| JsonpController.java:59:32:59:68 | getParameter(...) : String | JsonpController.java:62:16:62:24 | resultStr | +| JsonpController.java:61:21:61:54 | ... + ... : String | JsonpController.java:62:16:62:24 | resultStr | +| JsonpController.java:69:32:69:68 | getParameter(...) : String | JsonpController.java:77:20:77:28 | resultStr | +| JsonpController.java:76:21:76:54 | ... + ... : String | JsonpController.java:77:20:77:28 | resultStr | +| JsonpController.java:84:32:84:68 | getParameter(...) : String | JsonpController.java:91:20:91:28 | resultStr | +| JsonpController.java:90:21:90:54 | ... + ... : String | JsonpController.java:91:20:91:28 | resultStr | +| JsonpController.java:99:24:99:52 | getParameter(...) : String | JsonpController.java:101:24:101:28 | token | +| JsonpController.java:102:36:102:72 | getParameter(...) : String | JsonpController.java:105:20:105:28 | resultStr | +| JsonpController.java:104:25:104:59 | ... + ... : String | JsonpController.java:105:20:105:28 | resultStr | +| JsonpInjectionServlet1.java:31:32:31:64 | getParameter(...) : String | JsonpInjectionServlet1.java:45:24:45:32 | resultStr | +| JsonpInjectionServlet1.java:36:26:36:49 | getHeader(...) : String | JsonpInjectionServlet1.java:38:39:38:45 | referer | +| JsonpInjectionServlet1.java:44:25:44:62 | ... + ... : String | JsonpInjectionServlet1.java:45:24:45:32 | resultStr | +| JsonpInjectionServlet2.java:31:32:31:64 | getParameter(...) : String | JsonpInjectionServlet2.java:39:20:39:28 | resultStr | +| JsonpInjectionServlet2.java:38:21:38:54 | ... + ... : String | JsonpInjectionServlet2.java:39:20:39:28 | resultStr | +| RefererFilter.java:22:26:22:53 | getHeader(...) : String | RefererFilter.java:23:39:23:45 | refefer | +nodes +| JsonpController.java:26:32:26:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:30:21:30:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:31:16:31:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:31:16:31:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:38:32:38:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:40:21:40:80 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:42:16:42:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:42:16:42:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:49:32:49:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:51:21:51:55 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:52:16:52:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:52:16:52:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:59:32:59:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:61:21:61:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:62:16:62:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:62:16:62:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:69:32:69:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:76:21:76:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:77:20:77:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:77:20:77:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:84:32:84:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:90:21:90:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:91:20:91:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:91:20:91:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:99:24:99:52 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:101:24:101:28 | token | semmle.label | token | +| JsonpController.java:102:36:102:72 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:104:25:104:59 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:105:20:105:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:105:20:105:28 | resultStr | semmle.label | resultStr | +| JsonpInjectionServlet1.java:31:32:31:64 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpInjectionServlet1.java:36:26:36:49 | getHeader(...) : String | semmle.label | getHeader(...) : String | +| JsonpInjectionServlet1.java:38:39:38:45 | referer | semmle.label | referer | +| JsonpInjectionServlet1.java:44:25:44:62 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpInjectionServlet1.java:45:24:45:32 | resultStr | semmle.label | resultStr | +| JsonpInjectionServlet1.java:45:24:45:32 | resultStr | semmle.label | resultStr | +| JsonpInjectionServlet2.java:31:32:31:64 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpInjectionServlet2.java:38:21:38:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpInjectionServlet2.java:39:20:39:28 | resultStr | semmle.label | resultStr | +| JsonpInjectionServlet2.java:39:20:39:28 | resultStr | semmle.label | resultStr | +| RefererFilter.java:22:26:22:53 | getHeader(...) : String | semmle.label | getHeader(...) : String | +| RefererFilter.java:23:39:23:45 | refefer | semmle.label | refefer | +#select \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/Readme b/java/ql/test/experimental/query-tests/security/CWE-352/Readme new file mode 100644 index 00000000000..15715d6187c --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-352/Readme @@ -0,0 +1,3 @@ +1. The JsonpInjection_1.expected result is obtained through the test of `JsonpController.java`. +2. The JsonpInjection_2.expected result is obtained through the test of `JsonpController.java`, `JsonpInjectionServlet1.java`, `JsonpInjectionServlet2.java`. +3. The JsonpInjection_3.expected result is obtained through the test of `JsonpController.java`, `JsonpInjectionServlet1.java`, `JsonpInjectionServlet2.java`, `RefererFilter.java`. \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/RefererFilter.java b/java/ql/test/experimental/query-tests/security/CWE-352/RefererFilter.java new file mode 100644 index 00000000000..97444932ae1 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-352/RefererFilter.java @@ -0,0 +1,43 @@ +import java.io.IOException; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.springframework.util.StringUtils; + +public class RefererFilter implements Filter { + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { + HttpServletRequest request = (HttpServletRequest) servletRequest; + HttpServletResponse response = (HttpServletResponse) servletResponse; + String refefer = request.getHeader("Referer"); + boolean result = verifReferer(refefer); + if (result){ + filterChain.doFilter(servletRequest, servletResponse); + } + response.sendError(444, "Referer xxx."); + } + + @Override + public void destroy() { + } + + public static boolean verifReferer(String referer){ + if (StringUtils.isEmpty(referer)){ + return false; + } + if (referer.startsWith("http://www.baidu.com/")){ + return true; + } + return false; + } +} diff --git a/java/ql/test/stubs/gson-2.8.6/com/google/gson/Gson.java b/java/ql/test/stubs/gson-2.8.6/com/google/gson/Gson.java new file mode 100644 index 00000000000..bbe53dc2a5f --- /dev/null +++ b/java/ql/test/stubs/gson-2.8.6/com/google/gson/Gson.java @@ -0,0 +1,7 @@ +package com.google.gson; + +public final class Gson { + public String toJson(Object src) { + return null; + } +} diff --git a/java/ql/test/stubs/spring-core-5.3.2/org/springframework/util/StringUtils.java b/java/ql/test/stubs/spring-core-5.3.2/org/springframework/util/StringUtils.java new file mode 100644 index 00000000000..6ee07f84593 --- /dev/null +++ b/java/ql/test/stubs/spring-core-5.3.2/org/springframework/util/StringUtils.java @@ -0,0 +1,8 @@ +package org.springframework.util; + +public abstract class StringUtils { + + public static boolean isEmpty(Object str) { + return str == null || "".equals(str); + } +} \ No newline at end of file diff --git a/java/ql/test/stubs/tomcat-embed-core-9.0.41/javax/servlet/Filter.java b/java/ql/test/stubs/tomcat-embed-core-9.0.41/javax/servlet/Filter.java new file mode 100644 index 00000000000..5833e3c909d --- /dev/null +++ b/java/ql/test/stubs/tomcat-embed-core-9.0.41/javax/servlet/Filter.java @@ -0,0 +1,13 @@ +package javax.servlet; + +import java.io.IOException; + +public interface Filter { + default void init(FilterConfig filterConfig) throws ServletException { + } + + void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException; + + default void destroy() { + } +} diff --git a/java/ql/test/stubs/tomcat-embed-core-9.0.41/javax/servlet/FilterChain.java b/java/ql/test/stubs/tomcat-embed-core-9.0.41/javax/servlet/FilterChain.java new file mode 100644 index 00000000000..6a1dfc588b6 --- /dev/null +++ b/java/ql/test/stubs/tomcat-embed-core-9.0.41/javax/servlet/FilterChain.java @@ -0,0 +1,8 @@ +package javax.servlet; + +import java.io.IOException; + +public interface FilterChain { + void doFilter(ServletRequest var1, ServletResponse var2) throws IOException, ServletException; +} + diff --git a/java/ql/test/stubs/tomcat-embed-core-9.0.41/javax/servlet/FilterConfig.java b/java/ql/test/stubs/tomcat-embed-core-9.0.41/javax/servlet/FilterConfig.java new file mode 100644 index 00000000000..66c13eb54f0 --- /dev/null +++ b/java/ql/test/stubs/tomcat-embed-core-9.0.41/javax/servlet/FilterConfig.java @@ -0,0 +1,3 @@ +package javax.servlet; + +public interface FilterConfig {} diff --git a/java/ql/test/stubs/tomcat-embed-core-9.0.41/javax/servlet/ServletException.java b/java/ql/test/stubs/tomcat-embed-core-9.0.41/javax/servlet/ServletException.java new file mode 100644 index 00000000000..ce5f7c4465a --- /dev/null +++ b/java/ql/test/stubs/tomcat-embed-core-9.0.41/javax/servlet/ServletException.java @@ -0,0 +1,8 @@ +package javax.servlet; + +public class ServletException extends Exception { + private static final long serialVersionUID = 1L; + + public ServletException() { + } +} diff --git a/java/ql/test/stubs/tomcat-embed-core-9.0.41/javax/servlet/ServletRequest.java b/java/ql/test/stubs/tomcat-embed-core-9.0.41/javax/servlet/ServletRequest.java new file mode 100644 index 00000000000..4ee0026d066 --- /dev/null +++ b/java/ql/test/stubs/tomcat-embed-core-9.0.41/javax/servlet/ServletRequest.java @@ -0,0 +1,87 @@ +package javax.servlet; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.Enumeration; +import java.util.Locale; +import java.util.Map; + +public interface ServletRequest { + Object getAttribute(String var1); + + Enumeration getAttributeNames(); + + String getCharacterEncoding(); + + void setCharacterEncoding(String var1) throws UnsupportedEncodingException; + + int getContentLength(); + + long getContentLengthLong(); + + String getContentType(); + + ServletInputStream getInputStream() throws IOException; + + String getParameter(String var1); + + Enumeration getParameterNames(); + + String[] getParameterValues(String var1); + + Map getParameterMap(); + + String getProtocol(); + + String getScheme(); + + String getServerName(); + + int getServerPort(); + + BufferedReader getReader() throws IOException; + + String getRemoteAddr(); + + String getRemoteHost(); + + void setAttribute(String var1, Object var2); + + void removeAttribute(String var1); + + Locale getLocale(); + + Enumeration getLocales(); + + boolean isSecure(); + + RequestDispatcher getRequestDispatcher(String var1); + + /** @deprecated */ + @Deprecated + String getRealPath(String var1); + + int getRemotePort(); + + String getLocalName(); + + String getLocalAddr(); + + int getLocalPort(); + + ServletContext getServletContext(); + + AsyncContext startAsync() throws IllegalStateException; + + AsyncContext startAsync(ServletRequest var1, ServletResponse var2) throws IllegalStateException; + + boolean isAsyncStarted(); + + boolean isAsyncSupported(); + + AsyncContext getAsyncContext(); + + DispatcherType getDispatcherType(); +} + diff --git a/java/ql/test/stubs/tomcat-embed-core-9.0.41/javax/servlet/ServletResponse.java b/java/ql/test/stubs/tomcat-embed-core-9.0.41/javax/servlet/ServletResponse.java new file mode 100644 index 00000000000..0aa6121e686 --- /dev/null +++ b/java/ql/test/stubs/tomcat-embed-core-9.0.41/javax/servlet/ServletResponse.java @@ -0,0 +1,39 @@ +package javax.servlet; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Locale; + +public interface ServletResponse { + String getCharacterEncoding(); + + String getContentType(); + + ServletOutputStream getOutputStream() throws IOException; + + PrintWriter getWriter() throws IOException; + + void setCharacterEncoding(String var1); + + void setContentLength(int var1); + + void setContentLengthLong(long var1); + + void setContentType(String var1); + + void setBufferSize(int var1); + + int getBufferSize(); + + void flushBuffer() throws IOException; + + void resetBuffer(); + + boolean isCommitted(); + + void reset(); + + void setLocale(Locale var1); + + Locale getLocale(); +} diff --git a/java/ql/test/stubs/tomcat-embed-core-9.0.41/javax/servlet/http/HttpServletRequest.java b/java/ql/test/stubs/tomcat-embed-core-9.0.41/javax/servlet/http/HttpServletRequest.java new file mode 100644 index 00000000000..02d53a96a33 --- /dev/null +++ b/java/ql/test/stubs/tomcat-embed-core-9.0.41/javax/servlet/http/HttpServletRequest.java @@ -0,0 +1,116 @@ +package javax.servlet.http; + +import java.io.IOException; +import java.security.Principal; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Map; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; + +public interface HttpServletRequest extends ServletRequest { + String BASIC_AUTH = "BASIC"; + String FORM_AUTH = "FORM"; + String CLIENT_CERT_AUTH = "CLIENT_CERT"; + String DIGEST_AUTH = "DIGEST"; + + String getAuthType(); + + Cookie[] getCookies(); + + long getDateHeader(String var1); + + String getHeader(String var1); + + Enumeration getHeaders(String var1); + + Enumeration getHeaderNames(); + + int getIntHeader(String var1); + + default HttpServletMapping getHttpServletMapping() { + return new HttpServletMapping() { + public String getMatchValue() { + return ""; + } + + public String getPattern() { + return ""; + } + + public String getServletName() { + return ""; + } + + public MappingMatch getMappingMatch() { + return null; + } + }; + } + + String getMethod(); + + String getPathInfo(); + + String getPathTranslated(); + + default PushBuilder newPushBuilder() { + return null; + } + + String getContextPath(); + + String getQueryString(); + + String getRemoteUser(); + + boolean isUserInRole(String var1); + + Principal getUserPrincipal(); + + String getRequestedSessionId(); + + String getRequestURI(); + + StringBuffer getRequestURL(); + + String getServletPath(); + + HttpSession getSession(boolean var1); + + HttpSession getSession(); + + String changeSessionId(); + + boolean isRequestedSessionIdValid(); + + boolean isRequestedSessionIdFromCookie(); + + boolean isRequestedSessionIdFromURL(); + + /** @deprecated */ + @Deprecated + boolean isRequestedSessionIdFromUrl(); + + boolean authenticate(HttpServletResponse var1) throws IOException, ServletException; + + void login(String var1, String var2) throws ServletException; + + void logout() throws ServletException; + + Collection getParts() throws IOException, ServletException; + + Part getPart(String var1) throws IOException, ServletException; + + T upgrade(Class var1) throws IOException, ServletException; + + default Map getTrailerFields() { + return Collections.emptyMap(); + } + + default boolean isTrailerFieldsReady() { + return false; + } +} + diff --git a/java/ql/test/stubs/tomcat-embed-core-9.0.41/javax/servlet/http/HttpServletResponse.java b/java/ql/test/stubs/tomcat-embed-core-9.0.41/javax/servlet/http/HttpServletResponse.java new file mode 100644 index 00000000000..0a2c6af0913 --- /dev/null +++ b/java/ql/test/stubs/tomcat-embed-core-9.0.41/javax/servlet/http/HttpServletResponse.java @@ -0,0 +1,106 @@ +package javax.servlet.http; + +import java.io.IOException; +import java.util.Collection; +import java.util.Map; +import java.util.function.Supplier; +import javax.servlet.ServletResponse; + +public interface HttpServletResponse extends ServletResponse { + int SC_CONTINUE = 100; + int SC_SWITCHING_PROTOCOLS = 101; + int SC_OK = 200; + int SC_CREATED = 201; + int SC_ACCEPTED = 202; + int SC_NON_AUTHORITATIVE_INFORMATION = 203; + int SC_NO_CONTENT = 204; + int SC_RESET_CONTENT = 205; + int SC_PARTIAL_CONTENT = 206; + int SC_MULTIPLE_CHOICES = 300; + int SC_MOVED_PERMANENTLY = 301; + int SC_MOVED_TEMPORARILY = 302; + int SC_FOUND = 302; + int SC_SEE_OTHER = 303; + int SC_NOT_MODIFIED = 304; + int SC_USE_PROXY = 305; + int SC_TEMPORARY_REDIRECT = 307; + int SC_BAD_REQUEST = 400; + int SC_UNAUTHORIZED = 401; + int SC_PAYMENT_REQUIRED = 402; + int SC_FORBIDDEN = 403; + int SC_NOT_FOUND = 404; + int SC_METHOD_NOT_ALLOWED = 405; + int SC_NOT_ACCEPTABLE = 406; + int SC_PROXY_AUTHENTICATION_REQUIRED = 407; + int SC_REQUEST_TIMEOUT = 408; + int SC_CONFLICT = 409; + int SC_GONE = 410; + int SC_LENGTH_REQUIRED = 411; + int SC_PRECONDITION_FAILED = 412; + int SC_REQUEST_ENTITY_TOO_LARGE = 413; + int SC_REQUEST_URI_TOO_LONG = 414; + int SC_UNSUPPORTED_MEDIA_TYPE = 415; + int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416; + int SC_EXPECTATION_FAILED = 417; + int SC_INTERNAL_SERVER_ERROR = 500; + int SC_NOT_IMPLEMENTED = 501; + int SC_BAD_GATEWAY = 502; + int SC_SERVICE_UNAVAILABLE = 503; + int SC_GATEWAY_TIMEOUT = 504; + int SC_HTTP_VERSION_NOT_SUPPORTED = 505; + + void addCookie(Cookie var1); + + boolean containsHeader(String var1); + + String encodeURL(String var1); + + String encodeRedirectURL(String var1); + + /** @deprecated */ + @Deprecated + String encodeUrl(String var1); + + /** @deprecated */ + @Deprecated + String encodeRedirectUrl(String var1); + + void sendError(int var1, String var2) throws IOException; + + void sendError(int var1) throws IOException; + + void sendRedirect(String var1) throws IOException; + + void setDateHeader(String var1, long var2); + + void addDateHeader(String var1, long var2); + + void setHeader(String var1, String var2); + + void addHeader(String var1, String var2); + + void setIntHeader(String var1, int var2); + + void addIntHeader(String var1, int var2); + + void setStatus(int var1); + + /** @deprecated */ + @Deprecated + void setStatus(int var1, String var2); + + int getStatus(); + + String getHeader(String var1); + + Collection getHeaders(String var1); + + Collection getHeaderNames(); + + default void setTrailerFields(Supplier> supplier) { + } + + default Supplier> getTrailerFields() { + return null; + } +} From 01c13c470350c2784d427c5a47d68a198a503fd1 Mon Sep 17 00:00:00 2001 From: ihsinme Date: Thu, 4 Mar 2021 16:14:11 +0300 Subject: [PATCH 079/725] Add files via upload --- ...ratorPrecedenceLogicErrorWhenUseBoolType.c | 11 +++++ ...rPrecedenceLogicErrorWhenUseBoolType.qhelp | 28 +++++++++++ ...atorPrecedenceLogicErrorWhenUseBoolType.ql | 48 +++++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 cpp/ql/src/experimental/Security/CWE/CWE-783/OperatorPrecedenceLogicErrorWhenUseBoolType.c create mode 100644 cpp/ql/src/experimental/Security/CWE/CWE-783/OperatorPrecedenceLogicErrorWhenUseBoolType.qhelp create mode 100644 cpp/ql/src/experimental/Security/CWE/CWE-783/OperatorPrecedenceLogicErrorWhenUseBoolType.ql diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-783/OperatorPrecedenceLogicErrorWhenUseBoolType.c b/cpp/ql/src/experimental/Security/CWE/CWE-783/OperatorPrecedenceLogicErrorWhenUseBoolType.c new file mode 100644 index 00000000000..8458d82f7ad --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-783/OperatorPrecedenceLogicErrorWhenUseBoolType.c @@ -0,0 +1,11 @@ +if(len=funcReadData()==0) return 1; // BAD: variable `len` will not equal the value returned by function `funcReadData()` +... +if((len=funcReadData())==0) return 1; // GOOD: variable `len` equal the value returned by function `funcReadData()` +... +bool a=true; +a++;// BAD: variable `a` does not change its meaning +bool b; +b=-a;// BAD: variable `b` equal `true` +... +a=false;// GOOD: variable `a` equal `false` +b=!a;// GOOD: variable `b` equal `false` diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-783/OperatorPrecedenceLogicErrorWhenUseBoolType.qhelp b/cpp/ql/src/experimental/Security/CWE/CWE-783/OperatorPrecedenceLogicErrorWhenUseBoolType.qhelp new file mode 100644 index 00000000000..8114da831fe --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-783/OperatorPrecedenceLogicErrorWhenUseBoolType.qhelp @@ -0,0 +1,28 @@ + + + +

    Finding places of confusing use of boolean type. For example, a unary minus does not work before a boolean type and an increment always gives true.

    + + +
    + + +

    we recommend making the code simpler.

    + +
    + +

    The following example demonstrates erroneous and fixed methods for using a boolean data type.

    + + +
    + + +
  • + CERT C Coding Standard: + EXP00-C. Use parentheses for precedence of operation. +
  • + +
    +
    diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-783/OperatorPrecedenceLogicErrorWhenUseBoolType.ql b/cpp/ql/src/experimental/Security/CWE/CWE-783/OperatorPrecedenceLogicErrorWhenUseBoolType.ql new file mode 100644 index 00000000000..1a116a83dbf --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-783/OperatorPrecedenceLogicErrorWhenUseBoolType.ql @@ -0,0 +1,48 @@ +/** + * @name Operator Precedence Logic Error When Use Bool Type + * @description --Finding places of confusing use of boolean type. + * --For example, a unary minus does not work before a boolean type and an increment always gives true. + * @kind problem + * @id cpp/operator-precedence-logic-error-when-use-bool-type + * @problem.severity warning + * @precision medium + * @tags correctness + * security + * external/cwe/cwe-783 + * external/cwe/cwe-480 + */ + +import cpp +import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis + +/** Holds, if it is an expression, a boolean increment. */ +predicate incrementBoolType(Expr exp) { + exp.(IncrementOperation).getOperand().getType() instanceof BoolType +} + +/** Holds, if this is an expression, applies a minus to a boolean type. */ +predicate revertSignBoolType(Expr exp) { + exp.(AssignExpr).getRValue().(UnaryMinusExpr).getAnOperand().getType() instanceof BoolType and + exp.(AssignExpr).getLValue().getType() instanceof BoolType +} + +/** Holds, if this is an expression, uses comparison and assignment outside of execution precedence. */ +predicate assignBoolType(Expr exp) { + exists(ComparisonOperation co | + exp.(AssignExpr).getRValue() = co and + exp.isCondition() and + not co.isParenthesised() and + not exp.(AssignExpr).getLValue().getType() instanceof BoolType and + co.getLeftOperand() instanceof FunctionCall and + not co.getRightOperand().getType() instanceof BoolType and + not co.getRightOperand().getValue() = "0" and + not co.getRightOperand().getValue() = "1" + ) +} + +from Expr exp +where + incrementBoolType(exp) or + revertSignBoolType(exp) or + assignBoolType(exp) +select exp, "this expression needs attention" From 10cc57428907c41e08786242051028c996935ef3 Mon Sep 17 00:00:00 2001 From: ihsinme Date: Thu, 4 Mar 2021 16:15:26 +0300 Subject: [PATCH 080/725] Add files via upload --- ...ecedenceLogicErrorWhenUseBoolType.expected | 5 ++++ ...rPrecedenceLogicErrorWhenUseBoolType.qlref | 1 + .../CWE/CWE-788/semmle/tests/test.cpp | 26 +++++++++++++++++++ 3 files changed, 32 insertions(+) create mode 100644 cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/OperatorPrecedenceLogicErrorWhenUseBoolType.expected create mode 100644 cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/OperatorPrecedenceLogicErrorWhenUseBoolType.qlref create mode 100644 cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/test.cpp diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/OperatorPrecedenceLogicErrorWhenUseBoolType.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/OperatorPrecedenceLogicErrorWhenUseBoolType.expected new file mode 100644 index 00000000000..76062fc360a --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/OperatorPrecedenceLogicErrorWhenUseBoolType.expected @@ -0,0 +1,5 @@ +| test.cpp:10:3:10:10 | ... = ... | this expression needs attention | +| test.cpp:12:3:12:6 | ... ++ | this expression needs attention | +| test.cpp:13:3:13:6 | ++ ... | this expression needs attention | +| test.cpp:14:6:14:21 | ... = ... | this expression needs attention | +| test.cpp:16:6:16:21 | ... = ... | this expression needs attention | diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/OperatorPrecedenceLogicErrorWhenUseBoolType.qlref b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/OperatorPrecedenceLogicErrorWhenUseBoolType.qlref new file mode 100644 index 00000000000..5189abcce5d --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/OperatorPrecedenceLogicErrorWhenUseBoolType.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-783/OperatorPrecedenceLogicErrorWhenUseBoolType.ql diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/test.cpp b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/test.cpp new file mode 100644 index 00000000000..f08d2a45757 --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/test.cpp @@ -0,0 +1,26 @@ +int tmpFunc() +{ + return 12; +} +void testFunction() +{ + int i1,i2,i3; + bool b1,b2,b3; + char c1,c2,c3; + b1 = -b2; //BAD + b1 = !b2; //GOOD + b1++; //BAD + ++b1; //BAD + if(i1=tmpFunc()!=i2) //BAD + return; + if(i1=tmpFunc()!=11) //BAD + return; + if((i1=tmpFunc())!=i2) //GOOD + return; + if((i1=tmpFunc())!=11) //GOOD + return; + if(i1=tmpFunc()!=1) //GOOD + return; + if(i1=tmpFunc()==b1) //GOOD + return; +} From 23876cb581fbd2249c7c94681deac78f54ccee31 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 4 Mar 2021 16:29:44 +0100 Subject: [PATCH 081/725] C++: Only allow taint to a FieldAddressInstruction if it's a union type. --- .../code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll | 2 +- cpp/ql/test/library-tests/dataflow/taint-tests/map.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll index c5c168efb0d..1f7808c5b5b 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll @@ -64,7 +64,7 @@ private predicate operandToInstructionTaintStep(Operand opFrom, Instruction inst or instrTo instanceof PointerArithmeticInstruction or - instrTo instanceof FieldAddressInstruction + instrTo.(FieldAddressInstruction).getField().getDeclaringType() instanceof Union or // The `CopyInstruction` case is also present in non-taint data flow, but // that uses `getDef` rather than `getAnyDef`. For taint, we want flow diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/map.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/map.cpp index 0154ef2c7bb..aabd898830e 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/map.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/map.cpp @@ -152,8 +152,8 @@ void test_map() for (i2 = m2.begin(); i2 != m2.end(); i2++) { sink(*i2); // $ ast,ir - sink(i2->first); // $ SPURIOUS: ir - sink(i2->second); // $ ir MISSING: ast + sink(i2->first); // clean + sink(i2->second); // $ MISSING: ast,ir } for (i3 = m3.begin(); i3 != m3.end(); i3++) { @@ -304,8 +304,8 @@ void test_unordered_map() for (i2 = m2.begin(); i2 != m2.end(); i2++) { sink(*i2); // $ ast,ir - sink(i2->first); // $ SPURIOUS: ir - sink(i2->second); // $ ir MISSING: ast + sink(i2->first); // clean + sink(i2->second); // $ MISSING: ast,ir } for (i3 = m3.begin(); i3 != m3.end(); i3++) { From abdebc29f9696ed8642ee81519f3a7a415b68c81 Mon Sep 17 00:00:00 2001 From: Francis Alexander Date: Fri, 5 Mar 2021 07:26:29 +0530 Subject: [PATCH 082/725] Move to experimental and review feedback --- .../Security/CWE/CWE-346/UnvalidatedCors.java | 0 .../Security/CWE/CWE-346/UnvalidatedCors.qhelp | 0 .../{ => experimental}/Security/CWE/CWE-346/UnvalidatedCors.ql | 2 +- .../query-tests/security/CWE-346/UnvalidatedCors.expected | 0 .../query-tests/security/CWE-346/UnvalidatedCors.java | 0 .../query-tests/security/CWE-346/UnvalidatedCors.qlref | 1 + java/ql/test/experimental/query-tests/security/CWE-346/options | 1 + java/ql/test/query-tests/security/CWE-346/UnvalidatedCors.qlref | 1 - java/ql/test/query-tests/security/CWE-346/options | 1 - 9 files changed, 3 insertions(+), 3 deletions(-) rename java/ql/src/{ => experimental}/Security/CWE/CWE-346/UnvalidatedCors.java (100%) rename java/ql/src/{ => experimental}/Security/CWE/CWE-346/UnvalidatedCors.qhelp (100%) rename java/ql/src/{ => experimental}/Security/CWE/CWE-346/UnvalidatedCors.ql (97%) rename java/ql/test/{ => experimental}/query-tests/security/CWE-346/UnvalidatedCors.expected (100%) rename java/ql/test/{ => experimental}/query-tests/security/CWE-346/UnvalidatedCors.java (100%) create mode 100644 java/ql/test/experimental/query-tests/security/CWE-346/UnvalidatedCors.qlref create mode 100644 java/ql/test/experimental/query-tests/security/CWE-346/options delete mode 100644 java/ql/test/query-tests/security/CWE-346/UnvalidatedCors.qlref delete mode 100644 java/ql/test/query-tests/security/CWE-346/options diff --git a/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.java b/java/ql/src/experimental/Security/CWE/CWE-346/UnvalidatedCors.java similarity index 100% rename from java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.java rename to java/ql/src/experimental/Security/CWE/CWE-346/UnvalidatedCors.java diff --git a/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.qhelp b/java/ql/src/experimental/Security/CWE/CWE-346/UnvalidatedCors.qhelp similarity index 100% rename from java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.qhelp rename to java/ql/src/experimental/Security/CWE/CWE-346/UnvalidatedCors.qhelp diff --git a/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql b/java/ql/src/experimental/Security/CWE/CWE-346/UnvalidatedCors.ql similarity index 97% rename from java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql rename to java/ql/src/experimental/Security/CWE/CWE-346/UnvalidatedCors.ql index 0cd99aea68a..c5a6c36d6a6 100644 --- a/java/ql/src/Security/CWE/CWE-346/UnvalidatedCors.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-346/UnvalidatedCors.ql @@ -59,7 +59,7 @@ class CorsSourceReachesCheckConfig extends TaintTracking2::Configuration { } } -class CorsOriginConfig extends TaintTracking::Configuration { +private class CorsOriginConfig extends TaintTracking::Configuration { CorsOriginConfig() { this = "CorsOriginConfig" } override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } diff --git a/java/ql/test/query-tests/security/CWE-346/UnvalidatedCors.expected b/java/ql/test/experimental/query-tests/security/CWE-346/UnvalidatedCors.expected similarity index 100% rename from java/ql/test/query-tests/security/CWE-346/UnvalidatedCors.expected rename to java/ql/test/experimental/query-tests/security/CWE-346/UnvalidatedCors.expected diff --git a/java/ql/test/query-tests/security/CWE-346/UnvalidatedCors.java b/java/ql/test/experimental/query-tests/security/CWE-346/UnvalidatedCors.java similarity index 100% rename from java/ql/test/query-tests/security/CWE-346/UnvalidatedCors.java rename to java/ql/test/experimental/query-tests/security/CWE-346/UnvalidatedCors.java diff --git a/java/ql/test/experimental/query-tests/security/CWE-346/UnvalidatedCors.qlref b/java/ql/test/experimental/query-tests/security/CWE-346/UnvalidatedCors.qlref new file mode 100644 index 00000000000..c41004f565c --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-346/UnvalidatedCors.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-346/UnvalidatedCors.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-346/options b/java/ql/test/experimental/query-tests/security/CWE-346/options new file mode 100644 index 00000000000..d105d863eb4 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-346/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/apache-commons-lang3-3.7 diff --git a/java/ql/test/query-tests/security/CWE-346/UnvalidatedCors.qlref b/java/ql/test/query-tests/security/CWE-346/UnvalidatedCors.qlref deleted file mode 100644 index 93df7860cb4..00000000000 --- a/java/ql/test/query-tests/security/CWE-346/UnvalidatedCors.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/CWE/CWE-346/UnvalidatedCors.ql diff --git a/java/ql/test/query-tests/security/CWE-346/options b/java/ql/test/query-tests/security/CWE-346/options deleted file mode 100644 index 4fd2033a3d4..00000000000 --- a/java/ql/test/query-tests/security/CWE-346/options +++ /dev/null @@ -1 +0,0 @@ -//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/apache-commons-lang3-3.7 From 919c6b4b0aae6053a1b4b4d1e3657ac50e4a94f5 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Fri, 5 Mar 2021 02:50:54 +0000 Subject: [PATCH 083/725] Optimize flow steps --- .../CWE-1004/SensitiveCookieNotHttpOnly.ql | 36 ++++++++++--------- .../SensitiveCookieNotHttpOnly.expected | 10 ++++-- .../CWE-1004/SensitiveCookieNotHttpOnly.java | 13 +++++-- 3 files changed, 37 insertions(+), 22 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql b/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql index d9104cbad97..f22e99e567c 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql @@ -8,6 +8,7 @@ */ import java +import semmle.code.java.dataflow.FlowSteps import semmle.code.java.frameworks.Servlets import semmle.code.java.dataflow.TaintTracking import DataFlow::PathGraph @@ -41,18 +42,31 @@ class SetCookieMethodAccess extends MethodAccess { } } +/** The cookie class of Java EE. */ +class CookieClass extends RefType { + CookieClass() { + this.getASupertype*() + .hasQualifiedName(["javax.servlet.http", "javax.ws.rs.core", "jakarta.ws.rs.core"], "Cookie") + } +} + +/** The method call `toString` to get a stringified cookie representation. */ +class CookieInstanceExpr extends TaintPreservingCallable { + CookieInstanceExpr() { + this.getDeclaringType() instanceof CookieClass and + this.hasName("toString") + } + + override predicate returnsTaintFrom(int arg) { arg = -1 } +} + /** Sensitive cookie name used in a `Cookie` constructor or a `Set-Cookie` call. */ class SensitiveCookieNameExpr extends Expr { SensitiveCookieNameExpr() { exists( ClassInstanceExpr cie // new Cookie("jwt_token", token) | - ( - cie.getConstructedType().hasQualifiedName("javax.servlet.http", "Cookie") or - cie.getConstructedType() - .getASupertype*() - .hasQualifiedName(["javax.ws.rs.core", "jakarta.ws.rs.core"], "Cookie") - ) and + cie.getConstructedType() instanceof CookieClass and this = cie and isSensitiveCookieNameExpr(cie.getArgument(0)) ) @@ -169,16 +183,6 @@ class MissingHttpOnlyConfiguration extends TaintTracking::Configuration { // Test class or method isTestMethod(node) } - - override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { - exists( - MethodAccess ma // `toString` call on a cookie object - | - ma.getQualifier() = pred.asExpr() and - ma.getMethod().hasName("toString") and - ma = succ.asExpr() - ) - } } from DataFlow::PathNode source, DataFlow::PathNode sink, MissingHttpOnlyConfiguration c diff --git a/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.expected b/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.expected index e2d05a9b24d..5ccd2bb19f9 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.expected @@ -1,13 +1,17 @@ edges -| SensitiveCookieNotHttpOnly.java:22:27:22:60 | new Cookie(...) : Cookie | SensitiveCookieNotHttpOnly.java:28:28:28:36 | jwtCookie | +| SensitiveCookieNotHttpOnly.java:22:28:22:61 | new Cookie(...) : Cookie | SensitiveCookieNotHttpOnly.java:28:28:28:36 | jwtCookie | | SensitiveCookieNotHttpOnly.java:49:42:49:113 | new NewCookie(...) : NewCookie | SensitiveCookieNotHttpOnly.java:49:42:49:124 | toString(...) | +| SensitiveCookieNotHttpOnly.java:60:37:60:115 | new NewCookie(...) : NewCookie | SensitiveCookieNotHttpOnly.java:62:42:62:47 | keyStr | nodes -| SensitiveCookieNotHttpOnly.java:22:27:22:60 | new Cookie(...) : Cookie | semmle.label | new Cookie(...) : Cookie | +| SensitiveCookieNotHttpOnly.java:22:28:22:61 | new Cookie(...) : Cookie | semmle.label | new Cookie(...) : Cookie | | SensitiveCookieNotHttpOnly.java:28:28:28:36 | jwtCookie | semmle.label | jwtCookie | | SensitiveCookieNotHttpOnly.java:39:42:39:69 | ... + ... | semmle.label | ... + ... | | SensitiveCookieNotHttpOnly.java:49:42:49:113 | new NewCookie(...) : NewCookie | semmle.label | new NewCookie(...) : NewCookie | | SensitiveCookieNotHttpOnly.java:49:42:49:124 | toString(...) | semmle.label | toString(...) | +| SensitiveCookieNotHttpOnly.java:60:37:60:115 | new NewCookie(...) : NewCookie | semmle.label | new NewCookie(...) : NewCookie | +| SensitiveCookieNotHttpOnly.java:62:42:62:47 | keyStr | semmle.label | keyStr | #select -| SensitiveCookieNotHttpOnly.java:28:28:28:36 | jwtCookie | SensitiveCookieNotHttpOnly.java:22:27:22:60 | new Cookie(...) : Cookie | SensitiveCookieNotHttpOnly.java:28:28:28:36 | jwtCookie | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:22:27:22:60 | new Cookie(...) | This sensitive cookie | +| SensitiveCookieNotHttpOnly.java:28:28:28:36 | jwtCookie | SensitiveCookieNotHttpOnly.java:22:28:22:61 | new Cookie(...) : Cookie | SensitiveCookieNotHttpOnly.java:28:28:28:36 | jwtCookie | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:22:28:22:61 | new Cookie(...) | This sensitive cookie | | SensitiveCookieNotHttpOnly.java:39:42:39:69 | ... + ... | SensitiveCookieNotHttpOnly.java:39:42:39:69 | ... + ... | SensitiveCookieNotHttpOnly.java:39:42:39:69 | ... + ... | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:39:42:39:69 | ... + ... | This sensitive cookie | | SensitiveCookieNotHttpOnly.java:49:42:49:124 | toString(...) | SensitiveCookieNotHttpOnly.java:49:42:49:113 | new NewCookie(...) : NewCookie | SensitiveCookieNotHttpOnly.java:49:42:49:124 | toString(...) | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:49:42:49:113 | new NewCookie(...) | This sensitive cookie | +| SensitiveCookieNotHttpOnly.java:62:42:62:47 | keyStr | SensitiveCookieNotHttpOnly.java:60:37:60:115 | new NewCookie(...) : NewCookie | SensitiveCookieNotHttpOnly.java:62:42:62:47 | keyStr | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:60:37:60:115 | new NewCookie(...) | This sensitive cookie | diff --git a/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.java b/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.java index 5e4f349f7c8..1d1e6986b44 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.java +++ b/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.java @@ -10,7 +10,7 @@ import javax.ws.rs.core.NewCookie; class SensitiveCookieNotHttpOnly { // GOOD - Tests adding a sensitive cookie with the `HttpOnly` flag set. public void addCookie(String jwt_token, HttpServletRequest request, HttpServletResponse response) { - Cookie jwtCookie =new Cookie("jwt_token", jwt_token); + Cookie jwtCookie = new Cookie("jwt_token", jwt_token); jwtCookie.setPath("/"); jwtCookie.setMaxAge(3600*24*7); jwtCookie.setHttpOnly(true); @@ -19,8 +19,8 @@ class SensitiveCookieNotHttpOnly { // BAD - Tests adding a sensitive cookie without the `HttpOnly` flag set. public void addCookie2(String jwt_token, String userId, HttpServletRequest request, HttpServletResponse response) { - Cookie jwtCookie =new Cookie("jwt_token", jwt_token); - Cookie userIdCookie =new Cookie("user_id", userId.toString()); + Cookie jwtCookie = new Cookie("jwt_token", jwt_token); + Cookie userIdCookie = new Cookie("user_id", userId); jwtCookie.setPath("/"); userIdCookie.setPath("/"); jwtCookie.setMaxAge(3600*24*7); @@ -54,4 +54,11 @@ class SensitiveCookieNotHttpOnly { NewCookie accessKeyCookie = new NewCookie("session-access-key", accessKey, "/", null, null, 0, true, true); response.setHeader("Set-Cookie", accessKeyCookie.toString()); } + + // BAD - Tests set a sensitive cookie header using the class `javax.ws.rs.core.Cookie` without the `HttpOnly` flag set. + public void addCookie8(String accessKey, HttpServletRequest request, HttpServletResponse response) { + NewCookie accessKeyCookie = new NewCookie("session-access-key", accessKey, "/", null, 0, null, 86400, true); + String keyStr = accessKeyCookie.toString(); + response.setHeader("Set-Cookie", keyStr); + } } From a93aabab408442a96a9ae8e46718f94291b269b8 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Fri, 5 Mar 2021 03:05:49 +0000 Subject: [PATCH 084/725] Add the toString() method --- .../jsr311-api-1.1.1/javax/ws/rs/core/NewCookie.java | 11 +++++++++++ .../servlet-api-2.4/javax/servlet/http/Cookie.java | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/java/ql/test/stubs/jsr311-api-1.1.1/javax/ws/rs/core/NewCookie.java b/java/ql/test/stubs/jsr311-api-1.1.1/javax/ws/rs/core/NewCookie.java index 7f2e3ec0535..26279d7fe0a 100644 --- a/java/ql/test/stubs/jsr311-api-1.1.1/javax/ws/rs/core/NewCookie.java +++ b/java/ql/test/stubs/jsr311-api-1.1.1/javax/ws/rs/core/NewCookie.java @@ -320,4 +320,15 @@ public class NewCookie extends Cookie { public Cookie toCookie() { return null; } + + /** + * Convert the cookie to a string suitable for use as the value of the + * corresponding HTTP header. + * + * @return a stringified cookie. + */ + @Override + public String toString() { + return null; + } } \ No newline at end of file diff --git a/java/ql/test/stubs/servlet-api-2.4/javax/servlet/http/Cookie.java b/java/ql/test/stubs/servlet-api-2.4/javax/servlet/http/Cookie.java index a93fec853e0..47b1d883e47 100644 --- a/java/ql/test/stubs/servlet-api-2.4/javax/servlet/http/Cookie.java +++ b/java/ql/test/stubs/servlet-api-2.4/javax/servlet/http/Cookie.java @@ -114,4 +114,15 @@ public class Cookie implements Cloneable { public boolean isHttpOnly() { return isHttpOnly; } + + /** + * Convert the cookie to a string suitable for use as the value of the + * corresponding HTTP header. + * + * @return a stringified cookie. + */ + @Override + public String toString() { + return null; + } } From ecdadd182632faba8e532ecf2ba42e1c1aa40d2b Mon Sep 17 00:00:00 2001 From: haby0 Date: Fri, 5 Mar 2021 14:38:04 +0800 Subject: [PATCH 085/725] move the query to experimental folder --- .../Security/CWE/CWE-652/XQueryInjection.java | 0 .../Security/CWE/CWE-652/XQueryInjection.qhelp | 0 .../{ => experimental}/Security/CWE/CWE-652/XQueryInjection.ql | 0 .../Security/CWE/CWE-652/XQueryInjectionLib.qll | 0 .../query-tests/security/CWE-652/XQueryInjection.qlref | 2 +- 5 files changed, 1 insertion(+), 1 deletion(-) rename java/ql/src/{ => experimental}/Security/CWE/CWE-652/XQueryInjection.java (100%) rename java/ql/src/{ => experimental}/Security/CWE/CWE-652/XQueryInjection.qhelp (100%) rename java/ql/src/{ => experimental}/Security/CWE/CWE-652/XQueryInjection.ql (100%) rename java/ql/src/{ => experimental}/Security/CWE/CWE-652/XQueryInjectionLib.qll (100%) diff --git a/java/ql/src/Security/CWE/CWE-652/XQueryInjection.java b/java/ql/src/experimental/Security/CWE/CWE-652/XQueryInjection.java similarity index 100% rename from java/ql/src/Security/CWE/CWE-652/XQueryInjection.java rename to java/ql/src/experimental/Security/CWE/CWE-652/XQueryInjection.java diff --git a/java/ql/src/Security/CWE/CWE-652/XQueryInjection.qhelp b/java/ql/src/experimental/Security/CWE/CWE-652/XQueryInjection.qhelp similarity index 100% rename from java/ql/src/Security/CWE/CWE-652/XQueryInjection.qhelp rename to java/ql/src/experimental/Security/CWE/CWE-652/XQueryInjection.qhelp diff --git a/java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql b/java/ql/src/experimental/Security/CWE/CWE-652/XQueryInjection.ql similarity index 100% rename from java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql rename to java/ql/src/experimental/Security/CWE/CWE-652/XQueryInjection.ql diff --git a/java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-652/XQueryInjectionLib.qll similarity index 100% rename from java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll rename to java/ql/src/experimental/Security/CWE/CWE-652/XQueryInjectionLib.qll diff --git a/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.qlref b/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.qlref index 9bdeeeffa0f..dd59ba7582f 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.qlref @@ -1 +1 @@ -Security/CWE/CWE-652/XQueryInjection.ql +experimental/Security/CWE/CWE-652/XQueryInjection.ql From 863497c69505dbb98f437042f5453f517f484738 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Fri, 5 Mar 2021 14:36:26 -0500 Subject: [PATCH 086/725] C++: Update naming of queries and paths to use "summary" instead of "metrics" --- cpp/ql/src/{Diagnostics => Summary}/Files.ql | 2 +- cpp/ql/src/{Diagnostics => Summary}/Lines.ql | 2 +- cpp/ql/src/{Diagnostics => Summary}/LinesOfCode.ql | 2 +- cpp/ql/src/{Diagnostics => Summary}/LinesOfCodePerFile.ql | 2 +- cpp/ql/src/{Diagnostics => Summary}/LinesPerFile.ql | 2 +- cpp/ql/test/query-tests/Diagnostics/Files.qlref | 1 - cpp/ql/test/query-tests/Diagnostics/Lines.qlref | 1 - cpp/ql/test/query-tests/Diagnostics/LinesOfCode.qlref | 1 - cpp/ql/test/query-tests/Diagnostics/LinesOfCodePerFile.qlref | 1 - cpp/ql/test/query-tests/Diagnostics/LinesPerFile.qlref | 1 - cpp/ql/test/query-tests/{Diagnostics => Summary}/Files.expected | 0 cpp/ql/test/query-tests/Summary/Files.qlref | 1 + cpp/ql/test/query-tests/{Diagnostics => Summary}/Lines.expected | 0 cpp/ql/test/query-tests/Summary/Lines.qlref | 1 + .../query-tests/{Diagnostics => Summary}/LinesOfCode.expected | 0 cpp/ql/test/query-tests/Summary/LinesOfCode.qlref | 1 + .../{Diagnostics => Summary}/LinesOfCodePerFile.expected | 0 cpp/ql/test/query-tests/Summary/LinesOfCodePerFile.qlref | 1 + .../query-tests/{Diagnostics => Summary}/LinesPerFile.expected | 0 cpp/ql/test/query-tests/Summary/LinesPerFile.qlref | 1 + cpp/ql/test/query-tests/{Diagnostics => Summary}/empty-file.cpp | 0 cpp/ql/test/query-tests/{Diagnostics => Summary}/large-file.cpp | 0 cpp/ql/test/query-tests/{Diagnostics => Summary}/short-file.cpp | 0 23 files changed, 10 insertions(+), 10 deletions(-) rename cpp/ql/src/{Diagnostics => Summary}/Files.ql (85%) rename cpp/ql/src/{Diagnostics => Summary}/Lines.ql (89%) rename cpp/ql/src/{Diagnostics => Summary}/LinesOfCode.ql (86%) rename cpp/ql/src/{Diagnostics => Summary}/LinesOfCodePerFile.ql (84%) rename cpp/ql/src/{Diagnostics => Summary}/LinesPerFile.ql (86%) delete mode 100644 cpp/ql/test/query-tests/Diagnostics/Files.qlref delete mode 100644 cpp/ql/test/query-tests/Diagnostics/Lines.qlref delete mode 100644 cpp/ql/test/query-tests/Diagnostics/LinesOfCode.qlref delete mode 100644 cpp/ql/test/query-tests/Diagnostics/LinesOfCodePerFile.qlref delete mode 100644 cpp/ql/test/query-tests/Diagnostics/LinesPerFile.qlref rename cpp/ql/test/query-tests/{Diagnostics => Summary}/Files.expected (100%) create mode 100644 cpp/ql/test/query-tests/Summary/Files.qlref rename cpp/ql/test/query-tests/{Diagnostics => Summary}/Lines.expected (100%) create mode 100644 cpp/ql/test/query-tests/Summary/Lines.qlref rename cpp/ql/test/query-tests/{Diagnostics => Summary}/LinesOfCode.expected (100%) create mode 100644 cpp/ql/test/query-tests/Summary/LinesOfCode.qlref rename cpp/ql/test/query-tests/{Diagnostics => Summary}/LinesOfCodePerFile.expected (100%) create mode 100644 cpp/ql/test/query-tests/Summary/LinesOfCodePerFile.qlref rename cpp/ql/test/query-tests/{Diagnostics => Summary}/LinesPerFile.expected (100%) create mode 100644 cpp/ql/test/query-tests/Summary/LinesPerFile.qlref rename cpp/ql/test/query-tests/{Diagnostics => Summary}/empty-file.cpp (100%) rename cpp/ql/test/query-tests/{Diagnostics => Summary}/large-file.cpp (100%) rename cpp/ql/test/query-tests/{Diagnostics => Summary}/short-file.cpp (100%) diff --git a/cpp/ql/src/Diagnostics/Files.ql b/cpp/ql/src/Summary/Files.ql similarity index 85% rename from cpp/ql/src/Diagnostics/Files.ql rename to cpp/ql/src/Summary/Files.ql index 0759284541f..5ea01b25631 100644 --- a/cpp/ql/src/Diagnostics/Files.ql +++ b/cpp/ql/src/Summary/Files.ql @@ -2,7 +2,7 @@ * @name Total source files * @description The total number of source files. * @kind metric - * @id cpp/metrics/files + * @id cpp/summary/files */ import cpp diff --git a/cpp/ql/src/Diagnostics/Lines.ql b/cpp/ql/src/Summary/Lines.ql similarity index 89% rename from cpp/ql/src/Diagnostics/Lines.ql rename to cpp/ql/src/Summary/Lines.ql index cce3e42c00f..87feb1f7d6f 100644 --- a/cpp/ql/src/Diagnostics/Lines.ql +++ b/cpp/ql/src/Summary/Lines.ql @@ -2,7 +2,7 @@ * @name Total lines of text * @description The total number of lines of text across all source files. * @kind metric - * @id cpp/metrics/lines + * @id cpp/summary/lines */ import cpp diff --git a/cpp/ql/src/Diagnostics/LinesOfCode.ql b/cpp/ql/src/Summary/LinesOfCode.ql similarity index 86% rename from cpp/ql/src/Diagnostics/LinesOfCode.ql rename to cpp/ql/src/Summary/LinesOfCode.ql index 9553e39b3e4..7d8ae36f79e 100644 --- a/cpp/ql/src/Diagnostics/LinesOfCode.ql +++ b/cpp/ql/src/Summary/LinesOfCode.ql @@ -2,7 +2,7 @@ * @name Total lines of code * @description The total number of lines of code across all source files. * @kind metric - * @id cpp/metrics/lines-of-code + * @id cpp/summary/lines-of-code */ import cpp diff --git a/cpp/ql/src/Diagnostics/LinesOfCodePerFile.ql b/cpp/ql/src/Summary/LinesOfCodePerFile.ql similarity index 84% rename from cpp/ql/src/Diagnostics/LinesOfCodePerFile.ql rename to cpp/ql/src/Summary/LinesOfCodePerFile.ql index ebb9a19c447..818e4312dcf 100644 --- a/cpp/ql/src/Diagnostics/LinesOfCodePerFile.ql +++ b/cpp/ql/src/Summary/LinesOfCodePerFile.ql @@ -2,7 +2,7 @@ * @name Lines of code per source file * @description The number of lines of code for each source file. * @kind metric - * @id cpp/metrics/lines-of-code-per-file + * @id cpp/summary/lines-of-code-per-file */ import cpp diff --git a/cpp/ql/src/Diagnostics/LinesPerFile.ql b/cpp/ql/src/Summary/LinesPerFile.ql similarity index 86% rename from cpp/ql/src/Diagnostics/LinesPerFile.ql rename to cpp/ql/src/Summary/LinesPerFile.ql index 4fa3608d293..54a0a75d2e0 100644 --- a/cpp/ql/src/Diagnostics/LinesPerFile.ql +++ b/cpp/ql/src/Summary/LinesPerFile.ql @@ -2,7 +2,7 @@ * @name Lines of text per source file * @description The number of lines of text for each source file. * @kind metric - * @id cpp/metrics/lines-per-file + * @id cpp/summary/lines-per-file */ import cpp diff --git a/cpp/ql/test/query-tests/Diagnostics/Files.qlref b/cpp/ql/test/query-tests/Diagnostics/Files.qlref deleted file mode 100644 index f29d0010003..00000000000 --- a/cpp/ql/test/query-tests/Diagnostics/Files.qlref +++ /dev/null @@ -1 +0,0 @@ -Diagnostics/Files.ql \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Diagnostics/Lines.qlref b/cpp/ql/test/query-tests/Diagnostics/Lines.qlref deleted file mode 100644 index 0b62ca77ec6..00000000000 --- a/cpp/ql/test/query-tests/Diagnostics/Lines.qlref +++ /dev/null @@ -1 +0,0 @@ -Diagnostics/Lines.ql diff --git a/cpp/ql/test/query-tests/Diagnostics/LinesOfCode.qlref b/cpp/ql/test/query-tests/Diagnostics/LinesOfCode.qlref deleted file mode 100644 index b07f3413688..00000000000 --- a/cpp/ql/test/query-tests/Diagnostics/LinesOfCode.qlref +++ /dev/null @@ -1 +0,0 @@ -Diagnostics/LinesOfCode.ql \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Diagnostics/LinesOfCodePerFile.qlref b/cpp/ql/test/query-tests/Diagnostics/LinesOfCodePerFile.qlref deleted file mode 100644 index ea50143078c..00000000000 --- a/cpp/ql/test/query-tests/Diagnostics/LinesOfCodePerFile.qlref +++ /dev/null @@ -1 +0,0 @@ -Diagnostics/LinesOfCodePerFile.ql \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Diagnostics/LinesPerFile.qlref b/cpp/ql/test/query-tests/Diagnostics/LinesPerFile.qlref deleted file mode 100644 index 768a83875e6..00000000000 --- a/cpp/ql/test/query-tests/Diagnostics/LinesPerFile.qlref +++ /dev/null @@ -1 +0,0 @@ -Diagnostics/LinesPerFile.ql \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Diagnostics/Files.expected b/cpp/ql/test/query-tests/Summary/Files.expected similarity index 100% rename from cpp/ql/test/query-tests/Diagnostics/Files.expected rename to cpp/ql/test/query-tests/Summary/Files.expected diff --git a/cpp/ql/test/query-tests/Summary/Files.qlref b/cpp/ql/test/query-tests/Summary/Files.qlref new file mode 100644 index 00000000000..f3bea020f4e --- /dev/null +++ b/cpp/ql/test/query-tests/Summary/Files.qlref @@ -0,0 +1 @@ +Summary/Files.ql \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Diagnostics/Lines.expected b/cpp/ql/test/query-tests/Summary/Lines.expected similarity index 100% rename from cpp/ql/test/query-tests/Diagnostics/Lines.expected rename to cpp/ql/test/query-tests/Summary/Lines.expected diff --git a/cpp/ql/test/query-tests/Summary/Lines.qlref b/cpp/ql/test/query-tests/Summary/Lines.qlref new file mode 100644 index 00000000000..62b3a59a14b --- /dev/null +++ b/cpp/ql/test/query-tests/Summary/Lines.qlref @@ -0,0 +1 @@ +Summary/Lines.ql diff --git a/cpp/ql/test/query-tests/Diagnostics/LinesOfCode.expected b/cpp/ql/test/query-tests/Summary/LinesOfCode.expected similarity index 100% rename from cpp/ql/test/query-tests/Diagnostics/LinesOfCode.expected rename to cpp/ql/test/query-tests/Summary/LinesOfCode.expected diff --git a/cpp/ql/test/query-tests/Summary/LinesOfCode.qlref b/cpp/ql/test/query-tests/Summary/LinesOfCode.qlref new file mode 100644 index 00000000000..ac8650d6dcc --- /dev/null +++ b/cpp/ql/test/query-tests/Summary/LinesOfCode.qlref @@ -0,0 +1 @@ +Summary/LinesOfCode.ql \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Diagnostics/LinesOfCodePerFile.expected b/cpp/ql/test/query-tests/Summary/LinesOfCodePerFile.expected similarity index 100% rename from cpp/ql/test/query-tests/Diagnostics/LinesOfCodePerFile.expected rename to cpp/ql/test/query-tests/Summary/LinesOfCodePerFile.expected diff --git a/cpp/ql/test/query-tests/Summary/LinesOfCodePerFile.qlref b/cpp/ql/test/query-tests/Summary/LinesOfCodePerFile.qlref new file mode 100644 index 00000000000..eb64c0d8a46 --- /dev/null +++ b/cpp/ql/test/query-tests/Summary/LinesOfCodePerFile.qlref @@ -0,0 +1 @@ +Summary/LinesOfCodePerFile.ql \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Diagnostics/LinesPerFile.expected b/cpp/ql/test/query-tests/Summary/LinesPerFile.expected similarity index 100% rename from cpp/ql/test/query-tests/Diagnostics/LinesPerFile.expected rename to cpp/ql/test/query-tests/Summary/LinesPerFile.expected diff --git a/cpp/ql/test/query-tests/Summary/LinesPerFile.qlref b/cpp/ql/test/query-tests/Summary/LinesPerFile.qlref new file mode 100644 index 00000000000..d967fcb9a8c --- /dev/null +++ b/cpp/ql/test/query-tests/Summary/LinesPerFile.qlref @@ -0,0 +1 @@ +Summary/LinesPerFile.ql \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Diagnostics/empty-file.cpp b/cpp/ql/test/query-tests/Summary/empty-file.cpp similarity index 100% rename from cpp/ql/test/query-tests/Diagnostics/empty-file.cpp rename to cpp/ql/test/query-tests/Summary/empty-file.cpp diff --git a/cpp/ql/test/query-tests/Diagnostics/large-file.cpp b/cpp/ql/test/query-tests/Summary/large-file.cpp similarity index 100% rename from cpp/ql/test/query-tests/Diagnostics/large-file.cpp rename to cpp/ql/test/query-tests/Summary/large-file.cpp diff --git a/cpp/ql/test/query-tests/Diagnostics/short-file.cpp b/cpp/ql/test/query-tests/Summary/short-file.cpp similarity index 100% rename from cpp/ql/test/query-tests/Diagnostics/short-file.cpp rename to cpp/ql/test/query-tests/Summary/short-file.cpp From 31eaa80f5b881531bc66551e568fed1ffc380325 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Sat, 6 Mar 2021 00:56:15 +0000 Subject: [PATCH 087/725] Revamp the source --- .../CWE-1004/SensitiveCookieNotHttpOnly.ql | 24 ++++------ .../SensitiveCookieNotHttpOnly.expected | 44 +++++++++++++------ .../CWE-1004/SensitiveCookieNotHttpOnly.java | 9 +++- 3 files changed, 46 insertions(+), 31 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql b/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql index f22e99e567c..229a9d50325 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql @@ -60,24 +60,16 @@ class CookieInstanceExpr extends TaintPreservingCallable { override predicate returnsTaintFrom(int arg) { arg = -1 } } +/** The cookie constructor. */ +class CookieTaintPreservingConstructor extends Constructor, TaintPreservingCallable { + CookieTaintPreservingConstructor() { this.getDeclaringType() instanceof CookieClass } + + override predicate returnsTaintFrom(int arg) { arg = 0 } +} + /** Sensitive cookie name used in a `Cookie` constructor or a `Set-Cookie` call. */ class SensitiveCookieNameExpr extends Expr { - SensitiveCookieNameExpr() { - exists( - ClassInstanceExpr cie // new Cookie("jwt_token", token) - | - cie.getConstructedType() instanceof CookieClass and - this = cie and - isSensitiveCookieNameExpr(cie.getArgument(0)) - ) - or - exists( - SetCookieMethodAccess ma // response.addHeader("Set-Cookie: token=" +authId + ";HttpOnly;Secure") - | - this = ma.getArgument(1) and - isSensitiveCookieNameExpr(this) - ) - } + SensitiveCookieNameExpr() { isSensitiveCookieNameExpr(this) } } /** Sink of adding a cookie to the HTTP response. */ diff --git a/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.expected b/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.expected index 5ccd2bb19f9..c9fe15d4082 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.expected @@ -1,17 +1,33 @@ edges -| SensitiveCookieNotHttpOnly.java:22:28:22:61 | new Cookie(...) : Cookie | SensitiveCookieNotHttpOnly.java:28:28:28:36 | jwtCookie | -| SensitiveCookieNotHttpOnly.java:49:42:49:113 | new NewCookie(...) : NewCookie | SensitiveCookieNotHttpOnly.java:49:42:49:124 | toString(...) | -| SensitiveCookieNotHttpOnly.java:60:37:60:115 | new NewCookie(...) : NewCookie | SensitiveCookieNotHttpOnly.java:62:42:62:47 | keyStr | +| SensitiveCookieNotHttpOnly.java:22:33:22:43 | "jwt_token" : String | SensitiveCookieNotHttpOnly.java:29:28:29:36 | jwtCookie | +| SensitiveCookieNotHttpOnly.java:40:42:40:49 | "token=" : String | SensitiveCookieNotHttpOnly.java:40:42:40:69 | ... + ... | +| SensitiveCookieNotHttpOnly.java:40:42:40:57 | ... + ... : String | SensitiveCookieNotHttpOnly.java:40:42:40:69 | ... + ... | +| SensitiveCookieNotHttpOnly.java:50:56:50:75 | "session-access-key" : String | SensitiveCookieNotHttpOnly.java:50:42:50:124 | toString(...) | +| SensitiveCookieNotHttpOnly.java:61:51:61:70 | "session-access-key" : String | SensitiveCookieNotHttpOnly.java:63:42:63:47 | keyStr | +| SensitiveCookieNotHttpOnly.java:68:28:68:35 | "token=" : String | SensitiveCookieNotHttpOnly.java:69:42:69:50 | secString | +| SensitiveCookieNotHttpOnly.java:68:28:68:43 | ... + ... : String | SensitiveCookieNotHttpOnly.java:69:42:69:50 | secString | +| SensitiveCookieNotHttpOnly.java:68:28:68:55 | ... + ... : String | SensitiveCookieNotHttpOnly.java:69:42:69:50 | secString | nodes -| SensitiveCookieNotHttpOnly.java:22:28:22:61 | new Cookie(...) : Cookie | semmle.label | new Cookie(...) : Cookie | -| SensitiveCookieNotHttpOnly.java:28:28:28:36 | jwtCookie | semmle.label | jwtCookie | -| SensitiveCookieNotHttpOnly.java:39:42:39:69 | ... + ... | semmle.label | ... + ... | -| SensitiveCookieNotHttpOnly.java:49:42:49:113 | new NewCookie(...) : NewCookie | semmle.label | new NewCookie(...) : NewCookie | -| SensitiveCookieNotHttpOnly.java:49:42:49:124 | toString(...) | semmle.label | toString(...) | -| SensitiveCookieNotHttpOnly.java:60:37:60:115 | new NewCookie(...) : NewCookie | semmle.label | new NewCookie(...) : NewCookie | -| SensitiveCookieNotHttpOnly.java:62:42:62:47 | keyStr | semmle.label | keyStr | +| SensitiveCookieNotHttpOnly.java:22:33:22:43 | "jwt_token" : String | semmle.label | "jwt_token" : String | +| SensitiveCookieNotHttpOnly.java:29:28:29:36 | jwtCookie | semmle.label | jwtCookie | +| SensitiveCookieNotHttpOnly.java:40:42:40:49 | "token=" : String | semmle.label | "token=" : String | +| SensitiveCookieNotHttpOnly.java:40:42:40:57 | ... + ... : String | semmle.label | ... + ... : String | +| SensitiveCookieNotHttpOnly.java:40:42:40:69 | ... + ... | semmle.label | ... + ... | +| SensitiveCookieNotHttpOnly.java:50:42:50:124 | toString(...) | semmle.label | toString(...) | +| SensitiveCookieNotHttpOnly.java:50:56:50:75 | "session-access-key" : String | semmle.label | "session-access-key" : String | +| SensitiveCookieNotHttpOnly.java:61:51:61:70 | "session-access-key" : String | semmle.label | "session-access-key" : String | +| SensitiveCookieNotHttpOnly.java:63:42:63:47 | keyStr | semmle.label | keyStr | +| SensitiveCookieNotHttpOnly.java:68:28:68:35 | "token=" : String | semmle.label | "token=" : String | +| SensitiveCookieNotHttpOnly.java:68:28:68:43 | ... + ... : String | semmle.label | ... + ... : String | +| SensitiveCookieNotHttpOnly.java:68:28:68:55 | ... + ... : String | semmle.label | ... + ... : String | +| SensitiveCookieNotHttpOnly.java:69:42:69:50 | secString | semmle.label | secString | #select -| SensitiveCookieNotHttpOnly.java:28:28:28:36 | jwtCookie | SensitiveCookieNotHttpOnly.java:22:28:22:61 | new Cookie(...) : Cookie | SensitiveCookieNotHttpOnly.java:28:28:28:36 | jwtCookie | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:22:28:22:61 | new Cookie(...) | This sensitive cookie | -| SensitiveCookieNotHttpOnly.java:39:42:39:69 | ... + ... | SensitiveCookieNotHttpOnly.java:39:42:39:69 | ... + ... | SensitiveCookieNotHttpOnly.java:39:42:39:69 | ... + ... | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:39:42:39:69 | ... + ... | This sensitive cookie | -| SensitiveCookieNotHttpOnly.java:49:42:49:124 | toString(...) | SensitiveCookieNotHttpOnly.java:49:42:49:113 | new NewCookie(...) : NewCookie | SensitiveCookieNotHttpOnly.java:49:42:49:124 | toString(...) | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:49:42:49:113 | new NewCookie(...) | This sensitive cookie | -| SensitiveCookieNotHttpOnly.java:62:42:62:47 | keyStr | SensitiveCookieNotHttpOnly.java:60:37:60:115 | new NewCookie(...) : NewCookie | SensitiveCookieNotHttpOnly.java:62:42:62:47 | keyStr | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:60:37:60:115 | new NewCookie(...) | This sensitive cookie | +| SensitiveCookieNotHttpOnly.java:29:28:29:36 | jwtCookie | SensitiveCookieNotHttpOnly.java:22:33:22:43 | "jwt_token" : String | SensitiveCookieNotHttpOnly.java:29:28:29:36 | jwtCookie | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:22:33:22:43 | "jwt_token" | This sensitive cookie | +| SensitiveCookieNotHttpOnly.java:40:42:40:69 | ... + ... | SensitiveCookieNotHttpOnly.java:40:42:40:49 | "token=" : String | SensitiveCookieNotHttpOnly.java:40:42:40:69 | ... + ... | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:40:42:40:49 | "token=" | This sensitive cookie | +| SensitiveCookieNotHttpOnly.java:40:42:40:69 | ... + ... | SensitiveCookieNotHttpOnly.java:40:42:40:57 | ... + ... : String | SensitiveCookieNotHttpOnly.java:40:42:40:69 | ... + ... | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:40:42:40:57 | ... + ... | This sensitive cookie | +| SensitiveCookieNotHttpOnly.java:40:42:40:69 | ... + ... | SensitiveCookieNotHttpOnly.java:40:42:40:69 | ... + ... | SensitiveCookieNotHttpOnly.java:40:42:40:69 | ... + ... | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:40:42:40:69 | ... + ... | This sensitive cookie | +| SensitiveCookieNotHttpOnly.java:50:42:50:124 | toString(...) | SensitiveCookieNotHttpOnly.java:50:56:50:75 | "session-access-key" : String | SensitiveCookieNotHttpOnly.java:50:42:50:124 | toString(...) | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:50:56:50:75 | "session-access-key" | This sensitive cookie | +| SensitiveCookieNotHttpOnly.java:63:42:63:47 | keyStr | SensitiveCookieNotHttpOnly.java:61:51:61:70 | "session-access-key" : String | SensitiveCookieNotHttpOnly.java:63:42:63:47 | keyStr | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:61:51:61:70 | "session-access-key" | This sensitive cookie | +| SensitiveCookieNotHttpOnly.java:69:42:69:50 | secString | SensitiveCookieNotHttpOnly.java:68:28:68:35 | "token=" : String | SensitiveCookieNotHttpOnly.java:69:42:69:50 | secString | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:68:28:68:35 | "token=" | This sensitive cookie | +| SensitiveCookieNotHttpOnly.java:69:42:69:50 | secString | SensitiveCookieNotHttpOnly.java:68:28:68:43 | ... + ... : String | SensitiveCookieNotHttpOnly.java:69:42:69:50 | secString | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:68:28:68:43 | ... + ... | This sensitive cookie | +| SensitiveCookieNotHttpOnly.java:69:42:69:50 | secString | SensitiveCookieNotHttpOnly.java:68:28:68:55 | ... + ... : String | SensitiveCookieNotHttpOnly.java:69:42:69:50 | secString | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:68:28:68:55 | ... + ... | This sensitive cookie | diff --git a/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.java b/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.java index 1d1e6986b44..6572577a697 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.java +++ b/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.java @@ -19,7 +19,8 @@ class SensitiveCookieNotHttpOnly { // BAD - Tests adding a sensitive cookie without the `HttpOnly` flag set. public void addCookie2(String jwt_token, String userId, HttpServletRequest request, HttpServletResponse response) { - Cookie jwtCookie = new Cookie("jwt_token", jwt_token); + String tokenCookieStr = "jwt_token"; + Cookie jwtCookie = new Cookie(tokenCookieStr, jwt_token); Cookie userIdCookie = new Cookie("user_id", userId); jwtCookie.setPath("/"); userIdCookie.setPath("/"); @@ -61,4 +62,10 @@ class SensitiveCookieNotHttpOnly { String keyStr = accessKeyCookie.toString(); response.setHeader("Set-Cookie", keyStr); } + + // BAD - Tests set a sensitive cookie header using a variable without the `HttpOnly` flag set. + public void addCookie9(String authId, HttpServletRequest request, HttpServletResponse response) { + String secString = "token=" +authId + ";Secure"; + response.addHeader("Set-Cookie", secString); + } } From dcabce679abb6f9b9c1fcceb1ffc25e38484e05d Mon Sep 17 00:00:00 2001 From: Artem Smotrakov Date: Sat, 6 Mar 2021 21:40:35 +0100 Subject: [PATCH 088/725] Cover beans from XML configs in SpringHttpInvokerUnsafeDeserialization.ql --- .../SpringHttpInvokerUnsafeDeserialization.ql | 65 +++++++++++-------- ...gHttpInvokerUnsafeDeserialization.expected | 6 +- ...pringHttpInvokerUnsafeDeserialization.java | 2 +- .../query-tests/security/CWE-502/beans.xml | 19 ++++++ 4 files changed, 62 insertions(+), 30 deletions(-) create mode 100644 java/ql/test/experimental/query-tests/security/CWE-502/beans.xml diff --git a/java/ql/src/experimental/Security/CWE/CWE-502/SpringHttpInvokerUnsafeDeserialization.ql b/java/ql/src/experimental/Security/CWE/CWE-502/SpringHttpInvokerUnsafeDeserialization.ql index 54e8272575b..417f1c8790b 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-502/SpringHttpInvokerUnsafeDeserialization.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-502/SpringHttpInvokerUnsafeDeserialization.ql @@ -1,7 +1,8 @@ /** - * @name Unsafe deserialization with spring's remote service exporters. - * @description Creating a bean based on RemoteInvocationSerializingExporter - * may lead to arbitrary code execution. + * @name Unsafe deserialization with Spring's remote service exporters. + * @description A Spring bean, which is based on RemoteInvocationSerializingExporter, + * initializes an endpoint that uses ObjectInputStream to deserialize + * incoming data. In the worst case, that may lead to remote code execution. * @kind problem * @problem.severity error * @precision high @@ -11,26 +12,14 @@ */ import java - -/** - * Holds if `method` initializes a bean. - */ -private predicate createsBean(Method method) { - method.hasAnnotation("org.springframework.context.annotation", "Bean") -} +import semmle.code.java.frameworks.spring.SpringBean /** * Holds if `type` is `RemoteInvocationSerializingExporter`. */ private predicate isRemoteInvocationSerializingExporter(RefType type) { - type.hasQualifiedName("org.springframework.remoting.rmi", "RemoteInvocationSerializingExporter") -} - -/** - * Holds if `method` returns an object that extends `RemoteInvocationSerializingExporter`. - */ -private predicate returnsRemoteInvocationSerializingExporter(Method method) { - isRemoteInvocationSerializingExporter(method.getReturnType().(RefType).getASupertype*()) + type.getASupertype*() + .hasQualifiedName("org.springframework.remoting.rmi", "RemoteInvocationSerializingExporter") } /** @@ -41,15 +30,37 @@ private predicate isInConfiguration(Method method) { } /** - * Holds if `method` initializes a bean that is based on `RemoteInvocationSerializingExporter`. + * A method that initializes a unsafe bean based on `RemoteInvocationSerializingExporter`. */ -private predicate createsRemoteInvocationSerializingExporterBean(Method method) { - isInConfiguration(method) and - createsBean(method) and - returnsRemoteInvocationSerializingExporter(method) +private class UnsafeBeanInitMethod extends Method { + string identifier; + + UnsafeBeanInitMethod() { + isInConfiguration(this) and + isRemoteInvocationSerializingExporter(this.getReturnType()) and + exists(Annotation a | + a.getType().hasQualifiedName("org.springframework.context.annotation", "Bean") + | + this.getAnAnnotation() = a and + if a.getValue("name") instanceof StringLiteral + then identifier = a.getValue("name").(StringLiteral).getRepresentedString() + else identifier = this.getName() + ) + } + + string getBeanIdentifier() { result = identifier } } -from Method method -where createsRemoteInvocationSerializingExporterBean(method) -select method, - "Unsafe deserialization in a remote service exporter in '" + method.getName() + "' method" +from File file, string identifier +where + exists(UnsafeBeanInitMethod method | + file = method.getFile() and + identifier = method.getBeanIdentifier() + ) + or + exists(SpringBean bean | + isRemoteInvocationSerializingExporter(bean.getClass()) and + file = bean.getFile() and + identifier = bean.getBeanIdentifier() + ) +select file, "Unsafe deserialization in Spring exporter bean '" + identifier + "'" diff --git a/java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.expected b/java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.expected index b76f3edc57e..58fc508c1a4 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.expected @@ -1,2 +1,4 @@ -| SpringHttpInvokerUnsafeDeserialization.java:10:32:10:63 | unsafeHttpInvokerServiceExporter | Unasafe deserialization in a remote service exporter in 'unsafeHttpInvokerServiceExporter' method | -| SpringHttpInvokerUnsafeDeserialization.java:18:41:18:88 | unsafeCustomeRemoteInvocationSerializingExporter | Unasafe deserialization in a remote service exporter in 'unsafeCustomeRemoteInvocationSerializingExporter' method | +| SpringHttpInvokerUnsafeDeserialization.java:0:0:0:0 | SpringHttpInvokerUnsafeDeserialization | Unsafe deserialization in a remote service exporter bean '/unsafeCustomeRemoteInvocationSerializingExporter' | +| SpringHttpInvokerUnsafeDeserialization.java:0:0:0:0 | SpringHttpInvokerUnsafeDeserialization | Unsafe deserialization in a remote service exporter bean '/unsafeHttpInvokerServiceExporter' | +| beans.xml:0:0:0:0 | beans.xml | Unsafe deserialization in a remote service exporter bean '/unsafeBooking' | +| beans.xml:0:0:0:0 | beans.xml | Unsafe deserialization in a remote service exporter bean 'org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter' | diff --git a/java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.java b/java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.java index 9d99aa1cbce..6811131fb5f 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.java +++ b/java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.java @@ -5,7 +5,7 @@ import org.springframework.remoting.rmi.RemoteInvocationSerializingExporter; @Configuration public class SpringHttpInvokerUnsafeDeserialization { - + @Bean(name = "/unsafeHttpInvokerServiceExporter") HttpInvokerServiceExporter unsafeHttpInvokerServiceExporter() { HttpInvokerServiceExporter exporter = new HttpInvokerServiceExporter(); diff --git a/java/ql/test/experimental/query-tests/security/CWE-502/beans.xml b/java/ql/test/experimental/query-tests/security/CWE-502/beans.xml new file mode 100644 index 00000000000..bdb4e5fa651 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-502/beans.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + From 82cb4a8d68a76d6abd909e88d243874afb515407 Mon Sep 17 00:00:00 2001 From: Artem Smotrakov Date: Sat, 6 Mar 2021 21:48:35 +0100 Subject: [PATCH 089/725] Renamed SpringHttpInvokerUnsafeDeserialization.ql --- ...Endpoint.java => SpringExporterUnsafeDeserialization.java} | 0 ...zation.qhelp => SpringExporterUnsafeDeserialization.qhelp} | 0 ...erialization.ql => SpringExporterUnsafeDeserialization.ql} | 0 .../CWE-502/SpringExporterUnsafeDeserialization.expected | 4 ++++ ...lization.java => SpringExporterUnsafeDeserialization.java} | 2 +- .../CWE-502/SpringExporterUnsafeDeserialization.qlref | 1 + .../CWE-502/SpringHttpInvokerUnsafeDeserialization.expected | 4 ---- .../CWE-502/SpringHttpInvokerUnsafeDeserialization.qlref | 1 - 8 files changed, 6 insertions(+), 6 deletions(-) rename java/ql/src/experimental/Security/CWE/CWE-502/{UnsafeHttpInvokerEndpoint.java => SpringExporterUnsafeDeserialization.java} (100%) rename java/ql/src/experimental/Security/CWE/CWE-502/{SpringHttpInvokerUnsafeDeserialization.qhelp => SpringExporterUnsafeDeserialization.qhelp} (100%) rename java/ql/src/experimental/Security/CWE/CWE-502/{SpringHttpInvokerUnsafeDeserialization.ql => SpringExporterUnsafeDeserialization.ql} (100%) create mode 100644 java/ql/test/experimental/query-tests/security/CWE-502/SpringExporterUnsafeDeserialization.expected rename java/ql/test/experimental/query-tests/security/CWE-502/{SpringHttpInvokerUnsafeDeserialization.java => SpringExporterUnsafeDeserialization.java} (97%) create mode 100644 java/ql/test/experimental/query-tests/security/CWE-502/SpringExporterUnsafeDeserialization.qlref delete mode 100644 java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.expected delete mode 100644 java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.qlref diff --git a/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeHttpInvokerEndpoint.java b/java/ql/src/experimental/Security/CWE/CWE-502/SpringExporterUnsafeDeserialization.java similarity index 100% rename from java/ql/src/experimental/Security/CWE/CWE-502/UnsafeHttpInvokerEndpoint.java rename to java/ql/src/experimental/Security/CWE/CWE-502/SpringExporterUnsafeDeserialization.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-502/SpringHttpInvokerUnsafeDeserialization.qhelp b/java/ql/src/experimental/Security/CWE/CWE-502/SpringExporterUnsafeDeserialization.qhelp similarity index 100% rename from java/ql/src/experimental/Security/CWE/CWE-502/SpringHttpInvokerUnsafeDeserialization.qhelp rename to java/ql/src/experimental/Security/CWE/CWE-502/SpringExporterUnsafeDeserialization.qhelp diff --git a/java/ql/src/experimental/Security/CWE/CWE-502/SpringHttpInvokerUnsafeDeserialization.ql b/java/ql/src/experimental/Security/CWE/CWE-502/SpringExporterUnsafeDeserialization.ql similarity index 100% rename from java/ql/src/experimental/Security/CWE/CWE-502/SpringHttpInvokerUnsafeDeserialization.ql rename to java/ql/src/experimental/Security/CWE/CWE-502/SpringExporterUnsafeDeserialization.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-502/SpringExporterUnsafeDeserialization.expected b/java/ql/test/experimental/query-tests/security/CWE-502/SpringExporterUnsafeDeserialization.expected new file mode 100644 index 00000000000..1b5c1d2e67d --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-502/SpringExporterUnsafeDeserialization.expected @@ -0,0 +1,4 @@ +| SpringExporterUnsafeDeserialization.java:0:0:0:0 | SpringExporterUnsafeDeserialization | Unsafe deserialization in Spring exporter bean '/unsafeCustomeRemoteInvocationSerializingExporter' | +| SpringExporterUnsafeDeserialization.java:0:0:0:0 | SpringExporterUnsafeDeserialization | Unsafe deserialization in Spring exporter bean '/unsafeHttpInvokerServiceExporter' | +| beans.xml:0:0:0:0 | beans.xml | Unsafe deserialization in Spring exporter bean '/unsafeBooking' | +| beans.xml:0:0:0:0 | beans.xml | Unsafe deserialization in Spring exporter bean 'org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter' | diff --git a/java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.java b/java/ql/test/experimental/query-tests/security/CWE-502/SpringExporterUnsafeDeserialization.java similarity index 97% rename from java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.java rename to java/ql/test/experimental/query-tests/security/CWE-502/SpringExporterUnsafeDeserialization.java index 6811131fb5f..c89668fc6bb 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.java +++ b/java/ql/test/experimental/query-tests/security/CWE-502/SpringExporterUnsafeDeserialization.java @@ -4,7 +4,7 @@ import org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter; import org.springframework.remoting.rmi.RemoteInvocationSerializingExporter; @Configuration -public class SpringHttpInvokerUnsafeDeserialization { +public class SpringExporterUnsafeDeserialization { @Bean(name = "/unsafeHttpInvokerServiceExporter") HttpInvokerServiceExporter unsafeHttpInvokerServiceExporter() { diff --git a/java/ql/test/experimental/query-tests/security/CWE-502/SpringExporterUnsafeDeserialization.qlref b/java/ql/test/experimental/query-tests/security/CWE-502/SpringExporterUnsafeDeserialization.qlref new file mode 100644 index 00000000000..7be52b73cba --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-502/SpringExporterUnsafeDeserialization.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-502/SpringExporterUnsafeDeserialization.ql \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.expected b/java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.expected deleted file mode 100644 index 58fc508c1a4..00000000000 --- a/java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.expected +++ /dev/null @@ -1,4 +0,0 @@ -| SpringHttpInvokerUnsafeDeserialization.java:0:0:0:0 | SpringHttpInvokerUnsafeDeserialization | Unsafe deserialization in a remote service exporter bean '/unsafeCustomeRemoteInvocationSerializingExporter' | -| SpringHttpInvokerUnsafeDeserialization.java:0:0:0:0 | SpringHttpInvokerUnsafeDeserialization | Unsafe deserialization in a remote service exporter bean '/unsafeHttpInvokerServiceExporter' | -| beans.xml:0:0:0:0 | beans.xml | Unsafe deserialization in a remote service exporter bean '/unsafeBooking' | -| beans.xml:0:0:0:0 | beans.xml | Unsafe deserialization in a remote service exporter bean 'org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter' | diff --git a/java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.qlref b/java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.qlref deleted file mode 100644 index 014b0872ea4..00000000000 --- a/java/ql/test/experimental/query-tests/security/CWE-502/SpringHttpInvokerUnsafeDeserialization.qlref +++ /dev/null @@ -1 +0,0 @@ -experimental/Security/CWE/CWE-502/SpringHttpInvokerUnsafeDeserialization.ql \ No newline at end of file From bda223771bddcdc2d67b86714d76d0faf895ffda Mon Sep 17 00:00:00 2001 From: Artem Smotrakov Date: Sat, 6 Mar 2021 22:05:00 +0100 Subject: [PATCH 090/725] Added another example for SpringExporterUnsafeDeserialization.ql --- .../SpringExporterUnsafeDeserialization.qhelp | 15 ++++++++++----- .../SpringExporterUnsafeDeserialization.xml | 4 ++++ 2 files changed, 14 insertions(+), 5 deletions(-) create mode 100644 java/ql/src/experimental/Security/CWE/CWE-502/SpringExporterUnsafeDeserialization.xml diff --git a/java/ql/src/experimental/Security/CWE/CWE-502/SpringExporterUnsafeDeserialization.qhelp b/java/ql/src/experimental/Security/CWE/CWE-502/SpringExporterUnsafeDeserialization.qhelp index ffb8dddae56..da681b7125c 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-502/SpringExporterUnsafeDeserialization.qhelp +++ b/java/ql/src/experimental/Security/CWE/CWE-502/SpringExporterUnsafeDeserialization.qhelp @@ -4,7 +4,7 @@

    The Spring Framework provides an abstract base class RemoteInvocationSerializingExporter -for defining remote service exporters. +for creating remote service exporters. A Spring exporter, which is based on this class, deserializes incoming data using ObjectInputStream. Deserializing untrusted data is easily exploitable and in many cases allows an attacker to execute arbitrary code. @@ -24,7 +24,8 @@ using unsafe ObjectInputStream. If a remote attacker can reach such it results in remote code execution in the worst case.

    -CVE-2016-1000027 has been assigned to this issue in the Spring Framework. It is regarded as a design limitation, and can be mitigated but not fixed outright. +CVE-2016-1000027 has been assigned to this issue in the Spring Framework. +It is regarded as a design limitation, and can be mitigated but not fixed outright.

    @@ -35,16 +36,20 @@ and any other exporter that is based on RemoteInvocationSerializingExporte Instead, use other message formats for API endpoints (for example, JSON), but make sure that the underlying deserialization mechanism is properly configured so that deserialization attacks are not possible. If the vulnerable exporters can not be replaced, -consider using global deserialization filters introduced by JEP 290. -In general, avoid using Java's built-in deserialization methods on untrusted data. +consider using global deserialization filters introduced in JEP 290.

    -The following example defines a vulnerable HTTP endpoint: +The following example shows how a vulnerable HTTP endpoint can be defined +using HttpInvokerServiceExporter and Spring annotations:

    +

    +The next examples shows how the same vulnerable endpoint can be defined in a Spring XML config: +

    +
    diff --git a/java/ql/src/experimental/Security/CWE/CWE-502/SpringExporterUnsafeDeserialization.xml b/java/ql/src/experimental/Security/CWE/CWE-502/SpringExporterUnsafeDeserialization.xml new file mode 100644 index 00000000000..bf058cfffc1 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-502/SpringExporterUnsafeDeserialization.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file From 891b975899bafae5e8777c2f0b9de4c299c7835b Mon Sep 17 00:00:00 2001 From: Artem Smotrakov Date: Sat, 6 Mar 2021 22:07:43 +0100 Subject: [PATCH 091/725] Use correct file names in SpringExporterUnsafeDeserialization.qhelp --- .../CWE/CWE-502/SpringExporterUnsafeDeserialization.qhelp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-502/SpringExporterUnsafeDeserialization.qhelp b/java/ql/src/experimental/Security/CWE/CWE-502/SpringExporterUnsafeDeserialization.qhelp index da681b7125c..04ddac33aaf 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-502/SpringExporterUnsafeDeserialization.qhelp +++ b/java/ql/src/experimental/Security/CWE/CWE-502/SpringExporterUnsafeDeserialization.qhelp @@ -45,11 +45,11 @@ consider using global deserialization filters introduced in JEP 290. The following example shows how a vulnerable HTTP endpoint can be defined using HttpInvokerServiceExporter and Spring annotations:

    - +

    The next examples shows how the same vulnerable endpoint can be defined in a Spring XML config:

    - + From 0ef3eee4edc48adb290ad6f5eb73b4682aa6f33c Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Sat, 6 Mar 2021 22:41:54 +0000 Subject: [PATCH 092/725] Revamp the source and the sink of the query --- .../Security/CWE/CWE-759/HashWithoutSalt.ql | 101 +++++++++++++----- .../security/CWE-759/HashWithoutSalt.expected | 16 ++- .../security/CWE-759/HashWithoutSalt.java | 54 ++++++---- 3 files changed, 121 insertions(+), 50 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql b/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql index 7ea8c7598d2..343a073a27b 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql @@ -9,9 +9,26 @@ import java import semmle.code.java.dataflow.TaintTracking -import semmle.code.java.dataflow.TaintTracking2 import DataFlow::PathGraph +/** + * Gets a regular expression for matching common names of variables + * that indicate the value being held is a password. + */ +string getPasswordRegex() { result = "(?i).*pass(wd|word|code|phrase).*" } + +/** Finds variables that hold password information judging by their names. */ +class PasswordVarExpr extends VarAccess { + PasswordVarExpr() { + exists(string name | name = this.getVariable().getName().toLowerCase() | + name.regexpMatch(getPasswordRegex()) and not name.matches("%hash%") // Exclude variable names such as `passwordHash` since their values were already hashed + ) + } +} + +/** Holds if `Expr` e is a direct or indirect operand of `ae`. */ +predicate hasAddExprAncestor(AddExpr ae, Expr e) { ae.getAnOperand+() = e } + /** The Java class `java.security.MessageDigest`. */ class MessageDigest extends RefType { MessageDigest() { this.hasQualifiedName("java.security", "MessageDigest") } @@ -54,41 +71,66 @@ class MDHashMethodAccess extends MethodAccess { } } -/** Gets a regular expression for matching common names of variables that indicate the value being held is a password. */ -string getPasswordRegex() { result = "(?i).*pass(wd|word|code|phrase).*" } - -/** Finds variables that hold password information judging by their names. */ -class PasswordVarExpr extends VarAccess { - PasswordVarExpr() { - exists(string name | name = this.getVariable().getName().toLowerCase() | - name.regexpMatch(getPasswordRegex()) and not name.matches("%hash%") // Exclude variable names such as `passwordHash` since their values were already hashed - ) - } +/** + * Holds if `MethodAccess` ma is a method access of `MDHashMethodAccess` or + * invokes a method access of `MDHashMethodAccess` directly or indirectly. + */ +predicate isHashAccess(MethodAccess ma) { + ma instanceof MDHashMethodAccess + or + exists(MethodAccess mca | + ma.getMethod().calls(mca.getMethod()) and + isHashAccess(mca) and + DataFlow::localExprFlow(ma.getMethod().getAParameter().getAnAccess(), mca.getAnArgument()) + ) } -/** Holds if `Expr` e is a direct or indirect operand of `ae`. */ -predicate hasAddExprAncestor(AddExpr ae, Expr e) { ae.getAnOperand+() = e } - -/** Holds if `MDHashMethodAccess ma` is a second `MDHashMethodAccess` call by the same object. */ -predicate hasAnotherHashCall(MDHashMethodAccess ma) { - exists(MDHashMethodAccess ma2 | +/** + * Holds if there is a second method access that satisfies `isHashAccess` whose qualifier or argument + * is the same as the method call `ma` that satisfies `isHashAccess`. + */ +predicate hasAnotherHashCall(MethodAccess ma) { + isHashAccess(ma) and + exists(MethodAccess ma2, VarAccess va | ma2 != ma and - ma2.getQualifier() = ma.getQualifier().(VarAccess).getVariable().getAnAccess() + isHashAccess(ma2) and + not va.getVariable().getType() instanceof PrimitiveType and + ( + ma.getQualifier() = va and + ma2.getQualifier() = va.getVariable().getAnAccess() + or + ma.getQualifier() = va and + ma2.getAnArgument() = va.getVariable().getAnAccess() + or + ma.getAnArgument() = va and + ma2.getQualifier() = va.getVariable().getAnAccess() + or + ma.getAnArgument() = va and + ma2.getAnArgument() = va.getVariable().getAnAccess() + ) + ) +} + +/** + * Holds if `MethodAccess` ma is part of a call graph that satisfies `isHashAccess` + * but is not at the top of the call hierarchy. + */ +predicate hasHashAncestor(MethodAccess ma) { + exists(MethodAccess mpa | + mpa.getMethod().calls(ma.getMethod()) and + isHashAccess(mpa) and + DataFlow::localExprFlow(mpa.getMethod().getAParameter().getAnAccess(), ma.getAnArgument()) ) } /** Holds if `MethodAccess` ma is a hashing call without a sibling node making another hashing call. */ -predicate isSingleHashMethodCall(MDHashMethodAccess ma) { not hasAnotherHashCall(ma) } - -/** Holds if `MethodAccess` ma is invoked by `MethodAccess` ma2 either directly or indirectly. */ -predicate hasParentCall(MethodAccess ma2, MethodAccess ma) { ma.getCaller() = ma2.getMethod() } - -/** Holds if `MethodAccess` is a single hashing call that is not invoked by a wrapper method. */ -predicate isSink(MethodAccess ma) { - isSingleHashMethodCall(ma) and - not hasParentCall(_, ma) // Not invoked by a wrapper method which could invoke MDHashMethod in another call stack. This reduces FPs. +predicate isSingleHashMethodCall(MethodAccess ma) { + isHashAccess(ma) and not hasAnotherHashCall(ma) } +/** Holds if `MethodAccess` ma is a single hashing call that is not invoked by a wrapper method. */ +predicate isSink(MethodAccess ma) { isSingleHashMethodCall(ma) and not hasHashAncestor(ma) } + /** Sink of hashing calls. */ class HashWithoutSaltSink extends DataFlow::ExprNode { HashWithoutSaltSink() { @@ -99,7 +141,10 @@ class HashWithoutSaltSink extends DataFlow::ExprNode { } } -/** Taint configuration tracking flow from an expression whose name suggests it holds password data to a method call that generates a hash without a salt. */ +/** + * Taint configuration tracking flow from an expression whose name suggests it holds password data + * to a method call that generates a hash without a salt. + */ class HashWithoutSaltConfiguration extends TaintTracking::Configuration { HashWithoutSaltConfiguration() { this = "HashWithoutSaltConfiguration" } diff --git a/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.expected b/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.expected index fa36297a8a1..b7a5ea8ee4a 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.expected @@ -1,11 +1,19 @@ edges | HashWithoutSalt.java:10:36:10:43 | password : String | HashWithoutSalt.java:10:36:10:54 | getBytes(...) | -| HashWithoutSalt.java:17:13:17:20 | password : String | HashWithoutSalt.java:17:13:17:31 | getBytes(...) | +| HashWithoutSalt.java:25:13:25:20 | password : String | HashWithoutSalt.java:25:13:25:31 | getBytes(...) | +| HashWithoutSalt.java:93:22:93:29 | password : String | HashWithoutSalt.java:94:17:94:25 | passBytes | +| HashWithoutSalt.java:111:22:111:29 | password : String | HashWithoutSalt.java:112:18:112:26 | passBytes | nodes | HashWithoutSalt.java:10:36:10:43 | password : String | semmle.label | password : String | | HashWithoutSalt.java:10:36:10:54 | getBytes(...) | semmle.label | getBytes(...) | -| HashWithoutSalt.java:17:13:17:20 | password : String | semmle.label | password : String | -| HashWithoutSalt.java:17:13:17:31 | getBytes(...) | semmle.label | getBytes(...) | +| HashWithoutSalt.java:25:13:25:20 | password : String | semmle.label | password : String | +| HashWithoutSalt.java:25:13:25:31 | getBytes(...) | semmle.label | getBytes(...) | +| HashWithoutSalt.java:93:22:93:29 | password : String | semmle.label | password : String | +| HashWithoutSalt.java:94:17:94:25 | passBytes | semmle.label | passBytes | +| HashWithoutSalt.java:111:22:111:29 | password : String | semmle.label | password : String | +| HashWithoutSalt.java:112:18:112:26 | passBytes | semmle.label | passBytes | #select | HashWithoutSalt.java:10:36:10:54 | getBytes(...) | HashWithoutSalt.java:10:36:10:43 | password : String | HashWithoutSalt.java:10:36:10:54 | getBytes(...) | $@ is hashed without a salt. | HashWithoutSalt.java:10:36:10:43 | password : String | The password | -| HashWithoutSalt.java:17:13:17:31 | getBytes(...) | HashWithoutSalt.java:17:13:17:20 | password : String | HashWithoutSalt.java:17:13:17:31 | getBytes(...) | $@ is hashed without a salt. | HashWithoutSalt.java:17:13:17:20 | password : String | The password | +| HashWithoutSalt.java:25:13:25:31 | getBytes(...) | HashWithoutSalt.java:25:13:25:20 | password : String | HashWithoutSalt.java:25:13:25:31 | getBytes(...) | $@ is hashed without a salt. | HashWithoutSalt.java:25:13:25:20 | password : String | The password | +| HashWithoutSalt.java:94:17:94:25 | passBytes | HashWithoutSalt.java:93:22:93:29 | password : String | HashWithoutSalt.java:94:17:94:25 | passBytes | $@ is hashed without a salt. | HashWithoutSalt.java:93:22:93:29 | password : String | The password | +| HashWithoutSalt.java:112:18:112:26 | passBytes | HashWithoutSalt.java:111:22:111:29 | password : String | HashWithoutSalt.java:112:18:112:26 | passBytes | $@ is hashed without a salt. | HashWithoutSalt.java:111:22:111:29 | password : String | The password | diff --git a/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.java b/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.java index 026ccfa70be..48911486db1 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.java +++ b/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.java @@ -11,14 +11,6 @@ public class HashWithoutSalt { return Base64.getEncoder().encodeToString(messageDigest); } - // BAD - Hash without a salt. - public String getSHA256Hash2(String password) throws NoSuchAlgorithmException { - MessageDigest md = MessageDigest.getInstance("SHA-256"); - md.update(password.getBytes()); - byte[] messageDigest = md.digest(); - return Base64.getEncoder().encodeToString(messageDigest); - } - // GOOD - Hash with a salt. public String getSHA256Hash(String password, byte[] salt) throws NoSuchAlgorithmException { MessageDigest md = MessageDigest.getInstance("SHA-256"); @@ -27,6 +19,14 @@ public class HashWithoutSalt { return Base64.getEncoder().encodeToString(messageDigest); } + // BAD - Hash without a salt. + public String getSHA256Hash2(String password) throws NoSuchAlgorithmException { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + md.update(password.getBytes()); + byte[] messageDigest = md.digest(); + return Base64.getEncoder().encodeToString(messageDigest); + } + // GOOD - Hash with a salt. public String getSHA256Hash2(String password, byte[] salt) throws NoSuchAlgorithmException { MessageDigest md = MessageDigest.getInstance("SHA-256"); @@ -77,8 +77,8 @@ public class HashWithoutSalt { sha256.update(foo, start, len); } - // BAD - Invoking a wrapper implementation without a salt is not detected. - public String getSHA256Hash4(String password) throws NoSuchAlgorithmException, ClassNotFoundException, IllegalAccessException, InstantiationException { + // GOOD - Invoking a wrapper implementation through qualifier with a salt. + public String getWrapperSHA256Hash(String password) throws NoSuchAlgorithmException, ClassNotFoundException, IllegalAccessException, InstantiationException { SHA256 sha256 = new SHA256(); byte[] salt = getSalt(); byte[] passBytes = password.getBytes(); @@ -87,8 +87,16 @@ public class HashWithoutSalt { return Base64.getEncoder().encodeToString(sha256.digest()); } - // BAD - Invoking a wrapper implementation without a salt is not detected. - public String getSHA256Hash5(String password) throws NoSuchAlgorithmException { + // BAD - Invoking a wrapper implementation through qualifier without a salt. + public String getWrapperSHA256Hash2(String password) throws NoSuchAlgorithmException, ClassNotFoundException, IllegalAccessException, InstantiationException { + SHA256 sha256 = new SHA256(); + byte[] passBytes = password.getBytes(); + sha256.update(passBytes, 0, passBytes.length); + return Base64.getEncoder().encodeToString(sha256.digest()); + } + + // GOOD - Invoking a wrapper implementation through qualifier and argument with a salt. + public String getWrapperSHA256Hash3(String password) throws NoSuchAlgorithmException { SHA256 sha256 = new SHA256(); byte[] salt = getSalt(); byte[] passBytes = password.getBytes(); @@ -97,16 +105,26 @@ public class HashWithoutSalt { return Base64.getEncoder().encodeToString(sha256.digest()); } - // BAD - Invoking a wrapper implementation without a salt is not detected. - public String getSHA512Hash6(String password) throws NoSuchAlgorithmException { - SHA512 sha512 = new SHA512(); + // BAD - Invoking a wrapper implementation through argument without a salt. + public String getWrapperSHA256Hash4(String password) throws NoSuchAlgorithmException { + SHA256 sha256 = new SHA256(); byte[] passBytes = password.getBytes(); - sha512.update(passBytes, 0, passBytes.length); - return Base64.getEncoder().encodeToString(sha512.digest()); + update(sha256, passBytes, 0, passBytes.length); + return Base64.getEncoder().encodeToString(sha256.digest()); + } + + // GOOD - Invoking a wrapper implementation through argument with a salt. + public String getWrapperSHA256Hash5(String password) throws NoSuchAlgorithmException { + SHA256 sha256 = new SHA256(); + byte[] salt = getSalt(); + byte[] passBytes = password.getBytes(); + update(sha256, passBytes, 0, passBytes.length); + update(sha256, salt, 0, salt.length); + return Base64.getEncoder().encodeToString(sha256.digest()); } // BAD - Invoke a wrapper implementation with a salt, which is not detected with an interface type variable. - public String getSHA512Hash7(byte[] passphrase) throws NoSuchAlgorithmException, ClassNotFoundException, IllegalAccessException, InstantiationException { + public String getSHA512Hash8(byte[] passphrase) throws NoSuchAlgorithmException, ClassNotFoundException, IllegalAccessException, InstantiationException { Class c = Class.forName("SHA512"); HASH sha512 = (HASH) (c.newInstance()); byte[] tmp = new byte[4]; From bb53780ba9aa9278deb35f1f6c23d1a719546e9b Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Mon, 8 Mar 2021 09:42:47 +0100 Subject: [PATCH 093/725] C++: Add flow through unary instructions and pointer/indirection conflation for parameters. These rules are copy/pasted from DefaultTaintTracking. The conflation rules will hopefully be removed as part of #5089. --- .../dataflow/internal/TaintTrackingUtil.qll | 39 ++++++++++++++++++- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll index 1f7808c5b5b..ab1177daea9 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll @@ -64,14 +64,26 @@ private predicate operandToInstructionTaintStep(Operand opFrom, Instruction inst or instrTo instanceof PointerArithmeticInstruction or - instrTo.(FieldAddressInstruction).getField().getDeclaringType() instanceof Union - or // The `CopyInstruction` case is also present in non-taint data flow, but // that uses `getDef` rather than `getAnyDef`. For taint, we want flow // from a definition of `myStruct` to a `myStruct.myField` expression. instrTo instanceof CopyInstruction ) or + // Unary instructions tend to preserve enough information in practice that we + // want taint to flow through. + // The exception is `FieldAddressInstruction`. Together with the rules below for + // `LoadInstruction`s and `ChiInstruction`s, flow through `FieldAddressInstruction` + // could cause flow into one field to come out an unrelated field. + // This would happen across function boundaries, where the IR would not be able to + // match loads to stores. + instrTo.(UnaryInstruction).getUnaryOperand() = opFrom and + ( + not instrTo instanceof FieldAddressInstruction + or + instrTo.(FieldAddressInstruction).getField().getDeclaringType() instanceof Union + ) + or instrTo.(LoadInstruction).getSourceAddressOperand() = opFrom or // Flow from an element to an array or union that contains it. @@ -83,6 +95,29 @@ private predicate operandToInstructionTaintStep(Operand opFrom, Instruction inst t instanceof ArrayType ) or + // Until we have flow through indirections across calls, we'll take flow out + // of the indirection and into the argument. + // When we get proper flow through indirections across calls, this code can be + // moved to `adjusedSink` or possibly into the `DataFlow::ExprNode` class. + exists(ReadSideEffectInstruction read | + read.getSideEffectOperand() = opFrom and + read.getArgumentDef() = instrTo + ) + or + // Until we have from through indirections across calls, we'll take flow out + // of the parameter and into its indirection. + // `InitializeIndirectionInstruction` only has a single operand: the address of the + // value whose indirection we are initializing. When initializing an indirection of a parameter `p`, + // the IR looks like this: + // ``` + // m1 = InitializeParameter[p] : &r1 + // r2 = Load[p] : r2, m1 + // m3 = InitializeIndirection[p] : &r2 + // ``` + // So by having flow from `r2` to `m3` we're enabling flow from `m1` to `m3`. This relies on the + // `LoadOperand`'s overlap being exact. + instrTo.(InitializeIndirectionInstruction).getAnOperand() = opFrom + or modeledTaintStep(opFrom, instrTo) } From a78f2115f22cf0becb7214bc4fed48c75bbfa617 Mon Sep 17 00:00:00 2001 From: Artem Smotrakov Date: Tue, 9 Mar 2021 00:02:57 +0300 Subject: [PATCH 094/725] Split SpringExporterUnsafeDeserialization.ql --- ...eSpringExporterInConfigurationClass.qhelp} | 4 - ...safeSpringExporterInConfigurationClass.ql} | 37 ++------- ...safeSpringExporterInXMLConfiguration.qhelp | 81 +++++++++++++++++++ .../UnsafeSpringExporterInXMLConfiguration.ql | 20 +++++ .../CWE/CWE-502/UnsafeSpringExporterLib.qll | 9 +++ ...ringExporterUnsafeDeserialization.expected | 4 - .../SpringExporterUnsafeDeserialization.qlref | 1 - ...pringExporterInConfigurationClass.expected | 2 + ...feSpringExporterInConfigurationClass.qlref | 1 + ...eSpringExporterInXMLConfiguration.expected | 2 + ...safeSpringExporterInXMLConfiguration.qlref | 1 + 11 files changed, 122 insertions(+), 40 deletions(-) rename java/ql/src/experimental/Security/CWE/CWE-502/{SpringExporterUnsafeDeserialization.qhelp => UnsafeSpringExporterInConfigurationClass.qhelp} (94%) rename java/ql/src/experimental/Security/CWE/CWE-502/{SpringExporterUnsafeDeserialization.ql => UnsafeSpringExporterInConfigurationClass.ql} (52%) create mode 100644 java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInXMLConfiguration.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInXMLConfiguration.ql create mode 100644 java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterLib.qll delete mode 100644 java/ql/test/experimental/query-tests/security/CWE-502/SpringExporterUnsafeDeserialization.expected delete mode 100644 java/ql/test/experimental/query-tests/security/CWE-502/SpringExporterUnsafeDeserialization.qlref create mode 100644 java/ql/test/experimental/query-tests/security/CWE-502/UnsafeSpringExporterInConfigurationClass.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-502/UnsafeSpringExporterInConfigurationClass.qlref create mode 100644 java/ql/test/experimental/query-tests/security/CWE-502/UnsafeSpringExporterInXMLConfiguration.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-502/UnsafeSpringExporterInXMLConfiguration.qlref diff --git a/java/ql/src/experimental/Security/CWE/CWE-502/SpringExporterUnsafeDeserialization.qhelp b/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInConfigurationClass.qhelp similarity index 94% rename from java/ql/src/experimental/Security/CWE/CWE-502/SpringExporterUnsafeDeserialization.qhelp rename to java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInConfigurationClass.qhelp index 04ddac33aaf..87a57b0a43c 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-502/SpringExporterUnsafeDeserialization.qhelp +++ b/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInConfigurationClass.qhelp @@ -46,10 +46,6 @@ The following example shows how a vulnerable HTTP endpoint can be defined using HttpInvokerServiceExporter and Spring annotations:

    -

    -The next examples shows how the same vulnerable endpoint can be defined in a Spring XML config: -

    - diff --git a/java/ql/src/experimental/Security/CWE/CWE-502/SpringExporterUnsafeDeserialization.ql b/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInConfigurationClass.ql similarity index 52% rename from java/ql/src/experimental/Security/CWE/CWE-502/SpringExporterUnsafeDeserialization.ql rename to java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInConfigurationClass.ql index 417f1c8790b..34605d16fbd 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-502/SpringExporterUnsafeDeserialization.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInConfigurationClass.ql @@ -6,28 +6,13 @@ * @kind problem * @problem.severity error * @precision high - * @id java/spring-exporter-unsafe-deserialization + * @id java/unsafe-deserialization-spring-exporter-in-configuration-class * @tags security * external/cwe/cwe-502 */ import java -import semmle.code.java.frameworks.spring.SpringBean - -/** - * Holds if `type` is `RemoteInvocationSerializingExporter`. - */ -private predicate isRemoteInvocationSerializingExporter(RefType type) { - type.getASupertype*() - .hasQualifiedName("org.springframework.remoting.rmi", "RemoteInvocationSerializingExporter") -} - -/** - * Holds if `method` belongs to a Spring configuration. - */ -private predicate isInConfiguration(Method method) { - method.getDeclaringType().hasAnnotation("org.springframework.context.annotation", "Configuration") -} +import UnsafeSpringExporterLib /** * A method that initializes a unsafe bean based on `RemoteInvocationSerializingExporter`. @@ -36,8 +21,8 @@ private class UnsafeBeanInitMethod extends Method { string identifier; UnsafeBeanInitMethod() { - isInConfiguration(this) and isRemoteInvocationSerializingExporter(this.getReturnType()) and + this.getDeclaringType().hasAnnotation("org.springframework.context.annotation", "Configuration") and exists(Annotation a | a.getType().hasQualifiedName("org.springframework.context.annotation", "Bean") | @@ -51,16 +36,6 @@ private class UnsafeBeanInitMethod extends Method { string getBeanIdentifier() { result = identifier } } -from File file, string identifier -where - exists(UnsafeBeanInitMethod method | - file = method.getFile() and - identifier = method.getBeanIdentifier() - ) - or - exists(SpringBean bean | - isRemoteInvocationSerializingExporter(bean.getClass()) and - file = bean.getFile() and - identifier = bean.getBeanIdentifier() - ) -select file, "Unsafe deserialization in Spring exporter bean '" + identifier + "'" +from UnsafeBeanInitMethod method +select method, + "Unsafe deserialization in a Spring exporter bean '" + method.getBeanIdentifier() + "'" diff --git a/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInXMLConfiguration.qhelp b/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInXMLConfiguration.qhelp new file mode 100644 index 00000000000..dcefdfb97b0 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInXMLConfiguration.qhelp @@ -0,0 +1,81 @@ + + + + +

    +The Spring Framework provides an abstract base class RemoteInvocationSerializingExporter +for creating remote service exporters. +A Spring exporter, which is based on this class, deserializes incoming data using ObjectInputStream. +Deserializing untrusted data is easily exploitable and in many cases allows an attacker +to execute arbitrary code. +

    +

    +The Spring Framework also provides two classes that extend RemoteInvocationSerializingExporter: +

  • +HttpInvokerServiceExporter +
  • +
  • +SimpleHttpInvokerServiceExporter +
  • +

    +

    +These classes export specified beans as HTTP endpoints that deserialize data from an HTTP request +using unsafe ObjectInputStream. If a remote attacker can reach such endpoints, +it results in remote code execution in the worst case. +

    +

    +CVE-2016-1000027 has been assigned to this issue in the Spring Framework. +It is regarded as a design limitation, and can be mitigated but not fixed outright. +

    +
    + + +

    +Avoid using HttpInvokerServiceExporter, SimpleHttpInvokerServiceExporter +and any other exporter that is based on RemoteInvocationSerializingExporter. +Instead, use other message formats for API endpoints (for example, JSON), +but make sure that the underlying deserialization mechanism is properly configured +so that deserialization attacks are not possible. If the vulnerable exporters can not be replaced, +consider using global deserialization filters introduced in JEP 290. +

    +
    + + +

    +The following examples shows how a vulnerable HTTP endpoint can be defined in a Spring XML config: +

    + +
    + + +
  • +OWASP: +Deserialization of untrusted data. +
  • +
  • +Spring Framework API documentation: +RemoteInvocationSerializingExporter class +
  • +
  • +Spring Framework API documentation: +HttpInvokerServiceExporter class +
  • +
  • +National Vulnerability Database: +CVE-2016-1000027 +
  • +
  • +Tenable Research Advisory: +[R2] Pivotal Spring Framework HttpInvokerServiceExporter readRemoteInvocation Method Untrusted Java Deserialization +
  • +
  • +Spring Framework bug tracker: +Sonatype vulnerability CVE-2016-1000027 in Spring-web project +
  • +
  • +OpenJDK: +JEP 290: Filter Incoming Serialization Data +
  • +
    + +
    \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInXMLConfiguration.ql b/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInXMLConfiguration.ql new file mode 100644 index 00000000000..d7606587df3 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInXMLConfiguration.ql @@ -0,0 +1,20 @@ +/** + * @name Unsafe deserialization with Spring's remote service exporters. + * @description A Spring bean, which is based on RemoteInvocationSerializingExporter, + * initializes an endpoint that uses ObjectInputStream to deserialize + * incoming data. In the worst case, that may lead to remote code execution. + * @kind problem + * @problem.severity error + * @precision high + * @id java/unsafe-deserialization-spring-exporter-in-xml-configuration + * @tags security + * external/cwe/cwe-502 + */ + +import java +import semmle.code.java.frameworks.spring.SpringBean +import UnsafeSpringExporterLib + +from SpringBean bean +where isRemoteInvocationSerializingExporter(bean.getClass()) +select bean, "Unsafe deserialization in a Spring exporter bean '" + bean.getBeanIdentifier() + "'" diff --git a/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterLib.qll b/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterLib.qll new file mode 100644 index 00000000000..f49ee44304f --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterLib.qll @@ -0,0 +1,9 @@ +import java + +/** + * Holds if `type` is `RemoteInvocationSerializingExporter`. + */ +predicate isRemoteInvocationSerializingExporter(RefType type) { + type.getASupertype*() + .hasQualifiedName("org.springframework.remoting.rmi", "RemoteInvocationSerializingExporter") +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-502/SpringExporterUnsafeDeserialization.expected b/java/ql/test/experimental/query-tests/security/CWE-502/SpringExporterUnsafeDeserialization.expected deleted file mode 100644 index 1b5c1d2e67d..00000000000 --- a/java/ql/test/experimental/query-tests/security/CWE-502/SpringExporterUnsafeDeserialization.expected +++ /dev/null @@ -1,4 +0,0 @@ -| SpringExporterUnsafeDeserialization.java:0:0:0:0 | SpringExporterUnsafeDeserialization | Unsafe deserialization in Spring exporter bean '/unsafeCustomeRemoteInvocationSerializingExporter' | -| SpringExporterUnsafeDeserialization.java:0:0:0:0 | SpringExporterUnsafeDeserialization | Unsafe deserialization in Spring exporter bean '/unsafeHttpInvokerServiceExporter' | -| beans.xml:0:0:0:0 | beans.xml | Unsafe deserialization in Spring exporter bean '/unsafeBooking' | -| beans.xml:0:0:0:0 | beans.xml | Unsafe deserialization in Spring exporter bean 'org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter' | diff --git a/java/ql/test/experimental/query-tests/security/CWE-502/SpringExporterUnsafeDeserialization.qlref b/java/ql/test/experimental/query-tests/security/CWE-502/SpringExporterUnsafeDeserialization.qlref deleted file mode 100644 index 7be52b73cba..00000000000 --- a/java/ql/test/experimental/query-tests/security/CWE-502/SpringExporterUnsafeDeserialization.qlref +++ /dev/null @@ -1 +0,0 @@ -experimental/Security/CWE/CWE-502/SpringExporterUnsafeDeserialization.ql \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-502/UnsafeSpringExporterInConfigurationClass.expected b/java/ql/test/experimental/query-tests/security/CWE-502/UnsafeSpringExporterInConfigurationClass.expected new file mode 100644 index 00000000000..926eff89403 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-502/UnsafeSpringExporterInConfigurationClass.expected @@ -0,0 +1,2 @@ +| SpringExporterUnsafeDeserialization.java:10:32:10:63 | unsafeHttpInvokerServiceExporter | Unsafe deserialization in a Spring exporter bean '/unsafeHttpInvokerServiceExporter' | +| SpringExporterUnsafeDeserialization.java:18:41:18:88 | unsafeCustomeRemoteInvocationSerializingExporter | Unsafe deserialization in a Spring exporter bean '/unsafeCustomeRemoteInvocationSerializingExporter' | diff --git a/java/ql/test/experimental/query-tests/security/CWE-502/UnsafeSpringExporterInConfigurationClass.qlref b/java/ql/test/experimental/query-tests/security/CWE-502/UnsafeSpringExporterInConfigurationClass.qlref new file mode 100644 index 00000000000..823c7735ec5 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-502/UnsafeSpringExporterInConfigurationClass.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-502/UnsafeSpringExporterInConfigurationClass.ql \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-502/UnsafeSpringExporterInXMLConfiguration.expected b/java/ql/test/experimental/query-tests/security/CWE-502/UnsafeSpringExporterInXMLConfiguration.expected new file mode 100644 index 00000000000..edcb3668557 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-502/UnsafeSpringExporterInXMLConfiguration.expected @@ -0,0 +1,2 @@ +| beans.xml:10:5:13:12 | /unsafeBooking | Unsafe deserialization in a Spring exporter bean '/unsafeBooking' | +| beans.xml:15:5:18:12 | org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter | Unsafe deserialization in a Spring exporter bean 'org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter' | diff --git a/java/ql/test/experimental/query-tests/security/CWE-502/UnsafeSpringExporterInXMLConfiguration.qlref b/java/ql/test/experimental/query-tests/security/CWE-502/UnsafeSpringExporterInXMLConfiguration.qlref new file mode 100644 index 00000000000..46024a0b6b3 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-502/UnsafeSpringExporterInXMLConfiguration.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-502/UnsafeSpringExporterInXMLConfiguration.ql \ No newline at end of file From 48975fa7d220b7debe5d0c8a0b84c8ec64351435 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Wed, 10 Mar 2021 00:17:26 +0000 Subject: [PATCH 095/725] Replace sanitizers --- .../CWE-1004/SensitiveCookieNotHttpOnly.ql | 105 +++++++----------- 1 file changed, 41 insertions(+), 64 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql b/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql index 229a9d50325..716975d0486 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql @@ -50,23 +50,6 @@ class CookieClass extends RefType { } } -/** The method call `toString` to get a stringified cookie representation. */ -class CookieInstanceExpr extends TaintPreservingCallable { - CookieInstanceExpr() { - this.getDeclaringType() instanceof CookieClass and - this.hasName("toString") - } - - override predicate returnsTaintFrom(int arg) { arg = -1 } -} - -/** The cookie constructor. */ -class CookieTaintPreservingConstructor extends Constructor, TaintPreservingCallable { - CookieTaintPreservingConstructor() { this.getDeclaringType() instanceof CookieClass } - - override predicate returnsTaintFrom(int arg) { arg = 0 } -} - /** Sensitive cookie name used in a `Cookie` constructor or a `Set-Cookie` call. */ class SensitiveCookieNameExpr extends Expr { SensitiveCookieNameExpr() { isSensitiveCookieNameExpr(this) } @@ -78,55 +61,58 @@ class CookieResponseSink extends DataFlow::ExprNode { exists(MethodAccess ma | ( ma.getMethod() instanceof ResponseAddCookieMethod and - this.getExpr() = ma.getArgument(0) + this.getExpr() = ma.getArgument(0) and + not exists( + MethodAccess ma2 // cookie.setHttpOnly(true) + | + ma2.getMethod().getName() = "setHttpOnly" and + ma2.getArgument(0).(BooleanLiteral).getBooleanValue() = true and + DataFlow::localExprFlow(ma2.getQualifier(), this.getExpr()) + ) or ma instanceof SetCookieMethodAccess and - this.getExpr() = ma.getArgument(1) + this.getExpr() = ma.getArgument(1) and + not hasHttpOnlyExpr(this.getExpr()) // response.addHeader("Set-Cookie", "token=" +authId + ";HttpOnly;Secure") ) ) } } -/** - * Holds if `node` is an access to a variable which has `setHttpOnly(true)` called on it and is also - * the first argument to a call to the method `addCookie` of `javax.servlet.http.HttpServletResponse`. - */ -predicate setHttpOnlyMethodAccess(DataFlow::Node node) { - exists( - MethodAccess addCookie, Variable cookie, MethodAccess m // jwtCookie.setHttpOnly(true) - | - addCookie.getMethod() instanceof ResponseAddCookieMethod and - addCookie.getArgument(0) = cookie.getAnAccess() and - m.getMethod().getName() = "setHttpOnly" and - m.getArgument(0).(BooleanLiteral).getBooleanValue() = true and - m.getQualifier() = cookie.getAnAccess() and - node.asExpr() = cookie.getAnAccess() - ) +/** A JAX-RS `NewCookie` constructor that sets `HttpOnly` to true. */ +class HttpOnlyNewCookie extends ClassInstanceExpr { + HttpOnlyNewCookie() { + this.getConstructedType() + .hasQualifiedName(["javax.ws.rs.core", "jakarta.ws.rs.core"], "NewCookie") and + ( + this.getNumArgument() = 6 and this.getArgument(5).(BooleanLiteral).getBooleanValue() = true // NewCookie(Cookie cookie, String comment, int maxAge, Date expiry, boolean secure, boolean httpOnly) + or + this.getNumArgument() = 8 and + this.getArgument(6).getType() instanceof BooleanType and + this.getArgument(7).(BooleanLiteral).getBooleanValue() = true // NewCookie(String name, String value, String path, String domain, String comment, int maxAge, boolean secure, boolean httpOnly) + or + this.getNumArgument() = 10 and this.getArgument(9).(BooleanLiteral).getBooleanValue() = true // NewCookie(String name, String value, String path, String domain, int version, String comment, int maxAge, Date expiry, boolean secure, boolean httpOnly) + ) + } } -/** - * Holds if `node` is a string that contains `httponly` and which flows to the second argument - * of a method to set a cookie. - */ -predicate setHttpOnlyInSetCookie(DataFlow::Node node) { - exists(SetCookieMethodAccess sa | - hasHttpOnlyExpr(node.asExpr()) and - DataFlow::localExprFlow(node.asExpr(), sa.getArgument(1)) - ) +/** The cookie constructor. */ +class CookieTaintPreservingConstructor extends Constructor, TaintPreservingCallable { + CookieTaintPreservingConstructor() { + this.getDeclaringType() instanceof CookieClass and + not exists(HttpOnlyNewCookie hie | hie.getConstructor() = this) + } + + override predicate returnsTaintFrom(int arg) { arg = 0 } } -/** Holds if `cie` is an invocation of a JAX-RS `NewCookie` constructor that sets `HttpOnly` to true. */ -predicate setHttpOnlyInNewCookie(ClassInstanceExpr cie) { - cie.getConstructedType().hasQualifiedName(["javax.ws.rs.core", "jakarta.ws.rs.core"], "NewCookie") and - ( - cie.getNumArgument() = 6 and cie.getArgument(5).(BooleanLiteral).getBooleanValue() = true // NewCookie(Cookie cookie, String comment, int maxAge, Date expiry, boolean secure, boolean httpOnly) - or - cie.getNumArgument() = 8 and - cie.getArgument(6).getType() instanceof BooleanType and - cie.getArgument(7).(BooleanLiteral).getBooleanValue() = true // NewCookie(String name, String value, String path, String domain, String comment, int maxAge, boolean secure, boolean httpOnly) - or - cie.getNumArgument() = 10 and cie.getArgument(9).(BooleanLiteral).getBooleanValue() = true // NewCookie(String name, String value, String path, String domain, int version, String comment, int maxAge, Date expiry, boolean secure, boolean httpOnly) - ) +/** The method call `toString` to get a stringified cookie representation. */ +class CookieInstanceExpr extends TaintPreservingCallable { + CookieInstanceExpr() { + this.getDeclaringType() instanceof CookieClass and + this.hasName("toString") + } + + override predicate returnsTaintFrom(int arg) { arg = -1 } } /** @@ -163,15 +149,6 @@ class MissingHttpOnlyConfiguration extends TaintTracking::Configuration { override predicate isSink(DataFlow::Node sink) { sink instanceof CookieResponseSink } override predicate isSanitizer(DataFlow::Node node) { - // cookie.setHttpOnly(true) - setHttpOnlyMethodAccess(node) - or - // response.addHeader("Set-Cookie", "token=" +authId + ";HttpOnly;Secure") - setHttpOnlyInSetCookie(node) - or - // new NewCookie("session-access-key", accessKey, "/", null, null, 0, true, true) - setHttpOnlyInNewCookie(node.asExpr()) - or // Test class or method isTestMethod(node) } From df60268023493fe0fa6a4aa723f22435fb769451 Mon Sep 17 00:00:00 2001 From: Artem Smotrakov Date: Wed, 10 Mar 2021 10:38:08 +0300 Subject: [PATCH 096/725] Split qhelp files --- ...feSpringExporterInConfigurationClass.qhelp | 86 ++----------------- ...orterInConfigurationClassExample.inc.qhelp | 14 +++ ...safeSpringExporterInXMLConfiguration.qhelp | 85 ++---------------- ...xporterInXMLConfigurationExample.inc.qhelp | 13 +++ .../UnsafeSpringExporterQuery.inc.qhelp | 41 +++++++++ .../UnsafeSpringExporterReferences.inc.qhelp | 37 ++++++++ 6 files changed, 117 insertions(+), 159 deletions(-) create mode 100644 java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInConfigurationClassExample.inc.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInXMLConfigurationExample.inc.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterQuery.inc.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterReferences.inc.qhelp diff --git a/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInConfigurationClass.qhelp b/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInConfigurationClass.qhelp index 87a57b0a43c..8580092b8a1 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInConfigurationClass.qhelp +++ b/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInConfigurationClass.qhelp @@ -1,82 +1,8 @@ - + - - -

    -The Spring Framework provides an abstract base class RemoteInvocationSerializingExporter -for creating remote service exporters. -A Spring exporter, which is based on this class, deserializes incoming data using ObjectInputStream. -Deserializing untrusted data is easily exploitable and in many cases allows an attacker -to execute arbitrary code. -

    -

    -The Spring Framework also provides two classes that extend RemoteInvocationSerializingExporter: -

  • -HttpInvokerServiceExporter -
  • -
  • -SimpleHttpInvokerServiceExporter -
  • -

    -

    -These classes export specified beans as HTTP endpoints that deserialize data from an HTTP request -using unsafe ObjectInputStream. If a remote attacker can reach such endpoints, -it results in remote code execution in the worst case. -

    -

    -CVE-2016-1000027 has been assigned to this issue in the Spring Framework. -It is regarded as a design limitation, and can be mitigated but not fixed outright. -

    -
    - - -

    -Avoid using HttpInvokerServiceExporter, SimpleHttpInvokerServiceExporter -and any other exporter that is based on RemoteInvocationSerializingExporter. -Instead, use other message formats for API endpoints (for example, JSON), -but make sure that the underlying deserialization mechanism is properly configured -so that deserialization attacks are not possible. If the vulnerable exporters can not be replaced, -consider using global deserialization filters introduced in JEP 290. -

    -
    - - -

    -The following example shows how a vulnerable HTTP endpoint can be defined -using HttpInvokerServiceExporter and Spring annotations: -

    - -
    - - -
  • -OWASP: -Deserialization of untrusted data. -
  • -
  • -Spring Framework API documentation: -RemoteInvocationSerializingExporter class -
  • -
  • -Spring Framework API documentation: -HttpInvokerServiceExporter class -
  • -
  • -National Vulnerability Database: -CVE-2016-1000027 -
  • -
  • -Tenable Research Advisory: -[R2] Pivotal Spring Framework HttpInvokerServiceExporter readRemoteInvocation Method Untrusted Java Deserialization -
  • -
  • -Spring Framework bug tracker: -Sonatype vulnerability CVE-2016-1000027 in Spring-web project -
  • -
  • -OpenJDK: -JEP 290: Filter Incoming Serialization Data -
  • -
    - + + +
    \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInConfigurationClassExample.inc.qhelp b/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInConfigurationClassExample.inc.qhelp new file mode 100644 index 00000000000..ed33a03fabe --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInConfigurationClassExample.inc.qhelp @@ -0,0 +1,14 @@ + + + + +

    +The following example shows how a vulnerable HTTP endpoint can be defined +using HttpInvokerServiceExporter and Spring annotations: +

    + +
    + +
    \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInXMLConfiguration.qhelp b/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInXMLConfiguration.qhelp index dcefdfb97b0..76dda5842b3 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInXMLConfiguration.qhelp +++ b/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInXMLConfiguration.qhelp @@ -1,81 +1,8 @@ - + - - -

    -The Spring Framework provides an abstract base class RemoteInvocationSerializingExporter -for creating remote service exporters. -A Spring exporter, which is based on this class, deserializes incoming data using ObjectInputStream. -Deserializing untrusted data is easily exploitable and in many cases allows an attacker -to execute arbitrary code. -

    -

    -The Spring Framework also provides two classes that extend RemoteInvocationSerializingExporter: -

  • -HttpInvokerServiceExporter -
  • -
  • -SimpleHttpInvokerServiceExporter -
  • -

    -

    -These classes export specified beans as HTTP endpoints that deserialize data from an HTTP request -using unsafe ObjectInputStream. If a remote attacker can reach such endpoints, -it results in remote code execution in the worst case. -

    -

    -CVE-2016-1000027 has been assigned to this issue in the Spring Framework. -It is regarded as a design limitation, and can be mitigated but not fixed outright. -

    -
    - - -

    -Avoid using HttpInvokerServiceExporter, SimpleHttpInvokerServiceExporter -and any other exporter that is based on RemoteInvocationSerializingExporter. -Instead, use other message formats for API endpoints (for example, JSON), -but make sure that the underlying deserialization mechanism is properly configured -so that deserialization attacks are not possible. If the vulnerable exporters can not be replaced, -consider using global deserialization filters introduced in JEP 290. -

    -
    - - -

    -The following examples shows how a vulnerable HTTP endpoint can be defined in a Spring XML config: -

    - -
    - - -
  • -OWASP: -Deserialization of untrusted data. -
  • -
  • -Spring Framework API documentation: -RemoteInvocationSerializingExporter class -
  • -
  • -Spring Framework API documentation: -HttpInvokerServiceExporter class -
  • -
  • -National Vulnerability Database: -CVE-2016-1000027 -
  • -
  • -Tenable Research Advisory: -[R2] Pivotal Spring Framework HttpInvokerServiceExporter readRemoteInvocation Method Untrusted Java Deserialization -
  • -
  • -Spring Framework bug tracker: -Sonatype vulnerability CVE-2016-1000027 in Spring-web project -
  • -
  • -OpenJDK: -JEP 290: Filter Incoming Serialization Data -
  • -
    - + + +
    \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInXMLConfigurationExample.inc.qhelp b/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInXMLConfigurationExample.inc.qhelp new file mode 100644 index 00000000000..bc18f4dc233 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInXMLConfigurationExample.inc.qhelp @@ -0,0 +1,13 @@ + + + + +

    +The following examples shows how a vulnerable HTTP endpoint can be defined in a Spring XML config: +

    + +
    + +
    \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterQuery.inc.qhelp b/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterQuery.inc.qhelp new file mode 100644 index 00000000000..732c5c7e545 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterQuery.inc.qhelp @@ -0,0 +1,41 @@ + + + + +

    +The Spring Framework provides an abstract base class RemoteInvocationSerializingExporter +for creating remote service exporters. +A Spring exporter, which is based on this class, deserializes incoming data using ObjectInputStream. +Deserializing untrusted data is easily exploitable and in many cases allows an attacker +to execute arbitrary code. +

    +

    +The Spring Framework also provides HttpInvokerServiceExporter +and SimpleHttpInvokerServiceExporter classes +that extend RemoteInvocationSerializingExporter. +

    +

    +These classes export specified beans as HTTP endpoints that deserialize data from an HTTP request +using unsafe ObjectInputStream. If a remote attacker can reach such endpoints, +it results in remote code execution in the worst case. +

    +

    +CVE-2016-1000027 has been assigned to this issue in the Spring Framework. +It is regarded as a design limitation, and can be mitigated but not fixed outright. +

    +
    + + +

    +Avoid using HttpInvokerServiceExporter, SimpleHttpInvokerServiceExporter +and any other exporter that is based on RemoteInvocationSerializingExporter. +Instead, use other message formats for API endpoints (for example, JSON), +but make sure that the underlying deserialization mechanism is properly configured +so that deserialization attacks are not possible. If the vulnerable exporters can not be replaced, +consider using global deserialization filters introduced in JEP 290. +

    +
    + +
    \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterReferences.inc.qhelp b/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterReferences.inc.qhelp new file mode 100644 index 00000000000..94d269e35d0 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterReferences.inc.qhelp @@ -0,0 +1,37 @@ + + + + +
  • +OWASP: +Deserialization of untrusted data. +
  • +
  • +Spring Framework API documentation: +RemoteInvocationSerializingExporter class +
  • +
  • +Spring Framework API documentation: +HttpInvokerServiceExporter class +
  • +
  • +National Vulnerability Database: +CVE-2016-1000027 +
  • +
  • +Tenable Research Advisory: +[R2] Pivotal Spring Framework HttpInvokerServiceExporter readRemoteInvocation Method Untrusted Java Deserialization +
  • +
  • +Spring Framework bug tracker: +Sonatype vulnerability CVE-2016-1000027 in Spring-web project +
  • +
  • +OpenJDK: +JEP 290: Filter Incoming Serialization Data +
  • +
    + +
    \ No newline at end of file From 4941d9b7bf97fee023afa5f0b9f4061a66e95cf9 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Wed, 10 Mar 2021 12:03:44 +0100 Subject: [PATCH 097/725] Java: Add query for CSV framework coverage. --- java/ql/src/meta/frameworks/Coverage.ql | 14 +++++++++++ .../code/java/dataflow/ExternalFlow.qll | 23 +++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 java/ql/src/meta/frameworks/Coverage.ql diff --git a/java/ql/src/meta/frameworks/Coverage.ql b/java/ql/src/meta/frameworks/Coverage.ql new file mode 100644 index 00000000000..d945d7b4002 --- /dev/null +++ b/java/ql/src/meta/frameworks/Coverage.ql @@ -0,0 +1,14 @@ +/** + * @name Framework coverage + * @description The number of API endpoints covered by CSV models sorted by + * package and source-, sink-, and summary-kind. + * @kind metric + * @id java/meta/framework-coverage + */ + +import java +import semmle.code.java.dataflow.ExternalFlow + +from string package, string kind, string part, int n +where modelCoverage(package, kind, part, n) +select package, kind, part, n diff --git a/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll b/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll index 7197caea351..2f285d5a115 100644 --- a/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll +++ b/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll @@ -204,6 +204,29 @@ private predicate summaryModel( ) } +/** + * Holds if CSV framework coverage of `package` is `n` api endpoints of the + * kind `(kind, part)`. + */ +predicate modelCoverage(string package, string kind, string part, int n) { + part = "source" and + n = + strictcount(string type, boolean subtypes, string name, string signature, string ext, + string output | sourceModel(package, type, subtypes, name, signature, ext, output, kind)) + or + part = "sink" and + n = + strictcount(string type, boolean subtypes, string name, string signature, string ext, + string input | sinkModel(package, type, subtypes, name, signature, ext, input, kind)) + or + part = "summary" and + n = + strictcount(string type, boolean subtypes, string name, string signature, string ext, + string input, string output | + summaryModel(package, type, subtypes, name, signature, ext, input, output, kind) + ) +} + /** Provides a query predicate to check the CSV data for validation errors. */ module CsvValidation { /** Holds if some row in a CSV-based flow model appears to contain typos. */ From 16a3dfa30a4fb3fb176398a8374e24653a13c650 Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Wed, 10 Mar 2021 11:15:55 +0000 Subject: [PATCH 098/725] C++: Update summary metrics query format. --- cpp/ql/src/Summary/Files.ql | 3 ++- cpp/ql/src/Summary/Lines.ql | 3 ++- cpp/ql/src/Summary/LinesOfCode.ql | 3 ++- cpp/ql/src/Summary/LinesOfCodePerFile.ql | 3 ++- cpp/ql/src/Summary/LinesPerFile.ql | 3 ++- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/cpp/ql/src/Summary/Files.ql b/cpp/ql/src/Summary/Files.ql index 5ea01b25631..83007c2fec6 100644 --- a/cpp/ql/src/Summary/Files.ql +++ b/cpp/ql/src/Summary/Files.ql @@ -1,8 +1,9 @@ /** + * @id cpp/summary/files * @name Total source files * @description The total number of source files. * @kind metric - * @id cpp/summary/files + * @tags summary */ import cpp diff --git a/cpp/ql/src/Summary/Lines.ql b/cpp/ql/src/Summary/Lines.ql index 87feb1f7d6f..dec466c5468 100644 --- a/cpp/ql/src/Summary/Lines.ql +++ b/cpp/ql/src/Summary/Lines.ql @@ -1,8 +1,9 @@ /** + * @id cpp/summary/lines * @name Total lines of text * @description The total number of lines of text across all source files. * @kind metric - * @id cpp/summary/lines + * @tags summary */ import cpp diff --git a/cpp/ql/src/Summary/LinesOfCode.ql b/cpp/ql/src/Summary/LinesOfCode.ql index 7d8ae36f79e..4dc7dc88c05 100644 --- a/cpp/ql/src/Summary/LinesOfCode.ql +++ b/cpp/ql/src/Summary/LinesOfCode.ql @@ -1,8 +1,9 @@ /** + * @id cpp/summary/lines-of-code * @name Total lines of code * @description The total number of lines of code across all source files. * @kind metric - * @id cpp/summary/lines-of-code + * @tags summary */ import cpp diff --git a/cpp/ql/src/Summary/LinesOfCodePerFile.ql b/cpp/ql/src/Summary/LinesOfCodePerFile.ql index 818e4312dcf..c98d8a3d196 100644 --- a/cpp/ql/src/Summary/LinesOfCodePerFile.ql +++ b/cpp/ql/src/Summary/LinesOfCodePerFile.ql @@ -1,8 +1,9 @@ /** + * @id cpp/summary/lines-of-code-per-file * @name Lines of code per source file * @description The number of lines of code for each source file. * @kind metric - * @id cpp/summary/lines-of-code-per-file + * @tags summary */ import cpp diff --git a/cpp/ql/src/Summary/LinesPerFile.ql b/cpp/ql/src/Summary/LinesPerFile.ql index 54a0a75d2e0..bfc78e4d284 100644 --- a/cpp/ql/src/Summary/LinesPerFile.ql +++ b/cpp/ql/src/Summary/LinesPerFile.ql @@ -1,8 +1,9 @@ /** + * @id cpp/summary/lines-per-file * @name Lines of text per source file * @description The number of lines of text for each source file. * @kind metric - * @id cpp/summary/lines-per-file + * @tags summary */ import cpp From 72f28513eb6478024cb184f9affe71490c8217d3 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Wed, 10 Mar 2021 12:12:27 +0000 Subject: [PATCH 099/725] Move test check to the sink --- .../CWE-1004/SensitiveCookieNotHttpOnly.ql | 44 ++++++++----------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql b/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql index 716975d0486..eee4d8c89d1 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql @@ -73,34 +73,29 @@ class CookieResponseSink extends DataFlow::ExprNode { ma instanceof SetCookieMethodAccess and this.getExpr() = ma.getArgument(1) and not hasHttpOnlyExpr(this.getExpr()) // response.addHeader("Set-Cookie", "token=" +authId + ";HttpOnly;Secure") - ) + ) and + not isTestMethod(ma) // Test class or method ) } } -/** A JAX-RS `NewCookie` constructor that sets `HttpOnly` to true. */ -class HttpOnlyNewCookie extends ClassInstanceExpr { - HttpOnlyNewCookie() { - this.getConstructedType() - .hasQualifiedName(["javax.ws.rs.core", "jakarta.ws.rs.core"], "NewCookie") and - ( - this.getNumArgument() = 6 and this.getArgument(5).(BooleanLiteral).getBooleanValue() = true // NewCookie(Cookie cookie, String comment, int maxAge, Date expiry, boolean secure, boolean httpOnly) - or - this.getNumArgument() = 8 and - this.getArgument(6).getType() instanceof BooleanType and - this.getArgument(7).(BooleanLiteral).getBooleanValue() = true // NewCookie(String name, String value, String path, String domain, String comment, int maxAge, boolean secure, boolean httpOnly) - or - this.getNumArgument() = 10 and this.getArgument(9).(BooleanLiteral).getBooleanValue() = true // NewCookie(String name, String value, String path, String domain, int version, String comment, int maxAge, Date expiry, boolean secure, boolean httpOnly) - ) - } +/** Holds if `cie` is an invocation of a JAX-RS `NewCookie` constructor that sets `HttpOnly` to true. */ +predicate setHttpOnlyInNewCookie(ClassInstanceExpr cie) { + cie.getConstructedType().hasQualifiedName(["javax.ws.rs.core", "jakarta.ws.rs.core"], "NewCookie") and + ( + cie.getNumArgument() = 6 and cie.getArgument(5).(BooleanLiteral).getBooleanValue() = true // NewCookie(Cookie cookie, String comment, int maxAge, Date expiry, boolean secure, boolean httpOnly) + or + cie.getNumArgument() = 8 and + cie.getArgument(6).getType() instanceof BooleanType and + cie.getArgument(7).(BooleanLiteral).getBooleanValue() = true // NewCookie(String name, String value, String path, String domain, String comment, int maxAge, boolean secure, boolean httpOnly) + or + cie.getNumArgument() = 10 and cie.getArgument(9).(BooleanLiteral).getBooleanValue() = true // NewCookie(String name, String value, String path, String domain, int version, String comment, int maxAge, Date expiry, boolean secure, boolean httpOnly) + ) } /** The cookie constructor. */ class CookieTaintPreservingConstructor extends Constructor, TaintPreservingCallable { - CookieTaintPreservingConstructor() { - this.getDeclaringType() instanceof CookieClass and - not exists(HttpOnlyNewCookie hie | hie.getConstructor() = this) - } + CookieTaintPreservingConstructor() { this.getDeclaringType() instanceof CookieClass } override predicate returnsTaintFrom(int arg) { arg = 0 } } @@ -122,9 +117,8 @@ class CookieInstanceExpr extends TaintPreservingCallable { * c) in a test class whose name has the word `test` * d) in a test class implementing a test framework such as JUnit or TestNG */ -predicate isTestMethod(DataFlow::Node node) { - exists(MethodAccess ma, Method m | - node.asExpr() = ma.getAnArgument() and +predicate isTestMethod(MethodAccess ma) { + exists(Method m | m = ma.getEnclosingCallable() and ( m.getDeclaringType().getName().toLowerCase().matches("%test%") or // Simple check to exclude test classes to reduce FPs @@ -149,8 +143,8 @@ class MissingHttpOnlyConfiguration extends TaintTracking::Configuration { override predicate isSink(DataFlow::Node sink) { sink instanceof CookieResponseSink } override predicate isSanitizer(DataFlow::Node node) { - // Test class or method - isTestMethod(node) + // new NewCookie("session-access-key", accessKey, "/", null, null, 0, true, true) + setHttpOnlyInNewCookie(node.asExpr()) } } From f0ddfc9283607f01603a93e6a05357aa27a579ce Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Wed, 10 Mar 2021 12:18:55 +0000 Subject: [PATCH 100/725] Minor qldoc changes --- .../Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql b/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql index eee4d8c89d1..c3f9349dbc8 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql @@ -79,7 +79,10 @@ class CookieResponseSink extends DataFlow::ExprNode { } } -/** Holds if `cie` is an invocation of a JAX-RS `NewCookie` constructor that sets `HttpOnly` to true. */ +/** + * Holds if `ClassInstanceExpr` cie is an invocation of a JAX-RS `NewCookie` constructor + * that sets `HttpOnly` to true. + */ predicate setHttpOnlyInNewCookie(ClassInstanceExpr cie) { cie.getConstructedType().hasQualifiedName(["javax.ws.rs.core", "jakarta.ws.rs.core"], "NewCookie") and ( @@ -111,7 +114,7 @@ class CookieInstanceExpr extends TaintPreservingCallable { } /** - * Holds if the node is a test method indicated by: + * Holds if the MethodAccess `ma` is a test method call indicated by: * a) in a test directory such as `src/test/java` * b) in a test package whose name has the word `test` * c) in a test class whose name has the word `test` From 0b6589c8bea669afe492a0308f7decbf23f68eb4 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 10 Mar 2021 15:47:06 +0100 Subject: [PATCH 101/725] C++: Accept test changes. --- .../annotate_sinks_only/stl.cpp | 4 +- .../security-taint/tainted_diff.expected | 2 - .../security-taint/tainted_ir.expected | 2 + .../dataflow/taint-tests/string.cpp | 4 +- .../dataflow/taint-tests/stringstream.cpp | 6 +-- .../CWE-022/semmle/tests/TaintedPath.expected | 4 ++ .../CWE-089/SqlTainted/SqlTainted.expected | 4 ++ .../semmle/tests/UnboundedWrite.expected | 20 +++++++++ .../CWE-134/semmle/funcs/funcsLocal.expected | 24 ++++++++++ .../CWE/CWE-134/semmle/ifs/ifs.expected | 44 +++++++++++++++++++ .../semmle/TaintedAllocationSize/test.cpp | 2 +- .../AuthenticationBypass.expected | 12 +++++ .../tests/CleartextBufferWrite.expected | 4 ++ 13 files changed, 122 insertions(+), 10 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/stl.cpp b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/stl.cpp index 0264f29f4af..8a15071ef3c 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/stl.cpp +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/stl.cpp @@ -91,12 +91,12 @@ void test_stringstream() sink(ss2); // $ ir MISSING: ast sink(ss3); // $ MISSING: ast,ir sink(ss4); // $ ir MISSING: ast - sink(ss5); // $ MISSING: ast,ir + sink(ss5); // $ ir MISSING: ast sink(ss1.str()); sink(ss2.str()); // $ ir MISSING: ast sink(ss3.str()); // $ MISSING: ast,ir sink(ss4.str()); // $ ir MISSING: ast - sink(ss5.str()); // $ MISSING: ast,ir + sink(ss5.str()); // $ ir MISSING: ast } void test_stringstream_int(int source) diff --git a/cpp/ql/test/library-tests/dataflow/security-taint/tainted_diff.expected b/cpp/ql/test/library-tests/dataflow/security-taint/tainted_diff.expected index 9050ad322f8..2b1b021716b 100644 --- a/cpp/ql/test/library-tests/dataflow/security-taint/tainted_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/security-taint/tainted_diff.expected @@ -28,7 +28,6 @@ | test.cpp:83:28:83:33 | call to getenv | test.cpp:85:8:85:11 | copy | AST only | | test.cpp:83:28:83:33 | call to getenv | test.cpp:86:2:86:7 | call to strcpy | AST only | | test.cpp:83:28:83:33 | call to getenv | test.cpp:86:9:86:12 | copy | AST only | -| test.cpp:83:28:83:33 | call to getenv | test.cpp:88:14:88:17 | (const char *)... | AST only | | test.cpp:100:12:100:15 | call to gets | test.cpp:98:8:98:14 | pointer | AST only | | test.cpp:100:12:100:15 | call to gets | test.cpp:100:2:100:8 | pointer | AST only | | test.cpp:100:17:100:22 | buffer | test.cpp:93:18:93:18 | s | AST only | @@ -41,4 +40,3 @@ | test.cpp:106:28:106:33 | call to getenv | test.cpp:108:8:108:11 | copy | AST only | | test.cpp:106:28:106:33 | call to getenv | test.cpp:109:2:109:7 | call to strcpy | AST only | | test.cpp:106:28:106:33 | call to getenv | test.cpp:109:9:109:12 | copy | AST only | -| test.cpp:106:28:106:33 | call to getenv | test.cpp:111:14:111:17 | (const char *)... | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/security-taint/tainted_ir.expected b/cpp/ql/test/library-tests/dataflow/security-taint/tainted_ir.expected index 7f3044e6715..fb19ea7fc9f 100644 --- a/cpp/ql/test/library-tests/dataflow/security-taint/tainted_ir.expected +++ b/cpp/ql/test/library-tests/dataflow/security-taint/tainted_ir.expected @@ -33,6 +33,7 @@ | test.cpp:83:28:83:33 | call to getenv | test.cpp:88:6:88:27 | ! ... | | test.cpp:83:28:83:33 | call to getenv | test.cpp:88:7:88:12 | call to strcmp | | test.cpp:83:28:83:33 | call to getenv | test.cpp:88:7:88:27 | (bool)... | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:88:14:88:17 | (const char *)... | | test.cpp:83:28:83:33 | call to getenv | test.cpp:88:14:88:17 | copy | | test.cpp:100:12:100:15 | call to gets | test.cpp:100:12:100:15 | call to gets | | test.cpp:100:17:100:22 | buffer | test.cpp:100:17:100:22 | array to pointer conversion | @@ -43,4 +44,5 @@ | test.cpp:106:28:106:33 | call to getenv | test.cpp:111:6:111:27 | ! ... | | test.cpp:106:28:106:33 | call to getenv | test.cpp:111:7:111:12 | call to strcmp | | test.cpp:106:28:106:33 | call to getenv | test.cpp:111:7:111:27 | (bool)... | +| test.cpp:106:28:106:33 | call to getenv | test.cpp:111:14:111:17 | (const char *)... | | test.cpp:106:28:106:33 | call to getenv | test.cpp:111:14:111:17 | copy | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/string.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/string.cpp index 43b6e9bc53b..0e29d314887 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/string.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/string.cpp @@ -406,9 +406,9 @@ void test_string_iterators() { i6--; sink(*i6); // $ ast,ir i7 = i2; - sink(*(i7+=1)); // $ ast MISSING: ir + sink(*(i7+=1)); // $ ast,ir i8 = i2; - sink(*(i8-=1)); // $ ast MISSING: ir + sink(*(i8-=1)); // $ ast,ir i9 = s2.end(); --i9; diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/stringstream.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/stringstream.cpp index 7a6c5e51820..4d28955aaa0 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/stringstream.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/stringstream.cpp @@ -32,18 +32,18 @@ void test_stringstream_string(int amount) sink(ss2 << source()); // $ ast,ir sink(ss3 << "123" << source()); // $ ast,ir sink(ss4 << source() << "456"); // $ ast,ir - sink(ss5 << t); // $ ast MISSING: ir + sink(ss5 << t); // $ ast,ir sink(ss1); sink(ss2); // $ ast,ir sink(ss3); // $ ast MISSING: ir sink(ss4); // $ ast,ir - sink(ss5); // $ ast MISSING: ir + sink(ss5); // $ ast MISSIN,ir sink(ss1.str()); sink(ss2.str()); // $ ast,ir sink(ss3.str()); // $ ast MISSING: ir sink(ss4.str()); // $ ast,ir - sink(ss5.str()); // $ ast MISSING: ir + sink(ss5.str()); // $ ast,ir ss6.str("abc"); ss6.str(source()); // (overwrites) diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-022/semmle/tests/TaintedPath.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-022/semmle/tests/TaintedPath.expected index 7383fbbd215..60898414224 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-022/semmle/tests/TaintedPath.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-022/semmle/tests/TaintedPath.expected @@ -1,4 +1,6 @@ edges +| test.c:9:23:9:26 | argv | test.c:17:11:17:18 | (const char *)... | +| test.c:9:23:9:26 | argv | test.c:17:11:17:18 | (const char *)... | | test.c:9:23:9:26 | argv | test.c:17:11:17:18 | Argument 0 indirection | | test.c:9:23:9:26 | argv | test.c:17:11:17:18 | Argument 0 indirection | | test.c:9:23:9:26 | argv | test.c:17:11:17:18 | fileName | @@ -6,6 +8,8 @@ edges nodes | test.c:9:23:9:26 | argv | semmle.label | argv | | test.c:9:23:9:26 | argv | semmle.label | argv | +| test.c:17:11:17:18 | (const char *)... | semmle.label | (const char *)... | +| test.c:17:11:17:18 | (const char *)... | semmle.label | (const char *)... | | test.c:17:11:17:18 | Argument 0 indirection | semmle.label | Argument 0 indirection | | test.c:17:11:17:18 | Argument 0 indirection | semmle.label | Argument 0 indirection | | test.c:17:11:17:18 | fileName | semmle.label | fileName | 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 af50f184740..fe84a80654c 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,6 +1,8 @@ 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 | (const char *)... | +| test.c:15:20:15:23 | argv | test.c:21:18:21:23 | Argument 1 indirection | +| test.c:15:20:15:23 | argv | test.c:21:18:21:23 | Argument 1 indirection | | 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 | nodes @@ -8,6 +10,8 @@ nodes | test.c:15:20:15:23 | 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 | Argument 1 indirection | semmle.label | Argument 1 indirection | +| test.c:21:18:21:23 | Argument 1 indirection | semmle.label | Argument 1 indirection | | test.c:21:18:21:23 | query1 | semmle.label | query1 | #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) | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-120/semmle/tests/UnboundedWrite.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-120/semmle/tests/UnboundedWrite.expected index cc314aa5d0e..a0db8029b2b 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-120/semmle/tests/UnboundedWrite.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-120/semmle/tests/UnboundedWrite.expected @@ -1,6 +1,8 @@ edges | tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | (const char *)... | | tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | (const char *)... | +| tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | Argument 1 indirection | +| tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | Argument 1 indirection | | tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array | | tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array | | tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array | @@ -13,6 +15,8 @@ edges | tests.c:28:22:28:25 | argv | tests.c:33:21:33:29 | Argument 2 indirection | | tests.c:28:22:28:25 | argv | tests.c:33:21:33:29 | buffer100 | | tests.c:28:22:28:25 | argv | tests.c:33:21:33:29 | buffer100 | +| tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | Argument 2 indirection | +| tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | Argument 2 indirection | | tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | access to array | | tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | access to array | | tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | access to array | @@ -25,12 +29,22 @@ edges | tests.c:29:28:29:31 | argv | tests.c:33:21:33:29 | Argument 2 indirection | | tests.c:29:28:29:31 | argv | tests.c:33:21:33:29 | buffer100 | | tests.c:29:28:29:31 | argv | tests.c:33:21:33:29 | buffer100 | +| tests.c:31:15:31:23 | array to pointer conversion | tests.c:31:15:31:23 | Argument 1 indirection | +| tests.c:31:15:31:23 | array to pointer conversion | tests.c:31:15:31:23 | buffer100 | +| tests.c:31:15:31:23 | buffer100 | tests.c:31:15:31:23 | Argument 1 indirection | +| tests.c:31:15:31:23 | buffer100 | tests.c:31:15:31:23 | buffer100 | | tests.c:31:15:31:23 | buffer100 | tests.c:33:21:33:29 | Argument 2 indirection | | tests.c:31:15:31:23 | buffer100 | tests.c:33:21:33:29 | buffer100 | | tests.c:31:15:31:23 | scanf output argument | tests.c:33:21:33:29 | Argument 2 indirection | | tests.c:31:15:31:23 | scanf output argument | tests.c:33:21:33:29 | buffer100 | +| tests.c:33:21:33:29 | array to pointer conversion | tests.c:33:21:33:29 | Argument 2 indirection | +| tests.c:33:21:33:29 | array to pointer conversion | tests.c:33:21:33:29 | buffer100 | +| tests.c:33:21:33:29 | buffer100 | tests.c:33:21:33:29 | Argument 2 indirection | +| tests.c:33:21:33:29 | buffer100 | tests.c:33:21:33:29 | buffer100 | | tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | (const char *)... | | tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | (const char *)... | +| tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | Argument 0 indirection | +| tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | Argument 0 indirection | | tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | access to array | | tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | access to array | | tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | access to array | @@ -40,11 +54,15 @@ nodes | tests.c:28:22:28:25 | argv | semmle.label | argv | | tests.c:28:22:28:28 | (const char *)... | semmle.label | (const char *)... | | tests.c:28:22:28:28 | (const char *)... | semmle.label | (const char *)... | +| tests.c:28:22:28:28 | Argument 1 indirection | semmle.label | Argument 1 indirection | +| tests.c:28:22:28:28 | Argument 1 indirection | semmle.label | Argument 1 indirection | | tests.c:28:22:28:28 | access to array | semmle.label | access to array | | tests.c:28:22:28:28 | access to array | semmle.label | access to array | | tests.c:28:22:28:28 | access to array | semmle.label | access to array | | tests.c:29:28:29:31 | argv | semmle.label | argv | | tests.c:29:28:29:31 | argv | semmle.label | argv | +| tests.c:29:28:29:34 | Argument 2 indirection | semmle.label | Argument 2 indirection | +| tests.c:29:28:29:34 | Argument 2 indirection | semmle.label | Argument 2 indirection | | tests.c:29:28:29:34 | access to array | semmle.label | access to array | | tests.c:29:28:29:34 | access to array | semmle.label | access to array | | tests.c:29:28:29:34 | access to array | semmle.label | access to array | @@ -67,6 +85,8 @@ nodes | tests.c:34:10:34:13 | argv | semmle.label | argv | | tests.c:34:10:34:16 | (const char *)... | semmle.label | (const char *)... | | tests.c:34:10:34:16 | (const char *)... | semmle.label | (const char *)... | +| tests.c:34:10:34:16 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| tests.c:34:10:34:16 | Argument 0 indirection | semmle.label | Argument 0 indirection | | tests.c:34:10:34:16 | access to array | semmle.label | access to array | | tests.c:34:10:34:16 | access to array | semmle.label | access to array | | tests.c:34:10:34:16 | access to array | semmle.label | access to array | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/funcs/funcsLocal.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/funcs/funcsLocal.expected index 5d04ac6149d..963c37bef48 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/funcs/funcsLocal.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/funcs/funcsLocal.expected @@ -1,48 +1,68 @@ edges +| funcsLocal.c:16:8:16:9 | fread output argument | funcsLocal.c:17:9:17:10 | (const char *)... | | funcsLocal.c:16:8:16:9 | fread output argument | funcsLocal.c:17:9:17:10 | Argument 0 indirection | | funcsLocal.c:16:8:16:9 | fread output argument | funcsLocal.c:17:9:17:10 | i1 | +| funcsLocal.c:16:8:16:9 | fread output argument | funcsLocal.c:58:9:58:10 | (const char *)... | | funcsLocal.c:16:8:16:9 | fread output argument | funcsLocal.c:58:9:58:10 | Argument 0 indirection | | funcsLocal.c:16:8:16:9 | fread output argument | funcsLocal.c:58:9:58:10 | e1 | +| funcsLocal.c:16:8:16:9 | i1 | funcsLocal.c:17:9:17:10 | (const char *)... | | funcsLocal.c:16:8:16:9 | i1 | funcsLocal.c:17:9:17:10 | Argument 0 indirection | | funcsLocal.c:16:8:16:9 | i1 | funcsLocal.c:17:9:17:10 | i1 | +| funcsLocal.c:16:8:16:9 | i1 | funcsLocal.c:58:9:58:10 | (const char *)... | | funcsLocal.c:16:8:16:9 | i1 | funcsLocal.c:58:9:58:10 | Argument 0 indirection | | funcsLocal.c:16:8:16:9 | i1 | funcsLocal.c:58:9:58:10 | e1 | +| funcsLocal.c:26:8:26:9 | fgets output argument | funcsLocal.c:27:9:27:10 | (const char *)... | | funcsLocal.c:26:8:26:9 | fgets output argument | funcsLocal.c:27:9:27:10 | Argument 0 indirection | | funcsLocal.c:26:8:26:9 | fgets output argument | funcsLocal.c:27:9:27:10 | i3 | +| funcsLocal.c:26:8:26:9 | i3 | funcsLocal.c:27:9:27:10 | (const char *)... | | funcsLocal.c:26:8:26:9 | i3 | funcsLocal.c:27:9:27:10 | Argument 0 indirection | | funcsLocal.c:26:8:26:9 | i3 | funcsLocal.c:27:9:27:10 | i3 | | funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | (const char *)... | | funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | (const char *)... | +| funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | Argument 0 indirection | +| funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | Argument 0 indirection | | funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | i4 | | funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | i4 | | funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | i4 | | funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | i4 | +| funcsLocal.c:31:19:31:21 | fgets output argument | funcsLocal.c:32:9:32:10 | (const char *)... | | funcsLocal.c:31:19:31:21 | fgets output argument | funcsLocal.c:32:9:32:10 | Argument 0 indirection | | funcsLocal.c:31:19:31:21 | fgets output argument | funcsLocal.c:32:9:32:10 | i4 | +| funcsLocal.c:31:19:31:21 | i41 | funcsLocal.c:32:9:32:10 | (const char *)... | | funcsLocal.c:31:19:31:21 | i41 | funcsLocal.c:32:9:32:10 | Argument 0 indirection | | funcsLocal.c:31:19:31:21 | i41 | funcsLocal.c:32:9:32:10 | i4 | +| funcsLocal.c:36:7:36:8 | gets output argument | funcsLocal.c:37:9:37:10 | (const char *)... | | funcsLocal.c:36:7:36:8 | gets output argument | funcsLocal.c:37:9:37:10 | Argument 0 indirection | | funcsLocal.c:36:7:36:8 | gets output argument | funcsLocal.c:37:9:37:10 | i5 | +| funcsLocal.c:36:7:36:8 | i5 | funcsLocal.c:37:9:37:10 | (const char *)... | | funcsLocal.c:36:7:36:8 | i5 | funcsLocal.c:37:9:37:10 | Argument 0 indirection | | funcsLocal.c:36:7:36:8 | i5 | funcsLocal.c:37:9:37:10 | i5 | | funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | (const char *)... | | funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | (const char *)... | +| funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | Argument 0 indirection | +| funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | Argument 0 indirection | | funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | i6 | | funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | i6 | | funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | i6 | | funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | i6 | +| funcsLocal.c:41:18:41:20 | gets output argument | funcsLocal.c:42:9:42:10 | (const char *)... | | funcsLocal.c:41:18:41:20 | gets output argument | funcsLocal.c:42:9:42:10 | Argument 0 indirection | | funcsLocal.c:41:18:41:20 | gets output argument | funcsLocal.c:42:9:42:10 | i6 | +| funcsLocal.c:41:18:41:20 | i61 | funcsLocal.c:42:9:42:10 | (const char *)... | | funcsLocal.c:41:18:41:20 | i61 | funcsLocal.c:42:9:42:10 | Argument 0 indirection | | funcsLocal.c:41:18:41:20 | i61 | funcsLocal.c:42:9:42:10 | i6 | nodes | funcsLocal.c:16:8:16:9 | fread output argument | semmle.label | fread output argument | | funcsLocal.c:16:8:16:9 | i1 | semmle.label | i1 | +| funcsLocal.c:17:9:17:10 | (const char *)... | semmle.label | (const char *)... | +| funcsLocal.c:17:9:17:10 | (const char *)... | semmle.label | (const char *)... | | funcsLocal.c:17:9:17:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | | funcsLocal.c:17:9:17:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | | funcsLocal.c:17:9:17:10 | i1 | semmle.label | i1 | | funcsLocal.c:26:8:26:9 | fgets output argument | semmle.label | fgets output argument | | funcsLocal.c:26:8:26:9 | i3 | semmle.label | i3 | +| funcsLocal.c:27:9:27:10 | (const char *)... | semmle.label | (const char *)... | +| funcsLocal.c:27:9:27:10 | (const char *)... | semmle.label | (const char *)... | | funcsLocal.c:27:9:27:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | | funcsLocal.c:27:9:27:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | | funcsLocal.c:27:9:27:10 | i3 | semmle.label | i3 | @@ -59,6 +79,8 @@ nodes | funcsLocal.c:32:9:32:10 | i4 | semmle.label | i4 | | funcsLocal.c:36:7:36:8 | gets output argument | semmle.label | gets output argument | | funcsLocal.c:36:7:36:8 | i5 | semmle.label | i5 | +| funcsLocal.c:37:9:37:10 | (const char *)... | semmle.label | (const char *)... | +| funcsLocal.c:37:9:37:10 | (const char *)... | semmle.label | (const char *)... | | funcsLocal.c:37:9:37:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | | funcsLocal.c:37:9:37:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | | funcsLocal.c:37:9:37:10 | i5 | semmle.label | i5 | @@ -73,6 +95,8 @@ nodes | funcsLocal.c:42:9:42:10 | i6 | semmle.label | i6 | | funcsLocal.c:42:9:42:10 | i6 | semmle.label | i6 | | funcsLocal.c:42:9:42:10 | i6 | semmle.label | i6 | +| funcsLocal.c:58:9:58:10 | (const char *)... | semmle.label | (const char *)... | +| funcsLocal.c:58:9:58:10 | (const char *)... | semmle.label | (const char *)... | | funcsLocal.c:58:9:58:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | | funcsLocal.c:58:9:58:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | | funcsLocal.c:58:9:58:10 | e1 | semmle.label | e1 | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/ifs/ifs.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/ifs/ifs.expected index 62c36d0192d..e769c072f84 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/ifs/ifs.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/ifs/ifs.expected @@ -1,66 +1,88 @@ edges | ifs.c:61:8:61:11 | argv | ifs.c:62:9:62:10 | (const char *)... | | ifs.c:61:8:61:11 | argv | ifs.c:62:9:62:10 | (const char *)... | +| ifs.c:61:8:61:11 | argv | ifs.c:62:9:62:10 | Argument 0 indirection | +| ifs.c:61:8:61:11 | argv | ifs.c:62:9:62:10 | Argument 0 indirection | | ifs.c:61:8:61:11 | argv | ifs.c:62:9:62:10 | c7 | | ifs.c:61:8:61:11 | argv | ifs.c:62:9:62:10 | c7 | | ifs.c:61:8:61:11 | argv | ifs.c:62:9:62:10 | c7 | | ifs.c:61:8:61:11 | argv | ifs.c:62:9:62:10 | c7 | | ifs.c:68:8:68:11 | argv | ifs.c:69:9:69:10 | (const char *)... | | ifs.c:68:8:68:11 | argv | ifs.c:69:9:69:10 | (const char *)... | +| ifs.c:68:8:68:11 | argv | ifs.c:69:9:69:10 | Argument 0 indirection | +| ifs.c:68:8:68:11 | argv | ifs.c:69:9:69:10 | Argument 0 indirection | | ifs.c:68:8:68:11 | argv | ifs.c:69:9:69:10 | c8 | | ifs.c:68:8:68:11 | argv | ifs.c:69:9:69:10 | c8 | | ifs.c:68:8:68:11 | argv | ifs.c:69:9:69:10 | c8 | | ifs.c:68:8:68:11 | argv | ifs.c:69:9:69:10 | c8 | | ifs.c:74:8:74:11 | argv | ifs.c:75:9:75:10 | (const char *)... | | ifs.c:74:8:74:11 | argv | ifs.c:75:9:75:10 | (const char *)... | +| ifs.c:74:8:74:11 | argv | ifs.c:75:9:75:10 | Argument 0 indirection | +| ifs.c:74:8:74:11 | argv | ifs.c:75:9:75:10 | Argument 0 indirection | | ifs.c:74:8:74:11 | argv | ifs.c:75:9:75:10 | i1 | | ifs.c:74:8:74:11 | argv | ifs.c:75:9:75:10 | i1 | | ifs.c:74:8:74:11 | argv | ifs.c:75:9:75:10 | i1 | | ifs.c:74:8:74:11 | argv | ifs.c:75:9:75:10 | i1 | | ifs.c:80:8:80:11 | argv | ifs.c:81:9:81:10 | (const char *)... | | ifs.c:80:8:80:11 | argv | ifs.c:81:9:81:10 | (const char *)... | +| ifs.c:80:8:80:11 | argv | ifs.c:81:9:81:10 | Argument 0 indirection | +| ifs.c:80:8:80:11 | argv | ifs.c:81:9:81:10 | Argument 0 indirection | | ifs.c:80:8:80:11 | argv | ifs.c:81:9:81:10 | i2 | | ifs.c:80:8:80:11 | argv | ifs.c:81:9:81:10 | i2 | | ifs.c:80:8:80:11 | argv | ifs.c:81:9:81:10 | i2 | | ifs.c:80:8:80:11 | argv | ifs.c:81:9:81:10 | i2 | | ifs.c:86:8:86:11 | argv | ifs.c:87:9:87:10 | (const char *)... | | ifs.c:86:8:86:11 | argv | ifs.c:87:9:87:10 | (const char *)... | +| ifs.c:86:8:86:11 | argv | ifs.c:87:9:87:10 | Argument 0 indirection | +| ifs.c:86:8:86:11 | argv | ifs.c:87:9:87:10 | Argument 0 indirection | | ifs.c:86:8:86:11 | argv | ifs.c:87:9:87:10 | i3 | | ifs.c:86:8:86:11 | argv | ifs.c:87:9:87:10 | i3 | | ifs.c:86:8:86:11 | argv | ifs.c:87:9:87:10 | i3 | | ifs.c:86:8:86:11 | argv | ifs.c:87:9:87:10 | i3 | | ifs.c:92:8:92:11 | argv | ifs.c:93:9:93:10 | (const char *)... | | ifs.c:92:8:92:11 | argv | ifs.c:93:9:93:10 | (const char *)... | +| ifs.c:92:8:92:11 | argv | ifs.c:93:9:93:10 | Argument 0 indirection | +| ifs.c:92:8:92:11 | argv | ifs.c:93:9:93:10 | Argument 0 indirection | | ifs.c:92:8:92:11 | argv | ifs.c:93:9:93:10 | i4 | | ifs.c:92:8:92:11 | argv | ifs.c:93:9:93:10 | i4 | | ifs.c:92:8:92:11 | argv | ifs.c:93:9:93:10 | i4 | | ifs.c:92:8:92:11 | argv | ifs.c:93:9:93:10 | i4 | | ifs.c:98:8:98:11 | argv | ifs.c:99:9:99:10 | (const char *)... | | ifs.c:98:8:98:11 | argv | ifs.c:99:9:99:10 | (const char *)... | +| ifs.c:98:8:98:11 | argv | ifs.c:99:9:99:10 | Argument 0 indirection | +| ifs.c:98:8:98:11 | argv | ifs.c:99:9:99:10 | Argument 0 indirection | | ifs.c:98:8:98:11 | argv | ifs.c:99:9:99:10 | i5 | | ifs.c:98:8:98:11 | argv | ifs.c:99:9:99:10 | i5 | | ifs.c:98:8:98:11 | argv | ifs.c:99:9:99:10 | i5 | | ifs.c:98:8:98:11 | argv | ifs.c:99:9:99:10 | i5 | | ifs.c:105:8:105:11 | argv | ifs.c:106:9:106:10 | (const char *)... | | ifs.c:105:8:105:11 | argv | ifs.c:106:9:106:10 | (const char *)... | +| ifs.c:105:8:105:11 | argv | ifs.c:106:9:106:10 | Argument 0 indirection | +| ifs.c:105:8:105:11 | argv | ifs.c:106:9:106:10 | Argument 0 indirection | | ifs.c:105:8:105:11 | argv | ifs.c:106:9:106:10 | i6 | | ifs.c:105:8:105:11 | argv | ifs.c:106:9:106:10 | i6 | | ifs.c:105:8:105:11 | argv | ifs.c:106:9:106:10 | i6 | | ifs.c:105:8:105:11 | argv | ifs.c:106:9:106:10 | i6 | | ifs.c:111:8:111:11 | argv | ifs.c:112:9:112:10 | (const char *)... | | ifs.c:111:8:111:11 | argv | ifs.c:112:9:112:10 | (const char *)... | +| ifs.c:111:8:111:11 | argv | ifs.c:112:9:112:10 | Argument 0 indirection | +| ifs.c:111:8:111:11 | argv | ifs.c:112:9:112:10 | Argument 0 indirection | | ifs.c:111:8:111:11 | argv | ifs.c:112:9:112:10 | i7 | | ifs.c:111:8:111:11 | argv | ifs.c:112:9:112:10 | i7 | | ifs.c:111:8:111:11 | argv | ifs.c:112:9:112:10 | i7 | | ifs.c:111:8:111:11 | argv | ifs.c:112:9:112:10 | i7 | | ifs.c:117:8:117:11 | argv | ifs.c:118:9:118:10 | (const char *)... | | ifs.c:117:8:117:11 | argv | ifs.c:118:9:118:10 | (const char *)... | +| ifs.c:117:8:117:11 | argv | ifs.c:118:9:118:10 | Argument 0 indirection | +| ifs.c:117:8:117:11 | argv | ifs.c:118:9:118:10 | Argument 0 indirection | | ifs.c:117:8:117:11 | argv | ifs.c:118:9:118:10 | i8 | | ifs.c:117:8:117:11 | argv | ifs.c:118:9:118:10 | i8 | | ifs.c:117:8:117:11 | argv | ifs.c:118:9:118:10 | i8 | | ifs.c:117:8:117:11 | argv | ifs.c:118:9:118:10 | i8 | | ifs.c:123:8:123:11 | argv | ifs.c:124:9:124:10 | (const char *)... | | ifs.c:123:8:123:11 | argv | ifs.c:124:9:124:10 | (const char *)... | +| ifs.c:123:8:123:11 | argv | ifs.c:124:9:124:10 | Argument 0 indirection | +| ifs.c:123:8:123:11 | argv | ifs.c:124:9:124:10 | Argument 0 indirection | | ifs.c:123:8:123:11 | argv | ifs.c:124:9:124:10 | i9 | | ifs.c:123:8:123:11 | argv | ifs.c:124:9:124:10 | i9 | | ifs.c:123:8:123:11 | argv | ifs.c:124:9:124:10 | i9 | @@ -70,6 +92,8 @@ nodes | ifs.c:61:8:61:11 | argv | semmle.label | argv | | ifs.c:62:9:62:10 | (const char *)... | semmle.label | (const char *)... | | ifs.c:62:9:62:10 | (const char *)... | semmle.label | (const char *)... | +| ifs.c:62:9:62:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| ifs.c:62:9:62:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | | ifs.c:62:9:62:10 | c7 | semmle.label | c7 | | ifs.c:62:9:62:10 | c7 | semmle.label | c7 | | ifs.c:62:9:62:10 | c7 | semmle.label | c7 | @@ -77,6 +101,8 @@ nodes | ifs.c:68:8:68:11 | argv | semmle.label | argv | | ifs.c:69:9:69:10 | (const char *)... | semmle.label | (const char *)... | | ifs.c:69:9:69:10 | (const char *)... | semmle.label | (const char *)... | +| ifs.c:69:9:69:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| ifs.c:69:9:69:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | | ifs.c:69:9:69:10 | c8 | semmle.label | c8 | | ifs.c:69:9:69:10 | c8 | semmle.label | c8 | | ifs.c:69:9:69:10 | c8 | semmle.label | c8 | @@ -84,6 +110,8 @@ nodes | ifs.c:74:8:74:11 | argv | semmle.label | argv | | ifs.c:75:9:75:10 | (const char *)... | semmle.label | (const char *)... | | ifs.c:75:9:75:10 | (const char *)... | semmle.label | (const char *)... | +| ifs.c:75:9:75:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| ifs.c:75:9:75:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | | ifs.c:75:9:75:10 | i1 | semmle.label | i1 | | ifs.c:75:9:75:10 | i1 | semmle.label | i1 | | ifs.c:75:9:75:10 | i1 | semmle.label | i1 | @@ -91,6 +119,8 @@ nodes | ifs.c:80:8:80:11 | argv | semmle.label | argv | | ifs.c:81:9:81:10 | (const char *)... | semmle.label | (const char *)... | | ifs.c:81:9:81:10 | (const char *)... | semmle.label | (const char *)... | +| ifs.c:81:9:81:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| ifs.c:81:9:81:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | | ifs.c:81:9:81:10 | i2 | semmle.label | i2 | | ifs.c:81:9:81:10 | i2 | semmle.label | i2 | | ifs.c:81:9:81:10 | i2 | semmle.label | i2 | @@ -98,6 +128,8 @@ nodes | ifs.c:86:8:86:11 | argv | semmle.label | argv | | ifs.c:87:9:87:10 | (const char *)... | semmle.label | (const char *)... | | ifs.c:87:9:87:10 | (const char *)... | semmle.label | (const char *)... | +| ifs.c:87:9:87:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| ifs.c:87:9:87:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | | ifs.c:87:9:87:10 | i3 | semmle.label | i3 | | ifs.c:87:9:87:10 | i3 | semmle.label | i3 | | ifs.c:87:9:87:10 | i3 | semmle.label | i3 | @@ -105,6 +137,8 @@ nodes | ifs.c:92:8:92:11 | argv | semmle.label | argv | | ifs.c:93:9:93:10 | (const char *)... | semmle.label | (const char *)... | | ifs.c:93:9:93:10 | (const char *)... | semmle.label | (const char *)... | +| ifs.c:93:9:93:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| ifs.c:93:9:93:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | | ifs.c:93:9:93:10 | i4 | semmle.label | i4 | | ifs.c:93:9:93:10 | i4 | semmle.label | i4 | | ifs.c:93:9:93:10 | i4 | semmle.label | i4 | @@ -112,6 +146,8 @@ nodes | ifs.c:98:8:98:11 | argv | semmle.label | argv | | ifs.c:99:9:99:10 | (const char *)... | semmle.label | (const char *)... | | ifs.c:99:9:99:10 | (const char *)... | semmle.label | (const char *)... | +| ifs.c:99:9:99:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| ifs.c:99:9:99:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | | ifs.c:99:9:99:10 | i5 | semmle.label | i5 | | ifs.c:99:9:99:10 | i5 | semmle.label | i5 | | ifs.c:99:9:99:10 | i5 | semmle.label | i5 | @@ -119,6 +155,8 @@ nodes | ifs.c:105:8:105:11 | argv | semmle.label | argv | | ifs.c:106:9:106:10 | (const char *)... | semmle.label | (const char *)... | | ifs.c:106:9:106:10 | (const char *)... | semmle.label | (const char *)... | +| ifs.c:106:9:106:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| ifs.c:106:9:106:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | | ifs.c:106:9:106:10 | i6 | semmle.label | i6 | | ifs.c:106:9:106:10 | i6 | semmle.label | i6 | | ifs.c:106:9:106:10 | i6 | semmle.label | i6 | @@ -126,6 +164,8 @@ nodes | ifs.c:111:8:111:11 | argv | semmle.label | argv | | ifs.c:112:9:112:10 | (const char *)... | semmle.label | (const char *)... | | ifs.c:112:9:112:10 | (const char *)... | semmle.label | (const char *)... | +| ifs.c:112:9:112:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| ifs.c:112:9:112:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | | ifs.c:112:9:112:10 | i7 | semmle.label | i7 | | ifs.c:112:9:112:10 | i7 | semmle.label | i7 | | ifs.c:112:9:112:10 | i7 | semmle.label | i7 | @@ -133,6 +173,8 @@ nodes | ifs.c:117:8:117:11 | argv | semmle.label | argv | | ifs.c:118:9:118:10 | (const char *)... | semmle.label | (const char *)... | | ifs.c:118:9:118:10 | (const char *)... | semmle.label | (const char *)... | +| ifs.c:118:9:118:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| ifs.c:118:9:118:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | | ifs.c:118:9:118:10 | i8 | semmle.label | i8 | | ifs.c:118:9:118:10 | i8 | semmle.label | i8 | | ifs.c:118:9:118:10 | i8 | semmle.label | i8 | @@ -140,6 +182,8 @@ nodes | ifs.c:123:8:123:11 | argv | semmle.label | argv | | ifs.c:124:9:124:10 | (const char *)... | semmle.label | (const char *)... | | ifs.c:124:9:124:10 | (const char *)... | semmle.label | (const char *)... | +| ifs.c:124:9:124:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| ifs.c:124:9:124:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | | ifs.c:124:9:124:10 | i9 | semmle.label | i9 | | ifs.c:124:9:124:10 | i9 | semmle.label | i9 | | ifs.c:124:9:124:10 | i9 | semmle.label | i9 | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/test.cpp index 0683f7211e3..943bc3b1214 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/test.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/test.cpp @@ -76,7 +76,7 @@ void processData2(char *start, char *end) { char *copy; - copy = new char[end - start]; // GOOD + copy = new char[end - start]; // GOOD [FALSE POSITIVE] // ... diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-290/semmle/AuthenticationBypass/AuthenticationBypass.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-290/semmle/AuthenticationBypass/AuthenticationBypass.expected index e2671c07952..dfbb01bf264 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-290/semmle/AuthenticationBypass/AuthenticationBypass.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-290/semmle/AuthenticationBypass/AuthenticationBypass.expected @@ -1,29 +1,41 @@ edges +| test.cpp:16:25:16:30 | call to getenv | test.cpp:20:14:20:20 | Argument 0 indirection | | test.cpp:16:25:16:30 | call to getenv | test.cpp:20:14:20:20 | address | | test.cpp:16:25:16:30 | call to getenv | test.cpp:20:14:20:20 | address | +| test.cpp:16:25:16:42 | (const char *)... | test.cpp:20:14:20:20 | Argument 0 indirection | | test.cpp:16:25:16:42 | (const char *)... | test.cpp:20:14:20:20 | address | | test.cpp:16:25:16:42 | (const char *)... | test.cpp:20:14:20:20 | address | +| test.cpp:27:25:27:30 | call to getenv | test.cpp:31:14:31:20 | Argument 0 indirection | | test.cpp:27:25:27:30 | call to getenv | test.cpp:31:14:31:20 | address | | test.cpp:27:25:27:30 | call to getenv | test.cpp:31:14:31:20 | address | +| test.cpp:27:25:27:42 | (const char *)... | test.cpp:31:14:31:20 | Argument 0 indirection | | test.cpp:27:25:27:42 | (const char *)... | test.cpp:31:14:31:20 | address | | test.cpp:27:25:27:42 | (const char *)... | test.cpp:31:14:31:20 | address | +| test.cpp:38:25:38:30 | call to getenv | test.cpp:42:14:42:20 | Argument 0 indirection | | test.cpp:38:25:38:30 | call to getenv | test.cpp:42:14:42:20 | address | | test.cpp:38:25:38:30 | call to getenv | test.cpp:42:14:42:20 | address | +| test.cpp:38:25:38:42 | (const char *)... | test.cpp:42:14:42:20 | Argument 0 indirection | | test.cpp:38:25:38:42 | (const char *)... | test.cpp:42:14:42:20 | address | | test.cpp:38:25:38:42 | (const char *)... | test.cpp:42:14:42:20 | address | nodes | test.cpp:16:25:16:30 | call to getenv | semmle.label | call to getenv | | test.cpp:16:25:16:42 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:20:14:20:20 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| test.cpp:20:14:20:20 | Argument 0 indirection | semmle.label | Argument 0 indirection | | test.cpp:20:14:20:20 | address | semmle.label | address | | test.cpp:20:14:20:20 | address | semmle.label | address | | test.cpp:20:14:20:20 | address | semmle.label | address | | test.cpp:27:25:27:30 | call to getenv | semmle.label | call to getenv | | test.cpp:27:25:27:42 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:31:14:31:20 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| test.cpp:31:14:31:20 | Argument 0 indirection | semmle.label | Argument 0 indirection | | test.cpp:31:14:31:20 | address | semmle.label | address | | test.cpp:31:14:31:20 | address | semmle.label | address | | test.cpp:31:14:31:20 | address | semmle.label | address | | test.cpp:38:25:38:30 | call to getenv | semmle.label | call to getenv | | test.cpp:38:25:38:42 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:42:14:42:20 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| test.cpp:42:14:42:20 | Argument 0 indirection | semmle.label | Argument 0 indirection | | test.cpp:42:14:42:20 | address | semmle.label | address | | test.cpp:42:14:42:20 | address | semmle.label | address | | test.cpp:42:14:42:20 | address | semmle.label | address | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-311/semmle/tests/CleartextBufferWrite.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-311/semmle/tests/CleartextBufferWrite.expected index f78d75eeed1..559e491417b 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-311/semmle/tests/CleartextBufferWrite.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-311/semmle/tests/CleartextBufferWrite.expected @@ -1,4 +1,6 @@ edges +| test.cpp:54:17:54:20 | argv | test.cpp:58:25:58:29 | Argument 2 indirection | +| test.cpp:54:17:54:20 | argv | test.cpp:58:25:58:29 | Argument 2 indirection | | test.cpp:54:17:54:20 | argv | test.cpp:58:25:58:29 | input | | test.cpp:54:17:54:20 | argv | test.cpp:58:25:58:29 | input | | test.cpp:54:17:54:20 | argv | test.cpp:58:25:58:29 | input | @@ -6,6 +8,8 @@ edges nodes | test.cpp:54:17:54:20 | argv | semmle.label | argv | | test.cpp:54:17:54:20 | argv | semmle.label | argv | +| test.cpp:58:25:58:29 | Argument 2 indirection | semmle.label | Argument 2 indirection | +| test.cpp:58:25:58:29 | Argument 2 indirection | semmle.label | Argument 2 indirection | | test.cpp:58:25:58:29 | input | semmle.label | input | | test.cpp:58:25:58:29 | input | semmle.label | input | | test.cpp:58:25:58:29 | input | semmle.label | input | From bc36e0db43ad67b83eec48d7ba8f0b35e2630995 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 10 Mar 2021 16:51:13 +0100 Subject: [PATCH 102/725] C++: Accept more test changes. --- .../TaintedAllocationSize.expected | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) 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 7c2f1491281..35228fc70b2 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 @@ -27,6 +27,24 @@ edges | test.cpp:39:21:39:24 | argv | test.cpp:52:35:52:60 | ... * ... | | test.cpp:39:21:39:24 | argv | test.cpp:52:35:52:60 | ... * ... | | test.cpp:39:21:39:24 | argv | test.cpp:52:35:52:60 | ... * ... | +| test.cpp:75:25:75:29 | start | test.cpp:79:18:79:28 | ... - ... | +| test.cpp:75:25:75:29 | start | test.cpp:79:18:79:28 | ... - ... | +| test.cpp:75:38:75:40 | end | test.cpp:79:18:79:28 | ... - ... | +| test.cpp:75:38:75:40 | end | test.cpp:79:18:79:28 | ... - ... | +| test.cpp:97:18:97:23 | buffer | test.cpp:100:4:100:15 | Argument 0 | +| test.cpp:97:18:97:23 | buffer | test.cpp:100:17:100:22 | Argument 0 indirection | +| test.cpp:97:18:97:23 | buffer | test.cpp:101:4:101:15 | Argument 0 | +| test.cpp:97:18:97:23 | buffer | test.cpp:101:4:101:15 | Argument 1 | +| test.cpp:97:18:97:23 | fread output argument | test.cpp:100:4:100:15 | Argument 0 | +| test.cpp:97:18:97:23 | fread output argument | test.cpp:100:17:100:22 | Argument 0 indirection | +| test.cpp:97:18:97:23 | fread output argument | test.cpp:101:4:101:15 | Argument 0 | +| test.cpp:97:18:97:23 | fread output argument | test.cpp:101:4:101:15 | Argument 1 | +| test.cpp:100:4:100:15 | Argument 0 | test.cpp:100:17:100:22 | processData1 output argument | +| test.cpp:100:17:100:22 | Argument 0 indirection | test.cpp:100:17:100:22 | processData1 output argument | +| test.cpp:100:17:100:22 | processData1 output argument | test.cpp:101:4:101:15 | Argument 0 | +| test.cpp:100:17:100:22 | processData1 output argument | test.cpp:101:4:101:15 | Argument 1 | +| test.cpp:101:4:101:15 | Argument 0 | test.cpp:75:25:75:29 | start | +| test.cpp:101:4:101:15 | Argument 1 | test.cpp:75:38:75:40 | end | | test.cpp:123:18:123:23 | call to getenv | test.cpp:127:24:127:41 | ... * ... | | test.cpp:123:18:123:23 | call to getenv | test.cpp:127:24:127:41 | ... * ... | | test.cpp:123:18:123:31 | (const char *)... | test.cpp:127:24:127:41 | ... * ... | @@ -106,6 +124,21 @@ nodes | test.cpp:52:35:52:60 | ... * ... | semmle.label | ... * ... | | test.cpp:52:35:52:60 | ... * ... | semmle.label | ... * ... | | test.cpp:52:35:52:60 | ... * ... | semmle.label | ... * ... | +| test.cpp:64:25:64:30 | *buffer | semmle.label | *buffer | +| test.cpp:64:25:64:30 | *buffer | semmle.label | *buffer | +| test.cpp:64:25:64:30 | buffer | semmle.label | buffer | +| test.cpp:75:25:75:29 | start | semmle.label | start | +| test.cpp:75:38:75:40 | end | semmle.label | end | +| test.cpp:79:18:79:28 | ... - ... | semmle.label | ... - ... | +| test.cpp:79:18:79:28 | ... - ... | semmle.label | ... - ... | +| test.cpp:79:18:79:28 | ... - ... | semmle.label | ... - ... | +| test.cpp:97:18:97:23 | buffer | semmle.label | buffer | +| test.cpp:97:18:97:23 | fread output argument | semmle.label | fread output argument | +| test.cpp:100:4:100:15 | Argument 0 | semmle.label | Argument 0 | +| test.cpp:100:17:100:22 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| test.cpp:100:17:100:22 | processData1 output argument | semmle.label | processData1 output argument | +| test.cpp:101:4:101:15 | Argument 0 | semmle.label | Argument 0 | +| test.cpp:101:4:101:15 | Argument 1 | semmle.label | Argument 1 | | test.cpp:123:18:123:23 | call to getenv | semmle.label | call to getenv | | test.cpp:123:18:123:31 | (const char *)... | semmle.label | (const char *)... | | test.cpp:127:24:127:41 | ... * ... | semmle.label | ... * ... | @@ -180,6 +213,7 @@ nodes | test.cpp:48:25:48:30 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:48:32:48:35 | size | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | | test.cpp:49:17:49:30 | new[] | test.cpp:39:21:39:24 | argv | test.cpp:49:26:49:29 | size | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | | test.cpp:52:21:52:27 | call to realloc | test.cpp:39:21:39:24 | argv | test.cpp:52:35:52:60 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | +| test.cpp:79:9:79:29 | new[] | test.cpp:97:18:97:23 | buffer | test.cpp:79:18:79:28 | ... - ... | This allocation size is derived from $@ and might overflow | test.cpp:97:18:97:23 | buffer | user input (fread) | | test.cpp:127:17:127:22 | call to malloc | test.cpp:123:18:123:23 | call to getenv | test.cpp:127:24:127:41 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:123:18:123:23 | call to getenv | user input (getenv) | | test.cpp:134:3:134:8 | call to malloc | test.cpp:132:19:132:24 | call to getenv | test.cpp:134:10:134:27 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:132:19:132:24 | call to getenv | user input (getenv) | | test.cpp:142:4:142:9 | call to malloc | test.cpp:138:19:138:24 | call to getenv | test.cpp:142:11:142:28 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:138:19:138:24 | call to getenv | user input (getenv) | From a0a1ddee86382c183b774e9cb88509a1b4aac1d9 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Wed, 10 Mar 2021 17:07:31 +0000 Subject: [PATCH 103/725] Update class name --- .../Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql b/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql index c3f9349dbc8..985c546b555 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql @@ -104,8 +104,8 @@ class CookieTaintPreservingConstructor extends Constructor, TaintPreservingCalla } /** The method call `toString` to get a stringified cookie representation. */ -class CookieInstanceExpr extends TaintPreservingCallable { - CookieInstanceExpr() { +class CookieToString extends TaintPreservingCallable { + CookieToString() { this.getDeclaringType() instanceof CookieClass and this.hasName("toString") } From 0a5d58ed8a15288a19394d74d39610a87869d864 Mon Sep 17 00:00:00 2001 From: Artem Smotrakov Date: Wed, 10 Mar 2021 21:15:19 +0300 Subject: [PATCH 104/725] Cover more configurations in UnsafeSpringExporterInConfigurationClass.ql --- ...nsafeSpringExporterInConfigurationClass.ql | 24 +++++++++++++---- .../SpringExporterUnsafeDeserialization.java | 26 +++++++++++++++++++ ...pringExporterInConfigurationClass.expected | 6 +++-- .../boot/SpringBootConfiguration.java | 10 +++++++ .../autoconfigure/SpringBootApplication.java | 12 +++++++++ 5 files changed, 71 insertions(+), 7 deletions(-) create mode 100644 java/ql/test/stubs/springframework-5.2.3/org/springframework/boot/SpringBootConfiguration.java create mode 100644 java/ql/test/stubs/springframework-5.2.3/org/springframework/boot/autoconfigure/SpringBootApplication.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInConfigurationClass.ql b/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInConfigurationClass.ql index 34605d16fbd..4b8fee3c83f 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInConfigurationClass.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInConfigurationClass.ql @@ -14,6 +14,22 @@ import java import UnsafeSpringExporterLib +/** + * Holds if `type` is a Spring configuration that declares beans. + */ +private predicate isConfiguration(RefType type) { + type.hasAnnotation("org.springframework.context.annotation", "Configuration") or + isConfigurationAnnotation(type.getAnAnnotation()) +} + +/** + * Holds if `annotation` is a Java annotations that declares a Spring configuration. + */ +private predicate isConfigurationAnnotation(Annotation annotation) { + isConfiguration(annotation.getType()) or + isConfigurationAnnotation(annotation.getType().getAnAnnotation()) +} + /** * A method that initializes a unsafe bean based on `RemoteInvocationSerializingExporter`. */ @@ -22,11 +38,9 @@ private class UnsafeBeanInitMethod extends Method { UnsafeBeanInitMethod() { isRemoteInvocationSerializingExporter(this.getReturnType()) and - this.getDeclaringType().hasAnnotation("org.springframework.context.annotation", "Configuration") and - exists(Annotation a | - a.getType().hasQualifiedName("org.springframework.context.annotation", "Bean") - | - this.getAnAnnotation() = a and + isConfiguration(this.getDeclaringType()) and + exists(Annotation a | this.getAnAnnotation() = a | + a.getType().hasQualifiedName("org.springframework.context.annotation", "Bean") and if a.getValue("name") instanceof StringLiteral then identifier = a.getValue("name").(StringLiteral).getRepresentedString() else identifier = this.getName() diff --git a/java/ql/test/experimental/query-tests/security/CWE-502/SpringExporterUnsafeDeserialization.java b/java/ql/test/experimental/query-tests/security/CWE-502/SpringExporterUnsafeDeserialization.java index c89668fc6bb..2bca24ee370 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-502/SpringExporterUnsafeDeserialization.java +++ b/java/ql/test/experimental/query-tests/security/CWE-502/SpringExporterUnsafeDeserialization.java @@ -1,3 +1,5 @@ +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter; @@ -27,6 +29,30 @@ public class SpringExporterUnsafeDeserialization { } } +@SpringBootApplication +class SpringBootTestApplication { + + @Bean(name = "/unsafeHttpInvokerServiceExporter") + HttpInvokerServiceExporter unsafeHttpInvokerServiceExporter() { + HttpInvokerServiceExporter exporter = new HttpInvokerServiceExporter(); + exporter.setService(new AccountServiceImpl()); + exporter.setServiceInterface(AccountService.class); + return exporter; + } +} + +@SpringBootConfiguration +class SpringBootTestConfiguration { + + @Bean(name = "/unsafeHttpInvokerServiceExporter") + HttpInvokerServiceExporter unsafeHttpInvokerServiceExporter() { + HttpInvokerServiceExporter exporter = new HttpInvokerServiceExporter(); + exporter.setService(new AccountServiceImpl()); + exporter.setServiceInterface(AccountService.class); + return exporter; + } +} + class CustomeRemoteInvocationSerializingExporter extends RemoteInvocationSerializingExporter {} class NotAConfiguration { diff --git a/java/ql/test/experimental/query-tests/security/CWE-502/UnsafeSpringExporterInConfigurationClass.expected b/java/ql/test/experimental/query-tests/security/CWE-502/UnsafeSpringExporterInConfigurationClass.expected index 926eff89403..2155d805e80 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-502/UnsafeSpringExporterInConfigurationClass.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-502/UnsafeSpringExporterInConfigurationClass.expected @@ -1,2 +1,4 @@ -| SpringExporterUnsafeDeserialization.java:10:32:10:63 | unsafeHttpInvokerServiceExporter | Unsafe deserialization in a Spring exporter bean '/unsafeHttpInvokerServiceExporter' | -| SpringExporterUnsafeDeserialization.java:18:41:18:88 | unsafeCustomeRemoteInvocationSerializingExporter | Unsafe deserialization in a Spring exporter bean '/unsafeCustomeRemoteInvocationSerializingExporter' | +| SpringExporterUnsafeDeserialization.java:12:32:12:63 | unsafeHttpInvokerServiceExporter | Unsafe deserialization in a Spring exporter bean '/unsafeHttpInvokerServiceExporter' | +| SpringExporterUnsafeDeserialization.java:20:41:20:88 | unsafeCustomeRemoteInvocationSerializingExporter | Unsafe deserialization in a Spring exporter bean '/unsafeCustomeRemoteInvocationSerializingExporter' | +| SpringExporterUnsafeDeserialization.java:36:32:36:63 | unsafeHttpInvokerServiceExporter | Unsafe deserialization in a Spring exporter bean '/unsafeHttpInvokerServiceExporter' | +| SpringExporterUnsafeDeserialization.java:48:32:48:63 | unsafeHttpInvokerServiceExporter | Unsafe deserialization in a Spring exporter bean '/unsafeHttpInvokerServiceExporter' | diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/boot/SpringBootConfiguration.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/boot/SpringBootConfiguration.java new file mode 100644 index 00000000000..483c5cc5606 --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/boot/SpringBootConfiguration.java @@ -0,0 +1,10 @@ +package org.springframework.boot; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; + +import org.springframework.context.annotation.Configuration; + +@Target(ElementType.TYPE) +@Configuration +public @interface SpringBootConfiguration {} \ No newline at end of file diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/boot/autoconfigure/SpringBootApplication.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/boot/autoconfigure/SpringBootApplication.java new file mode 100644 index 00000000000..38bbc35733e --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/boot/autoconfigure/SpringBootApplication.java @@ -0,0 +1,12 @@ +package org.springframework.boot.autoconfigure; + +import java.lang.annotation.Target; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; + +import org.springframework.boot.SpringBootConfiguration; + +@Target(ElementType.TYPE) +@Inherited +@SpringBootConfiguration +public @interface SpringBootApplication {} \ No newline at end of file From 4b7c57c077ff17eae1b94f69d90e67b1eb28e7ea Mon Sep 17 00:00:00 2001 From: Artem Smotrakov Date: Thu, 11 Mar 2021 11:52:07 +0100 Subject: [PATCH 105/725] Added a comment for getBeanIdentifier() Co-authored-by: Chris Smowton --- .../CWE/CWE-502/UnsafeSpringExporterInConfigurationClass.ql | 3 +++ 1 file changed, 3 insertions(+) diff --git a/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInConfigurationClass.ql b/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInConfigurationClass.ql index 4b8fee3c83f..81b56ce0e52 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInConfigurationClass.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInConfigurationClass.ql @@ -47,6 +47,9 @@ private class UnsafeBeanInitMethod extends Method { ) } + /** + * Gets this bean's name if given by the `Bean` annotation, or this method's identifier otherwise. + */ string getBeanIdentifier() { result = identifier } } From 97ab842010eda1f8fb2ef922227f37b2168bf670 Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Thu, 11 Mar 2021 12:44:30 +0000 Subject: [PATCH 106/725] C++: Update summary queries. --- cpp/ql/src/Summary/Files.ql | 11 ----------- cpp/ql/src/Summary/Lines.ql | 11 ----------- cpp/ql/src/Summary/LinesOfCode.ql | 6 +++--- cpp/ql/src/Summary/LinesOfCodePerFile.ql | 6 +++--- cpp/ql/src/Summary/LinesOfUserCode.ql | 11 +++++++++++ cpp/ql/src/Summary/LinesOfUserCodePerFile.ql | 13 +++++++++++++ cpp/ql/src/Summary/LinesPerFile.ql | 13 ------------- cpp/ql/test/query-tests/Summary/Files.expected | 1 - cpp/ql/test/query-tests/Summary/Files.qlref | 1 - cpp/ql/test/query-tests/Summary/Lines.qlref | 1 - .../test/query-tests/Summary/LinesOfCode.expected | 2 +- cpp/ql/test/query-tests/Summary/LinesOfCode.qlref | 2 +- .../query-tests/Summary/LinesOfCodePerFile.expected | 2 +- .../query-tests/Summary/LinesOfCodePerFile.qlref | 2 +- .../{Lines.expected => LinesOfUserCode.expected} | 0 .../test/query-tests/Summary/LinesOfUserCode.qlref | 1 + ...ile.expected => LinesOfUserCodePerFile.expected} | 0 .../Summary/LinesOfUserCodePerFile.qlref | 1 + cpp/ql/test/query-tests/Summary/LinesPerFile.qlref | 1 - 19 files changed, 36 insertions(+), 49 deletions(-) delete mode 100644 cpp/ql/src/Summary/Files.ql delete mode 100644 cpp/ql/src/Summary/Lines.ql create mode 100644 cpp/ql/src/Summary/LinesOfUserCode.ql create mode 100644 cpp/ql/src/Summary/LinesOfUserCodePerFile.ql delete mode 100644 cpp/ql/src/Summary/LinesPerFile.ql delete mode 100644 cpp/ql/test/query-tests/Summary/Files.expected delete mode 100644 cpp/ql/test/query-tests/Summary/Files.qlref delete mode 100644 cpp/ql/test/query-tests/Summary/Lines.qlref rename cpp/ql/test/query-tests/Summary/{Lines.expected => LinesOfUserCode.expected} (100%) create mode 100644 cpp/ql/test/query-tests/Summary/LinesOfUserCode.qlref rename cpp/ql/test/query-tests/Summary/{LinesPerFile.expected => LinesOfUserCodePerFile.expected} (100%) create mode 100644 cpp/ql/test/query-tests/Summary/LinesOfUserCodePerFile.qlref delete mode 100644 cpp/ql/test/query-tests/Summary/LinesPerFile.qlref diff --git a/cpp/ql/src/Summary/Files.ql b/cpp/ql/src/Summary/Files.ql deleted file mode 100644 index 83007c2fec6..00000000000 --- a/cpp/ql/src/Summary/Files.ql +++ /dev/null @@ -1,11 +0,0 @@ -/** - * @id cpp/summary/files - * @name Total source files - * @description The total number of source files. - * @kind metric - * @tags summary - */ - -import cpp - -select count(File f | f.fromSource()) diff --git a/cpp/ql/src/Summary/Lines.ql b/cpp/ql/src/Summary/Lines.ql deleted file mode 100644 index dec466c5468..00000000000 --- a/cpp/ql/src/Summary/Lines.ql +++ /dev/null @@ -1,11 +0,0 @@ -/** - * @id cpp/summary/lines - * @name Total lines of text - * @description The total number of lines of text across all source files. - * @kind metric - * @tags summary - */ - -import cpp - -select sum(File f | f.fromSource() | f.getMetrics().getNumberOfLines()) diff --git a/cpp/ql/src/Summary/LinesOfCode.ql b/cpp/ql/src/Summary/LinesOfCode.ql index 4dc7dc88c05..2d6fdf4b67b 100644 --- a/cpp/ql/src/Summary/LinesOfCode.ql +++ b/cpp/ql/src/Summary/LinesOfCode.ql @@ -1,11 +1,11 @@ /** * @id cpp/summary/lines-of-code - * @name Total lines of code - * @description The total number of lines of code across all source files. + * @name Total lines of C/C++ code + * @description The total number of lines of C/C++ code across all files, including system headers and libraries. * @kind metric * @tags summary */ import cpp -select sum(File f | f.fromSource() | f.getMetrics().getNumberOfLinesOfCode()) +select sum(File f | f.fromSource() | f.getMetrics().getNumberOfLines()) diff --git a/cpp/ql/src/Summary/LinesOfCodePerFile.ql b/cpp/ql/src/Summary/LinesOfCodePerFile.ql index c98d8a3d196..c94f337744a 100644 --- a/cpp/ql/src/Summary/LinesOfCodePerFile.ql +++ b/cpp/ql/src/Summary/LinesOfCodePerFile.ql @@ -1,7 +1,7 @@ /** * @id cpp/summary/lines-of-code-per-file - * @name Lines of code per source file - * @description The number of lines of code for each source file. + * @name Lines of C/C++ code per source file + * @description The number of lines of C/C++ code for each file in the database, including system headers and libraries. * @kind metric * @tags summary */ @@ -10,4 +10,4 @@ import cpp from File f where f.fromSource() -select f, f.getMetrics().getNumberOfLinesOfCode() +select f, f.getMetrics().getNumberOfLines() diff --git a/cpp/ql/src/Summary/LinesOfUserCode.ql b/cpp/ql/src/Summary/LinesOfUserCode.ql new file mode 100644 index 00000000000..e6466c6ddf6 --- /dev/null +++ b/cpp/ql/src/Summary/LinesOfUserCode.ql @@ -0,0 +1,11 @@ +/** + * @id cpp/summary/lines-of-user-code + * @name Total lines of C/C++ source code + * @description The total number of lines of C/C++ code across all files, excluding system headers and libraries. + * @kind metric + * @tags summary + */ + +import cpp + +select sum(File f | exists(f.getRelativePath()) | f.getMetrics().getNumberOfLines()) diff --git a/cpp/ql/src/Summary/LinesOfUserCodePerFile.ql b/cpp/ql/src/Summary/LinesOfUserCodePerFile.ql new file mode 100644 index 00000000000..a10e48c0359 --- /dev/null +++ b/cpp/ql/src/Summary/LinesOfUserCodePerFile.ql @@ -0,0 +1,13 @@ +/** + * @id cpp/summary/lines-of-user-code-per-file + * @name Lines of C/C++ code per source file + * @description The number of lines of C/C++ code for each file in the source directory. + * @kind metric + * @tags summary + */ + +import cpp + +from File f +where exists(f.getRelativePath()) +select f, f.getMetrics().getNumberOfLines() diff --git a/cpp/ql/src/Summary/LinesPerFile.ql b/cpp/ql/src/Summary/LinesPerFile.ql deleted file mode 100644 index bfc78e4d284..00000000000 --- a/cpp/ql/src/Summary/LinesPerFile.ql +++ /dev/null @@ -1,13 +0,0 @@ -/** - * @id cpp/summary/lines-per-file - * @name Lines of text per source file - * @description The number of lines of text for each source file. - * @kind metric - * @tags summary - */ - -import cpp - -from File f -where f.fromSource() -select f, f.getMetrics().getNumberOfLines() diff --git a/cpp/ql/test/query-tests/Summary/Files.expected b/cpp/ql/test/query-tests/Summary/Files.expected deleted file mode 100644 index 7621cebdd5f..00000000000 --- a/cpp/ql/test/query-tests/Summary/Files.expected +++ /dev/null @@ -1 +0,0 @@ -| 3 | diff --git a/cpp/ql/test/query-tests/Summary/Files.qlref b/cpp/ql/test/query-tests/Summary/Files.qlref deleted file mode 100644 index f3bea020f4e..00000000000 --- a/cpp/ql/test/query-tests/Summary/Files.qlref +++ /dev/null @@ -1 +0,0 @@ -Summary/Files.ql \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Summary/Lines.qlref b/cpp/ql/test/query-tests/Summary/Lines.qlref deleted file mode 100644 index 62b3a59a14b..00000000000 --- a/cpp/ql/test/query-tests/Summary/Lines.qlref +++ /dev/null @@ -1 +0,0 @@ -Summary/Lines.ql diff --git a/cpp/ql/test/query-tests/Summary/LinesOfCode.expected b/cpp/ql/test/query-tests/Summary/LinesOfCode.expected index a75c288c151..d847b050658 100644 --- a/cpp/ql/test/query-tests/Summary/LinesOfCode.expected +++ b/cpp/ql/test/query-tests/Summary/LinesOfCode.expected @@ -1 +1 @@ -| 93 | +| 122 | diff --git a/cpp/ql/test/query-tests/Summary/LinesOfCode.qlref b/cpp/ql/test/query-tests/Summary/LinesOfCode.qlref index ac8650d6dcc..b60eb791722 100644 --- a/cpp/ql/test/query-tests/Summary/LinesOfCode.qlref +++ b/cpp/ql/test/query-tests/Summary/LinesOfCode.qlref @@ -1 +1 @@ -Summary/LinesOfCode.ql \ No newline at end of file +Summary/LinesOfCode.ql diff --git a/cpp/ql/test/query-tests/Summary/LinesOfCodePerFile.expected b/cpp/ql/test/query-tests/Summary/LinesOfCodePerFile.expected index 076ee4121a4..e02d0591ab2 100644 --- a/cpp/ql/test/query-tests/Summary/LinesOfCodePerFile.expected +++ b/cpp/ql/test/query-tests/Summary/LinesOfCodePerFile.expected @@ -1,3 +1,3 @@ | empty-file.cpp:0:0:0:0 | empty-file.cpp | 0 | -| large-file.cpp:0:0:0:0 | large-file.cpp | 90 | +| large-file.cpp:0:0:0:0 | large-file.cpp | 119 | | short-file.cpp:0:0:0:0 | short-file.cpp | 3 | diff --git a/cpp/ql/test/query-tests/Summary/LinesOfCodePerFile.qlref b/cpp/ql/test/query-tests/Summary/LinesOfCodePerFile.qlref index eb64c0d8a46..33edfd15c7c 100644 --- a/cpp/ql/test/query-tests/Summary/LinesOfCodePerFile.qlref +++ b/cpp/ql/test/query-tests/Summary/LinesOfCodePerFile.qlref @@ -1 +1 @@ -Summary/LinesOfCodePerFile.ql \ No newline at end of file +Summary/LinesOfCodePerFile.ql diff --git a/cpp/ql/test/query-tests/Summary/Lines.expected b/cpp/ql/test/query-tests/Summary/LinesOfUserCode.expected similarity index 100% rename from cpp/ql/test/query-tests/Summary/Lines.expected rename to cpp/ql/test/query-tests/Summary/LinesOfUserCode.expected diff --git a/cpp/ql/test/query-tests/Summary/LinesOfUserCode.qlref b/cpp/ql/test/query-tests/Summary/LinesOfUserCode.qlref new file mode 100644 index 00000000000..baaa947e6af --- /dev/null +++ b/cpp/ql/test/query-tests/Summary/LinesOfUserCode.qlref @@ -0,0 +1 @@ +Summary/LinesOfUserCode.ql diff --git a/cpp/ql/test/query-tests/Summary/LinesPerFile.expected b/cpp/ql/test/query-tests/Summary/LinesOfUserCodePerFile.expected similarity index 100% rename from cpp/ql/test/query-tests/Summary/LinesPerFile.expected rename to cpp/ql/test/query-tests/Summary/LinesOfUserCodePerFile.expected diff --git a/cpp/ql/test/query-tests/Summary/LinesOfUserCodePerFile.qlref b/cpp/ql/test/query-tests/Summary/LinesOfUserCodePerFile.qlref new file mode 100644 index 00000000000..bb3fc603c4d --- /dev/null +++ b/cpp/ql/test/query-tests/Summary/LinesOfUserCodePerFile.qlref @@ -0,0 +1 @@ +Summary/LinesOfUserCodePerFile.ql diff --git a/cpp/ql/test/query-tests/Summary/LinesPerFile.qlref b/cpp/ql/test/query-tests/Summary/LinesPerFile.qlref deleted file mode 100644 index d967fcb9a8c..00000000000 --- a/cpp/ql/test/query-tests/Summary/LinesPerFile.qlref +++ /dev/null @@ -1 +0,0 @@ -Summary/LinesPerFile.ql \ No newline at end of file From eeac7e322ad0d450f8dac1f0dad9195e4d3b8c33 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Thu, 11 Mar 2021 13:46:32 +0000 Subject: [PATCH 107/725] Query to detect insecure configuration of Spring Boot Actuator --- .../InsecureSpringActuatorConfig.qhelp | 47 ++++++++ .../CWE-016/InsecureSpringActuatorConfig.ql | 112 ++++++++++++++++++ .../CWE/CWE-016/application.properties | 22 ++++ .../Security/CWE/CWE-016/pom_bad.xml | 50 ++++++++ .../Security/CWE/CWE-016/pom_good.xml | 50 ++++++++ .../InsecureSpringActuatorConfig.expected | 1 + .../InsecureSpringActuatorConfig.qlref | 1 + .../security/CWE-016/SensitiveInfo.java | 13 ++ .../security/CWE-016/application.properties | 14 +++ .../query-tests/security/CWE-016/pom.xml | 47 ++++++++ 10 files changed, 357 insertions(+) create mode 100644 java/ql/src/experimental/Security/CWE/CWE-016/InsecureSpringActuatorConfig.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-016/InsecureSpringActuatorConfig.ql create mode 100644 java/ql/src/experimental/Security/CWE/CWE-016/application.properties create mode 100644 java/ql/src/experimental/Security/CWE/CWE-016/pom_bad.xml create mode 100644 java/ql/src/experimental/Security/CWE/CWE-016/pom_good.xml create mode 100644 java/ql/test/experimental/query-tests/security/CWE-016/InsecureSpringActuatorConfig.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-016/InsecureSpringActuatorConfig.qlref create mode 100644 java/ql/test/experimental/query-tests/security/CWE-016/SensitiveInfo.java create mode 100644 java/ql/test/experimental/query-tests/security/CWE-016/application.properties create mode 100644 java/ql/test/experimental/query-tests/security/CWE-016/pom.xml diff --git a/java/ql/src/experimental/Security/CWE/CWE-016/InsecureSpringActuatorConfig.qhelp b/java/ql/src/experimental/Security/CWE/CWE-016/InsecureSpringActuatorConfig.qhelp new file mode 100644 index 00000000000..e201156728a --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-016/InsecureSpringActuatorConfig.qhelp @@ -0,0 +1,47 @@ + + + +

    Spring Boot is a popular framework that facilitates the development of stand-alone applications +and micro services. Spring Boot Actuator helps to expose production-ready support features against +Spring Boot applications.

    + +

    Endpoints of Spring Boot Actuator allow to monitor and interact with a Spring Boot application. +Exposing unprotected actuator endpoints through configuration files can lead to information disclosure +or even remote code execution vulnerability.

    + +

    Rather than programmatically permitting endpoint requests or enforcing access control, frequently +developers simply leave management endpoints publicly accessible in the application configuration file +application.properties without enforcing access control through Spring Security.

    +
    + + +

    Declare the Spring Boot Starter Security module in XML configuration or programmatically enforce +security checks on management endpoints using Spring Security. Otherwise accessing management endpoints +on a different HTTP port other than the port that the web application is listening on also helps to +improve the security.

    +
    + + +

    The following examples show both 'BAD' and 'GOOD' configurations. In the 'BAD' configuration, +no security module is declared and sensitive management endpoints are exposed. In the 'GOOD' configuration, +security is enforced and only endpoints requiring exposure are exposed.

    + + + +
    + + +
  • + Spring Boot documentation: + Spring Boot Actuator: Production-ready Features +
  • +
  • + VERACODE Blog: + Exploiting Spring Boot Actuators +
  • +
  • + HackerOne Report: + Spring Actuator endpoints publicly available, leading to account takeover +
  • +
    +
    diff --git a/java/ql/src/experimental/Security/CWE/CWE-016/InsecureSpringActuatorConfig.ql b/java/ql/src/experimental/Security/CWE/CWE-016/InsecureSpringActuatorConfig.ql new file mode 100644 index 00000000000..2dc11e8e38e --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-016/InsecureSpringActuatorConfig.ql @@ -0,0 +1,112 @@ +/** + * @name Insecure Spring Boot Actuator Configuration + * @description Exposed Spring Boot Actuator through configuration files without declarative or procedural security enforcement leads to information leak or even remote code execution. + * @kind problem + * @id java/insecure-spring-actuator-config + * @tags security + * external/cwe-016 + */ + +import java +import semmle.code.configfiles.ConfigFiles +import semmle.code.java.security.SensitiveActions +import semmle.code.xml.MavenPom + +/** The parent node of the `org.springframework.boot` group. */ +class SpringBootParent extends Parent { + SpringBootParent() { this.getGroup().getValue() = "org.springframework.boot" } +} + +/** Class of Spring Boot dependencies. */ +class SpringBootPom extends Pom { + SpringBootPom() { this.getParentElement() instanceof SpringBootParent } + + /** Holds if the Spring Boot Actuator module `spring-boot-starter-actuator` is used in the project. */ + predicate isSpringBootActuatorUsed() { + this.getADependency().getArtifact().getValue() = "spring-boot-starter-actuator" + } + + /** Holds if the Spring Boot Security module is used in the project, which brings in other security related libraries. */ + predicate isSpringBootSecurityUsed() { + this.getADependency().getArtifact().getValue() = "spring-boot-starter-security" + } +} + +/** The properties file `application.properties`. */ +class ApplicationProperties extends ConfigPair { + ApplicationProperties() { this.getFile().getBaseName() = "application.properties" } +} + +/** The configuration property `management.security.enabled`. */ +class ManagementSecurityEnabled extends ApplicationProperties { + ManagementSecurityEnabled() { this.getNameElement().getName() = "management.security.enabled" } + + string getManagementSecurityEnabled() { result = this.getValueElement().getValue() } + + predicate hasSecurityDisabled() { getManagementSecurityEnabled() = "false" } + + predicate hasSecurityEnabled() { getManagementSecurityEnabled() = "true" } +} + +/** The configuration property `management.endpoints.web.exposure.include`. */ +class ManagementEndPointInclude extends ApplicationProperties { + ManagementEndPointInclude() { + this.getNameElement().getName() = "management.endpoints.web.exposure.include" + } + + string getManagementEndPointInclude() { result = this.getValueElement().getValue().trim() } +} + +/** The configuration property `management.endpoints.web.exposure.exclude`. */ +class ManagementEndPointExclude extends ApplicationProperties { + ManagementEndPointExclude() { + this.getNameElement().getName() = "management.endpoints.web.exposure.exclude" + } + + string getManagementEndPointExclude() { result = this.getValueElement().getValue().trim() } +} + +/** Holds if an application handles sensitive information judging by its variable names. */ +predicate isProtectedApp() { + exists(VarAccess va | va.getVariable().getName().regexpMatch(getCommonSensitiveInfoRegex())) +} + +from SpringBootPom pom, ApplicationProperties ap, Dependency d +where + isProtectedApp() and + pom.isSpringBootActuatorUsed() and + not pom.isSpringBootSecurityUsed() and + ap.getFile() + .getParentContainer() + .getAbsolutePath() + .matches(pom.getFile().getParentContainer().getAbsolutePath() + "%") and // in the same sub-directory + exists(string s | s = pom.getParentElement().getVersionString() | + s.regexpMatch("1\\.[0|1|2|3|4].*") and + not exists(ManagementSecurityEnabled me | + me.hasSecurityEnabled() and me.getFile() = ap.getFile() + ) + or + s.regexpMatch("1\\.5.*") and + exists(ManagementSecurityEnabled me | me.hasSecurityDisabled() and me.getFile() = ap.getFile()) + or + s.regexpMatch("2.*") and + exists(ManagementEndPointInclude mi | + mi.getFile() = ap.getFile() and + ( + mi.getManagementEndPointInclude() = "*" // all endpoints are enabled + or + mi.getManagementEndPointInclude() + .matches([ + "%dump%", "%trace%", "%logfile%", "%shutdown%", "%startup%", "%mappings%", "%env%", + "%beans%", "%sessions%" + ]) // all endpoints apart from '/health' and '/info' are considered sensitive + ) and + not exists(ManagementEndPointExclude mx | + mx.getFile() = ap.getFile() and + mx.getManagementEndPointExclude() = mi.getManagementEndPointInclude() + ) + ) + ) and + d = pom.getADependency() and + d.getArtifact().getValue() = "spring-boot-starter-actuator" +select d, "Insecure configuration of Spring Boot Actuator exposes sensitive endpoints." diff --git a/java/ql/src/experimental/Security/CWE/CWE-016/application.properties b/java/ql/src/experimental/Security/CWE/CWE-016/application.properties new file mode 100644 index 00000000000..aa489435a12 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-016/application.properties @@ -0,0 +1,22 @@ +#management.endpoints.web.base-path=/admin + + +#### BAD: All management endpoints are accessible #### +# vulnerable configuration (spring boot 1.0 - 1.4): exposes actuators by default + +# vulnerable configuration (spring boot 1.5+): requires value false to expose sensitive actuators +management.security.enabled=false + +# vulnerable configuration (spring boot 2+): exposes health and info only by default +management.endpoints.web.exposure.include=* + + +#### GOOD: All management endpoints have access control #### +# safe configuration (spring boot 1.0 - 1.4): exposes actuators by default +management.security.enabled=true + +# safe configuration (spring boot 1.5+): requires value false to expose sensitive actuators +management.security.enabled=true + +# safe configuration (spring boot 2+): exposes health and info only by default +management.endpoints.web.exposure.include=beans,info,health diff --git a/java/ql/src/experimental/Security/CWE/CWE-016/pom_bad.xml b/java/ql/src/experimental/Security/CWE/CWE-016/pom_bad.xml new file mode 100644 index 00000000000..9dd5c9c188b --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-016/pom_bad.xml @@ -0,0 +1,50 @@ + + + 4.0.0 + + spring-boot-actuator-app + spring-boot-actuator-app + 1.0-SNAPSHOT + + + UTF-8 + 1.8 + 1.8 + + + + org.springframework.boot + spring-boot-starter-parent + 2.3.8.RELEASE + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-devtools + + + + + + + org.springframework.boot + spring-boot-test + + + + \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-016/pom_good.xml b/java/ql/src/experimental/Security/CWE/CWE-016/pom_good.xml new file mode 100644 index 00000000000..89f577f21e5 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-016/pom_good.xml @@ -0,0 +1,50 @@ + + + 4.0.0 + + spring-boot-actuator-app + spring-boot-actuator-app + 1.0-SNAPSHOT + + + UTF-8 + 1.8 + 1.8 + + + + org.springframework.boot + spring-boot-starter-parent + 2.3.8.RELEASE + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-devtools + + + + + org.springframework.boot + spring-boot-starter-security + + + + org.springframework.boot + spring-boot-test + + + + \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-016/InsecureSpringActuatorConfig.expected b/java/ql/test/experimental/query-tests/security/CWE-016/InsecureSpringActuatorConfig.expected new file mode 100644 index 00000000000..48630293985 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-016/InsecureSpringActuatorConfig.expected @@ -0,0 +1 @@ +| pom.xml:29:9:32:22 | dependency | Insecure configuration of Spring Boot Actuator exposes sensitive endpoints. | diff --git a/java/ql/test/experimental/query-tests/security/CWE-016/InsecureSpringActuatorConfig.qlref b/java/ql/test/experimental/query-tests/security/CWE-016/InsecureSpringActuatorConfig.qlref new file mode 100644 index 00000000000..9cd12d5e4fb --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-016/InsecureSpringActuatorConfig.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-016/InsecureSpringActuatorConfig.ql \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-016/SensitiveInfo.java b/java/ql/test/experimental/query-tests/security/CWE-016/SensitiveInfo.java new file mode 100644 index 00000000000..a3ff69c1b81 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-016/SensitiveInfo.java @@ -0,0 +1,13 @@ +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +public class SensitiveInfo { + @RequestMapping + public void handleLogin(@RequestParam String username, @RequestParam String password) throws Exception { + if (!username.equals("") && password.equals("")) { + //Blank processing + } + } +} \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-016/application.properties b/java/ql/test/experimental/query-tests/security/CWE-016/application.properties new file mode 100644 index 00000000000..95e704f3a1a --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-016/application.properties @@ -0,0 +1,14 @@ +#management.endpoints.web.base-path=/admin + +# vulnerable configuration (spring boot 1.0 - 1.4): exposes actuators by default + +# vulnerable configuration (spring boot 1.5+): requires value false to expose sensitive actuators +management.security.enabled=false + +# vulnerable configuration (spring boot 2+): exposes health and info only by default +management.endpoints.web.exposure.include=* +management.endpoints.web.exposure.exclude=beans + +management.endpoint.shutdown.enabled=true + +management.endpoint.health.show-details=when_authorized \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-016/pom.xml b/java/ql/test/experimental/query-tests/security/CWE-016/pom.xml new file mode 100644 index 00000000000..a9d5fa920c8 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-016/pom.xml @@ -0,0 +1,47 @@ + + + 4.0.0 + + spring-boot-actuator-app + spring-boot-actuator-app + 1.0-SNAPSHOT + + + UTF-8 + 1.8 + 1.8 + + + + org.springframework.boot + spring-boot-starter-parent + 2.3.8.RELEASE + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-devtools + + + + org.springframework.boot + spring-boot-test + + + + \ No newline at end of file From 57953c523c453c7be78a15f22d954e5c6cb78c59 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Thu, 11 Mar 2021 17:16:36 +0000 Subject: [PATCH 108/725] Update qldoc --- .../CWE/CWE-297/InsecureLdapEndpoint.qhelp | 21 ++++++++++++------- .../CWE/CWE-297/InsecureLdapEndpoint.ql | 11 +++++++--- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.qhelp b/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.qhelp index cb43f52515b..50e1febf894 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.qhelp +++ b/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.qhelp @@ -4,20 +4,27 @@ -

    Java versions 8u181 or greater have enabled LDAPS endpoint identification by default. Nowadays infrastructure services like LDAP are commonly deployed behind load balancers therefore the LDAP server name can be different from the FQDN of the LDAPS endpoint. If a service certificate does not properly contain a matching DNS name as part of the certificate, Java will reject it by default.

    -

    Instead of addressing the issue properly by having a compliant certificate deployed, frequently developers simply disable the LDAPS endpoint check.

    -

    Failing to validate the certificate makes the SSL session susceptible to a man-in-the-middle attack. This query checks whether the LDAPS endpoint check is disabled in system properties.

    +

    Java versions 8u181 or greater have enabled LDAPS endpoint identification by default. Nowadays + infrastructure services like LDAP are commonly deployed behind load balancers therefore the LDAP + server name can be different from the FQDN of the LDAPS endpoint. If a service certificate does not + properly contain a matching DNS name as part of the certificate, Java will reject it by default.

    +

    Instead of addressing the issue properly by having a compliant certificate deployed, frequently + developers simply disable the LDAPS endpoint check.

    +

    Failing to validate the certificate makes the SSL session susceptible to a man-in-the-middle attack. + This query checks whether the LDAPS endpoint check is disabled in system properties.

    -

    Replace any non-conforming LDAP server certificates to include a DNS name in the subjectAltName field of the certificate that matches the FQDN of the service.

    +

    Replace any non-conforming LDAP server certificates to include a DNS name in the subjectAltName field + of the certificate that matches the FQDN of the service.

    -

    The following two examples show two ways of configuring LDAPS endpoint. In the 'BAD' case, -endpoint check is disabled. In the 'GOOD' case, endpoint check is left enabled through the default Java configuration.

    +

    The following two examples show two ways of configuring LDAPS endpoint. In the 'BAD' case, + endpoint check is disabled. In the 'GOOD' case, endpoint check is left enabled through the + default Java configuration.

    -> +
    diff --git a/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.ql b/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.ql index c83aeb4a6a5..7780d2a0248 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.ql @@ -1,6 +1,7 @@ /** * @name Insecure LDAPS Endpoint Configuration - * @description Java application configured to disable LDAPS endpoint identification does not validate the SSL certificate to properly ensure that it is actually associated with that host. + * @description Java application configured to disable LDAPS endpoint identification does not validate + * the SSL certificate to properly ensure that it is actually associated with that host. * @kind problem * @id java/insecure-ldaps-endpoint * @tags security @@ -23,7 +24,8 @@ class TypeHashtable extends Class { } /** - * The method to set Java properties either through `setProperty` declared in the class `Properties` or `put` declared in its parent class `HashTable`. + * The method to set Java properties either through `setProperty` declared in the class `Properties` + * or `put` declared in its parent class `HashTable`. */ class SetPropertyMethod extends Method { SetPropertyMethod() { @@ -40,7 +42,10 @@ class SetSystemPropertiesMethod extends Method { } } -/** Holds if `expr` is evaluated to the string literal `com.sun.jndi.ldap.object.disableEndpointIdentification`. */ +/** + * Holds if `Expr` expr is evaluated to the string literal + * `com.sun.jndi.ldap.object.disableEndpointIdentification`. + */ predicate isPropertyDisableLdapEndpointId(Expr expr) { expr.(CompileTimeConstantExpr).getStringValue() = "com.sun.jndi.ldap.object.disableEndpointIdentification" From 0a35feef766249b88abfc78f8a9dd552664ab083 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Thu, 11 Mar 2021 17:28:07 +0000 Subject: [PATCH 109/725] Exclude CSRF cookies to reduce FPs --- .../CWE-1004/SensitiveCookieNotHttpOnly.ql | 16 +++-- .../SensitiveCookieNotHttpOnly.expected | 60 +++++++++---------- .../CWE-1004/SensitiveCookieNotHttpOnly.java | 22 ++++++- .../query-tests/security/CWE-1004/options | 2 +- .../security/web/csrf/CsrfToken.java | 50 ++++++++++++++++ 5 files changed, 113 insertions(+), 37 deletions(-) create mode 100644 java/ql/test/stubs/springframework-5.2.3/org/springframework/security/web/csrf/CsrfToken.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql b/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql index 985c546b555..693dad68082 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql @@ -16,12 +16,18 @@ import DataFlow::PathGraph /** Gets a regular expression for matching common names of sensitive cookies. */ string getSensitiveCookieNameRegex() { result = "(?i).*(auth|session|token|key|credential).*" } -/** Holds if a string is concatenated with the name of a sensitive cookie. */ +/** Gets a regular expression for matching CSRF cookies. */ +string getCsrfCookieNameRegex() { result = "(?i).*(csrf).*" } + +/** + * Holds if a string is concatenated with the name of a sensitive cookie. Excludes CSRF cookies since + * they are special cookies implementing the Synchronizer Token Pattern that can be used in JavaScript. + */ predicate isSensitiveCookieNameExpr(Expr expr) { - expr.(CompileTimeConstantExpr) - .getStringValue() - .toLowerCase() - .regexpMatch(getSensitiveCookieNameRegex()) or + exists(string s | s = expr.(CompileTimeConstantExpr).getStringValue().toLowerCase() | + s.regexpMatch(getSensitiveCookieNameRegex()) and not s.regexpMatch(getCsrfCookieNameRegex()) + ) + or isSensitiveCookieNameExpr(expr.(AddExpr).getAnOperand()) } diff --git a/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.expected b/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.expected index c9fe15d4082..8fa688bef2a 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.expected @@ -1,33 +1,33 @@ edges -| SensitiveCookieNotHttpOnly.java:22:33:22:43 | "jwt_token" : String | SensitiveCookieNotHttpOnly.java:29:28:29:36 | jwtCookie | -| SensitiveCookieNotHttpOnly.java:40:42:40:49 | "token=" : String | SensitiveCookieNotHttpOnly.java:40:42:40:69 | ... + ... | -| SensitiveCookieNotHttpOnly.java:40:42:40:57 | ... + ... : String | SensitiveCookieNotHttpOnly.java:40:42:40:69 | ... + ... | -| SensitiveCookieNotHttpOnly.java:50:56:50:75 | "session-access-key" : String | SensitiveCookieNotHttpOnly.java:50:42:50:124 | toString(...) | -| SensitiveCookieNotHttpOnly.java:61:51:61:70 | "session-access-key" : String | SensitiveCookieNotHttpOnly.java:63:42:63:47 | keyStr | -| SensitiveCookieNotHttpOnly.java:68:28:68:35 | "token=" : String | SensitiveCookieNotHttpOnly.java:69:42:69:50 | secString | -| SensitiveCookieNotHttpOnly.java:68:28:68:43 | ... + ... : String | SensitiveCookieNotHttpOnly.java:69:42:69:50 | secString | -| SensitiveCookieNotHttpOnly.java:68:28:68:55 | ... + ... : String | SensitiveCookieNotHttpOnly.java:69:42:69:50 | secString | +| SensitiveCookieNotHttpOnly.java:24:33:24:43 | "jwt_token" : String | SensitiveCookieNotHttpOnly.java:31:28:31:36 | jwtCookie | +| SensitiveCookieNotHttpOnly.java:42:42:42:49 | "token=" : String | SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... | +| SensitiveCookieNotHttpOnly.java:42:42:42:57 | ... + ... : String | SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... | +| SensitiveCookieNotHttpOnly.java:52:56:52:75 | "session-access-key" : String | SensitiveCookieNotHttpOnly.java:52:42:52:124 | toString(...) | +| SensitiveCookieNotHttpOnly.java:63:51:63:70 | "session-access-key" : String | SensitiveCookieNotHttpOnly.java:65:42:65:47 | keyStr | +| SensitiveCookieNotHttpOnly.java:70:28:70:35 | "token=" : String | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | +| SensitiveCookieNotHttpOnly.java:70:28:70:43 | ... + ... : String | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | +| SensitiveCookieNotHttpOnly.java:70:28:70:55 | ... + ... : String | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | nodes -| SensitiveCookieNotHttpOnly.java:22:33:22:43 | "jwt_token" : String | semmle.label | "jwt_token" : String | -| SensitiveCookieNotHttpOnly.java:29:28:29:36 | jwtCookie | semmle.label | jwtCookie | -| SensitiveCookieNotHttpOnly.java:40:42:40:49 | "token=" : String | semmle.label | "token=" : String | -| SensitiveCookieNotHttpOnly.java:40:42:40:57 | ... + ... : String | semmle.label | ... + ... : String | -| SensitiveCookieNotHttpOnly.java:40:42:40:69 | ... + ... | semmle.label | ... + ... | -| SensitiveCookieNotHttpOnly.java:50:42:50:124 | toString(...) | semmle.label | toString(...) | -| SensitiveCookieNotHttpOnly.java:50:56:50:75 | "session-access-key" : String | semmle.label | "session-access-key" : String | -| SensitiveCookieNotHttpOnly.java:61:51:61:70 | "session-access-key" : String | semmle.label | "session-access-key" : String | -| SensitiveCookieNotHttpOnly.java:63:42:63:47 | keyStr | semmle.label | keyStr | -| SensitiveCookieNotHttpOnly.java:68:28:68:35 | "token=" : String | semmle.label | "token=" : String | -| SensitiveCookieNotHttpOnly.java:68:28:68:43 | ... + ... : String | semmle.label | ... + ... : String | -| SensitiveCookieNotHttpOnly.java:68:28:68:55 | ... + ... : String | semmle.label | ... + ... : String | -| SensitiveCookieNotHttpOnly.java:69:42:69:50 | secString | semmle.label | secString | +| SensitiveCookieNotHttpOnly.java:24:33:24:43 | "jwt_token" : String | semmle.label | "jwt_token" : String | +| SensitiveCookieNotHttpOnly.java:31:28:31:36 | jwtCookie | semmle.label | jwtCookie | +| SensitiveCookieNotHttpOnly.java:42:42:42:49 | "token=" : String | semmle.label | "token=" : String | +| SensitiveCookieNotHttpOnly.java:42:42:42:57 | ... + ... : String | semmle.label | ... + ... : String | +| SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... | semmle.label | ... + ... | +| SensitiveCookieNotHttpOnly.java:52:42:52:124 | toString(...) | semmle.label | toString(...) | +| SensitiveCookieNotHttpOnly.java:52:56:52:75 | "session-access-key" : String | semmle.label | "session-access-key" : String | +| SensitiveCookieNotHttpOnly.java:63:51:63:70 | "session-access-key" : String | semmle.label | "session-access-key" : String | +| SensitiveCookieNotHttpOnly.java:65:42:65:47 | keyStr | semmle.label | keyStr | +| SensitiveCookieNotHttpOnly.java:70:28:70:35 | "token=" : String | semmle.label | "token=" : String | +| SensitiveCookieNotHttpOnly.java:70:28:70:43 | ... + ... : String | semmle.label | ... + ... : String | +| SensitiveCookieNotHttpOnly.java:70:28:70:55 | ... + ... : String | semmle.label | ... + ... : String | +| SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | semmle.label | secString | #select -| SensitiveCookieNotHttpOnly.java:29:28:29:36 | jwtCookie | SensitiveCookieNotHttpOnly.java:22:33:22:43 | "jwt_token" : String | SensitiveCookieNotHttpOnly.java:29:28:29:36 | jwtCookie | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:22:33:22:43 | "jwt_token" | This sensitive cookie | -| SensitiveCookieNotHttpOnly.java:40:42:40:69 | ... + ... | SensitiveCookieNotHttpOnly.java:40:42:40:49 | "token=" : String | SensitiveCookieNotHttpOnly.java:40:42:40:69 | ... + ... | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:40:42:40:49 | "token=" | This sensitive cookie | -| SensitiveCookieNotHttpOnly.java:40:42:40:69 | ... + ... | SensitiveCookieNotHttpOnly.java:40:42:40:57 | ... + ... : String | SensitiveCookieNotHttpOnly.java:40:42:40:69 | ... + ... | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:40:42:40:57 | ... + ... | This sensitive cookie | -| SensitiveCookieNotHttpOnly.java:40:42:40:69 | ... + ... | SensitiveCookieNotHttpOnly.java:40:42:40:69 | ... + ... | SensitiveCookieNotHttpOnly.java:40:42:40:69 | ... + ... | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:40:42:40:69 | ... + ... | This sensitive cookie | -| SensitiveCookieNotHttpOnly.java:50:42:50:124 | toString(...) | SensitiveCookieNotHttpOnly.java:50:56:50:75 | "session-access-key" : String | SensitiveCookieNotHttpOnly.java:50:42:50:124 | toString(...) | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:50:56:50:75 | "session-access-key" | This sensitive cookie | -| SensitiveCookieNotHttpOnly.java:63:42:63:47 | keyStr | SensitiveCookieNotHttpOnly.java:61:51:61:70 | "session-access-key" : String | SensitiveCookieNotHttpOnly.java:63:42:63:47 | keyStr | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:61:51:61:70 | "session-access-key" | This sensitive cookie | -| SensitiveCookieNotHttpOnly.java:69:42:69:50 | secString | SensitiveCookieNotHttpOnly.java:68:28:68:35 | "token=" : String | SensitiveCookieNotHttpOnly.java:69:42:69:50 | secString | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:68:28:68:35 | "token=" | This sensitive cookie | -| SensitiveCookieNotHttpOnly.java:69:42:69:50 | secString | SensitiveCookieNotHttpOnly.java:68:28:68:43 | ... + ... : String | SensitiveCookieNotHttpOnly.java:69:42:69:50 | secString | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:68:28:68:43 | ... + ... | This sensitive cookie | -| SensitiveCookieNotHttpOnly.java:69:42:69:50 | secString | SensitiveCookieNotHttpOnly.java:68:28:68:55 | ... + ... : String | SensitiveCookieNotHttpOnly.java:69:42:69:50 | secString | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:68:28:68:55 | ... + ... | This sensitive cookie | +| SensitiveCookieNotHttpOnly.java:31:28:31:36 | jwtCookie | SensitiveCookieNotHttpOnly.java:24:33:24:43 | "jwt_token" : String | SensitiveCookieNotHttpOnly.java:31:28:31:36 | jwtCookie | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:24:33:24:43 | "jwt_token" | This sensitive cookie | +| SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... | SensitiveCookieNotHttpOnly.java:42:42:42:49 | "token=" : String | SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:42:42:42:49 | "token=" | This sensitive cookie | +| SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... | SensitiveCookieNotHttpOnly.java:42:42:42:57 | ... + ... : String | SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:42:42:42:57 | ... + ... | This sensitive cookie | +| SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... | SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... | SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... | This sensitive cookie | +| SensitiveCookieNotHttpOnly.java:52:42:52:124 | toString(...) | SensitiveCookieNotHttpOnly.java:52:56:52:75 | "session-access-key" : String | SensitiveCookieNotHttpOnly.java:52:42:52:124 | toString(...) | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:52:56:52:75 | "session-access-key" | This sensitive cookie | +| SensitiveCookieNotHttpOnly.java:65:42:65:47 | keyStr | SensitiveCookieNotHttpOnly.java:63:51:63:70 | "session-access-key" : String | SensitiveCookieNotHttpOnly.java:65:42:65:47 | keyStr | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:63:51:63:70 | "session-access-key" | This sensitive cookie | +| SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | SensitiveCookieNotHttpOnly.java:70:28:70:35 | "token=" : String | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:70:28:70:35 | "token=" | This sensitive cookie | +| SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | SensitiveCookieNotHttpOnly.java:70:28:70:43 | ... + ... : String | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:70:28:70:43 | ... + ... | This sensitive cookie | +| SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | SensitiveCookieNotHttpOnly.java:70:28:70:55 | ... + ... : String | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:70:28:70:55 | ... + ... | This sensitive cookie | diff --git a/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.java b/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.java index 6572577a697..337a99cc096 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.java +++ b/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.java @@ -7,6 +7,8 @@ import javax.servlet.ServletException; import javax.ws.rs.core.NewCookie; +import org.springframework.security.web.csrf.CsrfToken; + class SensitiveCookieNotHttpOnly { // GOOD - Tests adding a sensitive cookie with the `HttpOnly` flag set. public void addCookie(String jwt_token, HttpServletRequest request, HttpServletResponse response) { @@ -67,5 +69,23 @@ class SensitiveCookieNotHttpOnly { public void addCookie9(String authId, HttpServletRequest request, HttpServletResponse response) { String secString = "token=" +authId + ";Secure"; response.addHeader("Set-Cookie", secString); - } + } + + // GOOD - CSRF token doesn't need to have the `HttpOnly` flag set. + public void addCsrfCookie(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + // Spring put the CSRF token in session attribute "_csrf" + CsrfToken csrfToken = (CsrfToken) request.getAttribute("_csrf"); + + // Send the cookie only if the token has changed + String actualToken = request.getHeader("X-CSRF-TOKEN"); + if (actualToken == null || !actualToken.equals(csrfToken.getToken())) { + // Session cookie that can be used by AngularJS + String pCookieName = "CSRF-TOKEN"; + Cookie cookie = new Cookie(pCookieName, csrfToken.getToken()); + cookie.setMaxAge(-1); + cookie.setHttpOnly(false); + cookie.setPath("/"); + response.addCookie(cookie); + } + } } diff --git a/java/ql/test/experimental/query-tests/security/CWE-1004/options b/java/ql/test/experimental/query-tests/security/CWE-1004/options index 7f2b253fb20..d61a358d97f 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-1004/options +++ b/java/ql/test/experimental/query-tests/security/CWE-1004/options @@ -1 +1 @@ -// semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/jsr311-api-1.1.1 \ No newline at end of file +// semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/jsr311-api-1.1.1:${testdir}/../../../../stubs/springframework-5.2.3 \ No newline at end of file diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/security/web/csrf/CsrfToken.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/security/web/csrf/CsrfToken.java new file mode 100644 index 00000000000..bc59a2e496a --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/security/web/csrf/CsrfToken.java @@ -0,0 +1,50 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.web.csrf; + +import java.io.Serializable; + +/** + * Provides the information about an expected CSRF token. + * + * @author Rob Winch + * @since 3.2 + * @see DefaultCsrfToken + */ +public interface CsrfToken extends Serializable { + + /** + * Gets the HTTP header that the CSRF is populated on the response and can be placed + * on requests instead of the parameter. Cannot be null. + * @return the HTTP header that the CSRF is populated on the response and can be + * placed on requests instead of the parameter + */ + String getHeaderName(); + + /** + * Gets the HTTP parameter name that should contain the token. Cannot be null. + * @return the HTTP parameter name that should contain the token. + */ + String getParameterName(); + + /** + * Gets the token value. Cannot be null. + * @return the token value + */ + String getToken(); + +} From 5667901a2a2a92fac5e79b3be67d44d24e6a5531 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 11 Mar 2021 21:16:57 +0100 Subject: [PATCH 110/725] C++: Accept test changes after merge from main (which changed the path explanations). --- .../CWE-022/semmle/tests/TaintedPath.expected | 8 +- .../CWE/CWE-079/semmle/CgiXss/CgiXss.expected | 16 ++-- .../CWE-089/SqlTainted/SqlTainted.expected | 8 +- .../UncontrolledProcessOperation.expected | 48 +++++----- .../semmle/tests/UnboundedWrite.expected | 60 ++++++------- .../CWE-134/semmle/funcs/funcsLocal.expected | 56 ++++++------ ...olledFormatStringThroughGlobalVar.expected | 30 +++---- .../CWE/CWE-134/semmle/ifs/ifs.expected | 88 +++++++++---------- .../TaintedAllocationSize.expected | 36 ++++---- .../AuthenticationBypass.expected | 24 ++--- .../tests/CleartextBufferWrite.expected | 8 +- 11 files changed, 191 insertions(+), 191 deletions(-) diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-022/semmle/tests/TaintedPath.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-022/semmle/tests/TaintedPath.expected index 60898414224..7b513c574ad 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-022/semmle/tests/TaintedPath.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-022/semmle/tests/TaintedPath.expected @@ -1,17 +1,17 @@ edges | test.c:9:23:9:26 | argv | test.c:17:11:17:18 | (const char *)... | | test.c:9:23:9:26 | argv | test.c:17:11:17:18 | (const char *)... | -| test.c:9:23:9:26 | argv | test.c:17:11:17:18 | Argument 0 indirection | -| test.c:9:23:9:26 | argv | test.c:17:11:17:18 | Argument 0 indirection | | test.c:9:23:9:26 | argv | test.c:17:11:17:18 | fileName | | test.c:9:23:9:26 | argv | test.c:17:11:17:18 | fileName | +| test.c:9:23:9:26 | argv | test.c:17:11:17:18 | fileName indirection | +| test.c:9:23:9:26 | argv | test.c:17:11:17:18 | fileName indirection | nodes | test.c:9:23:9:26 | argv | semmle.label | argv | | test.c:9:23:9:26 | argv | semmle.label | argv | | test.c:17:11:17:18 | (const char *)... | semmle.label | (const char *)... | | test.c:17:11:17:18 | (const char *)... | semmle.label | (const char *)... | -| test.c:17:11:17:18 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| test.c:17:11:17:18 | Argument 0 indirection | semmle.label | Argument 0 indirection | | test.c:17:11:17:18 | fileName | semmle.label | fileName | +| test.c:17:11:17:18 | fileName indirection | semmle.label | fileName indirection | +| test.c:17:11:17:18 | fileName indirection | semmle.label | fileName indirection | #select | test.c:17:11:17:18 | fileName | test.c:9:23:9:26 | argv | test.c:17:11:17:18 | fileName | This argument to a file access function is derived from $@ and then passed to fopen(filename) | test.c:9:23:9:26 | argv | user input (argv) | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/CgiXss.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/CgiXss.expected index 70615e0b606..d9fa0d7029f 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/CgiXss.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/CgiXss.expected @@ -1,17 +1,17 @@ edges | search.c:14:24:14:28 | *query | search.c:17:8:17:12 | (const char *)... | -| search.c:14:24:14:28 | *query | search.c:17:8:17:12 | Argument 0 indirection | | search.c:14:24:14:28 | *query | search.c:17:8:17:12 | query | +| search.c:14:24:14:28 | *query | search.c:17:8:17:12 | query indirection | | search.c:14:24:14:28 | query | search.c:17:8:17:12 | (const char *)... | -| search.c:14:24:14:28 | query | search.c:17:8:17:12 | Argument 0 indirection | | search.c:14:24:14:28 | query | search.c:17:8:17:12 | query | | search.c:14:24:14:28 | query | search.c:17:8:17:12 | query | -| search.c:22:24:22:28 | *query | search.c:23:39:23:43 | Argument 1 indirection | +| search.c:14:24:14:28 | query | search.c:17:8:17:12 | query indirection | | search.c:22:24:22:28 | *query | search.c:23:39:23:43 | query | | search.c:22:24:22:28 | *query | search.c:23:39:23:43 | query | -| search.c:22:24:22:28 | query | search.c:23:39:23:43 | Argument 1 indirection | +| search.c:22:24:22:28 | *query | search.c:23:39:23:43 | query indirection | | search.c:22:24:22:28 | query | search.c:23:39:23:43 | query | | search.c:22:24:22:28 | query | search.c:23:39:23:43 | query | +| search.c:22:24:22:28 | query | search.c:23:39:23:43 | query indirection | | search.c:51:21:51:26 | call to getenv | search.c:55:5:55:15 | raw_query | | search.c:51:21:51:26 | call to getenv | search.c:55:5:55:15 | raw_query | | search.c:51:21:51:26 | call to getenv | search.c:55:17:55:25 | raw_query indirection | @@ -29,18 +29,18 @@ nodes | search.c:14:24:14:28 | query | semmle.label | query | | search.c:17:8:17:12 | (const char *)... | semmle.label | (const char *)... | | search.c:17:8:17:12 | (const char *)... | semmle.label | (const char *)... | -| search.c:17:8:17:12 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| search.c:17:8:17:12 | Argument 0 indirection | semmle.label | Argument 0 indirection | | search.c:17:8:17:12 | query | semmle.label | query | | search.c:17:8:17:12 | query | semmle.label | query | | search.c:17:8:17:12 | query | semmle.label | query | +| search.c:17:8:17:12 | query indirection | semmle.label | query indirection | +| search.c:17:8:17:12 | query indirection | semmle.label | query indirection | | search.c:22:24:22:28 | *query | semmle.label | *query | | search.c:22:24:22:28 | query | semmle.label | query | -| search.c:23:39:23:43 | Argument 1 indirection | semmle.label | Argument 1 indirection | -| search.c:23:39:23:43 | Argument 1 indirection | semmle.label | Argument 1 indirection | | search.c:23:39:23:43 | query | semmle.label | query | | search.c:23:39:23:43 | query | semmle.label | query | | search.c:23:39:23:43 | query | semmle.label | query | +| search.c:23:39:23:43 | query indirection | semmle.label | query indirection | +| search.c:23:39:23:43 | query indirection | semmle.label | query indirection | | search.c:51:21:51:26 | call to getenv | semmle.label | call to getenv | | search.c:51:21:51:26 | call to getenv | semmle.label | call to getenv | | search.c:55:5:55:15 | raw_query | semmle.label | raw_query | 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 fe84a80654c..e267dd48bba 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,17 +1,17 @@ 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 | (const char *)... | -| test.c:15:20:15:23 | argv | test.c:21:18:21:23 | Argument 1 indirection | -| test.c:15:20:15:23 | argv | test.c:21:18:21:23 | Argument 1 indirection | | 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:15:20:15:23 | argv | test.c:21:18:21:23 | query1 indirection | +| test.c:15:20:15:23 | argv | test.c:21:18:21:23 | query1 indirection | nodes | test.c:15:20:15:23 | argv | semmle.label | argv | | test.c:15:20:15:23 | 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 | Argument 1 indirection | semmle.label | Argument 1 indirection | -| test.c:21:18:21:23 | Argument 1 indirection | semmle.label | Argument 1 indirection | | test.c:21:18:21:23 | query1 | semmle.label | query1 | +| test.c:21:18:21:23 | query1 indirection | semmle.label | query1 indirection | +| test.c:21:18:21:23 | query1 indirection | semmle.label | query1 indirection | #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) | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/UncontrolledProcessOperation.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/UncontrolledProcessOperation.expected index 062a59d2907..14f234f5999 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/UncontrolledProcessOperation.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/UncontrolledProcessOperation.expected @@ -1,16 +1,16 @@ edges -| test.cpp:24:30:24:36 | *command | test.cpp:26:10:26:16 | Argument 0 indirection | | test.cpp:24:30:24:36 | *command | test.cpp:26:10:26:16 | command | | test.cpp:24:30:24:36 | *command | test.cpp:26:10:26:16 | command | -| test.cpp:24:30:24:36 | command | test.cpp:26:10:26:16 | Argument 0 indirection | +| test.cpp:24:30:24:36 | *command | test.cpp:26:10:26:16 | command indirection | | test.cpp:24:30:24:36 | command | test.cpp:26:10:26:16 | command | | test.cpp:24:30:24:36 | command | test.cpp:26:10:26:16 | command | -| test.cpp:29:30:29:36 | *command | test.cpp:31:10:31:16 | Argument 0 indirection | +| test.cpp:24:30:24:36 | command | test.cpp:26:10:26:16 | command indirection | | test.cpp:29:30:29:36 | *command | test.cpp:31:10:31:16 | command | | test.cpp:29:30:29:36 | *command | test.cpp:31:10:31:16 | command | -| test.cpp:29:30:29:36 | command | test.cpp:31:10:31:16 | Argument 0 indirection | +| test.cpp:29:30:29:36 | *command | test.cpp:31:10:31:16 | command indirection | | test.cpp:29:30:29:36 | command | test.cpp:31:10:31:16 | command | | test.cpp:29:30:29:36 | command | test.cpp:31:10:31:16 | command | +| test.cpp:29:30:29:36 | command | test.cpp:31:10:31:16 | command indirection | | test.cpp:42:7:42:16 | call to getenv | test.cpp:24:30:24:36 | command | | test.cpp:42:18:42:23 | call to getenv | test.cpp:42:7:42:16 | call to getenv | | test.cpp:42:18:42:23 | call to getenv | test.cpp:42:18:42:34 | call to getenv indirection | @@ -24,44 +24,44 @@ edges | test.cpp:43:18:43:34 | (const char *)... | test.cpp:43:18:43:34 | call to getenv indirection | | test.cpp:43:18:43:34 | call to getenv indirection | test.cpp:29:30:29:36 | *command | | test.cpp:56:12:56:17 | buffer | test.cpp:62:10:62:15 | (const char *)... | -| test.cpp:56:12:56:17 | buffer | test.cpp:62:10:62:15 | Argument 0 indirection | | test.cpp:56:12:56:17 | buffer | test.cpp:62:10:62:15 | buffer | +| test.cpp:56:12:56:17 | buffer | test.cpp:62:10:62:15 | buffer indirection | | test.cpp:56:12:56:17 | buffer | test.cpp:63:10:63:13 | (const char *)... | -| test.cpp:56:12:56:17 | buffer | test.cpp:63:10:63:13 | Argument 0 indirection | | test.cpp:56:12:56:17 | buffer | test.cpp:63:10:63:13 | data | +| test.cpp:56:12:56:17 | buffer | test.cpp:63:10:63:13 | data indirection | | test.cpp:56:12:56:17 | fgets output argument | test.cpp:62:10:62:15 | (const char *)... | -| test.cpp:56:12:56:17 | fgets output argument | test.cpp:62:10:62:15 | Argument 0 indirection | | test.cpp:56:12:56:17 | fgets output argument | test.cpp:62:10:62:15 | buffer | +| test.cpp:56:12:56:17 | fgets output argument | test.cpp:62:10:62:15 | buffer indirection | | test.cpp:56:12:56:17 | fgets output argument | test.cpp:63:10:63:13 | (const char *)... | -| test.cpp:56:12:56:17 | fgets output argument | test.cpp:63:10:63:13 | Argument 0 indirection | | test.cpp:56:12:56:17 | fgets output argument | test.cpp:63:10:63:13 | data | +| test.cpp:56:12:56:17 | fgets output argument | test.cpp:63:10:63:13 | data indirection | | test.cpp:76:12:76:17 | buffer | test.cpp:78:10:78:15 | (const char *)... | -| test.cpp:76:12:76:17 | buffer | test.cpp:78:10:78:15 | Argument 0 indirection | | test.cpp:76:12:76:17 | buffer | test.cpp:78:10:78:15 | buffer | +| test.cpp:76:12:76:17 | buffer | test.cpp:78:10:78:15 | buffer indirection | | test.cpp:76:12:76:17 | buffer | test.cpp:79:10:79:13 | (const char *)... | -| test.cpp:76:12:76:17 | buffer | test.cpp:79:10:79:13 | Argument 0 indirection | | test.cpp:76:12:76:17 | buffer | test.cpp:79:10:79:13 | data | +| test.cpp:76:12:76:17 | buffer | test.cpp:79:10:79:13 | data indirection | | test.cpp:76:12:76:17 | fgets output argument | test.cpp:78:10:78:15 | (const char *)... | -| test.cpp:76:12:76:17 | fgets output argument | test.cpp:78:10:78:15 | Argument 0 indirection | | test.cpp:76:12:76:17 | fgets output argument | test.cpp:78:10:78:15 | buffer | +| test.cpp:76:12:76:17 | fgets output argument | test.cpp:78:10:78:15 | buffer indirection | | test.cpp:76:12:76:17 | fgets output argument | test.cpp:79:10:79:13 | (const char *)... | -| test.cpp:76:12:76:17 | fgets output argument | test.cpp:79:10:79:13 | Argument 0 indirection | | test.cpp:76:12:76:17 | fgets output argument | test.cpp:79:10:79:13 | data | +| test.cpp:76:12:76:17 | fgets output argument | test.cpp:79:10:79:13 | data indirection | nodes | test.cpp:24:30:24:36 | *command | semmle.label | *command | | test.cpp:24:30:24:36 | command | semmle.label | command | -| test.cpp:26:10:26:16 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| test.cpp:26:10:26:16 | Argument 0 indirection | semmle.label | Argument 0 indirection | | test.cpp:26:10:26:16 | command | semmle.label | command | | test.cpp:26:10:26:16 | command | semmle.label | command | | test.cpp:26:10:26:16 | command | semmle.label | command | +| test.cpp:26:10:26:16 | command indirection | semmle.label | command indirection | +| test.cpp:26:10:26:16 | command indirection | semmle.label | command indirection | | test.cpp:29:30:29:36 | *command | semmle.label | *command | | test.cpp:29:30:29:36 | command | semmle.label | command | -| test.cpp:31:10:31:16 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| test.cpp:31:10:31:16 | Argument 0 indirection | semmle.label | Argument 0 indirection | | test.cpp:31:10:31:16 | command | semmle.label | command | | test.cpp:31:10:31:16 | command | semmle.label | command | | test.cpp:31:10:31:16 | command | semmle.label | command | +| test.cpp:31:10:31:16 | command indirection | semmle.label | command indirection | +| test.cpp:31:10:31:16 | command indirection | semmle.label | command indirection | | test.cpp:42:7:42:16 | call to getenv | semmle.label | call to getenv | | test.cpp:42:18:42:23 | call to getenv | semmle.label | call to getenv | | test.cpp:42:18:42:34 | (const char *)... | semmle.label | (const char *)... | @@ -74,26 +74,26 @@ nodes | test.cpp:56:12:56:17 | fgets output argument | semmle.label | fgets output argument | | test.cpp:62:10:62:15 | (const char *)... | semmle.label | (const char *)... | | test.cpp:62:10:62:15 | (const char *)... | semmle.label | (const char *)... | -| test.cpp:62:10:62:15 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| test.cpp:62:10:62:15 | Argument 0 indirection | semmle.label | Argument 0 indirection | | test.cpp:62:10:62:15 | buffer | semmle.label | buffer | +| test.cpp:62:10:62:15 | buffer indirection | semmle.label | buffer indirection | +| test.cpp:62:10:62:15 | buffer indirection | semmle.label | buffer indirection | | test.cpp:63:10:63:13 | (const char *)... | semmle.label | (const char *)... | | test.cpp:63:10:63:13 | (const char *)... | semmle.label | (const char *)... | -| test.cpp:63:10:63:13 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| test.cpp:63:10:63:13 | Argument 0 indirection | semmle.label | Argument 0 indirection | | test.cpp:63:10:63:13 | data | semmle.label | data | +| test.cpp:63:10:63:13 | data indirection | semmle.label | data indirection | +| test.cpp:63:10:63:13 | data indirection | semmle.label | data indirection | | test.cpp:76:12:76:17 | buffer | semmle.label | buffer | | test.cpp:76:12:76:17 | fgets output argument | semmle.label | fgets output argument | | test.cpp:78:10:78:15 | (const char *)... | semmle.label | (const char *)... | | test.cpp:78:10:78:15 | (const char *)... | semmle.label | (const char *)... | -| test.cpp:78:10:78:15 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| test.cpp:78:10:78:15 | Argument 0 indirection | semmle.label | Argument 0 indirection | | test.cpp:78:10:78:15 | buffer | semmle.label | buffer | +| test.cpp:78:10:78:15 | buffer indirection | semmle.label | buffer indirection | +| test.cpp:78:10:78:15 | buffer indirection | semmle.label | buffer indirection | | test.cpp:79:10:79:13 | (const char *)... | semmle.label | (const char *)... | | test.cpp:79:10:79:13 | (const char *)... | semmle.label | (const char *)... | -| test.cpp:79:10:79:13 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| test.cpp:79:10:79:13 | Argument 0 indirection | semmle.label | Argument 0 indirection | | test.cpp:79:10:79:13 | data | semmle.label | data | +| test.cpp:79:10:79:13 | data indirection | semmle.label | data indirection | +| test.cpp:79:10:79:13 | data indirection | semmle.label | data indirection | #select | test.cpp:26:10:26:16 | command | test.cpp:42:18:42:23 | call to getenv | test.cpp:26:10:26:16 | command | The value of this argument may come from $@ and is being passed to system | test.cpp:42:18:42:23 | call to getenv | call to getenv | | test.cpp:31:10:31:16 | command | test.cpp:43:18:43:23 | call to getenv | test.cpp:31:10:31:16 | command | The value of this argument may come from $@ and is being passed to system | test.cpp:43:18:43:23 | call to getenv | call to getenv | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-120/semmle/tests/UnboundedWrite.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-120/semmle/tests/UnboundedWrite.expected index a0db8029b2b..5255753b235 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-120/semmle/tests/UnboundedWrite.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-120/semmle/tests/UnboundedWrite.expected @@ -1,95 +1,95 @@ edges | tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | (const char *)... | | tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | (const char *)... | -| tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | Argument 1 indirection | -| tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | Argument 1 indirection | | tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array | | tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array | | tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array | | tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array | -| tests.c:28:22:28:25 | argv | tests.c:31:15:31:23 | Argument 1 indirection | -| tests.c:28:22:28:25 | argv | tests.c:31:15:31:23 | Argument 1 indirection | +| tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array indirection | +| tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array indirection | | tests.c:28:22:28:25 | argv | tests.c:31:15:31:23 | buffer100 | | tests.c:28:22:28:25 | argv | tests.c:31:15:31:23 | buffer100 | -| tests.c:28:22:28:25 | argv | tests.c:33:21:33:29 | Argument 2 indirection | -| tests.c:28:22:28:25 | argv | tests.c:33:21:33:29 | Argument 2 indirection | +| tests.c:28:22:28:25 | argv | tests.c:31:15:31:23 | buffer100 indirection | +| tests.c:28:22:28:25 | argv | tests.c:31:15:31:23 | buffer100 indirection | | tests.c:28:22:28:25 | argv | tests.c:33:21:33:29 | buffer100 | | tests.c:28:22:28:25 | argv | tests.c:33:21:33:29 | buffer100 | -| tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | Argument 2 indirection | -| tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | Argument 2 indirection | +| tests.c:28:22:28:25 | argv | tests.c:33:21:33:29 | buffer100 indirection | +| tests.c:28:22:28:25 | argv | tests.c:33:21:33:29 | buffer100 indirection | | tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | access to array | | tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | access to array | | tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | access to array | | tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | access to array | -| tests.c:29:28:29:31 | argv | tests.c:31:15:31:23 | Argument 1 indirection | -| tests.c:29:28:29:31 | argv | tests.c:31:15:31:23 | Argument 1 indirection | +| tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | access to array indirection | +| tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | access to array indirection | | tests.c:29:28:29:31 | argv | tests.c:31:15:31:23 | buffer100 | | tests.c:29:28:29:31 | argv | tests.c:31:15:31:23 | buffer100 | -| tests.c:29:28:29:31 | argv | tests.c:33:21:33:29 | Argument 2 indirection | -| tests.c:29:28:29:31 | argv | tests.c:33:21:33:29 | Argument 2 indirection | +| tests.c:29:28:29:31 | argv | tests.c:31:15:31:23 | buffer100 indirection | +| tests.c:29:28:29:31 | argv | tests.c:31:15:31:23 | buffer100 indirection | | tests.c:29:28:29:31 | argv | tests.c:33:21:33:29 | buffer100 | | tests.c:29:28:29:31 | argv | tests.c:33:21:33:29 | buffer100 | -| tests.c:31:15:31:23 | array to pointer conversion | tests.c:31:15:31:23 | Argument 1 indirection | +| tests.c:29:28:29:31 | argv | tests.c:33:21:33:29 | buffer100 indirection | +| tests.c:29:28:29:31 | argv | tests.c:33:21:33:29 | buffer100 indirection | | tests.c:31:15:31:23 | array to pointer conversion | tests.c:31:15:31:23 | buffer100 | -| tests.c:31:15:31:23 | buffer100 | tests.c:31:15:31:23 | Argument 1 indirection | +| tests.c:31:15:31:23 | array to pointer conversion | tests.c:31:15:31:23 | buffer100 indirection | | tests.c:31:15:31:23 | buffer100 | tests.c:31:15:31:23 | buffer100 | -| tests.c:31:15:31:23 | buffer100 | tests.c:33:21:33:29 | Argument 2 indirection | +| tests.c:31:15:31:23 | buffer100 | tests.c:31:15:31:23 | buffer100 indirection | | tests.c:31:15:31:23 | buffer100 | tests.c:33:21:33:29 | buffer100 | -| tests.c:31:15:31:23 | scanf output argument | tests.c:33:21:33:29 | Argument 2 indirection | +| tests.c:31:15:31:23 | buffer100 | tests.c:33:21:33:29 | buffer100 indirection | | tests.c:31:15:31:23 | scanf output argument | tests.c:33:21:33:29 | buffer100 | -| tests.c:33:21:33:29 | array to pointer conversion | tests.c:33:21:33:29 | Argument 2 indirection | +| tests.c:31:15:31:23 | scanf output argument | tests.c:33:21:33:29 | buffer100 indirection | | tests.c:33:21:33:29 | array to pointer conversion | tests.c:33:21:33:29 | buffer100 | -| tests.c:33:21:33:29 | buffer100 | tests.c:33:21:33:29 | Argument 2 indirection | +| tests.c:33:21:33:29 | array to pointer conversion | tests.c:33:21:33:29 | buffer100 indirection | | tests.c:33:21:33:29 | buffer100 | tests.c:33:21:33:29 | buffer100 | +| tests.c:33:21:33:29 | buffer100 | tests.c:33:21:33:29 | buffer100 indirection | | tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | (const char *)... | | tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | (const char *)... | -| tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | Argument 0 indirection | -| tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | Argument 0 indirection | | tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | access to array | | tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | access to array | | tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | access to array | | tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | access to array | +| tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | access to array indirection | +| tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | access to array indirection | nodes | tests.c:28:22:28:25 | argv | semmle.label | argv | | tests.c:28:22:28:25 | argv | semmle.label | argv | | tests.c:28:22:28:28 | (const char *)... | semmle.label | (const char *)... | | tests.c:28:22:28:28 | (const char *)... | semmle.label | (const char *)... | -| tests.c:28:22:28:28 | Argument 1 indirection | semmle.label | Argument 1 indirection | -| tests.c:28:22:28:28 | Argument 1 indirection | semmle.label | Argument 1 indirection | | tests.c:28:22:28:28 | access to array | semmle.label | access to array | | tests.c:28:22:28:28 | access to array | semmle.label | access to array | | tests.c:28:22:28:28 | access to array | semmle.label | access to array | +| tests.c:28:22:28:28 | access to array indirection | semmle.label | access to array indirection | +| tests.c:28:22:28:28 | access to array indirection | semmle.label | access to array indirection | | tests.c:29:28:29:31 | argv | semmle.label | argv | | tests.c:29:28:29:31 | argv | semmle.label | argv | -| tests.c:29:28:29:34 | Argument 2 indirection | semmle.label | Argument 2 indirection | -| tests.c:29:28:29:34 | Argument 2 indirection | semmle.label | Argument 2 indirection | | tests.c:29:28:29:34 | access to array | semmle.label | access to array | | tests.c:29:28:29:34 | access to array | semmle.label | access to array | | tests.c:29:28:29:34 | access to array | semmle.label | access to array | -| tests.c:31:15:31:23 | Argument 1 indirection | semmle.label | Argument 1 indirection | -| tests.c:31:15:31:23 | Argument 1 indirection | semmle.label | Argument 1 indirection | +| tests.c:29:28:29:34 | access to array indirection | semmle.label | access to array indirection | +| tests.c:29:28:29:34 | access to array indirection | semmle.label | access to array indirection | | tests.c:31:15:31:23 | array to pointer conversion | semmle.label | array to pointer conversion | | tests.c:31:15:31:23 | array to pointer conversion | semmle.label | array to pointer conversion | | tests.c:31:15:31:23 | buffer100 | semmle.label | buffer100 | | tests.c:31:15:31:23 | buffer100 | semmle.label | buffer100 | | tests.c:31:15:31:23 | buffer100 | semmle.label | buffer100 | +| tests.c:31:15:31:23 | buffer100 indirection | semmle.label | buffer100 indirection | +| tests.c:31:15:31:23 | buffer100 indirection | semmle.label | buffer100 indirection | | tests.c:31:15:31:23 | scanf output argument | semmle.label | scanf output argument | -| tests.c:33:21:33:29 | Argument 2 indirection | semmle.label | Argument 2 indirection | -| tests.c:33:21:33:29 | Argument 2 indirection | semmle.label | Argument 2 indirection | | tests.c:33:21:33:29 | array to pointer conversion | semmle.label | array to pointer conversion | | tests.c:33:21:33:29 | array to pointer conversion | semmle.label | array to pointer conversion | | tests.c:33:21:33:29 | buffer100 | semmle.label | buffer100 | | tests.c:33:21:33:29 | buffer100 | semmle.label | buffer100 | | tests.c:33:21:33:29 | buffer100 | semmle.label | buffer100 | +| tests.c:33:21:33:29 | buffer100 indirection | semmle.label | buffer100 indirection | +| tests.c:33:21:33:29 | buffer100 indirection | semmle.label | buffer100 indirection | | tests.c:34:10:34:13 | argv | semmle.label | argv | | tests.c:34:10:34:13 | argv | semmle.label | argv | | tests.c:34:10:34:16 | (const char *)... | semmle.label | (const char *)... | | tests.c:34:10:34:16 | (const char *)... | semmle.label | (const char *)... | -| tests.c:34:10:34:16 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| tests.c:34:10:34:16 | Argument 0 indirection | semmle.label | Argument 0 indirection | | tests.c:34:10:34:16 | access to array | semmle.label | access to array | | tests.c:34:10:34:16 | access to array | semmle.label | access to array | | tests.c:34:10:34:16 | access to array | semmle.label | access to array | +| tests.c:34:10:34:16 | access to array indirection | semmle.label | access to array indirection | +| tests.c:34:10:34:16 | access to array indirection | semmle.label | access to array indirection | #select | tests.c:28:3:28:9 | call to sprintf | tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array | This 'call to sprintf' with input from $@ may overflow the destination. | tests.c:28:22:28:25 | argv | argv | | tests.c:29:3:29:9 | call to sprintf | tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | access to array | This 'call to sprintf' with input from $@ may overflow the destination. | tests.c:29:28:29:31 | argv | argv | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/funcs/funcsLocal.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/funcs/funcsLocal.expected index 963c37bef48..ceaf0489ec6 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/funcs/funcsLocal.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/funcs/funcsLocal.expected @@ -1,105 +1,105 @@ edges | funcsLocal.c:16:8:16:9 | fread output argument | funcsLocal.c:17:9:17:10 | (const char *)... | -| funcsLocal.c:16:8:16:9 | fread output argument | funcsLocal.c:17:9:17:10 | Argument 0 indirection | | funcsLocal.c:16:8:16:9 | fread output argument | funcsLocal.c:17:9:17:10 | i1 | +| funcsLocal.c:16:8:16:9 | fread output argument | funcsLocal.c:17:9:17:10 | i1 indirection | | funcsLocal.c:16:8:16:9 | fread output argument | funcsLocal.c:58:9:58:10 | (const char *)... | -| funcsLocal.c:16:8:16:9 | fread output argument | funcsLocal.c:58:9:58:10 | Argument 0 indirection | | funcsLocal.c:16:8:16:9 | fread output argument | funcsLocal.c:58:9:58:10 | e1 | +| funcsLocal.c:16:8:16:9 | fread output argument | funcsLocal.c:58:9:58:10 | e1 indirection | | funcsLocal.c:16:8:16:9 | i1 | funcsLocal.c:17:9:17:10 | (const char *)... | -| funcsLocal.c:16:8:16:9 | i1 | funcsLocal.c:17:9:17:10 | Argument 0 indirection | | funcsLocal.c:16:8:16:9 | i1 | funcsLocal.c:17:9:17:10 | i1 | +| funcsLocal.c:16:8:16:9 | i1 | funcsLocal.c:17:9:17:10 | i1 indirection | | funcsLocal.c:16:8:16:9 | i1 | funcsLocal.c:58:9:58:10 | (const char *)... | -| funcsLocal.c:16:8:16:9 | i1 | funcsLocal.c:58:9:58:10 | Argument 0 indirection | | funcsLocal.c:16:8:16:9 | i1 | funcsLocal.c:58:9:58:10 | e1 | +| funcsLocal.c:16:8:16:9 | i1 | funcsLocal.c:58:9:58:10 | e1 indirection | | funcsLocal.c:26:8:26:9 | fgets output argument | funcsLocal.c:27:9:27:10 | (const char *)... | -| funcsLocal.c:26:8:26:9 | fgets output argument | funcsLocal.c:27:9:27:10 | Argument 0 indirection | | funcsLocal.c:26:8:26:9 | fgets output argument | funcsLocal.c:27:9:27:10 | i3 | +| funcsLocal.c:26:8:26:9 | fgets output argument | funcsLocal.c:27:9:27:10 | i3 indirection | | funcsLocal.c:26:8:26:9 | i3 | funcsLocal.c:27:9:27:10 | (const char *)... | -| funcsLocal.c:26:8:26:9 | i3 | funcsLocal.c:27:9:27:10 | Argument 0 indirection | | funcsLocal.c:26:8:26:9 | i3 | funcsLocal.c:27:9:27:10 | i3 | +| funcsLocal.c:26:8:26:9 | i3 | funcsLocal.c:27:9:27:10 | i3 indirection | | funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | (const char *)... | | funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | (const char *)... | -| funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | Argument 0 indirection | -| funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | Argument 0 indirection | | funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | i4 | | funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | i4 | | funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | i4 | | funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | i4 | +| funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | i4 indirection | +| funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | i4 indirection | | funcsLocal.c:31:19:31:21 | fgets output argument | funcsLocal.c:32:9:32:10 | (const char *)... | -| funcsLocal.c:31:19:31:21 | fgets output argument | funcsLocal.c:32:9:32:10 | Argument 0 indirection | | funcsLocal.c:31:19:31:21 | fgets output argument | funcsLocal.c:32:9:32:10 | i4 | +| funcsLocal.c:31:19:31:21 | fgets output argument | funcsLocal.c:32:9:32:10 | i4 indirection | | funcsLocal.c:31:19:31:21 | i41 | funcsLocal.c:32:9:32:10 | (const char *)... | -| funcsLocal.c:31:19:31:21 | i41 | funcsLocal.c:32:9:32:10 | Argument 0 indirection | | funcsLocal.c:31:19:31:21 | i41 | funcsLocal.c:32:9:32:10 | i4 | +| funcsLocal.c:31:19:31:21 | i41 | funcsLocal.c:32:9:32:10 | i4 indirection | | funcsLocal.c:36:7:36:8 | gets output argument | funcsLocal.c:37:9:37:10 | (const char *)... | -| funcsLocal.c:36:7:36:8 | gets output argument | funcsLocal.c:37:9:37:10 | Argument 0 indirection | | funcsLocal.c:36:7:36:8 | gets output argument | funcsLocal.c:37:9:37:10 | i5 | +| funcsLocal.c:36:7:36:8 | gets output argument | funcsLocal.c:37:9:37:10 | i5 indirection | | funcsLocal.c:36:7:36:8 | i5 | funcsLocal.c:37:9:37:10 | (const char *)... | -| funcsLocal.c:36:7:36:8 | i5 | funcsLocal.c:37:9:37:10 | Argument 0 indirection | | funcsLocal.c:36:7:36:8 | i5 | funcsLocal.c:37:9:37:10 | i5 | +| funcsLocal.c:36:7:36:8 | i5 | funcsLocal.c:37:9:37:10 | i5 indirection | | funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | (const char *)... | | funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | (const char *)... | -| funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | Argument 0 indirection | -| funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | Argument 0 indirection | | funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | i6 | | funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | i6 | | funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | i6 | | funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | i6 | +| funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | i6 indirection | +| funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | i6 indirection | | funcsLocal.c:41:18:41:20 | gets output argument | funcsLocal.c:42:9:42:10 | (const char *)... | -| funcsLocal.c:41:18:41:20 | gets output argument | funcsLocal.c:42:9:42:10 | Argument 0 indirection | | funcsLocal.c:41:18:41:20 | gets output argument | funcsLocal.c:42:9:42:10 | i6 | +| funcsLocal.c:41:18:41:20 | gets output argument | funcsLocal.c:42:9:42:10 | i6 indirection | | funcsLocal.c:41:18:41:20 | i61 | funcsLocal.c:42:9:42:10 | (const char *)... | -| funcsLocal.c:41:18:41:20 | i61 | funcsLocal.c:42:9:42:10 | Argument 0 indirection | | funcsLocal.c:41:18:41:20 | i61 | funcsLocal.c:42:9:42:10 | i6 | +| funcsLocal.c:41:18:41:20 | i61 | funcsLocal.c:42:9:42:10 | i6 indirection | nodes | funcsLocal.c:16:8:16:9 | fread output argument | semmle.label | fread output argument | | funcsLocal.c:16:8:16:9 | i1 | semmle.label | i1 | | funcsLocal.c:17:9:17:10 | (const char *)... | semmle.label | (const char *)... | | funcsLocal.c:17:9:17:10 | (const char *)... | semmle.label | (const char *)... | -| funcsLocal.c:17:9:17:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| funcsLocal.c:17:9:17:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | | funcsLocal.c:17:9:17:10 | i1 | semmle.label | i1 | +| funcsLocal.c:17:9:17:10 | i1 indirection | semmle.label | i1 indirection | +| funcsLocal.c:17:9:17:10 | i1 indirection | semmle.label | i1 indirection | | funcsLocal.c:26:8:26:9 | fgets output argument | semmle.label | fgets output argument | | funcsLocal.c:26:8:26:9 | i3 | semmle.label | i3 | | funcsLocal.c:27:9:27:10 | (const char *)... | semmle.label | (const char *)... | | funcsLocal.c:27:9:27:10 | (const char *)... | semmle.label | (const char *)... | -| funcsLocal.c:27:9:27:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| funcsLocal.c:27:9:27:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | | funcsLocal.c:27:9:27:10 | i3 | semmle.label | i3 | +| funcsLocal.c:27:9:27:10 | i3 indirection | semmle.label | i3 indirection | +| funcsLocal.c:27:9:27:10 | i3 indirection | semmle.label | i3 indirection | | funcsLocal.c:31:13:31:17 | call to fgets | semmle.label | call to fgets | | funcsLocal.c:31:13:31:17 | call to fgets | semmle.label | call to fgets | | funcsLocal.c:31:19:31:21 | fgets output argument | semmle.label | fgets output argument | | funcsLocal.c:31:19:31:21 | i41 | semmle.label | i41 | | funcsLocal.c:32:9:32:10 | (const char *)... | semmle.label | (const char *)... | | funcsLocal.c:32:9:32:10 | (const char *)... | semmle.label | (const char *)... | -| funcsLocal.c:32:9:32:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| funcsLocal.c:32:9:32:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | | funcsLocal.c:32:9:32:10 | i4 | semmle.label | i4 | | funcsLocal.c:32:9:32:10 | i4 | semmle.label | i4 | | funcsLocal.c:32:9:32:10 | i4 | semmle.label | i4 | +| funcsLocal.c:32:9:32:10 | i4 indirection | semmle.label | i4 indirection | +| funcsLocal.c:32:9:32:10 | i4 indirection | semmle.label | i4 indirection | | funcsLocal.c:36:7:36:8 | gets output argument | semmle.label | gets output argument | | funcsLocal.c:36:7:36:8 | i5 | semmle.label | i5 | | funcsLocal.c:37:9:37:10 | (const char *)... | semmle.label | (const char *)... | | funcsLocal.c:37:9:37:10 | (const char *)... | semmle.label | (const char *)... | -| funcsLocal.c:37:9:37:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| funcsLocal.c:37:9:37:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | | funcsLocal.c:37:9:37:10 | i5 | semmle.label | i5 | +| funcsLocal.c:37:9:37:10 | i5 indirection | semmle.label | i5 indirection | +| funcsLocal.c:37:9:37:10 | i5 indirection | semmle.label | i5 indirection | | funcsLocal.c:41:13:41:16 | call to gets | semmle.label | call to gets | | funcsLocal.c:41:13:41:16 | call to gets | semmle.label | call to gets | | funcsLocal.c:41:18:41:20 | gets output argument | semmle.label | gets output argument | | funcsLocal.c:41:18:41:20 | i61 | semmle.label | i61 | | funcsLocal.c:42:9:42:10 | (const char *)... | semmle.label | (const char *)... | | funcsLocal.c:42:9:42:10 | (const char *)... | semmle.label | (const char *)... | -| funcsLocal.c:42:9:42:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| funcsLocal.c:42:9:42:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | | funcsLocal.c:42:9:42:10 | i6 | semmle.label | i6 | | funcsLocal.c:42:9:42:10 | i6 | semmle.label | i6 | | funcsLocal.c:42:9:42:10 | i6 | semmle.label | i6 | +| funcsLocal.c:42:9:42:10 | i6 indirection | semmle.label | i6 indirection | +| funcsLocal.c:42:9:42:10 | i6 indirection | semmle.label | i6 indirection | | funcsLocal.c:58:9:58:10 | (const char *)... | semmle.label | (const char *)... | | funcsLocal.c:58:9:58:10 | (const char *)... | semmle.label | (const char *)... | -| funcsLocal.c:58:9:58:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| funcsLocal.c:58:9:58:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | | funcsLocal.c:58:9:58:10 | e1 | semmle.label | e1 | +| funcsLocal.c:58:9:58:10 | e1 indirection | semmle.label | e1 indirection | +| funcsLocal.c:58:9:58:10 | e1 indirection | semmle.label | e1 indirection | #select | funcsLocal.c:17:9:17:10 | i1 | funcsLocal.c:16:8:16:9 | i1 | funcsLocal.c:17:9:17:10 | i1 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:16:8:16:9 | i1 | fread | | funcsLocal.c:27:9:27:10 | i3 | funcsLocal.c:26:8:26:9 | i3 | funcsLocal.c:27:9:27:10 | i3 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:26:8:26:9 | i3 | fgets | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatStringThroughGlobalVar.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatStringThroughGlobalVar.expected index 9c2ac36476e..f095153f39c 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatStringThroughGlobalVar.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatStringThroughGlobalVar.expected @@ -28,24 +28,24 @@ edges | globalVars.c:24:11:24:14 | argv | globalVars.c:24:11:24:14 | argv indirection | | globalVars.c:24:11:24:14 | argv indirection | globalVars.c:11:22:11:25 | *argv | | globalVars.c:27:9:27:12 | copy | globalVars.c:27:9:27:12 | (const char *)... | -| globalVars.c:27:9:27:12 | copy | globalVars.c:27:9:27:12 | Argument 0 indirection | | globalVars.c:27:9:27:12 | copy | globalVars.c:27:9:27:12 | copy | -| globalVars.c:30:15:30:18 | copy | globalVars.c:30:15:30:18 | Argument 0 indirection | +| globalVars.c:27:9:27:12 | copy | globalVars.c:27:9:27:12 | copy indirection | | globalVars.c:30:15:30:18 | copy | globalVars.c:30:15:30:18 | copy | | globalVars.c:30:15:30:18 | copy | globalVars.c:30:15:30:18 | copy | | globalVars.c:30:15:30:18 | copy | globalVars.c:30:15:30:18 | copy | +| globalVars.c:30:15:30:18 | copy | globalVars.c:30:15:30:18 | copy indirection | | globalVars.c:35:2:35:9 | copy | globalVars.c:15:21:15:23 | val | | globalVars.c:35:11:35:14 | copy | globalVars.c:35:2:35:9 | copy | | globalVars.c:38:9:38:13 | copy2 | globalVars.c:38:9:38:13 | (const char *)... | -| globalVars.c:38:9:38:13 | copy2 | globalVars.c:38:9:38:13 | Argument 0 indirection | | globalVars.c:38:9:38:13 | copy2 | globalVars.c:38:9:38:13 | copy2 | -| globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:15:41:19 | Argument 0 indirection | +| globalVars.c:38:9:38:13 | copy2 | globalVars.c:38:9:38:13 | copy2 indirection | | globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:15:41:19 | copy2 | | globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:15:41:19 | copy2 | | globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:15:41:19 | copy2 | +| globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:15:41:19 | copy2 indirection | | globalVars.c:50:9:50:13 | copy2 | globalVars.c:50:9:50:13 | (const char *)... | -| globalVars.c:50:9:50:13 | copy2 | globalVars.c:50:9:50:13 | Argument 0 indirection | | globalVars.c:50:9:50:13 | copy2 | globalVars.c:50:9:50:13 | copy2 | +| globalVars.c:50:9:50:13 | copy2 | globalVars.c:50:9:50:13 | copy2 indirection | nodes | globalVars.c:8:7:8:10 | copy | semmle.label | copy | | globalVars.c:9:7:9:11 | copy2 | semmle.label | copy2 | @@ -60,37 +60,37 @@ nodes | globalVars.c:24:11:24:14 | argv indirection | semmle.label | argv indirection | | globalVars.c:27:9:27:12 | (const char *)... | semmle.label | (const char *)... | | globalVars.c:27:9:27:12 | (const char *)... | semmle.label | (const char *)... | -| globalVars.c:27:9:27:12 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| globalVars.c:27:9:27:12 | Argument 0 indirection | semmle.label | Argument 0 indirection | | globalVars.c:27:9:27:12 | copy | semmle.label | copy | | globalVars.c:27:9:27:12 | copy | semmle.label | copy | | globalVars.c:27:9:27:12 | copy | semmle.label | copy | -| globalVars.c:30:15:30:18 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| globalVars.c:30:15:30:18 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| globalVars.c:27:9:27:12 | copy indirection | semmle.label | copy indirection | +| globalVars.c:27:9:27:12 | copy indirection | semmle.label | copy indirection | | globalVars.c:30:15:30:18 | copy | semmle.label | copy | | globalVars.c:30:15:30:18 | copy | semmle.label | copy | | globalVars.c:30:15:30:18 | copy | semmle.label | copy | +| globalVars.c:30:15:30:18 | copy indirection | semmle.label | copy indirection | +| globalVars.c:30:15:30:18 | copy indirection | semmle.label | copy indirection | | globalVars.c:35:2:35:9 | copy | semmle.label | copy | | globalVars.c:35:11:35:14 | copy | semmle.label | copy | | globalVars.c:38:9:38:13 | (const char *)... | semmle.label | (const char *)... | | globalVars.c:38:9:38:13 | (const char *)... | semmle.label | (const char *)... | -| globalVars.c:38:9:38:13 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| globalVars.c:38:9:38:13 | Argument 0 indirection | semmle.label | Argument 0 indirection | | globalVars.c:38:9:38:13 | copy2 | semmle.label | copy2 | | globalVars.c:38:9:38:13 | copy2 | semmle.label | copy2 | | globalVars.c:38:9:38:13 | copy2 | semmle.label | copy2 | -| globalVars.c:41:15:41:19 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| globalVars.c:41:15:41:19 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| globalVars.c:38:9:38:13 | copy2 indirection | semmle.label | copy2 indirection | +| globalVars.c:38:9:38:13 | copy2 indirection | semmle.label | copy2 indirection | | globalVars.c:41:15:41:19 | copy2 | semmle.label | copy2 | | globalVars.c:41:15:41:19 | copy2 | semmle.label | copy2 | | globalVars.c:41:15:41:19 | copy2 | semmle.label | copy2 | +| globalVars.c:41:15:41:19 | copy2 indirection | semmle.label | copy2 indirection | +| globalVars.c:41:15:41:19 | copy2 indirection | semmle.label | copy2 indirection | | globalVars.c:50:9:50:13 | (const char *)... | semmle.label | (const char *)... | | globalVars.c:50:9:50:13 | (const char *)... | semmle.label | (const char *)... | -| globalVars.c:50:9:50:13 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| globalVars.c:50:9:50:13 | Argument 0 indirection | semmle.label | Argument 0 indirection | | globalVars.c:50:9:50:13 | copy2 | semmle.label | copy2 | | globalVars.c:50:9:50:13 | copy2 | semmle.label | copy2 | | globalVars.c:50:9:50:13 | copy2 | semmle.label | copy2 | +| globalVars.c:50:9:50:13 | copy2 indirection | semmle.label | copy2 indirection | +| globalVars.c:50:9:50:13 | copy2 indirection | semmle.label | copy2 indirection | #select | globalVars.c:27:9:27:12 | copy | globalVars.c:24:11:24:14 | argv | globalVars.c:27:9:27:12 | copy | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | globalVars.c:24:11:24:14 | argv | argv | | globalVars.c:30:15:30:18 | copy | globalVars.c:24:11:24:14 | argv | globalVars.c:30:15:30:18 | copy | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(str), which calls printf(format) | globalVars.c:24:11:24:14 | argv | argv | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/ifs/ifs.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/ifs/ifs.expected index e769c072f84..50ae940400a 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/ifs/ifs.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/ifs/ifs.expected @@ -1,192 +1,192 @@ edges | ifs.c:61:8:61:11 | argv | ifs.c:62:9:62:10 | (const char *)... | | ifs.c:61:8:61:11 | argv | ifs.c:62:9:62:10 | (const char *)... | -| ifs.c:61:8:61:11 | argv | ifs.c:62:9:62:10 | Argument 0 indirection | -| ifs.c:61:8:61:11 | argv | ifs.c:62:9:62:10 | Argument 0 indirection | | ifs.c:61:8:61:11 | argv | ifs.c:62:9:62:10 | c7 | | ifs.c:61:8:61:11 | argv | ifs.c:62:9:62:10 | c7 | | ifs.c:61:8:61:11 | argv | ifs.c:62:9:62:10 | c7 | | ifs.c:61:8:61:11 | argv | ifs.c:62:9:62:10 | c7 | +| ifs.c:61:8:61:11 | argv | ifs.c:62:9:62:10 | c7 indirection | +| ifs.c:61:8:61:11 | argv | ifs.c:62:9:62:10 | c7 indirection | | ifs.c:68:8:68:11 | argv | ifs.c:69:9:69:10 | (const char *)... | | ifs.c:68:8:68:11 | argv | ifs.c:69:9:69:10 | (const char *)... | -| ifs.c:68:8:68:11 | argv | ifs.c:69:9:69:10 | Argument 0 indirection | -| ifs.c:68:8:68:11 | argv | ifs.c:69:9:69:10 | Argument 0 indirection | | ifs.c:68:8:68:11 | argv | ifs.c:69:9:69:10 | c8 | | ifs.c:68:8:68:11 | argv | ifs.c:69:9:69:10 | c8 | | ifs.c:68:8:68:11 | argv | ifs.c:69:9:69:10 | c8 | | ifs.c:68:8:68:11 | argv | ifs.c:69:9:69:10 | c8 | +| ifs.c:68:8:68:11 | argv | ifs.c:69:9:69:10 | c8 indirection | +| ifs.c:68:8:68:11 | argv | ifs.c:69:9:69:10 | c8 indirection | | ifs.c:74:8:74:11 | argv | ifs.c:75:9:75:10 | (const char *)... | | ifs.c:74:8:74:11 | argv | ifs.c:75:9:75:10 | (const char *)... | -| ifs.c:74:8:74:11 | argv | ifs.c:75:9:75:10 | Argument 0 indirection | -| ifs.c:74:8:74:11 | argv | ifs.c:75:9:75:10 | Argument 0 indirection | | ifs.c:74:8:74:11 | argv | ifs.c:75:9:75:10 | i1 | | ifs.c:74:8:74:11 | argv | ifs.c:75:9:75:10 | i1 | | ifs.c:74:8:74:11 | argv | ifs.c:75:9:75:10 | i1 | | ifs.c:74:8:74:11 | argv | ifs.c:75:9:75:10 | i1 | +| ifs.c:74:8:74:11 | argv | ifs.c:75:9:75:10 | i1 indirection | +| ifs.c:74:8:74:11 | argv | ifs.c:75:9:75:10 | i1 indirection | | ifs.c:80:8:80:11 | argv | ifs.c:81:9:81:10 | (const char *)... | | ifs.c:80:8:80:11 | argv | ifs.c:81:9:81:10 | (const char *)... | -| ifs.c:80:8:80:11 | argv | ifs.c:81:9:81:10 | Argument 0 indirection | -| ifs.c:80:8:80:11 | argv | ifs.c:81:9:81:10 | Argument 0 indirection | | ifs.c:80:8:80:11 | argv | ifs.c:81:9:81:10 | i2 | | ifs.c:80:8:80:11 | argv | ifs.c:81:9:81:10 | i2 | | ifs.c:80:8:80:11 | argv | ifs.c:81:9:81:10 | i2 | | ifs.c:80:8:80:11 | argv | ifs.c:81:9:81:10 | i2 | +| ifs.c:80:8:80:11 | argv | ifs.c:81:9:81:10 | i2 indirection | +| ifs.c:80:8:80:11 | argv | ifs.c:81:9:81:10 | i2 indirection | | ifs.c:86:8:86:11 | argv | ifs.c:87:9:87:10 | (const char *)... | | ifs.c:86:8:86:11 | argv | ifs.c:87:9:87:10 | (const char *)... | -| ifs.c:86:8:86:11 | argv | ifs.c:87:9:87:10 | Argument 0 indirection | -| ifs.c:86:8:86:11 | argv | ifs.c:87:9:87:10 | Argument 0 indirection | | ifs.c:86:8:86:11 | argv | ifs.c:87:9:87:10 | i3 | | ifs.c:86:8:86:11 | argv | ifs.c:87:9:87:10 | i3 | | ifs.c:86:8:86:11 | argv | ifs.c:87:9:87:10 | i3 | | ifs.c:86:8:86:11 | argv | ifs.c:87:9:87:10 | i3 | +| ifs.c:86:8:86:11 | argv | ifs.c:87:9:87:10 | i3 indirection | +| ifs.c:86:8:86:11 | argv | ifs.c:87:9:87:10 | i3 indirection | | ifs.c:92:8:92:11 | argv | ifs.c:93:9:93:10 | (const char *)... | | ifs.c:92:8:92:11 | argv | ifs.c:93:9:93:10 | (const char *)... | -| ifs.c:92:8:92:11 | argv | ifs.c:93:9:93:10 | Argument 0 indirection | -| ifs.c:92:8:92:11 | argv | ifs.c:93:9:93:10 | Argument 0 indirection | | ifs.c:92:8:92:11 | argv | ifs.c:93:9:93:10 | i4 | | ifs.c:92:8:92:11 | argv | ifs.c:93:9:93:10 | i4 | | ifs.c:92:8:92:11 | argv | ifs.c:93:9:93:10 | i4 | | ifs.c:92:8:92:11 | argv | ifs.c:93:9:93:10 | i4 | +| ifs.c:92:8:92:11 | argv | ifs.c:93:9:93:10 | i4 indirection | +| ifs.c:92:8:92:11 | argv | ifs.c:93:9:93:10 | i4 indirection | | ifs.c:98:8:98:11 | argv | ifs.c:99:9:99:10 | (const char *)... | | ifs.c:98:8:98:11 | argv | ifs.c:99:9:99:10 | (const char *)... | -| ifs.c:98:8:98:11 | argv | ifs.c:99:9:99:10 | Argument 0 indirection | -| ifs.c:98:8:98:11 | argv | ifs.c:99:9:99:10 | Argument 0 indirection | | ifs.c:98:8:98:11 | argv | ifs.c:99:9:99:10 | i5 | | ifs.c:98:8:98:11 | argv | ifs.c:99:9:99:10 | i5 | | ifs.c:98:8:98:11 | argv | ifs.c:99:9:99:10 | i5 | | ifs.c:98:8:98:11 | argv | ifs.c:99:9:99:10 | i5 | +| ifs.c:98:8:98:11 | argv | ifs.c:99:9:99:10 | i5 indirection | +| ifs.c:98:8:98:11 | argv | ifs.c:99:9:99:10 | i5 indirection | | ifs.c:105:8:105:11 | argv | ifs.c:106:9:106:10 | (const char *)... | | ifs.c:105:8:105:11 | argv | ifs.c:106:9:106:10 | (const char *)... | -| ifs.c:105:8:105:11 | argv | ifs.c:106:9:106:10 | Argument 0 indirection | -| ifs.c:105:8:105:11 | argv | ifs.c:106:9:106:10 | Argument 0 indirection | | ifs.c:105:8:105:11 | argv | ifs.c:106:9:106:10 | i6 | | ifs.c:105:8:105:11 | argv | ifs.c:106:9:106:10 | i6 | | ifs.c:105:8:105:11 | argv | ifs.c:106:9:106:10 | i6 | | ifs.c:105:8:105:11 | argv | ifs.c:106:9:106:10 | i6 | +| ifs.c:105:8:105:11 | argv | ifs.c:106:9:106:10 | i6 indirection | +| ifs.c:105:8:105:11 | argv | ifs.c:106:9:106:10 | i6 indirection | | ifs.c:111:8:111:11 | argv | ifs.c:112:9:112:10 | (const char *)... | | ifs.c:111:8:111:11 | argv | ifs.c:112:9:112:10 | (const char *)... | -| ifs.c:111:8:111:11 | argv | ifs.c:112:9:112:10 | Argument 0 indirection | -| ifs.c:111:8:111:11 | argv | ifs.c:112:9:112:10 | Argument 0 indirection | | ifs.c:111:8:111:11 | argv | ifs.c:112:9:112:10 | i7 | | ifs.c:111:8:111:11 | argv | ifs.c:112:9:112:10 | i7 | | ifs.c:111:8:111:11 | argv | ifs.c:112:9:112:10 | i7 | | ifs.c:111:8:111:11 | argv | ifs.c:112:9:112:10 | i7 | +| ifs.c:111:8:111:11 | argv | ifs.c:112:9:112:10 | i7 indirection | +| ifs.c:111:8:111:11 | argv | ifs.c:112:9:112:10 | i7 indirection | | ifs.c:117:8:117:11 | argv | ifs.c:118:9:118:10 | (const char *)... | | ifs.c:117:8:117:11 | argv | ifs.c:118:9:118:10 | (const char *)... | -| ifs.c:117:8:117:11 | argv | ifs.c:118:9:118:10 | Argument 0 indirection | -| ifs.c:117:8:117:11 | argv | ifs.c:118:9:118:10 | Argument 0 indirection | | ifs.c:117:8:117:11 | argv | ifs.c:118:9:118:10 | i8 | | ifs.c:117:8:117:11 | argv | ifs.c:118:9:118:10 | i8 | | ifs.c:117:8:117:11 | argv | ifs.c:118:9:118:10 | i8 | | ifs.c:117:8:117:11 | argv | ifs.c:118:9:118:10 | i8 | +| ifs.c:117:8:117:11 | argv | ifs.c:118:9:118:10 | i8 indirection | +| ifs.c:117:8:117:11 | argv | ifs.c:118:9:118:10 | i8 indirection | | ifs.c:123:8:123:11 | argv | ifs.c:124:9:124:10 | (const char *)... | | ifs.c:123:8:123:11 | argv | ifs.c:124:9:124:10 | (const char *)... | -| ifs.c:123:8:123:11 | argv | ifs.c:124:9:124:10 | Argument 0 indirection | -| ifs.c:123:8:123:11 | argv | ifs.c:124:9:124:10 | Argument 0 indirection | | ifs.c:123:8:123:11 | argv | ifs.c:124:9:124:10 | i9 | | ifs.c:123:8:123:11 | argv | ifs.c:124:9:124:10 | i9 | | ifs.c:123:8:123:11 | argv | ifs.c:124:9:124:10 | i9 | | ifs.c:123:8:123:11 | argv | ifs.c:124:9:124:10 | i9 | +| ifs.c:123:8:123:11 | argv | ifs.c:124:9:124:10 | i9 indirection | +| ifs.c:123:8:123:11 | argv | ifs.c:124:9:124:10 | i9 indirection | nodes | ifs.c:61:8:61:11 | argv | semmle.label | argv | | ifs.c:61:8:61:11 | argv | semmle.label | argv | | ifs.c:62:9:62:10 | (const char *)... | semmle.label | (const char *)... | | ifs.c:62:9:62:10 | (const char *)... | semmle.label | (const char *)... | -| ifs.c:62:9:62:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| ifs.c:62:9:62:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | | ifs.c:62:9:62:10 | c7 | semmle.label | c7 | | ifs.c:62:9:62:10 | c7 | semmle.label | c7 | | ifs.c:62:9:62:10 | c7 | semmle.label | c7 | +| ifs.c:62:9:62:10 | c7 indirection | semmle.label | c7 indirection | +| ifs.c:62:9:62:10 | c7 indirection | semmle.label | c7 indirection | | ifs.c:68:8:68:11 | argv | semmle.label | argv | | ifs.c:68:8:68:11 | argv | semmle.label | argv | | ifs.c:69:9:69:10 | (const char *)... | semmle.label | (const char *)... | | ifs.c:69:9:69:10 | (const char *)... | semmle.label | (const char *)... | -| ifs.c:69:9:69:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| ifs.c:69:9:69:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | | ifs.c:69:9:69:10 | c8 | semmle.label | c8 | | ifs.c:69:9:69:10 | c8 | semmle.label | c8 | | ifs.c:69:9:69:10 | c8 | semmle.label | c8 | +| ifs.c:69:9:69:10 | c8 indirection | semmle.label | c8 indirection | +| ifs.c:69:9:69:10 | c8 indirection | semmle.label | c8 indirection | | ifs.c:74:8:74:11 | argv | semmle.label | argv | | ifs.c:74:8:74:11 | argv | semmle.label | argv | | ifs.c:75:9:75:10 | (const char *)... | semmle.label | (const char *)... | | ifs.c:75:9:75:10 | (const char *)... | semmle.label | (const char *)... | -| ifs.c:75:9:75:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| ifs.c:75:9:75:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | | ifs.c:75:9:75:10 | i1 | semmle.label | i1 | | ifs.c:75:9:75:10 | i1 | semmle.label | i1 | | ifs.c:75:9:75:10 | i1 | semmle.label | i1 | +| ifs.c:75:9:75:10 | i1 indirection | semmle.label | i1 indirection | +| ifs.c:75:9:75:10 | i1 indirection | semmle.label | i1 indirection | | ifs.c:80:8:80:11 | argv | semmle.label | argv | | ifs.c:80:8:80:11 | argv | semmle.label | argv | | ifs.c:81:9:81:10 | (const char *)... | semmle.label | (const char *)... | | ifs.c:81:9:81:10 | (const char *)... | semmle.label | (const char *)... | -| ifs.c:81:9:81:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| ifs.c:81:9:81:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | | ifs.c:81:9:81:10 | i2 | semmle.label | i2 | | ifs.c:81:9:81:10 | i2 | semmle.label | i2 | | ifs.c:81:9:81:10 | i2 | semmle.label | i2 | +| ifs.c:81:9:81:10 | i2 indirection | semmle.label | i2 indirection | +| ifs.c:81:9:81:10 | i2 indirection | semmle.label | i2 indirection | | ifs.c:86:8:86:11 | argv | semmle.label | argv | | ifs.c:86:8:86:11 | argv | semmle.label | argv | | ifs.c:87:9:87:10 | (const char *)... | semmle.label | (const char *)... | | ifs.c:87:9:87:10 | (const char *)... | semmle.label | (const char *)... | -| ifs.c:87:9:87:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| ifs.c:87:9:87:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | | ifs.c:87:9:87:10 | i3 | semmle.label | i3 | | ifs.c:87:9:87:10 | i3 | semmle.label | i3 | | ifs.c:87:9:87:10 | i3 | semmle.label | i3 | +| ifs.c:87:9:87:10 | i3 indirection | semmle.label | i3 indirection | +| ifs.c:87:9:87:10 | i3 indirection | semmle.label | i3 indirection | | ifs.c:92:8:92:11 | argv | semmle.label | argv | | ifs.c:92:8:92:11 | argv | semmle.label | argv | | ifs.c:93:9:93:10 | (const char *)... | semmle.label | (const char *)... | | ifs.c:93:9:93:10 | (const char *)... | semmle.label | (const char *)... | -| ifs.c:93:9:93:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| ifs.c:93:9:93:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | | ifs.c:93:9:93:10 | i4 | semmle.label | i4 | | ifs.c:93:9:93:10 | i4 | semmle.label | i4 | | ifs.c:93:9:93:10 | i4 | semmle.label | i4 | +| ifs.c:93:9:93:10 | i4 indirection | semmle.label | i4 indirection | +| ifs.c:93:9:93:10 | i4 indirection | semmle.label | i4 indirection | | ifs.c:98:8:98:11 | argv | semmle.label | argv | | ifs.c:98:8:98:11 | argv | semmle.label | argv | | ifs.c:99:9:99:10 | (const char *)... | semmle.label | (const char *)... | | ifs.c:99:9:99:10 | (const char *)... | semmle.label | (const char *)... | -| ifs.c:99:9:99:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| ifs.c:99:9:99:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | | ifs.c:99:9:99:10 | i5 | semmle.label | i5 | | ifs.c:99:9:99:10 | i5 | semmle.label | i5 | | ifs.c:99:9:99:10 | i5 | semmle.label | i5 | +| ifs.c:99:9:99:10 | i5 indirection | semmle.label | i5 indirection | +| ifs.c:99:9:99:10 | i5 indirection | semmle.label | i5 indirection | | ifs.c:105:8:105:11 | argv | semmle.label | argv | | ifs.c:105:8:105:11 | argv | semmle.label | argv | | ifs.c:106:9:106:10 | (const char *)... | semmle.label | (const char *)... | | ifs.c:106:9:106:10 | (const char *)... | semmle.label | (const char *)... | -| ifs.c:106:9:106:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| ifs.c:106:9:106:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | | ifs.c:106:9:106:10 | i6 | semmle.label | i6 | | ifs.c:106:9:106:10 | i6 | semmle.label | i6 | | ifs.c:106:9:106:10 | i6 | semmle.label | i6 | +| ifs.c:106:9:106:10 | i6 indirection | semmle.label | i6 indirection | +| ifs.c:106:9:106:10 | i6 indirection | semmle.label | i6 indirection | | ifs.c:111:8:111:11 | argv | semmle.label | argv | | ifs.c:111:8:111:11 | argv | semmle.label | argv | | ifs.c:112:9:112:10 | (const char *)... | semmle.label | (const char *)... | | ifs.c:112:9:112:10 | (const char *)... | semmle.label | (const char *)... | -| ifs.c:112:9:112:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| ifs.c:112:9:112:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | | ifs.c:112:9:112:10 | i7 | semmle.label | i7 | | ifs.c:112:9:112:10 | i7 | semmle.label | i7 | | ifs.c:112:9:112:10 | i7 | semmle.label | i7 | +| ifs.c:112:9:112:10 | i7 indirection | semmle.label | i7 indirection | +| ifs.c:112:9:112:10 | i7 indirection | semmle.label | i7 indirection | | ifs.c:117:8:117:11 | argv | semmle.label | argv | | ifs.c:117:8:117:11 | argv | semmle.label | argv | | ifs.c:118:9:118:10 | (const char *)... | semmle.label | (const char *)... | | ifs.c:118:9:118:10 | (const char *)... | semmle.label | (const char *)... | -| ifs.c:118:9:118:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| ifs.c:118:9:118:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | | ifs.c:118:9:118:10 | i8 | semmle.label | i8 | | ifs.c:118:9:118:10 | i8 | semmle.label | i8 | | ifs.c:118:9:118:10 | i8 | semmle.label | i8 | +| ifs.c:118:9:118:10 | i8 indirection | semmle.label | i8 indirection | +| ifs.c:118:9:118:10 | i8 indirection | semmle.label | i8 indirection | | ifs.c:123:8:123:11 | argv | semmle.label | argv | | ifs.c:123:8:123:11 | argv | semmle.label | argv | | ifs.c:124:9:124:10 | (const char *)... | semmle.label | (const char *)... | | ifs.c:124:9:124:10 | (const char *)... | semmle.label | (const char *)... | -| ifs.c:124:9:124:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| ifs.c:124:9:124:10 | Argument 0 indirection | semmle.label | Argument 0 indirection | | ifs.c:124:9:124:10 | i9 | semmle.label | i9 | | ifs.c:124:9:124:10 | i9 | semmle.label | i9 | | ifs.c:124:9:124:10 | i9 | semmle.label | i9 | +| ifs.c:124:9:124:10 | i9 indirection | semmle.label | i9 indirection | +| ifs.c:124:9:124:10 | i9 indirection | semmle.label | i9 indirection | #select | ifs.c:62:9:62:10 | c7 | ifs.c:61:8:61:11 | argv | ifs.c:62:9:62:10 | c7 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:61:8:61:11 | argv | argv | | ifs.c:69:9:69:10 | c8 | ifs.c:68:8:68:11 | argv | ifs.c:69:9:69:10 | c8 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:68:8:68:11 | argv | argv | 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 704c511a6fa..25ff3162973 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 @@ -31,20 +31,20 @@ edges | test.cpp:75:25:75:29 | start | test.cpp:79:18:79:28 | ... - ... | | test.cpp:75:38:75:40 | end | test.cpp:79:18:79:28 | ... - ... | | test.cpp:75:38:75:40 | end | test.cpp:79:18:79:28 | ... - ... | -| test.cpp:97:18:97:23 | buffer | test.cpp:100:4:100:15 | Argument 0 | -| test.cpp:97:18:97:23 | buffer | test.cpp:100:17:100:22 | Argument 0 indirection | -| test.cpp:97:18:97:23 | buffer | test.cpp:101:4:101:15 | Argument 0 | -| test.cpp:97:18:97:23 | buffer | test.cpp:101:4:101:15 | Argument 1 | -| test.cpp:97:18:97:23 | fread output argument | test.cpp:100:4:100:15 | Argument 0 | -| test.cpp:97:18:97:23 | fread output argument | test.cpp:100:17:100:22 | Argument 0 indirection | -| test.cpp:97:18:97:23 | fread output argument | test.cpp:101:4:101:15 | Argument 0 | -| test.cpp:97:18:97:23 | fread output argument | test.cpp:101:4:101:15 | Argument 1 | -| test.cpp:100:4:100:15 | Argument 0 | test.cpp:100:17:100:22 | processData1 output argument | -| test.cpp:100:17:100:22 | Argument 0 indirection | test.cpp:100:17:100:22 | processData1 output argument | -| test.cpp:100:17:100:22 | processData1 output argument | test.cpp:101:4:101:15 | Argument 0 | -| test.cpp:100:17:100:22 | processData1 output argument | test.cpp:101:4:101:15 | Argument 1 | -| test.cpp:101:4:101:15 | Argument 0 | test.cpp:75:25:75:29 | start | -| test.cpp:101:4:101:15 | Argument 1 | test.cpp:75:38:75:40 | end | +| test.cpp:97:18:97:23 | buffer | test.cpp:100:4:100:15 | buffer | +| test.cpp:97:18:97:23 | buffer | test.cpp:100:17:100:22 | buffer indirection | +| test.cpp:97:18:97:23 | buffer | test.cpp:101:4:101:15 | ... + ... | +| test.cpp:97:18:97:23 | buffer | test.cpp:101:4:101:15 | buffer | +| test.cpp:97:18:97:23 | fread output argument | test.cpp:100:4:100:15 | buffer | +| test.cpp:97:18:97:23 | fread output argument | test.cpp:100:17:100:22 | buffer indirection | +| test.cpp:97:18:97:23 | fread output argument | test.cpp:101:4:101:15 | ... + ... | +| test.cpp:97:18:97:23 | fread output argument | test.cpp:101:4:101:15 | buffer | +| test.cpp:100:4:100:15 | buffer | test.cpp:100:17:100:22 | processData1 output argument | +| test.cpp:100:17:100:22 | buffer indirection | test.cpp:100:17:100:22 | processData1 output argument | +| test.cpp:100:17:100:22 | processData1 output argument | test.cpp:101:4:101:15 | ... + ... | +| test.cpp:100:17:100:22 | processData1 output argument | test.cpp:101:4:101:15 | buffer | +| test.cpp:101:4:101:15 | ... + ... | test.cpp:75:38:75:40 | end | +| test.cpp:101:4:101:15 | buffer | test.cpp:75:25:75:29 | start | | test.cpp:123:18:123:23 | call to getenv | test.cpp:127:24:127:41 | ... * ... | | test.cpp:123:18:123:23 | call to getenv | test.cpp:127:24:127:41 | ... * ... | | test.cpp:123:18:123:31 | (const char *)... | test.cpp:127:24:127:41 | ... * ... | @@ -134,11 +134,11 @@ nodes | test.cpp:79:18:79:28 | ... - ... | semmle.label | ... - ... | | test.cpp:97:18:97:23 | buffer | semmle.label | buffer | | test.cpp:97:18:97:23 | fread output argument | semmle.label | fread output argument | -| test.cpp:100:4:100:15 | Argument 0 | semmle.label | Argument 0 | -| test.cpp:100:17:100:22 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| test.cpp:100:4:100:15 | buffer | semmle.label | buffer | +| test.cpp:100:17:100:22 | buffer indirection | semmle.label | buffer indirection | | test.cpp:100:17:100:22 | processData1 output argument | semmle.label | processData1 output argument | -| test.cpp:101:4:101:15 | Argument 0 | semmle.label | Argument 0 | -| test.cpp:101:4:101:15 | Argument 1 | semmle.label | Argument 1 | +| test.cpp:101:4:101:15 | ... + ... | semmle.label | ... + ... | +| test.cpp:101:4:101:15 | buffer | semmle.label | buffer | | test.cpp:123:18:123:23 | call to getenv | semmle.label | call to getenv | | test.cpp:123:18:123:31 | (const char *)... | semmle.label | (const char *)... | | test.cpp:127:24:127:41 | ... * ... | semmle.label | ... * ... | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-290/semmle/AuthenticationBypass/AuthenticationBypass.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-290/semmle/AuthenticationBypass/AuthenticationBypass.expected index dfbb01bf264..1ad31c3f9f7 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-290/semmle/AuthenticationBypass/AuthenticationBypass.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-290/semmle/AuthenticationBypass/AuthenticationBypass.expected @@ -1,44 +1,44 @@ edges -| test.cpp:16:25:16:30 | call to getenv | test.cpp:20:14:20:20 | Argument 0 indirection | | test.cpp:16:25:16:30 | call to getenv | test.cpp:20:14:20:20 | address | | test.cpp:16:25:16:30 | call to getenv | test.cpp:20:14:20:20 | address | -| test.cpp:16:25:16:42 | (const char *)... | test.cpp:20:14:20:20 | Argument 0 indirection | +| test.cpp:16:25:16:30 | call to getenv | test.cpp:20:14:20:20 | address indirection | | test.cpp:16:25:16:42 | (const char *)... | test.cpp:20:14:20:20 | address | | test.cpp:16:25:16:42 | (const char *)... | test.cpp:20:14:20:20 | address | -| test.cpp:27:25:27:30 | call to getenv | test.cpp:31:14:31:20 | Argument 0 indirection | +| test.cpp:16:25:16:42 | (const char *)... | test.cpp:20:14:20:20 | address indirection | | test.cpp:27:25:27:30 | call to getenv | test.cpp:31:14:31:20 | address | | test.cpp:27:25:27:30 | call to getenv | test.cpp:31:14:31:20 | address | -| test.cpp:27:25:27:42 | (const char *)... | test.cpp:31:14:31:20 | Argument 0 indirection | +| test.cpp:27:25:27:30 | call to getenv | test.cpp:31:14:31:20 | address indirection | | test.cpp:27:25:27:42 | (const char *)... | test.cpp:31:14:31:20 | address | | test.cpp:27:25:27:42 | (const char *)... | test.cpp:31:14:31:20 | address | -| test.cpp:38:25:38:30 | call to getenv | test.cpp:42:14:42:20 | Argument 0 indirection | +| test.cpp:27:25:27:42 | (const char *)... | test.cpp:31:14:31:20 | address indirection | | test.cpp:38:25:38:30 | call to getenv | test.cpp:42:14:42:20 | address | | test.cpp:38:25:38:30 | call to getenv | test.cpp:42:14:42:20 | address | -| test.cpp:38:25:38:42 | (const char *)... | test.cpp:42:14:42:20 | Argument 0 indirection | +| test.cpp:38:25:38:30 | call to getenv | test.cpp:42:14:42:20 | address indirection | | test.cpp:38:25:38:42 | (const char *)... | test.cpp:42:14:42:20 | address | | test.cpp:38:25:38:42 | (const char *)... | test.cpp:42:14:42:20 | address | +| test.cpp:38:25:38:42 | (const char *)... | test.cpp:42:14:42:20 | address indirection | nodes | test.cpp:16:25:16:30 | call to getenv | semmle.label | call to getenv | | test.cpp:16:25:16:42 | (const char *)... | semmle.label | (const char *)... | -| test.cpp:20:14:20:20 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| test.cpp:20:14:20:20 | Argument 0 indirection | semmle.label | Argument 0 indirection | | test.cpp:20:14:20:20 | address | semmle.label | address | | test.cpp:20:14:20:20 | address | semmle.label | address | | test.cpp:20:14:20:20 | address | semmle.label | address | +| test.cpp:20:14:20:20 | address indirection | semmle.label | address indirection | +| test.cpp:20:14:20:20 | address indirection | semmle.label | address indirection | | test.cpp:27:25:27:30 | call to getenv | semmle.label | call to getenv | | test.cpp:27:25:27:42 | (const char *)... | semmle.label | (const char *)... | -| test.cpp:31:14:31:20 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| test.cpp:31:14:31:20 | Argument 0 indirection | semmle.label | Argument 0 indirection | | test.cpp:31:14:31:20 | address | semmle.label | address | | test.cpp:31:14:31:20 | address | semmle.label | address | | test.cpp:31:14:31:20 | address | semmle.label | address | +| test.cpp:31:14:31:20 | address indirection | semmle.label | address indirection | +| test.cpp:31:14:31:20 | address indirection | semmle.label | address indirection | | test.cpp:38:25:38:30 | call to getenv | semmle.label | call to getenv | | test.cpp:38:25:38:42 | (const char *)... | semmle.label | (const char *)... | -| test.cpp:42:14:42:20 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| test.cpp:42:14:42:20 | Argument 0 indirection | semmle.label | Argument 0 indirection | | test.cpp:42:14:42:20 | address | semmle.label | address | | test.cpp:42:14:42:20 | address | semmle.label | address | | test.cpp:42:14:42:20 | address | semmle.label | address | +| test.cpp:42:14:42:20 | address indirection | semmle.label | address indirection | +| test.cpp:42:14:42:20 | address indirection | semmle.label | address indirection | #select | test.cpp:20:7:20:12 | call to strcmp | test.cpp:16:25:16:30 | call to getenv | test.cpp:20:14:20:20 | address | Untrusted input $@ might be vulnerable to a spoofing attack. | test.cpp:16:25:16:30 | call to getenv | call to getenv | | test.cpp:31:7:31:12 | call to strcmp | test.cpp:27:25:27:30 | call to getenv | test.cpp:31:14:31:20 | address | Untrusted input $@ might be vulnerable to a spoofing attack. | test.cpp:27:25:27:30 | call to getenv | call to getenv | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-311/semmle/tests/CleartextBufferWrite.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-311/semmle/tests/CleartextBufferWrite.expected index 559e491417b..e4f9bc918a4 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-311/semmle/tests/CleartextBufferWrite.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-311/semmle/tests/CleartextBufferWrite.expected @@ -1,17 +1,17 @@ edges -| test.cpp:54:17:54:20 | argv | test.cpp:58:25:58:29 | Argument 2 indirection | -| test.cpp:54:17:54:20 | argv | test.cpp:58:25:58:29 | Argument 2 indirection | | test.cpp:54:17:54:20 | argv | test.cpp:58:25:58:29 | input | | test.cpp:54:17:54:20 | argv | test.cpp:58:25:58:29 | input | | test.cpp:54:17:54:20 | argv | test.cpp:58:25:58:29 | input | | test.cpp:54:17:54:20 | argv | test.cpp:58:25:58:29 | input | +| test.cpp:54:17:54:20 | argv | test.cpp:58:25:58:29 | input indirection | +| test.cpp:54:17:54:20 | argv | test.cpp:58:25:58:29 | input indirection | nodes | test.cpp:54:17:54:20 | argv | semmle.label | argv | | test.cpp:54:17:54:20 | argv | semmle.label | argv | -| test.cpp:58:25:58:29 | Argument 2 indirection | semmle.label | Argument 2 indirection | -| test.cpp:58:25:58:29 | Argument 2 indirection | semmle.label | Argument 2 indirection | | test.cpp:58:25:58:29 | input | semmle.label | input | | test.cpp:58:25:58:29 | input | semmle.label | input | | test.cpp:58:25:58:29 | input | semmle.label | input | +| test.cpp:58:25:58:29 | input indirection | semmle.label | input indirection | +| test.cpp:58:25:58:29 | input indirection | semmle.label | input indirection | #select | test.cpp:58:3:58:9 | call to sprintf | test.cpp:54:17:54:20 | argv | test.cpp:58:25:58:29 | input | This write into buffer 'passwd' may contain unencrypted data from $@ | test.cpp:54:17:54:20 | argv | user input (argv) | From c8b1bc3a89b6f0c6b006449f38f4966899f0bc3d Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Thu, 11 Mar 2021 21:41:34 +0000 Subject: [PATCH 111/725] Enhance the query --- .../CWE-016/InsecureSpringActuatorConfig.ql | 58 +++++++------------ .../CWE/CWE-016/application.properties | 4 +- .../security/CWE-016/application.properties | 2 +- 3 files changed, 24 insertions(+), 40 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-016/InsecureSpringActuatorConfig.ql b/java/ql/src/experimental/Security/CWE/CWE-016/InsecureSpringActuatorConfig.ql index 2dc11e8e38e..06ba0d8a288 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-016/InsecureSpringActuatorConfig.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-016/InsecureSpringActuatorConfig.ql @@ -1,6 +1,7 @@ /** * @name Insecure Spring Boot Actuator Configuration - * @description Exposed Spring Boot Actuator through configuration files without declarative or procedural security enforcement leads to information leak or even remote code execution. + * @description Exposed Spring Boot Actuator through configuration files without declarative or procedural + * security enforcement leads to information leak or even remote code execution. * @kind problem * @id java/insecure-spring-actuator-config * @tags security @@ -9,7 +10,6 @@ import java import semmle.code.configfiles.ConfigFiles -import semmle.code.java.security.SensitiveActions import semmle.code.xml.MavenPom /** The parent node of the `org.springframework.boot` group. */ @@ -26,7 +26,10 @@ class SpringBootPom extends Pom { this.getADependency().getArtifact().getValue() = "spring-boot-starter-actuator" } - /** Holds if the Spring Boot Security module is used in the project, which brings in other security related libraries. */ + /** + * Holds if the Spring Boot Security module is used in the project, which brings in other security + * related libraries. + */ predicate isSpringBootSecurityUsed() { this.getADependency().getArtifact().getValue() = "spring-boot-starter-security" } @@ -38,14 +41,14 @@ class ApplicationProperties extends ConfigPair { } /** The configuration property `management.security.enabled`. */ -class ManagementSecurityEnabled extends ApplicationProperties { - ManagementSecurityEnabled() { this.getNameElement().getName() = "management.security.enabled" } +class ManagementSecurityConfig extends ApplicationProperties { + ManagementSecurityConfig() { this.getNameElement().getName() = "management.security.enabled" } - string getManagementSecurityEnabled() { result = this.getValueElement().getValue() } + string getValue() { result = this.getValueElement().getValue().trim() } - predicate hasSecurityDisabled() { getManagementSecurityEnabled() = "false" } + predicate hasSecurityDisabled() { getValue() = "false" } - predicate hasSecurityEnabled() { getManagementSecurityEnabled() = "true" } + predicate hasSecurityEnabled() { getValue() = "true" } } /** The configuration property `management.endpoints.web.exposure.include`. */ @@ -54,56 +57,37 @@ class ManagementEndPointInclude extends ApplicationProperties { this.getNameElement().getName() = "management.endpoints.web.exposure.include" } - string getManagementEndPointInclude() { result = this.getValueElement().getValue().trim() } -} - -/** The configuration property `management.endpoints.web.exposure.exclude`. */ -class ManagementEndPointExclude extends ApplicationProperties { - ManagementEndPointExclude() { - this.getNameElement().getName() = "management.endpoints.web.exposure.exclude" - } - - string getManagementEndPointExclude() { result = this.getValueElement().getValue().trim() } -} - -/** Holds if an application handles sensitive information judging by its variable names. */ -predicate isProtectedApp() { - exists(VarAccess va | va.getVariable().getName().regexpMatch(getCommonSensitiveInfoRegex())) + string getValue() { result = this.getValueElement().getValue().trim() } } from SpringBootPom pom, ApplicationProperties ap, Dependency d where - isProtectedApp() and pom.isSpringBootActuatorUsed() and not pom.isSpringBootSecurityUsed() and ap.getFile() .getParentContainer() .getAbsolutePath() .matches(pom.getFile().getParentContainer().getAbsolutePath() + "%") and // in the same sub-directory - exists(string s | s = pom.getParentElement().getVersionString() | - s.regexpMatch("1\\.[0|1|2|3|4].*") and - not exists(ManagementSecurityEnabled me | + exists(string springBootVersion | springBootVersion = pom.getParentElement().getVersionString() | + springBootVersion.regexpMatch("1\\.[0-4].*") and // version 1.0, 1.1, ..., 1.4 + not exists(ManagementSecurityConfig me | me.hasSecurityEnabled() and me.getFile() = ap.getFile() ) or - s.regexpMatch("1\\.5.*") and - exists(ManagementSecurityEnabled me | me.hasSecurityDisabled() and me.getFile() = ap.getFile()) + springBootVersion.matches("1.5%") and // version 1.5 + exists(ManagementSecurityConfig me | me.hasSecurityDisabled() and me.getFile() = ap.getFile()) or - s.regexpMatch("2.*") and + springBootVersion.matches("2.%") and //version 2.x exists(ManagementEndPointInclude mi | mi.getFile() = ap.getFile() and ( - mi.getManagementEndPointInclude() = "*" // all endpoints are enabled + mi.getValue() = "*" // all endpoints are enabled or - mi.getManagementEndPointInclude() + mi.getValue() .matches([ "%dump%", "%trace%", "%logfile%", "%shutdown%", "%startup%", "%mappings%", "%env%", "%beans%", "%sessions%" - ]) // all endpoints apart from '/health' and '/info' are considered sensitive - ) and - not exists(ManagementEndPointExclude mx | - mx.getFile() = ap.getFile() and - mx.getManagementEndPointExclude() = mi.getManagementEndPointInclude() + ]) // confidential endpoints to check although all endpoints apart from '/health' and '/info' are considered sensitive by Spring ) ) ) and diff --git a/java/ql/src/experimental/Security/CWE/CWE-016/application.properties b/java/ql/src/experimental/Security/CWE/CWE-016/application.properties index aa489435a12..4f5defdd948 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-016/application.properties +++ b/java/ql/src/experimental/Security/CWE/CWE-016/application.properties @@ -7,7 +7,7 @@ # vulnerable configuration (spring boot 1.5+): requires value false to expose sensitive actuators management.security.enabled=false -# vulnerable configuration (spring boot 2+): exposes health and info only by default +# vulnerable configuration (spring boot 2+): exposes health and info only by default, here overridden to expose everything management.endpoints.web.exposure.include=* @@ -18,5 +18,5 @@ management.security.enabled=true # safe configuration (spring boot 1.5+): requires value false to expose sensitive actuators management.security.enabled=true -# safe configuration (spring boot 2+): exposes health and info only by default +# safe configuration (spring boot 2+): exposes health and info only by default, here overridden to expose one additional endpoint which we assume is intentional and safe. management.endpoints.web.exposure.include=beans,info,health diff --git a/java/ql/test/experimental/query-tests/security/CWE-016/application.properties b/java/ql/test/experimental/query-tests/security/CWE-016/application.properties index 95e704f3a1a..797906a3ca3 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-016/application.properties +++ b/java/ql/test/experimental/query-tests/security/CWE-016/application.properties @@ -5,7 +5,7 @@ # vulnerable configuration (spring boot 1.5+): requires value false to expose sensitive actuators management.security.enabled=false -# vulnerable configuration (spring boot 2+): exposes health and info only by default +# vulnerable configuration (spring boot 2+): exposes health and info only by default, here overridden to expose everything management.endpoints.web.exposure.include=* management.endpoints.web.exposure.exclude=beans From fe3824c202b6689e6cd3ea58c9e5a8dae9d5ff75 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Thu, 11 Mar 2021 21:22:33 +0100 Subject: [PATCH 112/725] Python: Document API graphs --- .../using-api-graphs-in-python.rst | 164 ++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 docs/codeql/codeql-language-guides/using-api-graphs-in-python.rst diff --git a/docs/codeql/codeql-language-guides/using-api-graphs-in-python.rst b/docs/codeql/codeql-language-guides/using-api-graphs-in-python.rst new file mode 100644 index 00000000000..ebfd70fe1fc --- /dev/null +++ b/docs/codeql/codeql-language-guides/using-api-graphs-in-python.rst @@ -0,0 +1,164 @@ +.. _using-api-graphs-in-python: + +Using API graphs in Python +========================== + +API graphs are a uniform interface for referring to functions, classes, and methods defined in +external libraries. + +About this article +------------------ + +This article describes how to use API graphs to reference classes and functions defined in library +code. This can be used to conveniently refer to external library functions when defining things like +remote flow sources. + + +Module imports +-------------- + +The most common entry point into the API graph will be the point where an external module or package is +imported. The API graph node corresponding to the ``re`` library, for instance, can be accessed +using the ``API::moduleImport`` method defined in the ``semmle.python.ApiGraphs`` module, as the +following snippet demonstrates. + +.. code-block:: ql + + import python + import semmle.python.ApiGraphs + + select API::moduleImport("re") + +➤ `See this in the query console on LGTM.com `__. + +On its own, this only selects the API graph node corresponding to the ``re`` module. To find +where this module is referenced, we use the ``getAUse`` method. Thus, the following query selects +all references to the ``re`` module in the current database. + +.. code-block:: ql + + import python + import semmle.python.ApiGraphs + + select API::moduleImport("re").getAUse() + +➤ `See this in the query console on LGTM.com `__. + +Note that the ``getAUse`` method accounts for local flow, so that ``my_re_compile`` +in the following snippet is +correctly recognized as a reference to the ``re.compile`` function. + +.. code-block:: python + + from re import compile as re_compile + + my_re_compile = re_compile + + r = my_re_compile(".*") + +If only immediate uses are required, without taking local flow into account, then the method +``getAnImmediateUse`` may be used instead. + +Note that the given module name *must not* contain any dots. Thus, something like +``API::moduleImport("flask.views")`` will not do what you expect. Instead, this should be decomposed +into an access of the ``views`` member of the API graph node for ``flask``, as described in the next +section. + +Accessing attributes +-------------------- + +Given a node in the API graph, we may access its attributes by using the ``getMember`` method. Using +the above ``re.compile`` example, we may now find references to ``re.compile`` by doing + +.. code-block:: ql + + import python + import semmle.python.ApiGraphs + + select API::moduleImport("re").getMember("compile").getAUse() + +➤ `See this in the query console on LGTM.com `__. + +In addition to ``getMember``, the method ``getUnknownMember`` can be used to find references to API +components where the name is not known statically, and the ``getAMember`` method can be used to +access all members, both known and unknown. + +Calls and class instantiations +------------------------------ + +To track instances of classes defined in external libraries, or the results of calling externally +defined functions, we may use the ``getReturn`` method. Thus, the following snippet finds all places +where the return value of ``re.compile`` is used: + +.. code-block:: ql + + import python + import semmle.python.ApiGraphs + + select API::moduleImport("re").getMember("compile").getReturn().getAUse() + +➤ `See this in the query console on LGTM.com `__. + +Note that this includes all uses of the result of ``re.compile``, including those reachable via +local flow. To get just the *calls* to ``re.compile``, we can use ``getAnImmediateUse`` instead of +``getAUse``. As this is a common occurrence, the method ``getACall`` can be used instead of +``getReturn`` followed by ``getAnImmediateUse``. + +➤ `See this in the query console on LGTM.com `__. + +Note that the API graph does not distinguish between class instantiations and function calls. As far +as it's concerned, both are simply places where an API graph node is called. + +Subclasses +---------- + +For many libraries, the main mode of usage is to extend one or more library classes. To track this +in the API graph, we can use the ``getASubclass`` method to get the API graph node corresponding to +all the immediate subclasses of this node. To find *all* subclasses, use ``*`` or ``+`` to apply the +method repeatedly, as in `getASubclass*`. + +Note that ``getASubclass`` does not account for any subclassing that takes place in library code +that has not been extracted. Thus, it may be necessary to account for this in the models you write. +For example, the ``flask.views.View`` class has a predefined subclass ``MethodView``, and so to find +all subclasses of ``View``, we must explicitly include the subclasses of ``MethodView`` as well. + +.. code-block:: ql + + import python + import semmle.python.ApiGraphs + + API::Node viewClass() { + result = + API::moduleImport("flask").getMember("views").getMember(["View", "MethodView"]).getASubclass*() + } + + select viewClass() + +➤ `See this in the query console on LGTM.com `__. + +Note the use of the set literal ``["View", "MethodView"]`` to match both classes simultaneously. + +Built-in functions and classes +------------------------------ + +Built-in functions and classes can be accessed using the ``API::builtin`` method, giving the name of +the built-in as an argument. + +To find all calls to the built-in ``open`` function, for instance, can be done using the following snippet + +.. code-block:: ql + + import python + import semmle.python.ApiGraphs + + select API::builtin("open").getACall() + + + + +Further reading +--------------- + + +.. include:: ../reusables/python-further-reading.rst +.. include:: ../reusables/codeql-ref-tools-further-reading.rst From 1a2e341b7c767fc4b6e21e9dc38d25110aa8b50e Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Fri, 12 Mar 2021 12:19:37 +0000 Subject: [PATCH 113/725] Refactor the business logic of the query into a separate predicate --- .../CWE/CWE-016/InsecureSpringActuatorConfig.ql | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-016/InsecureSpringActuatorConfig.ql b/java/ql/src/experimental/Security/CWE/CWE-016/InsecureSpringActuatorConfig.ql index 06ba0d8a288..3acd22e767a 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-016/InsecureSpringActuatorConfig.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-016/InsecureSpringActuatorConfig.ql @@ -60,8 +60,11 @@ class ManagementEndPointInclude extends ApplicationProperties { string getValue() { result = this.getValueElement().getValue().trim() } } -from SpringBootPom pom, ApplicationProperties ap, Dependency d -where +/** + * Holds if `ApplicationProperties` ap of a repository managed by `SpringBootPom` pom + * has a vulnerable configuration of Spring Boot Actuator management endpoints. + */ +predicate hasConfidentialEndPointExposed(SpringBootPom pom, ApplicationProperties ap) { pom.isSpringBootActuatorUsed() and not pom.isSpringBootSecurityUsed() and ap.getFile() @@ -90,7 +93,12 @@ where ]) // confidential endpoints to check although all endpoints apart from '/health' and '/info' are considered sensitive by Spring ) ) - ) and + ) +} + +from SpringBootPom pom, ApplicationProperties ap, Dependency d +where + hasConfidentialEndPointExposed(pom, ap) and d = pom.getADependency() and d.getArtifact().getValue() = "spring-boot-starter-actuator" select d, "Insecure configuration of Spring Boot Actuator exposes sensitive endpoints." From f75b969ffcfa047b8d47664aaf99e05f2b751741 Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Mon, 15 Mar 2021 11:32:10 +0000 Subject: [PATCH 114/725] C++: Only include sum of LoC in the new non-alert summary queries for now. --- cpp/ql/src/Summary/LinesOfCode.ql | 4 ++-- cpp/ql/src/Summary/LinesOfCodePerFile.ql | 13 ------------- cpp/ql/src/Summary/LinesOfUserCode.ql | 11 ----------- cpp/ql/src/Summary/LinesOfUserCodePerFile.ql | 13 ------------- .../query-tests/Summary/LinesOfCodePerFile.expected | 3 --- .../query-tests/Summary/LinesOfCodePerFile.qlref | 1 - .../query-tests/Summary/LinesOfUserCode.expected | 1 - .../test/query-tests/Summary/LinesOfUserCode.qlref | 1 - .../Summary/LinesOfUserCodePerFile.expected | 3 --- .../Summary/LinesOfUserCodePerFile.qlref | 1 - 10 files changed, 2 insertions(+), 49 deletions(-) delete mode 100644 cpp/ql/src/Summary/LinesOfCodePerFile.ql delete mode 100644 cpp/ql/src/Summary/LinesOfUserCode.ql delete mode 100644 cpp/ql/src/Summary/LinesOfUserCodePerFile.ql delete mode 100644 cpp/ql/test/query-tests/Summary/LinesOfCodePerFile.expected delete mode 100644 cpp/ql/test/query-tests/Summary/LinesOfCodePerFile.qlref delete mode 100644 cpp/ql/test/query-tests/Summary/LinesOfUserCode.expected delete mode 100644 cpp/ql/test/query-tests/Summary/LinesOfUserCode.qlref delete mode 100644 cpp/ql/test/query-tests/Summary/LinesOfUserCodePerFile.expected delete mode 100644 cpp/ql/test/query-tests/Summary/LinesOfUserCodePerFile.qlref diff --git a/cpp/ql/src/Summary/LinesOfCode.ql b/cpp/ql/src/Summary/LinesOfCode.ql index 2d6fdf4b67b..6ba027dbd14 100644 --- a/cpp/ql/src/Summary/LinesOfCode.ql +++ b/cpp/ql/src/Summary/LinesOfCode.ql @@ -1,7 +1,7 @@ /** * @id cpp/summary/lines-of-code - * @name Total lines of C/C++ code - * @description The total number of lines of C/C++ code across all files, including system headers and libraries. + * @name Total lines of C/C++ code in the database. + * @description The total number of lines of C/C++ code across all files, including system headers and libraries. This is a useful metric of the size of a database. * @kind metric * @tags summary */ diff --git a/cpp/ql/src/Summary/LinesOfCodePerFile.ql b/cpp/ql/src/Summary/LinesOfCodePerFile.ql deleted file mode 100644 index c94f337744a..00000000000 --- a/cpp/ql/src/Summary/LinesOfCodePerFile.ql +++ /dev/null @@ -1,13 +0,0 @@ -/** - * @id cpp/summary/lines-of-code-per-file - * @name Lines of C/C++ code per source file - * @description The number of lines of C/C++ code for each file in the database, including system headers and libraries. - * @kind metric - * @tags summary - */ - -import cpp - -from File f -where f.fromSource() -select f, f.getMetrics().getNumberOfLines() diff --git a/cpp/ql/src/Summary/LinesOfUserCode.ql b/cpp/ql/src/Summary/LinesOfUserCode.ql deleted file mode 100644 index e6466c6ddf6..00000000000 --- a/cpp/ql/src/Summary/LinesOfUserCode.ql +++ /dev/null @@ -1,11 +0,0 @@ -/** - * @id cpp/summary/lines-of-user-code - * @name Total lines of C/C++ source code - * @description The total number of lines of C/C++ code across all files, excluding system headers and libraries. - * @kind metric - * @tags summary - */ - -import cpp - -select sum(File f | exists(f.getRelativePath()) | f.getMetrics().getNumberOfLines()) diff --git a/cpp/ql/src/Summary/LinesOfUserCodePerFile.ql b/cpp/ql/src/Summary/LinesOfUserCodePerFile.ql deleted file mode 100644 index a10e48c0359..00000000000 --- a/cpp/ql/src/Summary/LinesOfUserCodePerFile.ql +++ /dev/null @@ -1,13 +0,0 @@ -/** - * @id cpp/summary/lines-of-user-code-per-file - * @name Lines of C/C++ code per source file - * @description The number of lines of C/C++ code for each file in the source directory. - * @kind metric - * @tags summary - */ - -import cpp - -from File f -where exists(f.getRelativePath()) -select f, f.getMetrics().getNumberOfLines() diff --git a/cpp/ql/test/query-tests/Summary/LinesOfCodePerFile.expected b/cpp/ql/test/query-tests/Summary/LinesOfCodePerFile.expected deleted file mode 100644 index e02d0591ab2..00000000000 --- a/cpp/ql/test/query-tests/Summary/LinesOfCodePerFile.expected +++ /dev/null @@ -1,3 +0,0 @@ -| empty-file.cpp:0:0:0:0 | empty-file.cpp | 0 | -| large-file.cpp:0:0:0:0 | large-file.cpp | 119 | -| short-file.cpp:0:0:0:0 | short-file.cpp | 3 | diff --git a/cpp/ql/test/query-tests/Summary/LinesOfCodePerFile.qlref b/cpp/ql/test/query-tests/Summary/LinesOfCodePerFile.qlref deleted file mode 100644 index 33edfd15c7c..00000000000 --- a/cpp/ql/test/query-tests/Summary/LinesOfCodePerFile.qlref +++ /dev/null @@ -1 +0,0 @@ -Summary/LinesOfCodePerFile.ql diff --git a/cpp/ql/test/query-tests/Summary/LinesOfUserCode.expected b/cpp/ql/test/query-tests/Summary/LinesOfUserCode.expected deleted file mode 100644 index d847b050658..00000000000 --- a/cpp/ql/test/query-tests/Summary/LinesOfUserCode.expected +++ /dev/null @@ -1 +0,0 @@ -| 122 | diff --git a/cpp/ql/test/query-tests/Summary/LinesOfUserCode.qlref b/cpp/ql/test/query-tests/Summary/LinesOfUserCode.qlref deleted file mode 100644 index baaa947e6af..00000000000 --- a/cpp/ql/test/query-tests/Summary/LinesOfUserCode.qlref +++ /dev/null @@ -1 +0,0 @@ -Summary/LinesOfUserCode.ql diff --git a/cpp/ql/test/query-tests/Summary/LinesOfUserCodePerFile.expected b/cpp/ql/test/query-tests/Summary/LinesOfUserCodePerFile.expected deleted file mode 100644 index e02d0591ab2..00000000000 --- a/cpp/ql/test/query-tests/Summary/LinesOfUserCodePerFile.expected +++ /dev/null @@ -1,3 +0,0 @@ -| empty-file.cpp:0:0:0:0 | empty-file.cpp | 0 | -| large-file.cpp:0:0:0:0 | large-file.cpp | 119 | -| short-file.cpp:0:0:0:0 | short-file.cpp | 3 | diff --git a/cpp/ql/test/query-tests/Summary/LinesOfUserCodePerFile.qlref b/cpp/ql/test/query-tests/Summary/LinesOfUserCodePerFile.qlref deleted file mode 100644 index bb3fc603c4d..00000000000 --- a/cpp/ql/test/query-tests/Summary/LinesOfUserCodePerFile.qlref +++ /dev/null @@ -1 +0,0 @@ -Summary/LinesOfUserCodePerFile.ql From 662e17ff85cc75305fc849c0c02df9e36ea5cca3 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Mon, 15 Mar 2021 15:09:03 +0100 Subject: [PATCH 115/725] Java: Bugfix dispatch to lambda in call context. --- .../dataflow/internal/DataFlowDispatch.qll | 14 +++-- .../dataflow/lambda/Executor.java | 63 +++++++++++++++++++ .../dataflow/lambda/Processor.java | 9 +++ .../dataflow/lambda/StringProcessor.java | 30 +++++++++ .../dataflow/lambda/flow.expected | 8 +++ .../library-tests/dataflow/lambda/flow.ql | 25 ++++++++ 6 files changed, 144 insertions(+), 5 deletions(-) create mode 100644 java/ql/test/library-tests/dataflow/lambda/Executor.java create mode 100644 java/ql/test/library-tests/dataflow/lambda/Processor.java create mode 100644 java/ql/test/library-tests/dataflow/lambda/StringProcessor.java create mode 100644 java/ql/test/library-tests/dataflow/lambda/flow.expected create mode 100644 java/ql/test/library-tests/dataflow/lambda/flow.ql diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowDispatch.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowDispatch.qll index ba99bffbf5f..223af728fe4 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowDispatch.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowDispatch.qll @@ -41,6 +41,12 @@ private module DispatchImpl { ) } + private RefType getPreciseType(Expr e) { + result = e.(FunctionalExpr).getConstructedType() + or + not e instanceof FunctionalExpr and result = e.getType() + } + /** * Holds if the `i`th argument of `ctx` has type `t` and `ctx` is a * relevant call context. @@ -55,7 +61,7 @@ private module DispatchImpl { ctx.getArgument(i) = arg | src = variableTrack(arg) and - srctype = src.getType() and + srctype = getPreciseType(src) and if src instanceof ClassInstanceExpr then exact = true else exact = false ) or @@ -67,11 +73,9 @@ private module DispatchImpl { if ctx instanceof ClassInstanceExpr then exact = true else exact = false ) | - exists(TypeVariable v | v = srctype | - t = v.getUpperBoundType+() and not t instanceof TypeVariable - ) + t = srctype.(BoundedType).getAnUltimateUpperBoundType() or - t = srctype and not srctype instanceof TypeVariable + t = srctype and not srctype instanceof BoundedType ) } diff --git a/java/ql/test/library-tests/dataflow/lambda/Executor.java b/java/ql/test/library-tests/dataflow/lambda/Executor.java new file mode 100644 index 00000000000..93f5e04221d --- /dev/null +++ b/java/ql/test/library-tests/dataflow/lambda/Executor.java @@ -0,0 +1,63 @@ +import java.lang.Runtime; +import java.util.function.Function; + +public class Executor { + + private static final Processor processor = new Processor(); + + private static String source() { return "taint"; } + + public static void main(String[] args) { + exec1(source()); + exec2(source()); + exec3(source()); + exec4(source()); + exec5(source()); + } + + private static void exec1(String command){ + command = process(s->s.toUpperCase(),command); + exec(command); + } + + private static void exec2(String command){ + command = process(s->"Taint stops here.",command); + exec(command); + } + + private static void exec3(String command){ + command = processor.process(s->s.toUpperCase(),command); + exec(command); + } + + private static void exec4(String command){ + command = processor.process(s->"Taint stops here.",command); + exec_b(command); + } + + private static void exec5(String command){ + command = processor.process(s->s.toUpperCase(),command); + exec_b(command); + } + + public static String process(Function fun, String command){ + return processor.process(fun, command); + } + + private static void exec(String command){ + command = process(s->s.trim(),command); + try { + Runtime.getRuntime().exec(command); + } + catch(Exception e) {} + } + + private static void exec_b(String command){ + command = processor.process(s->s.trim(),command); + try { + Runtime.getRuntime().exec(command); + } + catch(Exception e) {} + } +} + diff --git a/java/ql/test/library-tests/dataflow/lambda/Processor.java b/java/ql/test/library-tests/dataflow/lambda/Processor.java new file mode 100644 index 00000000000..c632519041c --- /dev/null +++ b/java/ql/test/library-tests/dataflow/lambda/Processor.java @@ -0,0 +1,9 @@ +import java.util.function.Function; + +public class Processor { + + public R process(Function function, T arg) { + return function.apply(arg); + } +} + diff --git a/java/ql/test/library-tests/dataflow/lambda/StringProcessor.java b/java/ql/test/library-tests/dataflow/lambda/StringProcessor.java new file mode 100644 index 00000000000..abe92ce5ca7 --- /dev/null +++ b/java/ql/test/library-tests/dataflow/lambda/StringProcessor.java @@ -0,0 +1,30 @@ +import java.util.function.Function; + +public class StringProcessor { + + private static final Processor processor = new Processor(); + + public static void main(String[] args) { + String command = args[0]; + lambdaExec(command); + } + + public static void lambdaExec(String command){ + processor.process(s->exec(s), command); + } + + public static String lambdaUnrelated(String command){ + return processor.process(s->s+"not related to anything", command); + } + + public static String exec(String command){ + try { + command = processor.process(s->s.trim(), command); + Runtime.getRuntime().exec(command); + return "Executed: "+command; + } catch(Exception e) { + return null; + } + } +} + diff --git a/java/ql/test/library-tests/dataflow/lambda/flow.expected b/java/ql/test/library-tests/dataflow/lambda/flow.expected new file mode 100644 index 00000000000..3b467de204b --- /dev/null +++ b/java/ql/test/library-tests/dataflow/lambda/flow.expected @@ -0,0 +1,8 @@ +| Executor.java:11:15:11:22 | source(...) | Executor.java:50:39:50:45 | command | +| Executor.java:11:15:11:22 | source(...) | StringProcessor.java:23:39:23:45 | command | +| Executor.java:12:15:12:22 | source(...) | Executor.java:50:39:50:45 | command | +| Executor.java:12:15:12:22 | source(...) | StringProcessor.java:23:39:23:45 | command | +| Executor.java:13:15:13:22 | source(...) | Executor.java:50:39:50:45 | command | +| Executor.java:13:15:13:22 | source(...) | StringProcessor.java:23:39:23:45 | command | +| Executor.java:15:15:15:22 | source(...) | Executor.java:58:39:58:45 | command | +| StringProcessor.java:8:26:8:29 | args | StringProcessor.java:23:39:23:45 | command | diff --git a/java/ql/test/library-tests/dataflow/lambda/flow.ql b/java/ql/test/library-tests/dataflow/lambda/flow.ql new file mode 100644 index 00000000000..61bc7a33307 --- /dev/null +++ b/java/ql/test/library-tests/dataflow/lambda/flow.ql @@ -0,0 +1,25 @@ +import java +import semmle.code.java.dataflow.TaintTracking + +class Conf extends TaintTracking::Configuration { + Conf() { this = "qltest lambda" } + + override predicate isSource(DataFlow::Node src) { + src.asExpr().(VarAccess).getVariable().hasName("args") + or + src.asExpr().(MethodAccess).getMethod().hasName("source") + } + + override predicate isSink(DataFlow::Node sink) { + sink.asExpr().(Argument).getCall() = + any(MethodAccess ma | + ma.getMethod().hasName("exec") and + ma.getQualifier().(MethodAccess).getMethod().hasName("getRuntime") + ) + } +} + +from DataFlow::Node src, DataFlow::Node sink, Conf c +where c.hasFlow(src, sink) +select src, sink + From d1f30d91645e203f739605ef5daeee288b47c539 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Mon, 15 Mar 2021 15:28:04 +0100 Subject: [PATCH 116/725] Java: Autoformat. --- java/ql/test/library-tests/dataflow/lambda/flow.ql | 1 - 1 file changed, 1 deletion(-) diff --git a/java/ql/test/library-tests/dataflow/lambda/flow.ql b/java/ql/test/library-tests/dataflow/lambda/flow.ql index 61bc7a33307..dc8d1c7d4b0 100644 --- a/java/ql/test/library-tests/dataflow/lambda/flow.ql +++ b/java/ql/test/library-tests/dataflow/lambda/flow.ql @@ -22,4 +22,3 @@ class Conf extends TaintTracking::Configuration { from DataFlow::Node src, DataFlow::Node sink, Conf c where c.hasFlow(src, sink) select src, sink - From fa3ac30894dba4a15868566d2e47dcd9d3036900 Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Tue, 16 Mar 2021 09:56:38 +0000 Subject: [PATCH 117/725] C++: Update query to latest spec. --- cpp/ql/src/Summary/LinesOfCode.ql | 4 ++-- cpp/ql/test/query-tests/Summary/LinesOfCode.expected | 2 +- cpp/ql/test/query-tests/Summary/empty-file.cpp | 1 + cpp/ql/test/query-tests/Summary/large-file.cpp | 4 ++++ 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/cpp/ql/src/Summary/LinesOfCode.ql b/cpp/ql/src/Summary/LinesOfCode.ql index 6ba027dbd14..6dfb1d1d741 100644 --- a/cpp/ql/src/Summary/LinesOfCode.ql +++ b/cpp/ql/src/Summary/LinesOfCode.ql @@ -1,11 +1,11 @@ /** * @id cpp/summary/lines-of-code * @name Total lines of C/C++ code in the database. - * @description The total number of lines of C/C++ code across all files, including system headers and libraries. This is a useful metric of the size of a database. + * @description The total number of lines of C/C++ code across all files, including system headers, libraries and auto-generated files. This is a useful metric of the size of a database. Lines of code are all lines in a file that was seen during the build that contain code, i.e. are not whitespace or comments. * @kind metric * @tags summary */ import cpp -select sum(File f | f.fromSource() | f.getMetrics().getNumberOfLines()) +select sum(File f | f.fromSource() | f.getMetrics().getNumberOfLinesOfCode()) diff --git a/cpp/ql/test/query-tests/Summary/LinesOfCode.expected b/cpp/ql/test/query-tests/Summary/LinesOfCode.expected index d847b050658..a75c288c151 100644 --- a/cpp/ql/test/query-tests/Summary/LinesOfCode.expected +++ b/cpp/ql/test/query-tests/Summary/LinesOfCode.expected @@ -1 +1 @@ -| 122 | +| 93 | diff --git a/cpp/ql/test/query-tests/Summary/empty-file.cpp b/cpp/ql/test/query-tests/Summary/empty-file.cpp index e69de29bb2d..8b137891791 100644 --- a/cpp/ql/test/query-tests/Summary/empty-file.cpp +++ b/cpp/ql/test/query-tests/Summary/empty-file.cpp @@ -0,0 +1 @@ + diff --git a/cpp/ql/test/query-tests/Summary/large-file.cpp b/cpp/ql/test/query-tests/Summary/large-file.cpp index d6d06518b66..b4af2da0cde 100644 --- a/cpp/ql/test/query-tests/Summary/large-file.cpp +++ b/cpp/ql/test/query-tests/Summary/large-file.cpp @@ -26,10 +26,14 @@ int a06(float x) { return (int)x; } +/** + * This is a multi-line comment + */ int a07(float x) { return (int)x; } +// this is a single-line comment int a08(float x) { return (int)x; } From 2e8e04f73ef9ebec6113381b14ae781925dae62c Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Tue, 16 Mar 2021 10:48:04 +0000 Subject: [PATCH 118/725] C++: Move FailedExtractions.ql to FailedCompilations.ql. --- .../{FailedExtractions.ql => FailedCompilations.ql} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename cpp/ql/src/Diagnostics/{FailedExtractions.ql => FailedCompilations.ql} (88%) diff --git a/cpp/ql/src/Diagnostics/FailedExtractions.ql b/cpp/ql/src/Diagnostics/FailedCompilations.ql similarity index 88% rename from cpp/ql/src/Diagnostics/FailedExtractions.ql rename to cpp/ql/src/Diagnostics/FailedCompilations.ql index 513c833f14f..8af1b0250c0 100644 --- a/cpp/ql/src/Diagnostics/FailedExtractions.ql +++ b/cpp/ql/src/Diagnostics/FailedCompilations.ql @@ -1,8 +1,8 @@ /** - * @name Failed extractions + * @name Failed compiler invocations. * @description Gives the command-line of compilations for which extraction did not run to completion. * @kind diagnostic - * @id cpp/diagnostics/failed-extractions + * @id cpp/diagnostics/failed-compilations */ import cpp From e092b317912dbabbe5682ef1ef12ae808a59f7b0 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 4 Mar 2021 13:50:15 +0100 Subject: [PATCH 119/725] C#: Add test exposing missing phi flow --- .../library-tests/dataflow/delegates/DelegateFlow.cs | 9 +++++++++ .../dataflow/delegates/DelegateFlow.expected | 1 + 2 files changed, 10 insertions(+) diff --git a/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.cs b/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.cs index 59c1c924a80..15d628aea9a 100644 --- a/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.cs @@ -124,4 +124,13 @@ class DelegateFlow delegate*, void> fnptr = &M2; fnptr((i) => { }); } + + void M19(Action a, bool b) + { + if (b) + a = () => {}; + a(); + } + + void M20(bool b) => M19(() => {}, b); } diff --git a/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.expected b/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.expected index 80ae0d0fe89..c620a7cf22a 100644 --- a/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.expected @@ -24,3 +24,4 @@ delegateCall | DelegateFlow.cs:89:35:89:37 | delegate call | DelegateFlow.cs:65:10:65:12 | M11 | DelegateFlow.cs:91:13:91:47 | delegate creation of type MyDelegate | | DelegateFlow.cs:89:35:89:37 | delegate call | DelegateFlow.cs:74:17:74:19 | M12 | DelegateFlow.cs:92:13:92:15 | delegate creation of type MyDelegate | | DelegateFlow.cs:89:35:89:37 | delegate call | DelegateFlow.cs:93:13:93:21 | (...) => ... | DelegateFlow.cs:93:13:93:21 | (...) => ... | +| DelegateFlow.cs:132:9:132:11 | delegate call | DelegateFlow.cs:131:17:131:24 | (...) => ... | file://:0:0:0:0 | | From 25adcfc39d2afda92f1f62be272e041c44499ef5 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 4 Mar 2021 10:22:11 +0100 Subject: [PATCH 120/725] C#: Fix missing phi flow --- .../semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll | 4 ++-- .../library-tests/dataflow/delegates/DelegateFlow.expected | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) 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 5e3ac64f7c2..ebd8f51a8f1 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -292,8 +292,8 @@ module LocalFlow { */ private predicate localFlowSsaInput(Node nodeFrom, Ssa::Definition def, Ssa::Definition next) { exists(ControlFlow::BasicBlock bb, int i | SsaImpl::lastRefBeforeRedef(def, bb, i, next) | - def = nodeFrom.(SsaDefinitionNode).getDefinition() and - def.definesAt(_, bb, i) + def.definesAt(_, bb, i) and + def = getSsaDefinition(nodeFrom) or nodeFrom.asExprAtNode(bb.getNode(i)) instanceof AssignableRead ) diff --git a/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.expected b/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.expected index c620a7cf22a..addcc3c0ff7 100644 --- a/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.expected @@ -25,3 +25,4 @@ delegateCall | DelegateFlow.cs:89:35:89:37 | delegate call | DelegateFlow.cs:74:17:74:19 | M12 | DelegateFlow.cs:92:13:92:15 | delegate creation of type MyDelegate | | DelegateFlow.cs:89:35:89:37 | delegate call | DelegateFlow.cs:93:13:93:21 | (...) => ... | DelegateFlow.cs:93:13:93:21 | (...) => ... | | DelegateFlow.cs:132:9:132:11 | delegate call | DelegateFlow.cs:131:17:131:24 | (...) => ... | file://:0:0:0:0 | | +| DelegateFlow.cs:132:9:132:11 | delegate call | DelegateFlow.cs:135:29:135:36 | (...) => ... | DelegateFlow.cs:135:29:135:36 | (...) => ... | From 29c6d221634e968943543df9c92b336e00352a36 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 4 Mar 2021 13:50:38 +0100 Subject: [PATCH 121/725] C#: Add test exposing missing delegate flow --- .../dataflow/global/GetAnOutNode.expected | 2 +- .../library-tests/dataflow/global/GlobalDataFlow.cs | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected b/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected index 5b4957a19e9..a074c7f5a79 100644 --- a/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected +++ b/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected @@ -196,7 +196,7 @@ | GlobalDataFlow.cs:472:25:472:50 | call to method ConfigureAwait | return | GlobalDataFlow.cs:472:25:472:50 | call to method ConfigureAwait | | GlobalDataFlow.cs:473:23:473:44 | call to method GetAwaiter | return | GlobalDataFlow.cs:473:23:473:44 | call to method GetAwaiter | | GlobalDataFlow.cs:474:22:474:40 | call to method GetResult | return | GlobalDataFlow.cs:474:22:474:40 | call to method GetResult | -| GlobalDataFlow.cs:486:44:486:47 | delegate call | return | GlobalDataFlow.cs:486:44:486:47 | delegate call | +| GlobalDataFlow.cs:498:44:498:47 | delegate call | return | GlobalDataFlow.cs:498:44:498:47 | delegate call | | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | return | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | return | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | | Splitting.cs:20:22:20:30 | call to method Return | return | Splitting.cs:20:22:20:30 | call to method Return | diff --git a/csharp/ql/test/library-tests/dataflow/global/GlobalDataFlow.cs b/csharp/ql/test/library-tests/dataflow/global/GlobalDataFlow.cs index 4d072ca4d1c..5405acd5a6c 100644 --- a/csharp/ql/test/library-tests/dataflow/global/GlobalDataFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/global/GlobalDataFlow.cs @@ -474,6 +474,18 @@ public class DataFlow var sink45 = awaiter.GetResult(); Check(sink45); } + + void M5(bool b) + { + void Inner(Action a, bool b, string arg) + { + if (b) + a = s => Check(s); + a(arg); + } + + Inner(_ => {}, b, "taint source"); + } } static class IEnumerableExtensions From e1e4016a5c7b4fb76c667fbced127b9480c1436a Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 4 Mar 2021 14:05:50 +0100 Subject: [PATCH 122/725] C#: Fix missing delegate flow --- .../code/csharp/dataflow/internal/DataFlowDispatch.qll | 6 ++++++ .../library-tests/dataflow/global/DataFlow.expected | 1 + .../dataflow/global/DataFlowPath.expected | 10 ++++++++++ .../dataflow/global/TaintTracking.expected | 1 + .../dataflow/global/TaintTrackingPath.expected | 10 ++++++++++ 5 files changed, 28 insertions(+) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll index c68ba38e0b5..d58fda11922 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll @@ -167,6 +167,12 @@ private module DispatchImpl { cc.isArgument(ctx.getExpr(), _) ) or + exists(DataFlowCallable enclosing | + mayBenefitFromCallContext(call, enclosing) and + ctx.getARuntimeTarget() = enclosing and + result = viableDelegateCallable(call, any(EmptyCallContext ecc)) + ) + or result = call.(NonDelegateDataFlowCall) .getDispatchCall() diff --git a/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected b/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected index 9c382aaee62..b0506ab3e4e 100644 --- a/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected @@ -52,6 +52,7 @@ | GlobalDataFlow.cs:401:15:401:20 | access to local variable sink11 | | GlobalDataFlow.cs:424:41:424:46 | access to local variable sink20 | | GlobalDataFlow.cs:475:15:475:20 | access to local variable sink45 | +| GlobalDataFlow.cs:483:32:483:32 | access to parameter s | | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | | Splitting.cs:11:19:11:19 | access to local variable x | diff --git a/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected b/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected index a806a9a6256..d07fcd39403 100644 --- a/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected +++ b/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected @@ -229,6 +229,10 @@ edges | GlobalDataFlow.cs:473:23:473:44 | call to method GetAwaiter [m_task, Result] : String | GlobalDataFlow.cs:474:22:474:28 | access to local variable awaiter [m_task, Result] : String | | GlobalDataFlow.cs:474:22:474:28 | access to local variable awaiter [m_task, Result] : String | GlobalDataFlow.cs:474:22:474:40 | call to method GetResult : String | | GlobalDataFlow.cs:474:22:474:40 | call to method GetResult : String | GlobalDataFlow.cs:475:15:475:20 | access to local variable sink45 | +| GlobalDataFlow.cs:480:53:480:55 | arg : String | GlobalDataFlow.cs:484:15:484:17 | access to parameter arg : String | +| GlobalDataFlow.cs:483:21:483:21 | s : String | GlobalDataFlow.cs:483:32:483:32 | access to parameter s | +| GlobalDataFlow.cs:484:15:484:17 | access to parameter arg : String | GlobalDataFlow.cs:483:21:483:21 | s : String | +| GlobalDataFlow.cs:487:27:487:40 | "taint source" : String | GlobalDataFlow.cs:480:53:480:55 | arg : String | | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted : String | | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted : String | | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | @@ -444,6 +448,11 @@ nodes | GlobalDataFlow.cs:474:22:474:28 | access to local variable awaiter [m_task, Result] : String | semmle.label | access to local variable awaiter [m_task, Result] : String | | GlobalDataFlow.cs:474:22:474:40 | call to method GetResult : String | semmle.label | call to method GetResult : String | | GlobalDataFlow.cs:475:15:475:20 | access to local variable sink45 | semmle.label | access to local variable sink45 | +| GlobalDataFlow.cs:480:53:480:55 | arg : String | semmle.label | arg : String | +| GlobalDataFlow.cs:483:21:483:21 | s : String | semmle.label | s : String | +| GlobalDataFlow.cs:483:32:483:32 | access to parameter s | semmle.label | access to parameter s | +| GlobalDataFlow.cs:484:15:484:17 | access to parameter arg : String | semmle.label | access to parameter arg : String | +| GlobalDataFlow.cs:487:27:487:40 | "taint source" : String | semmle.label | "taint source" : String | | Splitting.cs:3:28:3:34 | tainted : String | semmle.label | tainted : String | | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | semmle.label | [b (line 3): false] call to method Return : String | | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | semmle.label | [b (line 3): true] call to method Return : String | @@ -520,6 +529,7 @@ nodes | GlobalDataFlow.cs:182:15:182:19 | access to local variable sink9 | GlobalDataFlow.cs:180:35:180:48 | "taint source" : String | GlobalDataFlow.cs:182:15:182:19 | access to local variable sink9 | access to local variable sink9 | | Splitting.cs:11:19:11:19 | access to local variable x | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:11:19:11:19 | access to local variable x | access to local variable x | | Splitting.cs:34:19:34:19 | access to local variable x | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:34:19:34:19 | access to local variable x | access to local variable x | +| GlobalDataFlow.cs:483:32:483:32 | access to parameter s | GlobalDataFlow.cs:487:27:487:40 | "taint source" : String | GlobalDataFlow.cs:483:32:483:32 | access to parameter s | access to parameter s | | Capture.cs:57:27:57:32 | access to parameter sink39 | Capture.cs:7:20:7:26 | tainted : String | Capture.cs:57:27:57:32 | access to parameter sink39 | access to parameter sink39 | | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam0 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam0 | access to parameter sinkParam0 | | GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam1 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam1 | access to parameter sinkParam1 | diff --git a/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected b/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected index fd800913202..43e5ee21e42 100644 --- a/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected +++ b/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected @@ -58,6 +58,7 @@ | GlobalDataFlow.cs:453:15:453:20 | access to local variable sink43 | | GlobalDataFlow.cs:463:15:463:20 | access to local variable sink44 | | GlobalDataFlow.cs:475:15:475:20 | access to local variable sink45 | +| GlobalDataFlow.cs:483:32:483:32 | access to parameter s | | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | | Splitting.cs:11:19:11:19 | access to local variable x | diff --git a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected index 7297686b5e3..e9ba5973f50 100644 --- a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected +++ b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected @@ -249,6 +249,10 @@ edges | GlobalDataFlow.cs:473:23:473:44 | call to method GetAwaiter [m_task, Result] : String | GlobalDataFlow.cs:474:22:474:28 | access to local variable awaiter [m_task, Result] : String | | GlobalDataFlow.cs:474:22:474:28 | access to local variable awaiter [m_task, Result] : String | GlobalDataFlow.cs:474:22:474:40 | call to method GetResult : String | | GlobalDataFlow.cs:474:22:474:40 | call to method GetResult : String | GlobalDataFlow.cs:475:15:475:20 | access to local variable sink45 | +| GlobalDataFlow.cs:480:53:480:55 | arg : String | GlobalDataFlow.cs:484:15:484:17 | access to parameter arg : String | +| GlobalDataFlow.cs:483:21:483:21 | s : String | GlobalDataFlow.cs:483:32:483:32 | access to parameter s | +| GlobalDataFlow.cs:484:15:484:17 | access to parameter arg : String | GlobalDataFlow.cs:483:21:483:21 | s : String | +| GlobalDataFlow.cs:487:27:487:40 | "taint source" : String | GlobalDataFlow.cs:480:53:480:55 | arg : String | | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted : String | | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted : String | | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | @@ -486,6 +490,11 @@ nodes | GlobalDataFlow.cs:474:22:474:28 | access to local variable awaiter [m_task, Result] : String | semmle.label | access to local variable awaiter [m_task, Result] : String | | GlobalDataFlow.cs:474:22:474:40 | call to method GetResult : String | semmle.label | call to method GetResult : String | | GlobalDataFlow.cs:475:15:475:20 | access to local variable sink45 | semmle.label | access to local variable sink45 | +| GlobalDataFlow.cs:480:53:480:55 | arg : String | semmle.label | arg : String | +| GlobalDataFlow.cs:483:21:483:21 | s : String | semmle.label | s : String | +| GlobalDataFlow.cs:483:32:483:32 | access to parameter s | semmle.label | access to parameter s | +| GlobalDataFlow.cs:484:15:484:17 | access to parameter arg : String | semmle.label | access to parameter arg : String | +| GlobalDataFlow.cs:487:27:487:40 | "taint source" : String | semmle.label | "taint source" : String | | Splitting.cs:3:28:3:34 | tainted : String | semmle.label | tainted : String | | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | semmle.label | [b (line 3): false] call to method Return : String | | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | semmle.label | [b (line 3): true] call to method Return : String | @@ -573,6 +582,7 @@ nodes | GlobalDataFlow.cs:453:15:453:20 | access to local variable sink43 | GlobalDataFlow.cs:451:35:451:48 | "taint source" : String | GlobalDataFlow.cs:453:15:453:20 | access to local variable sink43 | access to local variable sink43 | | GlobalDataFlow.cs:463:15:463:20 | access to local variable sink44 | GlobalDataFlow.cs:462:51:462:64 | "taint source" : String | GlobalDataFlow.cs:463:15:463:20 | access to local variable sink44 | access to local variable sink44 | | GlobalDataFlow.cs:475:15:475:20 | access to local variable sink45 | GlobalDataFlow.cs:471:35:471:48 | "taint source" : String | GlobalDataFlow.cs:475:15:475:20 | access to local variable sink45 | access to local variable sink45 | +| GlobalDataFlow.cs:483:32:483:32 | access to parameter s | GlobalDataFlow.cs:487:27:487:40 | "taint source" : String | GlobalDataFlow.cs:483:32:483:32 | access to parameter s | access to parameter s | | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | [b (line 3): false] access to local variable x | | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | [b (line 3): true] access to local variable x | | Splitting.cs:11:19:11:19 | access to local variable x | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:11:19:11:19 | access to local variable x | access to local variable x | From 755fec466f97c610e4546e88f39d5081b17062ea Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Tue, 16 Mar 2021 13:21:57 +0100 Subject: [PATCH 123/725] Apply suggestions from code review Co-authored-by: Jonas Jensen --- cpp/ql/src/Summary/LinesOfCode.ql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/Summary/LinesOfCode.ql b/cpp/ql/src/Summary/LinesOfCode.ql index 6dfb1d1d741..79e4e7b16f2 100644 --- a/cpp/ql/src/Summary/LinesOfCode.ql +++ b/cpp/ql/src/Summary/LinesOfCode.ql @@ -1,7 +1,7 @@ /** * @id cpp/summary/lines-of-code - * @name Total lines of C/C++ code in the database. - * @description The total number of lines of C/C++ code across all files, including system headers, libraries and auto-generated files. This is a useful metric of the size of a database. Lines of code are all lines in a file that was seen during the build that contain code, i.e. are not whitespace or comments. + * @name Total lines of C/C++ code in the database + * @description The total number of lines of C/C++ code across all files, including system headers, libraries, and auto-generated files. This is a useful metric of the size of a database. Lines of code are all lines in a file that was seen during the build that contain code, i.e. are not whitespace or comments. * @kind metric * @tags summary */ From a373a523f69c4aad9f526c1dabf5a7f547cf1409 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Tue, 2 Mar 2021 20:12:08 +0100 Subject: [PATCH 124/725] Data flow: Move C# lambda flow logic into shared library --- .../code/csharp/dataflow/CallContext.qll | 31 +- .../dataflow/internal/DataFlowDispatch.qll | 61 +--- .../dataflow/internal/DataFlowImplCommon.qll | 309 +++++++++++++++++- .../dataflow/internal/DataFlowPrivate.qll | 69 +++- .../dataflow/internal/DelegateDataFlow.qll | 24 +- .../code/csharp/dataflow/internal/SsaImpl.qll | 1 - .../ql/src/semmle/code/csharp/exprs/Call.qll | 23 +- .../dataflow/delegates/DelegateFlow.expected | 81 +++-- .../dataflow/delegates/DelegateFlow.ql | 34 +- .../FunctionPointerFlow.expected | 29 +- .../functionpointers/FunctionPointerFlow.ql | 37 ++- 11 files changed, 552 insertions(+), 147 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/CallContext.qll b/csharp/ql/src/semmle/code/csharp/dataflow/CallContext.qll index 8be2fc0939f..47ff7f96111 100755 --- a/csharp/ql/src/semmle/code/csharp/dataflow/CallContext.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/CallContext.qll @@ -1,4 +1,6 @@ /** + * DEPRECATED. + * * Provides classes for data flow call contexts. */ @@ -15,11 +17,13 @@ private newtype TCallContext = TArgFunctionPointerCallContext(FunctionPointerCall fptrc, int i) { exists(fptrc.getArgument(i)) } /** + * DEPRECATED. + * * A call context. * * A call context records the origin of data flow into callables. */ -class CallContext extends TCallContext { +deprecated class CallContext extends TCallContext { /** Gets a textual representation of this call context. */ string toString() { none() } @@ -27,18 +31,20 @@ class CallContext extends TCallContext { Location getLocation() { none() } } -/** An empty call context. */ -class EmptyCallContext extends CallContext, TEmptyCallContext { +/** DEPRECATED. An empty call context. */ +deprecated class EmptyCallContext extends CallContext, TEmptyCallContext { override string toString() { result = "" } override EmptyLocation getLocation() { any() } } /** + * DEPRECATED. + * * An argument call context, that is a call argument through which data flows * into a callable. */ -abstract class ArgumentCallContext extends CallContext { +abstract deprecated class ArgumentCallContext extends CallContext { /** * Holds if this call context represents the argument at position `i` of the * call expression `call`. @@ -46,8 +52,9 @@ abstract class ArgumentCallContext extends CallContext { abstract predicate isArgument(Expr call, int i); } -/** An argument of a non-delegate call. */ -class NonDelegateCallArgumentCallContext extends ArgumentCallContext, TArgNonDelegateCallContext { +/** DEPRECATED. An argument of a non-delegate call. */ +deprecated class NonDelegateCallArgumentCallContext extends ArgumentCallContext, + TArgNonDelegateCallContext { Expr arg; NonDelegateCallArgumentCallContext() { this = TArgNonDelegateCallContext(arg) } @@ -61,8 +68,8 @@ class NonDelegateCallArgumentCallContext extends ArgumentCallContext, TArgNonDel override Location getLocation() { result = arg.getLocation() } } -/** An argument of a delegate or function pointer call. */ -class DelegateLikeCallArgumentCallContext extends ArgumentCallContext { +/** DEPRECATED. An argument of a delegate or function pointer call. */ +deprecated class DelegateLikeCallArgumentCallContext extends ArgumentCallContext { DelegateLikeCall dc; int arg; @@ -80,10 +87,10 @@ class DelegateLikeCallArgumentCallContext extends ArgumentCallContext { override Location getLocation() { result = dc.getArgument(arg).getLocation() } } -/** An argument of a delegate call. */ -class DelegateCallArgumentCallContext extends DelegateLikeCallArgumentCallContext, +/** DEPRECATED. An argument of a delegate call. */ +deprecated class DelegateCallArgumentCallContext extends DelegateLikeCallArgumentCallContext, TArgDelegateCallContext { } -/** An argument of a function pointer call. */ -class FunctionPointerCallArgumentCallContext extends DelegateLikeCallArgumentCallContext, +/** DEPRECATED. An argument of a function pointer call. */ +deprecated class FunctionPointerCallArgumentCallContext extends DelegateLikeCallArgumentCallContext, TArgFunctionPointerCallContext { } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll index d58fda11922..5f5da527cde 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll @@ -1,8 +1,8 @@ private import csharp private import cil private import dotnet +private import DataFlowPublic private import DataFlowPrivate -private import DelegateDataFlow private import FlowSummaryImpl as FlowSummaryImpl private import semmle.code.csharp.dataflow.FlowSummary private import semmle.code.csharp.dispatch.Dispatch @@ -131,51 +131,24 @@ private module Cached { import Cached private module DispatchImpl { - private import CallContext - - /** - * Gets a viable run-time target for the delegate call `call`, requiring - * call context `cc`. - */ - private DataFlowCallable viableDelegateCallable(DataFlowCall call, CallContext cc) { - result = call.(DelegateDataFlowCall).getARuntimeTarget(cc) - } - /** * Holds if the set of viable implementations that can be called by `call` * might be improved by knowing the call context. This is the case if the * call is a delegate call, or if the qualifier accesses a parameter of * the enclosing callable `c` (including the implicit `this` parameter). */ - predicate mayBenefitFromCallContext(DataFlowCall call, Callable c) { + predicate mayBenefitFromCallContext(NonDelegateDataFlowCall call, Callable c) { c = call.getEnclosingCallable() and - ( - exists(CallContext cc | exists(viableDelegateCallable(call, cc)) | - not cc instanceof EmptyCallContext - ) - or - call.(NonDelegateDataFlowCall).getDispatchCall().mayBenefitFromCallContext() - ) + call.getDispatchCall().mayBenefitFromCallContext() } /** * Gets a viable dispatch target of `call` in the context `ctx`. This is * restricted to those `call`s for which a context might make a difference. */ - DataFlowCallable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { - exists(ArgumentCallContext cc | result = viableDelegateCallable(call, cc) | - cc.isArgument(ctx.getExpr(), _) - ) - or - exists(DataFlowCallable enclosing | - mayBenefitFromCallContext(call, enclosing) and - ctx.getARuntimeTarget() = enclosing and - result = viableDelegateCallable(call, any(EmptyCallContext ecc)) - ) - or + DataFlowCallable viableImplInCallContext(NonDelegateDataFlowCall call, DataFlowCall ctx) { result = - call.(NonDelegateDataFlowCall) - .getDispatchCall() + call.getDispatchCall() .getADynamicTargetInCallContext(ctx.(NonDelegateDataFlowCall).getDispatchCall()) .getUnboundDeclaration() } @@ -307,12 +280,7 @@ class NonDelegateDataFlowCall extends DataFlowCall, TNonDelegateCall { } /** A delegate call relevant for data flow. */ -abstract class DelegateDataFlowCall extends DataFlowCall { - /** Gets a viable run-time target of this call requiring call context `cc`. */ - abstract DataFlowCallable getARuntimeTarget(CallContext::CallContext cc); - - override DataFlowCallable getARuntimeTarget() { result = this.getARuntimeTarget(_) } -} +abstract class DelegateDataFlowCall extends DataFlowCall { } /** An explicit delegate or function pointer call relevant for data flow. */ class ExplicitDelegateLikeDataFlowCall extends DelegateDataFlowCall, TExplicitDelegateLikeCall { @@ -321,8 +289,11 @@ class ExplicitDelegateLikeDataFlowCall extends DelegateDataFlowCall, TExplicitDe ExplicitDelegateLikeDataFlowCall() { this = TExplicitDelegateLikeCall(cfn, dc) } - override DataFlowCallable getARuntimeTarget(CallContext::CallContext cc) { - result = getCallableForDataFlow(dc.getARuntimeTarget(cc)) + /** Gets the underlying call. */ + DelegateLikeCall getCall() { result = dc } + + override DataFlowCallable getARuntimeTarget() { + none() // handled by the shared library } override ControlFlow::Nodes::ElementNode getControlFlowNode() { result = cfn } @@ -395,11 +366,11 @@ class SummaryDelegateCall extends DelegateDataFlowCall, TSummaryDelegateCall { SummaryDelegateCall() { this = TSummaryDelegateCall(c, pos) } - override DataFlowCallable getARuntimeTarget(CallContext::CallContext cc) { - exists(SummaryDelegateParameterSink p | - p.isParameterOf(c, pos) and - result = p.getARuntimeTarget(cc) - ) + /** Gets the parameter node that this delegate call targets. */ + ParameterNode getParameterNode() { result.isParameterOf(c, pos) } + + override DataFlowCallable getARuntimeTarget() { + none() // handled by the shared library } override ControlFlow::Nodes::ElementNode getControlFlowNode() { none() } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll index 1319f972037..a51c20c2288 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll @@ -26,15 +26,243 @@ predicate accessPathCostLimits(int apLimit, int tupleLimit) { tupleLimit = 1000 } +/** + * Provides a simple data-flow analysis for resolving lambda calls. The analysis + * currently excludes read-steps, store-steps, and flow-through. + * + * The analysis uses non-linear recursion: When computing a flow path in or out + * of a call, we use the results of the analysis recursively to resolve lamba + * calls. For this reason, we cannot reuse the code from `DataFlowImpl.qll` directly. + */ +private module LambdaFlow { + private predicate viableParamNonLambda(DataFlowCall call, int i, ParameterNode p) { + p.isParameterOf(viableCallable(call), i) + } + + private predicate viableParamLambda(DataFlowCall call, int i, ParameterNode p) { + p.isParameterOf(viableCallableLambda(call, _), i) + } + + private predicate viableParamArgNonLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) { + exists(int i | + viableParamNonLambda(call, i, p) and + arg.argumentOf(call, i) + ) + } + + private predicate viableParamArgLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) { + exists(int i | + viableParamLambda(call, i, p) and + arg.argumentOf(call, i) + ) + } + + private newtype TReturnPositionSimple = + TReturnPositionSimple0(DataFlowCallable c, ReturnKind kind) { + exists(ReturnNode ret | + c = getNodeEnclosingCallable(ret) and + kind = ret.getKind() + ) + } + + pragma[noinline] + private TReturnPositionSimple getReturnPositionSimple(ReturnNode ret, ReturnKind kind) { + result = TReturnPositionSimple0(getNodeEnclosingCallable(ret), kind) + } + + pragma[nomagic] + private TReturnPositionSimple viableReturnPosNonLambda(DataFlowCall call, ReturnKind kind) { + result = TReturnPositionSimple0(viableCallable(call), kind) + } + + pragma[nomagic] + private TReturnPositionSimple viableReturnPosLambda( + DataFlowCall call, DataFlowCallOption lastCall, ReturnKind kind + ) { + result = TReturnPositionSimple0(viableCallableLambda(call, lastCall), kind) + } + + private predicate viableReturnPosOutNonLambda( + DataFlowCall call, TReturnPositionSimple pos, OutNode out + ) { + exists(ReturnKind kind | + pos = viableReturnPosNonLambda(call, kind) and + out = getAnOutNode(call, kind) + ) + } + + private predicate viableReturnPosOutLambda( + DataFlowCall call, DataFlowCallOption lastCall, TReturnPositionSimple pos, OutNode out + ) { + exists(ReturnKind kind | + pos = viableReturnPosLambda(call, lastCall, kind) and + out = getAnOutNode(call, kind) + ) + } + + /** + * Holds if data can flow (inter-procedurally) from `node` (of type `t`) to + * the lambda call `lambdaCall`. + * + * The parameter `toReturn` indicates whether the path from `node` to + * `lambdaCall` goes through a return, and `toJump` whether the path goes + * through a jump step. + * + * The call context `lastCall` records the last call on the path from `node` + * to `lambdaCall`, if any. That is, `lastCall` is able to target the enclosing + * callable of `lambdaCall`. + */ + pragma[nomagic] + predicate revLambdaFlow( + DataFlowCall lambdaCall, LambdaCallKind kind, Node node, DataFlowType t, boolean toReturn, + boolean toJump, DataFlowCallOption lastCall + ) { + revLambdaFlow0(lambdaCall, kind, node, t, toReturn, toJump, lastCall) and + if node instanceof CastNode or node instanceof ArgumentNode or node instanceof ReturnNode + then compatibleTypes(t, getNodeType(node)) + else any() + } + + pragma[nomagic] + predicate revLambdaFlow0( + DataFlowCall lambdaCall, LambdaCallKind kind, Node node, DataFlowType t, boolean toReturn, + boolean toJump, DataFlowCallOption lastCall + ) { + lambdaCall(lambdaCall, kind, node) and + t = getNodeType(node) and + toReturn = false and + toJump = false and + lastCall = TDataFlowCallNone() + or + // local flow + exists(Node mid, DataFlowType t0 | + revLambdaFlow(lambdaCall, kind, mid, t0, toReturn, toJump, lastCall) + | + simpleLocalFlowStep(node, mid) and + t = t0 + or + exists(boolean preservesValue | + additionalLambdaFlowStep(node, mid, preservesValue) and + getNodeEnclosingCallable(node) = getNodeEnclosingCallable(mid) + | + preservesValue = false and + t = getNodeType(node) + or + preservesValue = true and + t = t0 + ) + ) + or + // jump step + exists(Node mid, DataFlowType t0 | + revLambdaFlow(lambdaCall, kind, mid, t0, _, _, _) and + toReturn = false and + toJump = true and + lastCall = TDataFlowCallNone() + | + jumpStep(node, mid) and + t = t0 + or + exists(boolean preservesValue | + additionalLambdaFlowStep(node, mid, preservesValue) and + getNodeEnclosingCallable(node) != getNodeEnclosingCallable(mid) + | + preservesValue = false and + t = getNodeType(node) + or + preservesValue = true and + t = t0 + ) + ) + or + // flow into a callable + exists(ParameterNode p, DataFlowCallOption lastCall0, DataFlowCall call | + revLambdaFlowIn(lambdaCall, kind, p, t, toJump, lastCall0) and + ( + if lastCall0 = TDataFlowCallNone() and toJump = false + then lastCall = TDataFlowCallSome(call) + else lastCall = lastCall0 + ) and + toReturn = false + | + viableParamArgNonLambda(call, p, node) + or + viableParamArgLambda(call, p, node) // non-linear recursion + ) + or + // flow out of a callable + exists(TReturnPositionSimple pos | + revLambdaFlowOut(lambdaCall, kind, pos, t, toJump, lastCall) and + getReturnPositionSimple(node, node.(ReturnNode).getKind()) = pos and + toReturn = true + ) + } + + pragma[nomagic] + predicate revLambdaFlowOutLambdaCall( + DataFlowCall lambdaCall, LambdaCallKind kind, OutNode out, DataFlowType t, boolean toJump, + DataFlowCall call, DataFlowCallOption lastCall + ) { + revLambdaFlow(lambdaCall, kind, out, t, _, toJump, lastCall) and + exists(ReturnKindExt rk | + out = rk.getAnOutNode(call) and + lambdaCall(call, _, _) + ) + } + + pragma[nomagic] + predicate revLambdaFlowOut( + DataFlowCall lambdaCall, LambdaCallKind kind, TReturnPositionSimple pos, DataFlowType t, + boolean toJump, DataFlowCallOption lastCall + ) { + exists(DataFlowCall call, OutNode out | + revLambdaFlow(lambdaCall, kind, out, t, _, toJump, lastCall) and + viableReturnPosOutNonLambda(call, pos, out) + or + // non-linear recursion + revLambdaFlowOutLambdaCall(lambdaCall, kind, out, t, toJump, call, lastCall) and + viableReturnPosOutLambda(call, _, pos, out) + ) + } + + pragma[nomagic] + predicate revLambdaFlowIn( + DataFlowCall lambdaCall, LambdaCallKind kind, ParameterNode p, DataFlowType t, boolean toJump, + DataFlowCallOption lastCall + ) { + revLambdaFlow(lambdaCall, kind, p, t, false, toJump, lastCall) + } +} + +private DataFlowCallable viableCallableExt(DataFlowCall call) { + result = viableCallable(call) + or + result = viableCallableLambda(call, _) +} + cached private module Cached { + /** + * Gets a viable target for the lambda call `call`. + * + * `lastCall` records the call required to reach `call` in order for the result + * to be a viable target, if any. + */ + cached + DataFlowCallable viableCallableLambda(DataFlowCall call, DataFlowCallOption lastCall) { + exists(Node creation, LambdaCallKind kind | + LambdaFlow::revLambdaFlow(call, kind, creation, _, _, _, lastCall) and + lambdaCreation(creation, kind, result) + ) + } + /** * Holds if `p` is the `i`th parameter of a viable dispatch target of `call`. * The instance parameter is considered to have index `-1`. */ pragma[nomagic] private predicate viableParam(DataFlowCall call, int i, ParameterNode p) { - p.isParameterOf(viableCallable(call), i) + p.isParameterOf(viableCallableExt(call), i) } /** @@ -52,7 +280,7 @@ private module Cached { pragma[nomagic] private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and + viableCallableExt(call) = result.getCallable() and kind = result.getKind() } @@ -317,6 +545,35 @@ private module Cached { cached private module DispatchWithCallContext { + /** + * Holds if the set of viable implementations that can be called by `call` + * might be improved by knowing the call context. + */ + pragma[nomagic] + private predicate mayBenefitFromCallContextExt(DataFlowCall call, DataFlowCallable callable) { + mayBenefitFromCallContext(call, callable) + or + callable = call.getEnclosingCallable() and + exists(viableCallableLambda(call, TDataFlowCallSome(_))) + } + + /** + * Gets a viable dispatch target of `call` in the context `ctx`. This is + * restricted to those `call`s for which a context might make a difference. + */ + pragma[nomagic] + private DataFlowCallable viableImplInCallContextExt(DataFlowCall call, DataFlowCall ctx) { + result = viableImplInCallContext(call, ctx) + or + result = viableCallableLambda(call, TDataFlowCallSome(ctx)) + or + exists(DataFlowCallable enclosing | + mayBenefitFromCallContextExt(call, enclosing) and + enclosing = viableCallableExt(ctx) and + result = viableCallableLambda(call, TDataFlowCallNone()) + ) + } + /** * Holds if the call context `ctx` reduces the set of viable run-time * dispatch targets of call `call` in `c`. @@ -324,10 +581,10 @@ private module Cached { cached predicate reducedViableImplInCallContext(DataFlowCall call, DataFlowCallable c, DataFlowCall ctx) { exists(int tgts, int ctxtgts | - mayBenefitFromCallContext(call, c) and - c = viableCallable(ctx) and - ctxtgts = count(viableImplInCallContext(call, ctx)) and - tgts = strictcount(viableCallable(call)) and + mayBenefitFromCallContextExt(call, c) and + c = viableCallableExt(ctx) and + ctxtgts = count(viableImplInCallContextExt(call, ctx)) and + tgts = strictcount(viableCallableExt(call)) and ctxtgts < tgts ) } @@ -339,7 +596,7 @@ private module Cached { */ cached DataFlowCallable prunedViableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { - result = viableImplInCallContext(call, ctx) and + result = viableImplInCallContextExt(call, ctx) and reducedViableImplInCallContext(call, _, ctx) } @@ -351,10 +608,10 @@ private module Cached { cached predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) { exists(int tgts, int ctxtgts | - mayBenefitFromCallContext(call, _) and - c = viableCallable(call) and - ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContext(call, ctx)) and - tgts = strictcount(DataFlowCall ctx | viableCallable(ctx) = call.getEnclosingCallable()) and + mayBenefitFromCallContextExt(call, _) and + c = viableCallableExt(call) and + ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContextExt(call, ctx)) and + tgts = strictcount(DataFlowCall ctx | viableCallableExt(ctx) = call.getEnclosingCallable()) and ctxtgts < tgts ) } @@ -367,7 +624,7 @@ private module Cached { */ cached DataFlowCallable prunedViableImplInCallContextReverse(DataFlowCall call, DataFlowCall ctx) { - result = viableImplInCallContext(call, ctx) and + result = viableImplInCallContextExt(call, ctx) and reducedViableImplInReturn(result, call) } } @@ -481,6 +738,11 @@ private module Cached { TBooleanNone() or TBooleanSome(boolean b) { b = true or b = false } + cached + newtype TDataFlowCallOption = + TDataFlowCallNone() or + TDataFlowCallSome(DataFlowCall call) + cached newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) } @@ -777,7 +1039,7 @@ ReturnPosition getReturnPosition(ReturnNodeExt ret) { bindingset[cc, callable] predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall call) { - cc instanceof CallContextAny and callable = viableCallable(call) + cc instanceof CallContextAny and callable = viableCallableExt(call) or exists(DataFlowCallable c0, DataFlowCall call0 | call0.getEnclosingCallable() = callable and @@ -791,14 +1053,14 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) { exists(DataFlowCall ctx | cc = TSpecificCall(ctx) | if reducedViableImplInCallContext(call, _, ctx) then result = prunedViableImplInCallContext(call, ctx) - else result = viableCallable(call) + else result = viableCallableExt(call) ) or - result = viableCallable(call) and cc instanceof CallContextSomeCall + result = viableCallableExt(call) and cc instanceof CallContextSomeCall or - result = viableCallable(call) and cc instanceof CallContextAny + result = viableCallableExt(call) and cc instanceof CallContextAny or - result = viableCallable(call) and cc instanceof CallContextReturn + result = viableCallableExt(call) and cc instanceof CallContextReturn } predicate read = readStep/3; @@ -812,6 +1074,19 @@ class BooleanOption extends TBooleanOption { } } +/** An optional `DataFlowCall`. */ +class DataFlowCallOption extends TDataFlowCallOption { + string toString() { + this = TDataFlowCallNone() and + result = "(none)" + or + exists(DataFlowCall call | + this = TDataFlowCallSome(call) and + result = call.toString() + ) + } +} + /** Content tagged with the type of a containing object. */ class TypedContent extends MkTypedContent { private Content c; 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 ebd8f51a8f1..a4591187c3d 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -5,7 +5,6 @@ private import DataFlowPublic private import DataFlowDispatch private import DataFlowImplCommon private import ControlFlowReachability -private import DelegateDataFlow private import FlowSummaryImpl as FlowSummaryImpl private import semmle.code.csharp.dataflow.FlowSummary private import semmle.code.csharp.Caching @@ -433,7 +432,7 @@ private class Argument extends Expr { this = dc.getQualifier() and arg = -1 and not dc.getAStaticTarget().(Modifiable).isStatic() ).getCall() or - this = call.(DelegateCall).getArgument(arg) + this = call.(DelegateLikeCall).getArgument(arg) } /** @@ -2022,3 +2021,69 @@ class Unit extends TUnit { * This predicate is only used for consistency checks. */ predicate isImmutableOrUnobservable(Node n) { none() } + +class LambdaCallKind = Unit; + +/** Holds if `creation` is an expression that creates a delegate for `c`. */ +predicate lambdaCreation(ExprNode creation, LambdaCallKind kind, DataFlowCallable c) { + exists(Expr e | e = creation.getExpr() | + c = e.(AnonymousFunctionExpr) + or + c = e.(CallableAccess).getTarget().getUnboundDeclaration() + or + c = e.(AddressOfExpr).getOperand().(CallableAccess).getTarget().getUnboundDeclaration() + ) and + kind = TMkUnit() +} + +private class LambdaConfiguration extends ControlFlowReachabilityConfiguration { + LambdaConfiguration() { this = "LambdaConfiguration" } + + override predicate candidate( + Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor + ) { + e1 = e2.(DelegateLikeCall).getExpr() and + exactScope = false and + scope = e2 and + isSuccessor = true + or + e1 = e2.(DelegateCreation).getArgument() and + exactScope = false and + scope = e2 and + isSuccessor = true + } +} + +/** Holds if `call` is a lambda call where `receiver` is the lambda expression. */ +predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) { + ( + exists(LambdaConfiguration x, DelegateLikeCall dc | + x.hasExprPath(dc.getExpr(), receiver.(ExprNode).getControlFlowNode(), dc, + call.getControlFlowNode()) + ) + or + receiver = call.(SummaryDelegateCall).getParameterNode() + ) and + kind = TMkUnit() +} + +/** Extra data-flow steps needed for lamba flow analysis. */ +predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { + exists(Ssa::Definition def | + LocalFlow::localSsaFlowStep(def, nodeFrom, nodeTo) and + LocalFlow::usesInstanceField(def) and + preservesValue = true + ) + or + exists(LambdaConfiguration x, DelegateCreation dc | + x.hasExprPath(dc.getArgument(), nodeFrom.(ExprNode).getControlFlowNode(), dc, + nodeTo.(ExprNode).getControlFlowNode()) and + preservesValue = false + ) + or + exists(AddEventExpr aee | + nodeFrom.asExpr() = aee.getRValue() and + nodeTo.asExpr().(EventRead).getTarget() = aee.getTarget() and + preservesValue = false + ) +} diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DelegateDataFlow.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DelegateDataFlow.qll index e6b15b95d7f..df6f62a3975 100755 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DelegateDataFlow.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DelegateDataFlow.qll @@ -1,4 +1,6 @@ /** + * DEPRECATED. + * * INTERNAL: Do not use. * * Provides classes for resolving delegate calls. @@ -108,7 +110,7 @@ abstract private class DelegateLikeFlowSink extends DataFlow::Node { * possible delegates resolved on line 6. */ cached - Callable getARuntimeTarget(CallContext context) { + deprecated Callable getARuntimeTarget(CallContext context) { exists(DelegateLikeFlowSource dfs | flowsFrom(this, dfs, _, context) and result = dfs.getCallable() @@ -117,7 +119,7 @@ abstract private class DelegateLikeFlowSink extends DataFlow::Node { } /** A delegate or function pointer call expression. */ -class DelegateLikeCallExpr extends DelegateLikeFlowSink, DataFlow::ExprNode { +deprecated class DelegateLikeCallExpr extends DelegateLikeFlowSink, DataFlow::ExprNode { DelegateLikeCall dc; DelegateLikeCallExpr() { this.getExpr() = dc.getExpr() } @@ -126,16 +128,8 @@ class DelegateLikeCallExpr extends DelegateLikeFlowSink, DataFlow::ExprNode { DelegateLikeCall getCall() { result = dc } } -/** A parameter of delegate type belonging to a callable with a flow summary. */ -class SummaryDelegateParameterSink extends DelegateLikeFlowSink, ParameterNode { - SummaryDelegateParameterSink() { - this.getType() instanceof SystemLinqExpressions::DelegateExtType and - this.isParameterOf(any(SummarizedCallable c), _) - } -} - /** A delegate expression that is added to an event. */ -class AddEventSource extends DelegateLikeFlowSink, DataFlow::ExprNode { +deprecated class AddEventSource extends DelegateLikeFlowSink, DataFlow::ExprNode { AddEventExpr ae; AddEventSource() { this.getExpr() = ae.getRValue() } @@ -173,7 +167,7 @@ private class NormalReturnNode extends Node { * `node` goes through a returned expression. The call context `lastCall` * records the last call on the path from `node` to `sink`, if any. */ -private predicate flowsFrom( +deprecated private predicate flowsFrom( DelegateLikeFlowSink sink, DataFlow::Node node, boolean isReturned, CallContext lastCall ) { // Base case @@ -244,7 +238,7 @@ private predicate flowsFrom( * previous call if it exists, otherwise `call` is the last call. */ bindingset[call, i] -private CallContext getLastCall(CallContext prevLastCall, Expr call, int i) { +deprecated private CallContext getLastCall(CallContext prevLastCall, Expr call, int i) { prevLastCall instanceof EmptyCallContext and result.(ArgumentCallContext).isArgument(call, i) or @@ -263,7 +257,7 @@ private predicate flowIntoNonDelegateCall(NonDelegateCall call, Expr arg, DotNet } pragma[noinline] -private predicate flowIntoDelegateCall(DelegateLikeCall call, Callable c, Expr arg, int i) { +deprecated private predicate flowIntoDelegateCall(DelegateLikeCall call, Callable c, Expr arg, int i) { exists(DelegateLikeFlowSource dfs, DelegateLikeCallExpr dce | // the call context is irrelevant because the delegate call // itself will be the context @@ -280,7 +274,7 @@ private predicate flowOutOfNonDelegateCall(NonDelegateCall call, NormalReturnNod } pragma[noinline] -private predicate flowOutOfDelegateCall( +deprecated private predicate flowOutOfDelegateCall( DelegateLikeCall dc, NormalReturnNode ret, CallContext lastCall ) { exists(DelegateLikeFlowSource dfs, DelegateLikeCallExpr dce, Callable c | diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImpl.qll index 7f54d3287d1..41da2b8f0b5 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImpl.qll @@ -235,7 +235,6 @@ private module CallGraph { } private module SimpleDelegateAnalysis { - private import semmle.code.csharp.dataflow.internal.DelegateDataFlow private import semmle.code.csharp.dataflow.internal.Steps private import semmle.code.csharp.frameworks.system.linq.Expressions diff --git a/csharp/ql/src/semmle/code/csharp/exprs/Call.qll b/csharp/ql/src/semmle/code/csharp/exprs/Call.qll index 078ecd1a52a..6dc88e941ef 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/Call.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/Call.qll @@ -8,6 +8,8 @@ import Expr import semmle.code.csharp.Callable import semmle.code.csharp.dataflow.CallContext as CallContext private import semmle.code.csharp.dataflow.internal.DelegateDataFlow +private import semmle.code.csharp.dataflow.internal.DataFlowDispatch +private import semmle.code.csharp.dataflow.internal.DataFlowImplCommon private import semmle.code.csharp.dispatch.Dispatch private import dotnet @@ -536,10 +538,12 @@ class DelegateLikeCall extends Call, DelegateLikeCall_ { override Callable getTarget() { none() } /** + * DEPRECATED: Use `getARuntimeTarget/0` instead. + * * Gets a potential run-time target of this delegate or function pointer call in the given * call context `cc`. */ - Callable getARuntimeTarget(CallContext::CallContext cc) { + deprecated Callable getARuntimeTarget(CallContext::CallContext cc) { exists(DelegateLikeCallExpr call | this = call.getCall() and result = call.getARuntimeTarget(cc) @@ -562,7 +566,12 @@ class DelegateLikeCall extends Call, DelegateLikeCall_ { */ Expr getExpr() { result = this.getChild(-1) } - override Callable getARuntimeTarget() { result = getARuntimeTarget(_) } + final override Callable getARuntimeTarget() { + exists(ExplicitDelegateLikeDataFlowCall call | + this = call.getCall() and + result = viableCallableLambda(call, _) + ) + } override Expr getRuntimeArgument(int i) { result = getArgument(i) } } @@ -582,10 +591,12 @@ class DelegateLikeCall extends Call, DelegateLikeCall_ { */ class DelegateCall extends DelegateLikeCall, @delegate_invocation_expr { /** + * DEPRECATED: Use `getARuntimeTarget/0` instead. + * * Gets a potential run-time target of this delegate call in the given * call context `cc`. */ - override Callable getARuntimeTarget(CallContext::CallContext cc) { + deprecated override Callable getARuntimeTarget(CallContext::CallContext cc) { result = DelegateLikeCall.super.getARuntimeTarget(cc) or exists(AddEventSource aes, CallContext::CallContext cc2 | @@ -601,16 +612,16 @@ class DelegateCall extends DelegateLikeCall, @delegate_invocation_expr { ) } - private AddEventSource getAnAddEventSource(Callable enclosingCallable) { + deprecated private AddEventSource getAnAddEventSource(Callable enclosingCallable) { this.getExpr().(EventAccess).getTarget() = result.getEvent() and enclosingCallable = result.getExpr().getEnclosingCallable() } - private AddEventSource getAnAddEventSourceSameEnclosingCallable() { + deprecated private AddEventSource getAnAddEventSourceSameEnclosingCallable() { result = getAnAddEventSource(this.getEnclosingCallable()) } - private AddEventSource getAnAddEventSourceDifferentEnclosingCallable() { + deprecated private AddEventSource getAnAddEventSourceDifferentEnclosingCallable() { exists(Callable c | result = getAnAddEventSource(c) | c != this.getEnclosingCallable()) } diff --git a/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.expected b/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.expected index addcc3c0ff7..731de330946 100644 --- a/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.expected @@ -1,28 +1,55 @@ -summaryDelegateCall -| file://:0:0:0:0 | valueFactory | DelegateFlow.cs:104:23:104:30 | (...) => ... | DelegateFlow.cs:105:23:105:23 | access to local variable f | -| file://:0:0:0:0 | valueFactory | DelegateFlow.cs:106:13:106:20 | (...) => ... | DelegateFlow.cs:107:23:107:23 | access to local variable f | delegateCall -| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:5:10:5:11 | M1 | DelegateFlow.cs:17:12:17:13 | delegate creation of type Action | -| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:5:10:5:11 | M1 | DelegateFlow.cs:22:12:22:12 | access to parameter a | -| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:16:12:16:19 | (...) => ... | DelegateFlow.cs:16:12:16:19 | (...) => ... | -| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:27:12:27:19 | (...) => ... | DelegateFlow.cs:22:12:22:12 | access to parameter a | -| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:98:9:98:37 | LocalFunction | DelegateFlow.cs:99:12:99:24 | delegate creation of type Action | -| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:119:18:119:27 | (...) => ... | DelegateFlow.cs:114:15:114:15 | access to parameter a | -| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:125:15:125:24 | (...) => ... | DelegateFlow.cs:125:15:125:24 | (...) => ... | -| DelegateFlow.cs:11:9:11:12 | delegate call | DelegateFlow.cs:10:13:10:20 | (...) => ... | file://:0:0:0:0 | | -| DelegateFlow.cs:33:9:33:13 | delegate call | DelegateFlow.cs:38:12:38:25 | (...) => ... | DelegateFlow.cs:38:12:38:25 | (...) => ... | -| DelegateFlow.cs:38:19:38:22 | delegate call | DelegateFlow.cs:5:10:5:11 | M1 | DelegateFlow.cs:33:12:33:12 | access to parameter a | -| DelegateFlow.cs:44:15:44:22 | delegate call | DelegateFlow.cs:43:22:43:29 | (...) => ... | DelegateFlow.cs:50:18:50:23 | dynamic access to member Prop | -| DelegateFlow.cs:57:9:57:11 | delegate call | DelegateFlow.cs:53:34:53:47 | (...) => ... | file://:0:0:0:0 | | -| DelegateFlow.cs:57:9:57:14 | delegate call | DelegateFlow.cs:53:40:53:47 | (...) => ... | file://:0:0:0:0 | | -| DelegateFlow.cs:67:9:67:16 | delegate call | DelegateFlow.cs:62:16:62:23 | (...) => ... | file://:0:0:0:0 | | -| DelegateFlow.cs:77:9:77:15 | delegate call | DelegateFlow.cs:55:10:55:11 | M9 | file://:0:0:0:0 | | -| DelegateFlow.cs:77:9:77:15 | delegate call | DelegateFlow.cs:65:10:65:12 | M11 | file://:0:0:0:0 | | -| DelegateFlow.cs:84:9:84:15 | delegate call | DelegateFlow.cs:55:10:55:11 | M9 | DelegateFlow.cs:78:13:78:14 | delegate creation of type EventHandler | -| DelegateFlow.cs:84:9:84:15 | delegate call | DelegateFlow.cs:65:10:65:12 | M11 | file://:0:0:0:0 | | -| DelegateFlow.cs:89:35:89:37 | delegate call | DelegateFlow.cs:55:10:55:11 | M9 | DelegateFlow.cs:90:13:90:30 | delegate creation of type MyDelegate | -| DelegateFlow.cs:89:35:89:37 | delegate call | DelegateFlow.cs:65:10:65:12 | M11 | DelegateFlow.cs:91:13:91:47 | delegate creation of type MyDelegate | -| DelegateFlow.cs:89:35:89:37 | delegate call | DelegateFlow.cs:74:17:74:19 | M12 | DelegateFlow.cs:92:13:92:15 | delegate creation of type MyDelegate | -| DelegateFlow.cs:89:35:89:37 | delegate call | DelegateFlow.cs:93:13:93:21 | (...) => ... | DelegateFlow.cs:93:13:93:21 | (...) => ... | -| DelegateFlow.cs:132:9:132:11 | delegate call | DelegateFlow.cs:131:17:131:24 | (...) => ... | file://:0:0:0:0 | | -| DelegateFlow.cs:132:9:132:11 | delegate call | DelegateFlow.cs:135:29:135:36 | (...) => ... | DelegateFlow.cs:135:29:135:36 | (...) => ... | +| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:5:10:5:11 | M1 | +| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:16:12:16:19 | (...) => ... | +| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:27:12:27:19 | (...) => ... | +| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:98:9:98:37 | LocalFunction | +| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:119:18:119:27 | (...) => ... | +| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:125:15:125:24 | (...) => ... | +| DelegateFlow.cs:11:9:11:12 | delegate call | DelegateFlow.cs:10:13:10:20 | (...) => ... | +| DelegateFlow.cs:33:9:33:13 | delegate call | DelegateFlow.cs:38:12:38:25 | (...) => ... | +| DelegateFlow.cs:38:19:38:22 | delegate call | DelegateFlow.cs:5:10:5:11 | M1 | +| DelegateFlow.cs:44:15:44:22 | delegate call | DelegateFlow.cs:43:22:43:29 | (...) => ... | +| DelegateFlow.cs:57:9:57:11 | delegate call | DelegateFlow.cs:53:34:53:47 | (...) => ... | +| DelegateFlow.cs:57:9:57:14 | delegate call | DelegateFlow.cs:53:40:53:47 | (...) => ... | +| DelegateFlow.cs:67:9:67:16 | delegate call | DelegateFlow.cs:62:16:62:23 | (...) => ... | +| DelegateFlow.cs:77:9:77:15 | delegate call | DelegateFlow.cs:55:10:55:11 | M9 | +| DelegateFlow.cs:77:9:77:15 | delegate call | DelegateFlow.cs:65:10:65:12 | M11 | +| DelegateFlow.cs:84:9:84:15 | delegate call | DelegateFlow.cs:55:10:55:11 | M9 | +| DelegateFlow.cs:84:9:84:15 | delegate call | DelegateFlow.cs:65:10:65:12 | M11 | +| DelegateFlow.cs:89:35:89:37 | delegate call | DelegateFlow.cs:55:10:55:11 | M9 | +| DelegateFlow.cs:89:35:89:37 | delegate call | DelegateFlow.cs:65:10:65:12 | M11 | +| DelegateFlow.cs:89:35:89:37 | delegate call | DelegateFlow.cs:74:17:74:19 | M12 | +| DelegateFlow.cs:89:35:89:37 | delegate call | DelegateFlow.cs:93:13:93:21 | (...) => ... | +| DelegateFlow.cs:114:9:114:16 | function pointer call | DelegateFlow.cs:7:17:7:18 | M2 | +| DelegateFlow.cs:125:9:125:25 | function pointer call | DelegateFlow.cs:7:17:7:18 | M2 | +| DelegateFlow.cs:132:9:132:11 | delegate call | DelegateFlow.cs:131:17:131:24 | (...) => ... | +| DelegateFlow.cs:132:9:132:11 | delegate call | DelegateFlow.cs:135:29:135:36 | (...) => ... | +viableLambda +| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:16:9:16:20 | call to method M2 | DelegateFlow.cs:16:12:16:19 | (...) => ... | +| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:17:9:17:14 | call to method M2 | DelegateFlow.cs:5:10:5:11 | M1 | +| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:22:9:22:13 | call to method M2 | DelegateFlow.cs:5:10:5:11 | M1 | +| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:22:9:22:13 | call to method M2 | DelegateFlow.cs:27:12:27:19 | (...) => ... | +| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:99:9:99:25 | call to method M2 | DelegateFlow.cs:98:9:98:37 | LocalFunction | +| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:114:9:114:16 | function pointer call | DelegateFlow.cs:119:18:119:27 | (...) => ... | +| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:125:9:125:25 | function pointer call | DelegateFlow.cs:125:15:125:24 | (...) => ... | +| DelegateFlow.cs:11:9:11:12 | delegate call | file://:0:0:0:0 | (none) | DelegateFlow.cs:10:13:10:20 | (...) => ... | +| DelegateFlow.cs:33:9:33:13 | delegate call | DelegateFlow.cs:38:9:38:30 | call to method M6 | DelegateFlow.cs:38:12:38:25 | (...) => ... | +| DelegateFlow.cs:38:19:38:22 | delegate call | DelegateFlow.cs:33:9:33:13 | delegate call | DelegateFlow.cs:5:10:5:11 | M1 | +| DelegateFlow.cs:44:15:44:22 | delegate call | DelegateFlow.cs:50:9:50:14 | dynamic access to member Prop | DelegateFlow.cs:43:22:43:29 | (...) => ... | +| DelegateFlow.cs:57:9:57:11 | delegate call | file://:0:0:0:0 | (none) | DelegateFlow.cs:53:34:53:47 | (...) => ... | +| DelegateFlow.cs:57:9:57:14 | delegate call | file://:0:0:0:0 | (none) | DelegateFlow.cs:53:40:53:47 | (...) => ... | +| DelegateFlow.cs:67:9:67:16 | delegate call | file://:0:0:0:0 | (none) | DelegateFlow.cs:62:16:62:23 | (...) => ... | +| DelegateFlow.cs:77:9:77:15 | delegate call | file://:0:0:0:0 | (none) | DelegateFlow.cs:55:10:55:11 | M9 | +| DelegateFlow.cs:77:9:77:15 | delegate call | file://:0:0:0:0 | (none) | DelegateFlow.cs:65:10:65:12 | M11 | +| DelegateFlow.cs:84:9:84:15 | delegate call | DelegateFlow.cs:78:9:78:15 | call to method M13 | DelegateFlow.cs:55:10:55:11 | M9 | +| DelegateFlow.cs:84:9:84:15 | delegate call | file://:0:0:0:0 | (none) | DelegateFlow.cs:65:10:65:12 | M11 | +| DelegateFlow.cs:89:35:89:37 | delegate call | DelegateFlow.cs:90:9:90:31 | call to local function M14 | DelegateFlow.cs:55:10:55:11 | M9 | +| DelegateFlow.cs:89:35:89:37 | delegate call | DelegateFlow.cs:91:9:91:48 | call to local function M14 | DelegateFlow.cs:65:10:65:12 | M11 | +| DelegateFlow.cs:89:35:89:37 | delegate call | DelegateFlow.cs:92:9:92:16 | call to local function M14 | DelegateFlow.cs:74:17:74:19 | M12 | +| DelegateFlow.cs:89:35:89:37 | delegate call | DelegateFlow.cs:93:9:93:22 | call to local function M14 | DelegateFlow.cs:93:13:93:21 | (...) => ... | +| DelegateFlow.cs:114:9:114:16 | function pointer call | DelegateFlow.cs:119:9:119:28 | call to method M16 | DelegateFlow.cs:7:17:7:18 | M2 | +| DelegateFlow.cs:125:9:125:25 | function pointer call | file://:0:0:0:0 | (none) | DelegateFlow.cs:7:17:7:18 | M2 | +| DelegateFlow.cs:132:9:132:11 | delegate call | DelegateFlow.cs:135:25:135:40 | call to method M19 | DelegateFlow.cs:135:29:135:36 | (...) => ... | +| DelegateFlow.cs:132:9:132:11 | delegate call | file://:0:0:0:0 | (none) | DelegateFlow.cs:131:17:131:24 | (...) => ... | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Lazy | DelegateFlow.cs:105:9:105:24 | object creation of type Lazy | DelegateFlow.cs:104:23:104:30 | (...) => ... | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Lazy | DelegateFlow.cs:107:9:107:24 | object creation of type Lazy | DelegateFlow.cs:106:13:106:20 | (...) => ... | diff --git a/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.ql b/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.ql index c01feabc2f9..6ec7637bf6c 100644 --- a/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.ql +++ b/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.ql @@ -1,22 +1,34 @@ import csharp -import semmle.code.csharp.dataflow.internal.DataFlowPrivate -import semmle.code.csharp.dataflow.internal.DelegateDataFlow +import semmle.code.csharp.dataflow.internal.DataFlowImplCommon +import semmle.code.csharp.dataflow.internal.DataFlowDispatch -private class NodeAdjusted extends TNode { - string toString() { result = this.(DataFlow::Node).toString() } +query predicate delegateCall(DelegateLikeCall dc, Callable c) { c = dc.getARuntimeTarget() } + +private class LocatableDataFlowCallOption extends DataFlowCallOption { + Location getLocation() { + this = TDataFlowCallNone() and + result instanceof EmptyLocation + or + exists(DataFlowCall call | + this = TDataFlowCallSome(call) and + result = call.getLocation() + ) + } +} + +private class LocatableDataFlowCall extends TDataFlowCall { + string toString() { result = this.(DataFlowCall).toString() } Location getLocation() { exists(Location l | - l = this.(DataFlow::Node).getLocation() and + l = this.(DataFlowCall).getLocation() and if l instanceof SourceLocation then result = l else result instanceof EmptyLocation ) } } -query predicate summaryDelegateCall(NodeAdjusted sink, Callable c, CallContext::CallContext cc) { - c = sink.(SummaryDelegateParameterSink).getARuntimeTarget(cc) -} - -query predicate delegateCall(DelegateCall dc, Callable c, CallContext::CallContext cc) { - c = dc.getARuntimeTarget(cc) +query predicate viableLambda( + LocatableDataFlowCall call, LocatableDataFlowCallOption lastCall, DataFlowCallable target +) { + target = viableCallableLambda(call, lastCall) } diff --git a/csharp/ql/test/library-tests/dataflow/functionpointers/FunctionPointerFlow.expected b/csharp/ql/test/library-tests/dataflow/functionpointers/FunctionPointerFlow.expected index ad2bfb887c0..a25f9c14539 100644 --- a/csharp/ql/test/library-tests/dataflow/functionpointers/FunctionPointerFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/functionpointers/FunctionPointerFlow.expected @@ -1,9 +1,20 @@ -| FunctionPointerFlow.cs:14:9:14:12 | function pointer call | FunctionPointerFlow.cs:5:24:5:27 | Log1 | FunctionPointerFlow.cs:21:12:21:16 | &... | -| FunctionPointerFlow.cs:14:9:14:12 | function pointer call | FunctionPointerFlow.cs:6:24:6:27 | Log2 | FunctionPointerFlow.cs:26:12:26:12 | access to parameter a | -| FunctionPointerFlow.cs:14:9:14:12 | function pointer call | FunctionPointerFlow.cs:10:24:10:27 | Log6 | FunctionPointerFlow.cs:26:12:26:12 | access to parameter a | -| FunctionPointerFlow.cs:14:9:14:12 | function pointer call | FunctionPointerFlow.cs:46:9:46:44 | LocalFunction | FunctionPointerFlow.cs:47:12:47:25 | &... | -| FunctionPointerFlow.cs:16:9:16:12 | function pointer call | FunctionPointerFlow.cs:7:24:7:27 | Log3 | file://:0:0:0:0 | | -| FunctionPointerFlow.cs:41:9:41:15 | function pointer call | FunctionPointerFlow.cs:8:24:8:27 | Log4 | file://:0:0:0:0 | | -| FunctionPointerFlow.cs:54:9:54:16 | function pointer call | FunctionPointerFlow.cs:9:24:9:27 | Log5 | file://:0:0:0:0 | | -| FunctionPointerFlow.cs:59:9:59:13 | function pointer call | FunctionPointerFlow.cs:24:24:24:25 | M4 | FunctionPointerFlow.cs:64:13:64:15 | &... | -| FunctionPointerFlow.cs:69:9:69:13 | function pointer call | FunctionPointerFlow.cs:72:24:72:26 | M17 | FunctionPointerFlow.cs:81:13:81:16 | &... | +fptrCall +| FunctionPointerFlow.cs:14:9:14:12 | function pointer call | FunctionPointerFlow.cs:5:24:5:27 | Log1 | +| FunctionPointerFlow.cs:14:9:14:12 | function pointer call | FunctionPointerFlow.cs:6:24:6:27 | Log2 | +| FunctionPointerFlow.cs:14:9:14:12 | function pointer call | FunctionPointerFlow.cs:10:24:10:27 | Log6 | +| FunctionPointerFlow.cs:14:9:14:12 | function pointer call | FunctionPointerFlow.cs:46:9:46:44 | LocalFunction | +| FunctionPointerFlow.cs:16:9:16:12 | function pointer call | FunctionPointerFlow.cs:7:24:7:27 | Log3 | +| FunctionPointerFlow.cs:41:9:41:15 | function pointer call | FunctionPointerFlow.cs:8:24:8:27 | Log4 | +| FunctionPointerFlow.cs:54:9:54:16 | function pointer call | FunctionPointerFlow.cs:9:24:9:27 | Log5 | +| FunctionPointerFlow.cs:59:9:59:13 | function pointer call | FunctionPointerFlow.cs:24:24:24:25 | M4 | +| FunctionPointerFlow.cs:69:9:69:13 | function pointer call | FunctionPointerFlow.cs:72:24:72:26 | M17 | +fptrCallContext +| FunctionPointerFlow.cs:14:9:14:12 | function pointer call | FunctionPointerFlow.cs:21:9:21:17 | call to method M2 | FunctionPointerFlow.cs:5:24:5:27 | Log1 | +| FunctionPointerFlow.cs:14:9:14:12 | function pointer call | FunctionPointerFlow.cs:26:9:26:13 | call to method M2 | FunctionPointerFlow.cs:6:24:6:27 | Log2 | +| FunctionPointerFlow.cs:14:9:14:12 | function pointer call | FunctionPointerFlow.cs:26:9:26:13 | call to method M2 | FunctionPointerFlow.cs:10:24:10:27 | Log6 | +| FunctionPointerFlow.cs:14:9:14:12 | function pointer call | FunctionPointerFlow.cs:47:9:47:26 | call to method M2 | FunctionPointerFlow.cs:46:9:46:44 | LocalFunction | +| FunctionPointerFlow.cs:16:9:16:12 | function pointer call | file://:0:0:0:0 | (none) | FunctionPointerFlow.cs:7:24:7:27 | Log3 | +| FunctionPointerFlow.cs:41:9:41:15 | function pointer call | file://:0:0:0:0 | (none) | FunctionPointerFlow.cs:8:24:8:27 | Log4 | +| FunctionPointerFlow.cs:54:9:54:16 | function pointer call | file://:0:0:0:0 | (none) | FunctionPointerFlow.cs:9:24:9:27 | Log5 | +| FunctionPointerFlow.cs:59:9:59:13 | function pointer call | FunctionPointerFlow.cs:64:9:64:23 | call to method M10 | FunctionPointerFlow.cs:24:24:24:25 | M4 | +| FunctionPointerFlow.cs:69:9:69:13 | function pointer call | FunctionPointerFlow.cs:81:9:81:29 | call to method M16 | FunctionPointerFlow.cs:72:24:72:26 | M17 | diff --git a/csharp/ql/test/library-tests/dataflow/functionpointers/FunctionPointerFlow.ql b/csharp/ql/test/library-tests/dataflow/functionpointers/FunctionPointerFlow.ql index 3434d068329..fced49bc9c6 100644 --- a/csharp/ql/test/library-tests/dataflow/functionpointers/FunctionPointerFlow.ql +++ b/csharp/ql/test/library-tests/dataflow/functionpointers/FunctionPointerFlow.ql @@ -1,5 +1,38 @@ import csharp +import semmle.code.csharp.dataflow.internal.DataFlowImplCommon +import semmle.code.csharp.dataflow.internal.DataFlowDispatch -query predicate fptrCall(FunctionPointerCall fptrc, Callable c, CallContext::CallContext cc) { - c = fptrc.getARuntimeTarget(cc) +query predicate fptrCall(FunctionPointerCall dc, Callable c) { c = dc.getARuntimeTarget() } + +private class LocatableDataFlowCallOption extends DataFlowCallOption { + Location getLocation() { + this = TDataFlowCallNone() and + result instanceof EmptyLocation + or + exists(DataFlowCall call | + this = TDataFlowCallSome(call) and + result = call.getLocation() + ) + } +} + +private class LocatableDataFlowCall extends TDataFlowCall { + LocatableDataFlowCall() { + this.(ExplicitDelegateLikeDataFlowCall).getCall() instanceof FunctionPointerCall + } + + string toString() { result = this.(DataFlowCall).toString() } + + Location getLocation() { + exists(Location l | + l = this.(DataFlowCall).getLocation() and + if l instanceof SourceLocation then result = l else result instanceof EmptyLocation + ) + } +} + +query predicate fptrCallContext( + LocatableDataFlowCall call, LocatableDataFlowCallOption lastCall, DataFlowCallable target +) { + target = viableCallableLambda(call, lastCall) } From b11e15154fc6aabd32c07b996920c0d514b36360 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 4 Mar 2021 09:12:02 +0100 Subject: [PATCH 125/725] Data flow: Sync files and add stubs --- .../dataflow/internal/DataFlowImplCommon.qll | 309 +++++++++++++++++- .../cpp/dataflow/internal/DataFlowPrivate.qll | 11 + .../dataflow/internal/DataFlowImplCommon.qll | 309 +++++++++++++++++- .../ir/dataflow/internal/DataFlowPrivate.qll | 11 + .../dataflow/internal/DataFlowImplCommon.qll | 309 +++++++++++++++++- .../dataflow/internal/DataFlowPrivate.qll | 11 + .../new/internal/DataFlowImplCommon.qll | 309 +++++++++++++++++- .../dataflow/new/internal/DataFlowPrivate.qll | 11 + 8 files changed, 1212 insertions(+), 68 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll index 1319f972037..a51c20c2288 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll @@ -26,15 +26,243 @@ predicate accessPathCostLimits(int apLimit, int tupleLimit) { tupleLimit = 1000 } +/** + * Provides a simple data-flow analysis for resolving lambda calls. The analysis + * currently excludes read-steps, store-steps, and flow-through. + * + * The analysis uses non-linear recursion: When computing a flow path in or out + * of a call, we use the results of the analysis recursively to resolve lamba + * calls. For this reason, we cannot reuse the code from `DataFlowImpl.qll` directly. + */ +private module LambdaFlow { + private predicate viableParamNonLambda(DataFlowCall call, int i, ParameterNode p) { + p.isParameterOf(viableCallable(call), i) + } + + private predicate viableParamLambda(DataFlowCall call, int i, ParameterNode p) { + p.isParameterOf(viableCallableLambda(call, _), i) + } + + private predicate viableParamArgNonLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) { + exists(int i | + viableParamNonLambda(call, i, p) and + arg.argumentOf(call, i) + ) + } + + private predicate viableParamArgLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) { + exists(int i | + viableParamLambda(call, i, p) and + arg.argumentOf(call, i) + ) + } + + private newtype TReturnPositionSimple = + TReturnPositionSimple0(DataFlowCallable c, ReturnKind kind) { + exists(ReturnNode ret | + c = getNodeEnclosingCallable(ret) and + kind = ret.getKind() + ) + } + + pragma[noinline] + private TReturnPositionSimple getReturnPositionSimple(ReturnNode ret, ReturnKind kind) { + result = TReturnPositionSimple0(getNodeEnclosingCallable(ret), kind) + } + + pragma[nomagic] + private TReturnPositionSimple viableReturnPosNonLambda(DataFlowCall call, ReturnKind kind) { + result = TReturnPositionSimple0(viableCallable(call), kind) + } + + pragma[nomagic] + private TReturnPositionSimple viableReturnPosLambda( + DataFlowCall call, DataFlowCallOption lastCall, ReturnKind kind + ) { + result = TReturnPositionSimple0(viableCallableLambda(call, lastCall), kind) + } + + private predicate viableReturnPosOutNonLambda( + DataFlowCall call, TReturnPositionSimple pos, OutNode out + ) { + exists(ReturnKind kind | + pos = viableReturnPosNonLambda(call, kind) and + out = getAnOutNode(call, kind) + ) + } + + private predicate viableReturnPosOutLambda( + DataFlowCall call, DataFlowCallOption lastCall, TReturnPositionSimple pos, OutNode out + ) { + exists(ReturnKind kind | + pos = viableReturnPosLambda(call, lastCall, kind) and + out = getAnOutNode(call, kind) + ) + } + + /** + * Holds if data can flow (inter-procedurally) from `node` (of type `t`) to + * the lambda call `lambdaCall`. + * + * The parameter `toReturn` indicates whether the path from `node` to + * `lambdaCall` goes through a return, and `toJump` whether the path goes + * through a jump step. + * + * The call context `lastCall` records the last call on the path from `node` + * to `lambdaCall`, if any. That is, `lastCall` is able to target the enclosing + * callable of `lambdaCall`. + */ + pragma[nomagic] + predicate revLambdaFlow( + DataFlowCall lambdaCall, LambdaCallKind kind, Node node, DataFlowType t, boolean toReturn, + boolean toJump, DataFlowCallOption lastCall + ) { + revLambdaFlow0(lambdaCall, kind, node, t, toReturn, toJump, lastCall) and + if node instanceof CastNode or node instanceof ArgumentNode or node instanceof ReturnNode + then compatibleTypes(t, getNodeType(node)) + else any() + } + + pragma[nomagic] + predicate revLambdaFlow0( + DataFlowCall lambdaCall, LambdaCallKind kind, Node node, DataFlowType t, boolean toReturn, + boolean toJump, DataFlowCallOption lastCall + ) { + lambdaCall(lambdaCall, kind, node) and + t = getNodeType(node) and + toReturn = false and + toJump = false and + lastCall = TDataFlowCallNone() + or + // local flow + exists(Node mid, DataFlowType t0 | + revLambdaFlow(lambdaCall, kind, mid, t0, toReturn, toJump, lastCall) + | + simpleLocalFlowStep(node, mid) and + t = t0 + or + exists(boolean preservesValue | + additionalLambdaFlowStep(node, mid, preservesValue) and + getNodeEnclosingCallable(node) = getNodeEnclosingCallable(mid) + | + preservesValue = false and + t = getNodeType(node) + or + preservesValue = true and + t = t0 + ) + ) + or + // jump step + exists(Node mid, DataFlowType t0 | + revLambdaFlow(lambdaCall, kind, mid, t0, _, _, _) and + toReturn = false and + toJump = true and + lastCall = TDataFlowCallNone() + | + jumpStep(node, mid) and + t = t0 + or + exists(boolean preservesValue | + additionalLambdaFlowStep(node, mid, preservesValue) and + getNodeEnclosingCallable(node) != getNodeEnclosingCallable(mid) + | + preservesValue = false and + t = getNodeType(node) + or + preservesValue = true and + t = t0 + ) + ) + or + // flow into a callable + exists(ParameterNode p, DataFlowCallOption lastCall0, DataFlowCall call | + revLambdaFlowIn(lambdaCall, kind, p, t, toJump, lastCall0) and + ( + if lastCall0 = TDataFlowCallNone() and toJump = false + then lastCall = TDataFlowCallSome(call) + else lastCall = lastCall0 + ) and + toReturn = false + | + viableParamArgNonLambda(call, p, node) + or + viableParamArgLambda(call, p, node) // non-linear recursion + ) + or + // flow out of a callable + exists(TReturnPositionSimple pos | + revLambdaFlowOut(lambdaCall, kind, pos, t, toJump, lastCall) and + getReturnPositionSimple(node, node.(ReturnNode).getKind()) = pos and + toReturn = true + ) + } + + pragma[nomagic] + predicate revLambdaFlowOutLambdaCall( + DataFlowCall lambdaCall, LambdaCallKind kind, OutNode out, DataFlowType t, boolean toJump, + DataFlowCall call, DataFlowCallOption lastCall + ) { + revLambdaFlow(lambdaCall, kind, out, t, _, toJump, lastCall) and + exists(ReturnKindExt rk | + out = rk.getAnOutNode(call) and + lambdaCall(call, _, _) + ) + } + + pragma[nomagic] + predicate revLambdaFlowOut( + DataFlowCall lambdaCall, LambdaCallKind kind, TReturnPositionSimple pos, DataFlowType t, + boolean toJump, DataFlowCallOption lastCall + ) { + exists(DataFlowCall call, OutNode out | + revLambdaFlow(lambdaCall, kind, out, t, _, toJump, lastCall) and + viableReturnPosOutNonLambda(call, pos, out) + or + // non-linear recursion + revLambdaFlowOutLambdaCall(lambdaCall, kind, out, t, toJump, call, lastCall) and + viableReturnPosOutLambda(call, _, pos, out) + ) + } + + pragma[nomagic] + predicate revLambdaFlowIn( + DataFlowCall lambdaCall, LambdaCallKind kind, ParameterNode p, DataFlowType t, boolean toJump, + DataFlowCallOption lastCall + ) { + revLambdaFlow(lambdaCall, kind, p, t, false, toJump, lastCall) + } +} + +private DataFlowCallable viableCallableExt(DataFlowCall call) { + result = viableCallable(call) + or + result = viableCallableLambda(call, _) +} + cached private module Cached { + /** + * Gets a viable target for the lambda call `call`. + * + * `lastCall` records the call required to reach `call` in order for the result + * to be a viable target, if any. + */ + cached + DataFlowCallable viableCallableLambda(DataFlowCall call, DataFlowCallOption lastCall) { + exists(Node creation, LambdaCallKind kind | + LambdaFlow::revLambdaFlow(call, kind, creation, _, _, _, lastCall) and + lambdaCreation(creation, kind, result) + ) + } + /** * Holds if `p` is the `i`th parameter of a viable dispatch target of `call`. * The instance parameter is considered to have index `-1`. */ pragma[nomagic] private predicate viableParam(DataFlowCall call, int i, ParameterNode p) { - p.isParameterOf(viableCallable(call), i) + p.isParameterOf(viableCallableExt(call), i) } /** @@ -52,7 +280,7 @@ private module Cached { pragma[nomagic] private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and + viableCallableExt(call) = result.getCallable() and kind = result.getKind() } @@ -317,6 +545,35 @@ private module Cached { cached private module DispatchWithCallContext { + /** + * Holds if the set of viable implementations that can be called by `call` + * might be improved by knowing the call context. + */ + pragma[nomagic] + private predicate mayBenefitFromCallContextExt(DataFlowCall call, DataFlowCallable callable) { + mayBenefitFromCallContext(call, callable) + or + callable = call.getEnclosingCallable() and + exists(viableCallableLambda(call, TDataFlowCallSome(_))) + } + + /** + * Gets a viable dispatch target of `call` in the context `ctx`. This is + * restricted to those `call`s for which a context might make a difference. + */ + pragma[nomagic] + private DataFlowCallable viableImplInCallContextExt(DataFlowCall call, DataFlowCall ctx) { + result = viableImplInCallContext(call, ctx) + or + result = viableCallableLambda(call, TDataFlowCallSome(ctx)) + or + exists(DataFlowCallable enclosing | + mayBenefitFromCallContextExt(call, enclosing) and + enclosing = viableCallableExt(ctx) and + result = viableCallableLambda(call, TDataFlowCallNone()) + ) + } + /** * Holds if the call context `ctx` reduces the set of viable run-time * dispatch targets of call `call` in `c`. @@ -324,10 +581,10 @@ private module Cached { cached predicate reducedViableImplInCallContext(DataFlowCall call, DataFlowCallable c, DataFlowCall ctx) { exists(int tgts, int ctxtgts | - mayBenefitFromCallContext(call, c) and - c = viableCallable(ctx) and - ctxtgts = count(viableImplInCallContext(call, ctx)) and - tgts = strictcount(viableCallable(call)) and + mayBenefitFromCallContextExt(call, c) and + c = viableCallableExt(ctx) and + ctxtgts = count(viableImplInCallContextExt(call, ctx)) and + tgts = strictcount(viableCallableExt(call)) and ctxtgts < tgts ) } @@ -339,7 +596,7 @@ private module Cached { */ cached DataFlowCallable prunedViableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { - result = viableImplInCallContext(call, ctx) and + result = viableImplInCallContextExt(call, ctx) and reducedViableImplInCallContext(call, _, ctx) } @@ -351,10 +608,10 @@ private module Cached { cached predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) { exists(int tgts, int ctxtgts | - mayBenefitFromCallContext(call, _) and - c = viableCallable(call) and - ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContext(call, ctx)) and - tgts = strictcount(DataFlowCall ctx | viableCallable(ctx) = call.getEnclosingCallable()) and + mayBenefitFromCallContextExt(call, _) and + c = viableCallableExt(call) and + ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContextExt(call, ctx)) and + tgts = strictcount(DataFlowCall ctx | viableCallableExt(ctx) = call.getEnclosingCallable()) and ctxtgts < tgts ) } @@ -367,7 +624,7 @@ private module Cached { */ cached DataFlowCallable prunedViableImplInCallContextReverse(DataFlowCall call, DataFlowCall ctx) { - result = viableImplInCallContext(call, ctx) and + result = viableImplInCallContextExt(call, ctx) and reducedViableImplInReturn(result, call) } } @@ -481,6 +738,11 @@ private module Cached { TBooleanNone() or TBooleanSome(boolean b) { b = true or b = false } + cached + newtype TDataFlowCallOption = + TDataFlowCallNone() or + TDataFlowCallSome(DataFlowCall call) + cached newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) } @@ -777,7 +1039,7 @@ ReturnPosition getReturnPosition(ReturnNodeExt ret) { bindingset[cc, callable] predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall call) { - cc instanceof CallContextAny and callable = viableCallable(call) + cc instanceof CallContextAny and callable = viableCallableExt(call) or exists(DataFlowCallable c0, DataFlowCall call0 | call0.getEnclosingCallable() = callable and @@ -791,14 +1053,14 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) { exists(DataFlowCall ctx | cc = TSpecificCall(ctx) | if reducedViableImplInCallContext(call, _, ctx) then result = prunedViableImplInCallContext(call, ctx) - else result = viableCallable(call) + else result = viableCallableExt(call) ) or - result = viableCallable(call) and cc instanceof CallContextSomeCall + result = viableCallableExt(call) and cc instanceof CallContextSomeCall or - result = viableCallable(call) and cc instanceof CallContextAny + result = viableCallableExt(call) and cc instanceof CallContextAny or - result = viableCallable(call) and cc instanceof CallContextReturn + result = viableCallableExt(call) and cc instanceof CallContextReturn } predicate read = readStep/3; @@ -812,6 +1074,19 @@ class BooleanOption extends TBooleanOption { } } +/** An optional `DataFlowCall`. */ +class DataFlowCallOption extends TDataFlowCallOption { + string toString() { + this = TDataFlowCallNone() and + result = "(none)" + or + exists(DataFlowCall call | + this = TDataFlowCallSome(call) and + result = call.toString() + ) + } +} + /** Content tagged with the type of a containing object. */ class TypedContent extends MkTypedContent { private Content c; diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll index da20528760f..835e6c46451 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll @@ -312,3 +312,14 @@ predicate isImmutableOrUnobservable(Node n) { /** Holds if `n` should be hidden from path explanations. */ predicate nodeIsHidden(Node n) { none() } + +class LambdaCallKind = Unit; + +/** Holds if `creation` is an expression that creates a lambda of kind `kind` for `c`. */ +predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) { none() } + +/** Holds if `call` is a lambda call of kind `kind` where `receiver` is the lambda expression. */ +predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) { none() } + +/** Extra data-flow steps needed for lamba flow analysis. */ +predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll index 1319f972037..a51c20c2288 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll @@ -26,15 +26,243 @@ predicate accessPathCostLimits(int apLimit, int tupleLimit) { tupleLimit = 1000 } +/** + * Provides a simple data-flow analysis for resolving lambda calls. The analysis + * currently excludes read-steps, store-steps, and flow-through. + * + * The analysis uses non-linear recursion: When computing a flow path in or out + * of a call, we use the results of the analysis recursively to resolve lamba + * calls. For this reason, we cannot reuse the code from `DataFlowImpl.qll` directly. + */ +private module LambdaFlow { + private predicate viableParamNonLambda(DataFlowCall call, int i, ParameterNode p) { + p.isParameterOf(viableCallable(call), i) + } + + private predicate viableParamLambda(DataFlowCall call, int i, ParameterNode p) { + p.isParameterOf(viableCallableLambda(call, _), i) + } + + private predicate viableParamArgNonLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) { + exists(int i | + viableParamNonLambda(call, i, p) and + arg.argumentOf(call, i) + ) + } + + private predicate viableParamArgLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) { + exists(int i | + viableParamLambda(call, i, p) and + arg.argumentOf(call, i) + ) + } + + private newtype TReturnPositionSimple = + TReturnPositionSimple0(DataFlowCallable c, ReturnKind kind) { + exists(ReturnNode ret | + c = getNodeEnclosingCallable(ret) and + kind = ret.getKind() + ) + } + + pragma[noinline] + private TReturnPositionSimple getReturnPositionSimple(ReturnNode ret, ReturnKind kind) { + result = TReturnPositionSimple0(getNodeEnclosingCallable(ret), kind) + } + + pragma[nomagic] + private TReturnPositionSimple viableReturnPosNonLambda(DataFlowCall call, ReturnKind kind) { + result = TReturnPositionSimple0(viableCallable(call), kind) + } + + pragma[nomagic] + private TReturnPositionSimple viableReturnPosLambda( + DataFlowCall call, DataFlowCallOption lastCall, ReturnKind kind + ) { + result = TReturnPositionSimple0(viableCallableLambda(call, lastCall), kind) + } + + private predicate viableReturnPosOutNonLambda( + DataFlowCall call, TReturnPositionSimple pos, OutNode out + ) { + exists(ReturnKind kind | + pos = viableReturnPosNonLambda(call, kind) and + out = getAnOutNode(call, kind) + ) + } + + private predicate viableReturnPosOutLambda( + DataFlowCall call, DataFlowCallOption lastCall, TReturnPositionSimple pos, OutNode out + ) { + exists(ReturnKind kind | + pos = viableReturnPosLambda(call, lastCall, kind) and + out = getAnOutNode(call, kind) + ) + } + + /** + * Holds if data can flow (inter-procedurally) from `node` (of type `t`) to + * the lambda call `lambdaCall`. + * + * The parameter `toReturn` indicates whether the path from `node` to + * `lambdaCall` goes through a return, and `toJump` whether the path goes + * through a jump step. + * + * The call context `lastCall` records the last call on the path from `node` + * to `lambdaCall`, if any. That is, `lastCall` is able to target the enclosing + * callable of `lambdaCall`. + */ + pragma[nomagic] + predicate revLambdaFlow( + DataFlowCall lambdaCall, LambdaCallKind kind, Node node, DataFlowType t, boolean toReturn, + boolean toJump, DataFlowCallOption lastCall + ) { + revLambdaFlow0(lambdaCall, kind, node, t, toReturn, toJump, lastCall) and + if node instanceof CastNode or node instanceof ArgumentNode or node instanceof ReturnNode + then compatibleTypes(t, getNodeType(node)) + else any() + } + + pragma[nomagic] + predicate revLambdaFlow0( + DataFlowCall lambdaCall, LambdaCallKind kind, Node node, DataFlowType t, boolean toReturn, + boolean toJump, DataFlowCallOption lastCall + ) { + lambdaCall(lambdaCall, kind, node) and + t = getNodeType(node) and + toReturn = false and + toJump = false and + lastCall = TDataFlowCallNone() + or + // local flow + exists(Node mid, DataFlowType t0 | + revLambdaFlow(lambdaCall, kind, mid, t0, toReturn, toJump, lastCall) + | + simpleLocalFlowStep(node, mid) and + t = t0 + or + exists(boolean preservesValue | + additionalLambdaFlowStep(node, mid, preservesValue) and + getNodeEnclosingCallable(node) = getNodeEnclosingCallable(mid) + | + preservesValue = false and + t = getNodeType(node) + or + preservesValue = true and + t = t0 + ) + ) + or + // jump step + exists(Node mid, DataFlowType t0 | + revLambdaFlow(lambdaCall, kind, mid, t0, _, _, _) and + toReturn = false and + toJump = true and + lastCall = TDataFlowCallNone() + | + jumpStep(node, mid) and + t = t0 + or + exists(boolean preservesValue | + additionalLambdaFlowStep(node, mid, preservesValue) and + getNodeEnclosingCallable(node) != getNodeEnclosingCallable(mid) + | + preservesValue = false and + t = getNodeType(node) + or + preservesValue = true and + t = t0 + ) + ) + or + // flow into a callable + exists(ParameterNode p, DataFlowCallOption lastCall0, DataFlowCall call | + revLambdaFlowIn(lambdaCall, kind, p, t, toJump, lastCall0) and + ( + if lastCall0 = TDataFlowCallNone() and toJump = false + then lastCall = TDataFlowCallSome(call) + else lastCall = lastCall0 + ) and + toReturn = false + | + viableParamArgNonLambda(call, p, node) + or + viableParamArgLambda(call, p, node) // non-linear recursion + ) + or + // flow out of a callable + exists(TReturnPositionSimple pos | + revLambdaFlowOut(lambdaCall, kind, pos, t, toJump, lastCall) and + getReturnPositionSimple(node, node.(ReturnNode).getKind()) = pos and + toReturn = true + ) + } + + pragma[nomagic] + predicate revLambdaFlowOutLambdaCall( + DataFlowCall lambdaCall, LambdaCallKind kind, OutNode out, DataFlowType t, boolean toJump, + DataFlowCall call, DataFlowCallOption lastCall + ) { + revLambdaFlow(lambdaCall, kind, out, t, _, toJump, lastCall) and + exists(ReturnKindExt rk | + out = rk.getAnOutNode(call) and + lambdaCall(call, _, _) + ) + } + + pragma[nomagic] + predicate revLambdaFlowOut( + DataFlowCall lambdaCall, LambdaCallKind kind, TReturnPositionSimple pos, DataFlowType t, + boolean toJump, DataFlowCallOption lastCall + ) { + exists(DataFlowCall call, OutNode out | + revLambdaFlow(lambdaCall, kind, out, t, _, toJump, lastCall) and + viableReturnPosOutNonLambda(call, pos, out) + or + // non-linear recursion + revLambdaFlowOutLambdaCall(lambdaCall, kind, out, t, toJump, call, lastCall) and + viableReturnPosOutLambda(call, _, pos, out) + ) + } + + pragma[nomagic] + predicate revLambdaFlowIn( + DataFlowCall lambdaCall, LambdaCallKind kind, ParameterNode p, DataFlowType t, boolean toJump, + DataFlowCallOption lastCall + ) { + revLambdaFlow(lambdaCall, kind, p, t, false, toJump, lastCall) + } +} + +private DataFlowCallable viableCallableExt(DataFlowCall call) { + result = viableCallable(call) + or + result = viableCallableLambda(call, _) +} + cached private module Cached { + /** + * Gets a viable target for the lambda call `call`. + * + * `lastCall` records the call required to reach `call` in order for the result + * to be a viable target, if any. + */ + cached + DataFlowCallable viableCallableLambda(DataFlowCall call, DataFlowCallOption lastCall) { + exists(Node creation, LambdaCallKind kind | + LambdaFlow::revLambdaFlow(call, kind, creation, _, _, _, lastCall) and + lambdaCreation(creation, kind, result) + ) + } + /** * Holds if `p` is the `i`th parameter of a viable dispatch target of `call`. * The instance parameter is considered to have index `-1`. */ pragma[nomagic] private predicate viableParam(DataFlowCall call, int i, ParameterNode p) { - p.isParameterOf(viableCallable(call), i) + p.isParameterOf(viableCallableExt(call), i) } /** @@ -52,7 +280,7 @@ private module Cached { pragma[nomagic] private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and + viableCallableExt(call) = result.getCallable() and kind = result.getKind() } @@ -317,6 +545,35 @@ private module Cached { cached private module DispatchWithCallContext { + /** + * Holds if the set of viable implementations that can be called by `call` + * might be improved by knowing the call context. + */ + pragma[nomagic] + private predicate mayBenefitFromCallContextExt(DataFlowCall call, DataFlowCallable callable) { + mayBenefitFromCallContext(call, callable) + or + callable = call.getEnclosingCallable() and + exists(viableCallableLambda(call, TDataFlowCallSome(_))) + } + + /** + * Gets a viable dispatch target of `call` in the context `ctx`. This is + * restricted to those `call`s for which a context might make a difference. + */ + pragma[nomagic] + private DataFlowCallable viableImplInCallContextExt(DataFlowCall call, DataFlowCall ctx) { + result = viableImplInCallContext(call, ctx) + or + result = viableCallableLambda(call, TDataFlowCallSome(ctx)) + or + exists(DataFlowCallable enclosing | + mayBenefitFromCallContextExt(call, enclosing) and + enclosing = viableCallableExt(ctx) and + result = viableCallableLambda(call, TDataFlowCallNone()) + ) + } + /** * Holds if the call context `ctx` reduces the set of viable run-time * dispatch targets of call `call` in `c`. @@ -324,10 +581,10 @@ private module Cached { cached predicate reducedViableImplInCallContext(DataFlowCall call, DataFlowCallable c, DataFlowCall ctx) { exists(int tgts, int ctxtgts | - mayBenefitFromCallContext(call, c) and - c = viableCallable(ctx) and - ctxtgts = count(viableImplInCallContext(call, ctx)) and - tgts = strictcount(viableCallable(call)) and + mayBenefitFromCallContextExt(call, c) and + c = viableCallableExt(ctx) and + ctxtgts = count(viableImplInCallContextExt(call, ctx)) and + tgts = strictcount(viableCallableExt(call)) and ctxtgts < tgts ) } @@ -339,7 +596,7 @@ private module Cached { */ cached DataFlowCallable prunedViableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { - result = viableImplInCallContext(call, ctx) and + result = viableImplInCallContextExt(call, ctx) and reducedViableImplInCallContext(call, _, ctx) } @@ -351,10 +608,10 @@ private module Cached { cached predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) { exists(int tgts, int ctxtgts | - mayBenefitFromCallContext(call, _) and - c = viableCallable(call) and - ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContext(call, ctx)) and - tgts = strictcount(DataFlowCall ctx | viableCallable(ctx) = call.getEnclosingCallable()) and + mayBenefitFromCallContextExt(call, _) and + c = viableCallableExt(call) and + ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContextExt(call, ctx)) and + tgts = strictcount(DataFlowCall ctx | viableCallableExt(ctx) = call.getEnclosingCallable()) and ctxtgts < tgts ) } @@ -367,7 +624,7 @@ private module Cached { */ cached DataFlowCallable prunedViableImplInCallContextReverse(DataFlowCall call, DataFlowCall ctx) { - result = viableImplInCallContext(call, ctx) and + result = viableImplInCallContextExt(call, ctx) and reducedViableImplInReturn(result, call) } } @@ -481,6 +738,11 @@ private module Cached { TBooleanNone() or TBooleanSome(boolean b) { b = true or b = false } + cached + newtype TDataFlowCallOption = + TDataFlowCallNone() or + TDataFlowCallSome(DataFlowCall call) + cached newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) } @@ -777,7 +1039,7 @@ ReturnPosition getReturnPosition(ReturnNodeExt ret) { bindingset[cc, callable] predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall call) { - cc instanceof CallContextAny and callable = viableCallable(call) + cc instanceof CallContextAny and callable = viableCallableExt(call) or exists(DataFlowCallable c0, DataFlowCall call0 | call0.getEnclosingCallable() = callable and @@ -791,14 +1053,14 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) { exists(DataFlowCall ctx | cc = TSpecificCall(ctx) | if reducedViableImplInCallContext(call, _, ctx) then result = prunedViableImplInCallContext(call, ctx) - else result = viableCallable(call) + else result = viableCallableExt(call) ) or - result = viableCallable(call) and cc instanceof CallContextSomeCall + result = viableCallableExt(call) and cc instanceof CallContextSomeCall or - result = viableCallable(call) and cc instanceof CallContextAny + result = viableCallableExt(call) and cc instanceof CallContextAny or - result = viableCallable(call) and cc instanceof CallContextReturn + result = viableCallableExt(call) and cc instanceof CallContextReturn } predicate read = readStep/3; @@ -812,6 +1074,19 @@ class BooleanOption extends TBooleanOption { } } +/** An optional `DataFlowCall`. */ +class DataFlowCallOption extends TDataFlowCallOption { + string toString() { + this = TDataFlowCallNone() and + result = "(none)" + or + exists(DataFlowCall call | + this = TDataFlowCallSome(call) and + result = call.toString() + ) + } +} + /** Content tagged with the type of a containing object. */ class TypedContent extends MkTypedContent { private Content c; 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 a2b1cae14d6..3b94e574de0 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 @@ -548,3 +548,14 @@ predicate isImmutableOrUnobservable(Node n) { /** Holds if `n` should be hidden from path explanations. */ predicate nodeIsHidden(Node n) { n instanceof OperandNode and not n instanceof ArgumentNode } + +class LambdaCallKind = Unit; + +/** Holds if `creation` is an expression that creates a lambda of kind `kind` for `c`. */ +predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) { none() } + +/** Holds if `call` is a lambda call of kind `kind` where `receiver` is the lambda expression. */ +predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) { none() } + +/** Extra data-flow steps needed for lamba flow analysis. */ +predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll index 1319f972037..a51c20c2288 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll @@ -26,15 +26,243 @@ predicate accessPathCostLimits(int apLimit, int tupleLimit) { tupleLimit = 1000 } +/** + * Provides a simple data-flow analysis for resolving lambda calls. The analysis + * currently excludes read-steps, store-steps, and flow-through. + * + * The analysis uses non-linear recursion: When computing a flow path in or out + * of a call, we use the results of the analysis recursively to resolve lamba + * calls. For this reason, we cannot reuse the code from `DataFlowImpl.qll` directly. + */ +private module LambdaFlow { + private predicate viableParamNonLambda(DataFlowCall call, int i, ParameterNode p) { + p.isParameterOf(viableCallable(call), i) + } + + private predicate viableParamLambda(DataFlowCall call, int i, ParameterNode p) { + p.isParameterOf(viableCallableLambda(call, _), i) + } + + private predicate viableParamArgNonLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) { + exists(int i | + viableParamNonLambda(call, i, p) and + arg.argumentOf(call, i) + ) + } + + private predicate viableParamArgLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) { + exists(int i | + viableParamLambda(call, i, p) and + arg.argumentOf(call, i) + ) + } + + private newtype TReturnPositionSimple = + TReturnPositionSimple0(DataFlowCallable c, ReturnKind kind) { + exists(ReturnNode ret | + c = getNodeEnclosingCallable(ret) and + kind = ret.getKind() + ) + } + + pragma[noinline] + private TReturnPositionSimple getReturnPositionSimple(ReturnNode ret, ReturnKind kind) { + result = TReturnPositionSimple0(getNodeEnclosingCallable(ret), kind) + } + + pragma[nomagic] + private TReturnPositionSimple viableReturnPosNonLambda(DataFlowCall call, ReturnKind kind) { + result = TReturnPositionSimple0(viableCallable(call), kind) + } + + pragma[nomagic] + private TReturnPositionSimple viableReturnPosLambda( + DataFlowCall call, DataFlowCallOption lastCall, ReturnKind kind + ) { + result = TReturnPositionSimple0(viableCallableLambda(call, lastCall), kind) + } + + private predicate viableReturnPosOutNonLambda( + DataFlowCall call, TReturnPositionSimple pos, OutNode out + ) { + exists(ReturnKind kind | + pos = viableReturnPosNonLambda(call, kind) and + out = getAnOutNode(call, kind) + ) + } + + private predicate viableReturnPosOutLambda( + DataFlowCall call, DataFlowCallOption lastCall, TReturnPositionSimple pos, OutNode out + ) { + exists(ReturnKind kind | + pos = viableReturnPosLambda(call, lastCall, kind) and + out = getAnOutNode(call, kind) + ) + } + + /** + * Holds if data can flow (inter-procedurally) from `node` (of type `t`) to + * the lambda call `lambdaCall`. + * + * The parameter `toReturn` indicates whether the path from `node` to + * `lambdaCall` goes through a return, and `toJump` whether the path goes + * through a jump step. + * + * The call context `lastCall` records the last call on the path from `node` + * to `lambdaCall`, if any. That is, `lastCall` is able to target the enclosing + * callable of `lambdaCall`. + */ + pragma[nomagic] + predicate revLambdaFlow( + DataFlowCall lambdaCall, LambdaCallKind kind, Node node, DataFlowType t, boolean toReturn, + boolean toJump, DataFlowCallOption lastCall + ) { + revLambdaFlow0(lambdaCall, kind, node, t, toReturn, toJump, lastCall) and + if node instanceof CastNode or node instanceof ArgumentNode or node instanceof ReturnNode + then compatibleTypes(t, getNodeType(node)) + else any() + } + + pragma[nomagic] + predicate revLambdaFlow0( + DataFlowCall lambdaCall, LambdaCallKind kind, Node node, DataFlowType t, boolean toReturn, + boolean toJump, DataFlowCallOption lastCall + ) { + lambdaCall(lambdaCall, kind, node) and + t = getNodeType(node) and + toReturn = false and + toJump = false and + lastCall = TDataFlowCallNone() + or + // local flow + exists(Node mid, DataFlowType t0 | + revLambdaFlow(lambdaCall, kind, mid, t0, toReturn, toJump, lastCall) + | + simpleLocalFlowStep(node, mid) and + t = t0 + or + exists(boolean preservesValue | + additionalLambdaFlowStep(node, mid, preservesValue) and + getNodeEnclosingCallable(node) = getNodeEnclosingCallable(mid) + | + preservesValue = false and + t = getNodeType(node) + or + preservesValue = true and + t = t0 + ) + ) + or + // jump step + exists(Node mid, DataFlowType t0 | + revLambdaFlow(lambdaCall, kind, mid, t0, _, _, _) and + toReturn = false and + toJump = true and + lastCall = TDataFlowCallNone() + | + jumpStep(node, mid) and + t = t0 + or + exists(boolean preservesValue | + additionalLambdaFlowStep(node, mid, preservesValue) and + getNodeEnclosingCallable(node) != getNodeEnclosingCallable(mid) + | + preservesValue = false and + t = getNodeType(node) + or + preservesValue = true and + t = t0 + ) + ) + or + // flow into a callable + exists(ParameterNode p, DataFlowCallOption lastCall0, DataFlowCall call | + revLambdaFlowIn(lambdaCall, kind, p, t, toJump, lastCall0) and + ( + if lastCall0 = TDataFlowCallNone() and toJump = false + then lastCall = TDataFlowCallSome(call) + else lastCall = lastCall0 + ) and + toReturn = false + | + viableParamArgNonLambda(call, p, node) + or + viableParamArgLambda(call, p, node) // non-linear recursion + ) + or + // flow out of a callable + exists(TReturnPositionSimple pos | + revLambdaFlowOut(lambdaCall, kind, pos, t, toJump, lastCall) and + getReturnPositionSimple(node, node.(ReturnNode).getKind()) = pos and + toReturn = true + ) + } + + pragma[nomagic] + predicate revLambdaFlowOutLambdaCall( + DataFlowCall lambdaCall, LambdaCallKind kind, OutNode out, DataFlowType t, boolean toJump, + DataFlowCall call, DataFlowCallOption lastCall + ) { + revLambdaFlow(lambdaCall, kind, out, t, _, toJump, lastCall) and + exists(ReturnKindExt rk | + out = rk.getAnOutNode(call) and + lambdaCall(call, _, _) + ) + } + + pragma[nomagic] + predicate revLambdaFlowOut( + DataFlowCall lambdaCall, LambdaCallKind kind, TReturnPositionSimple pos, DataFlowType t, + boolean toJump, DataFlowCallOption lastCall + ) { + exists(DataFlowCall call, OutNode out | + revLambdaFlow(lambdaCall, kind, out, t, _, toJump, lastCall) and + viableReturnPosOutNonLambda(call, pos, out) + or + // non-linear recursion + revLambdaFlowOutLambdaCall(lambdaCall, kind, out, t, toJump, call, lastCall) and + viableReturnPosOutLambda(call, _, pos, out) + ) + } + + pragma[nomagic] + predicate revLambdaFlowIn( + DataFlowCall lambdaCall, LambdaCallKind kind, ParameterNode p, DataFlowType t, boolean toJump, + DataFlowCallOption lastCall + ) { + revLambdaFlow(lambdaCall, kind, p, t, false, toJump, lastCall) + } +} + +private DataFlowCallable viableCallableExt(DataFlowCall call) { + result = viableCallable(call) + or + result = viableCallableLambda(call, _) +} + cached private module Cached { + /** + * Gets a viable target for the lambda call `call`. + * + * `lastCall` records the call required to reach `call` in order for the result + * to be a viable target, if any. + */ + cached + DataFlowCallable viableCallableLambda(DataFlowCall call, DataFlowCallOption lastCall) { + exists(Node creation, LambdaCallKind kind | + LambdaFlow::revLambdaFlow(call, kind, creation, _, _, _, lastCall) and + lambdaCreation(creation, kind, result) + ) + } + /** * Holds if `p` is the `i`th parameter of a viable dispatch target of `call`. * The instance parameter is considered to have index `-1`. */ pragma[nomagic] private predicate viableParam(DataFlowCall call, int i, ParameterNode p) { - p.isParameterOf(viableCallable(call), i) + p.isParameterOf(viableCallableExt(call), i) } /** @@ -52,7 +280,7 @@ private module Cached { pragma[nomagic] private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and + viableCallableExt(call) = result.getCallable() and kind = result.getKind() } @@ -317,6 +545,35 @@ private module Cached { cached private module DispatchWithCallContext { + /** + * Holds if the set of viable implementations that can be called by `call` + * might be improved by knowing the call context. + */ + pragma[nomagic] + private predicate mayBenefitFromCallContextExt(DataFlowCall call, DataFlowCallable callable) { + mayBenefitFromCallContext(call, callable) + or + callable = call.getEnclosingCallable() and + exists(viableCallableLambda(call, TDataFlowCallSome(_))) + } + + /** + * Gets a viable dispatch target of `call` in the context `ctx`. This is + * restricted to those `call`s for which a context might make a difference. + */ + pragma[nomagic] + private DataFlowCallable viableImplInCallContextExt(DataFlowCall call, DataFlowCall ctx) { + result = viableImplInCallContext(call, ctx) + or + result = viableCallableLambda(call, TDataFlowCallSome(ctx)) + or + exists(DataFlowCallable enclosing | + mayBenefitFromCallContextExt(call, enclosing) and + enclosing = viableCallableExt(ctx) and + result = viableCallableLambda(call, TDataFlowCallNone()) + ) + } + /** * Holds if the call context `ctx` reduces the set of viable run-time * dispatch targets of call `call` in `c`. @@ -324,10 +581,10 @@ private module Cached { cached predicate reducedViableImplInCallContext(DataFlowCall call, DataFlowCallable c, DataFlowCall ctx) { exists(int tgts, int ctxtgts | - mayBenefitFromCallContext(call, c) and - c = viableCallable(ctx) and - ctxtgts = count(viableImplInCallContext(call, ctx)) and - tgts = strictcount(viableCallable(call)) and + mayBenefitFromCallContextExt(call, c) and + c = viableCallableExt(ctx) and + ctxtgts = count(viableImplInCallContextExt(call, ctx)) and + tgts = strictcount(viableCallableExt(call)) and ctxtgts < tgts ) } @@ -339,7 +596,7 @@ private module Cached { */ cached DataFlowCallable prunedViableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { - result = viableImplInCallContext(call, ctx) and + result = viableImplInCallContextExt(call, ctx) and reducedViableImplInCallContext(call, _, ctx) } @@ -351,10 +608,10 @@ private module Cached { cached predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) { exists(int tgts, int ctxtgts | - mayBenefitFromCallContext(call, _) and - c = viableCallable(call) and - ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContext(call, ctx)) and - tgts = strictcount(DataFlowCall ctx | viableCallable(ctx) = call.getEnclosingCallable()) and + mayBenefitFromCallContextExt(call, _) and + c = viableCallableExt(call) and + ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContextExt(call, ctx)) and + tgts = strictcount(DataFlowCall ctx | viableCallableExt(ctx) = call.getEnclosingCallable()) and ctxtgts < tgts ) } @@ -367,7 +624,7 @@ private module Cached { */ cached DataFlowCallable prunedViableImplInCallContextReverse(DataFlowCall call, DataFlowCall ctx) { - result = viableImplInCallContext(call, ctx) and + result = viableImplInCallContextExt(call, ctx) and reducedViableImplInReturn(result, call) } } @@ -481,6 +738,11 @@ private module Cached { TBooleanNone() or TBooleanSome(boolean b) { b = true or b = false } + cached + newtype TDataFlowCallOption = + TDataFlowCallNone() or + TDataFlowCallSome(DataFlowCall call) + cached newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) } @@ -777,7 +1039,7 @@ ReturnPosition getReturnPosition(ReturnNodeExt ret) { bindingset[cc, callable] predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall call) { - cc instanceof CallContextAny and callable = viableCallable(call) + cc instanceof CallContextAny and callable = viableCallableExt(call) or exists(DataFlowCallable c0, DataFlowCall call0 | call0.getEnclosingCallable() = callable and @@ -791,14 +1053,14 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) { exists(DataFlowCall ctx | cc = TSpecificCall(ctx) | if reducedViableImplInCallContext(call, _, ctx) then result = prunedViableImplInCallContext(call, ctx) - else result = viableCallable(call) + else result = viableCallableExt(call) ) or - result = viableCallable(call) and cc instanceof CallContextSomeCall + result = viableCallableExt(call) and cc instanceof CallContextSomeCall or - result = viableCallable(call) and cc instanceof CallContextAny + result = viableCallableExt(call) and cc instanceof CallContextAny or - result = viableCallable(call) and cc instanceof CallContextReturn + result = viableCallableExt(call) and cc instanceof CallContextReturn } predicate read = readStep/3; @@ -812,6 +1074,19 @@ class BooleanOption extends TBooleanOption { } } +/** An optional `DataFlowCall`. */ +class DataFlowCallOption extends TDataFlowCallOption { + string toString() { + this = TDataFlowCallNone() and + result = "(none)" + or + exists(DataFlowCall call | + this = TDataFlowCallSome(call) and + result = call.toString() + ) + } +} + /** Content tagged with the type of a containing object. */ class TypedContent extends MkTypedContent { private Content c; diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowPrivate.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowPrivate.qll index c38d0df4e57..f49ca8d75d9 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowPrivate.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowPrivate.qll @@ -338,3 +338,14 @@ predicate isImmutableOrUnobservable(Node n) { /** Holds if `n` should be hidden from path explanations. */ predicate nodeIsHidden(Node n) { none() } + +class LambdaCallKind = Unit; + +/** Holds if `creation` is an expression that creates a lambda of kind `kind` for `c`. */ +predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) { none() } + +/** Holds if `call` is a lambda call of kind `kind` where `receiver` is the lambda expression. */ +predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) { none() } + +/** Extra data-flow steps needed for lamba flow analysis. */ +predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() } diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll index 1319f972037..a51c20c2288 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll @@ -26,15 +26,243 @@ predicate accessPathCostLimits(int apLimit, int tupleLimit) { tupleLimit = 1000 } +/** + * Provides a simple data-flow analysis for resolving lambda calls. The analysis + * currently excludes read-steps, store-steps, and flow-through. + * + * The analysis uses non-linear recursion: When computing a flow path in or out + * of a call, we use the results of the analysis recursively to resolve lamba + * calls. For this reason, we cannot reuse the code from `DataFlowImpl.qll` directly. + */ +private module LambdaFlow { + private predicate viableParamNonLambda(DataFlowCall call, int i, ParameterNode p) { + p.isParameterOf(viableCallable(call), i) + } + + private predicate viableParamLambda(DataFlowCall call, int i, ParameterNode p) { + p.isParameterOf(viableCallableLambda(call, _), i) + } + + private predicate viableParamArgNonLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) { + exists(int i | + viableParamNonLambda(call, i, p) and + arg.argumentOf(call, i) + ) + } + + private predicate viableParamArgLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) { + exists(int i | + viableParamLambda(call, i, p) and + arg.argumentOf(call, i) + ) + } + + private newtype TReturnPositionSimple = + TReturnPositionSimple0(DataFlowCallable c, ReturnKind kind) { + exists(ReturnNode ret | + c = getNodeEnclosingCallable(ret) and + kind = ret.getKind() + ) + } + + pragma[noinline] + private TReturnPositionSimple getReturnPositionSimple(ReturnNode ret, ReturnKind kind) { + result = TReturnPositionSimple0(getNodeEnclosingCallable(ret), kind) + } + + pragma[nomagic] + private TReturnPositionSimple viableReturnPosNonLambda(DataFlowCall call, ReturnKind kind) { + result = TReturnPositionSimple0(viableCallable(call), kind) + } + + pragma[nomagic] + private TReturnPositionSimple viableReturnPosLambda( + DataFlowCall call, DataFlowCallOption lastCall, ReturnKind kind + ) { + result = TReturnPositionSimple0(viableCallableLambda(call, lastCall), kind) + } + + private predicate viableReturnPosOutNonLambda( + DataFlowCall call, TReturnPositionSimple pos, OutNode out + ) { + exists(ReturnKind kind | + pos = viableReturnPosNonLambda(call, kind) and + out = getAnOutNode(call, kind) + ) + } + + private predicate viableReturnPosOutLambda( + DataFlowCall call, DataFlowCallOption lastCall, TReturnPositionSimple pos, OutNode out + ) { + exists(ReturnKind kind | + pos = viableReturnPosLambda(call, lastCall, kind) and + out = getAnOutNode(call, kind) + ) + } + + /** + * Holds if data can flow (inter-procedurally) from `node` (of type `t`) to + * the lambda call `lambdaCall`. + * + * The parameter `toReturn` indicates whether the path from `node` to + * `lambdaCall` goes through a return, and `toJump` whether the path goes + * through a jump step. + * + * The call context `lastCall` records the last call on the path from `node` + * to `lambdaCall`, if any. That is, `lastCall` is able to target the enclosing + * callable of `lambdaCall`. + */ + pragma[nomagic] + predicate revLambdaFlow( + DataFlowCall lambdaCall, LambdaCallKind kind, Node node, DataFlowType t, boolean toReturn, + boolean toJump, DataFlowCallOption lastCall + ) { + revLambdaFlow0(lambdaCall, kind, node, t, toReturn, toJump, lastCall) and + if node instanceof CastNode or node instanceof ArgumentNode or node instanceof ReturnNode + then compatibleTypes(t, getNodeType(node)) + else any() + } + + pragma[nomagic] + predicate revLambdaFlow0( + DataFlowCall lambdaCall, LambdaCallKind kind, Node node, DataFlowType t, boolean toReturn, + boolean toJump, DataFlowCallOption lastCall + ) { + lambdaCall(lambdaCall, kind, node) and + t = getNodeType(node) and + toReturn = false and + toJump = false and + lastCall = TDataFlowCallNone() + or + // local flow + exists(Node mid, DataFlowType t0 | + revLambdaFlow(lambdaCall, kind, mid, t0, toReturn, toJump, lastCall) + | + simpleLocalFlowStep(node, mid) and + t = t0 + or + exists(boolean preservesValue | + additionalLambdaFlowStep(node, mid, preservesValue) and + getNodeEnclosingCallable(node) = getNodeEnclosingCallable(mid) + | + preservesValue = false and + t = getNodeType(node) + or + preservesValue = true and + t = t0 + ) + ) + or + // jump step + exists(Node mid, DataFlowType t0 | + revLambdaFlow(lambdaCall, kind, mid, t0, _, _, _) and + toReturn = false and + toJump = true and + lastCall = TDataFlowCallNone() + | + jumpStep(node, mid) and + t = t0 + or + exists(boolean preservesValue | + additionalLambdaFlowStep(node, mid, preservesValue) and + getNodeEnclosingCallable(node) != getNodeEnclosingCallable(mid) + | + preservesValue = false and + t = getNodeType(node) + or + preservesValue = true and + t = t0 + ) + ) + or + // flow into a callable + exists(ParameterNode p, DataFlowCallOption lastCall0, DataFlowCall call | + revLambdaFlowIn(lambdaCall, kind, p, t, toJump, lastCall0) and + ( + if lastCall0 = TDataFlowCallNone() and toJump = false + then lastCall = TDataFlowCallSome(call) + else lastCall = lastCall0 + ) and + toReturn = false + | + viableParamArgNonLambda(call, p, node) + or + viableParamArgLambda(call, p, node) // non-linear recursion + ) + or + // flow out of a callable + exists(TReturnPositionSimple pos | + revLambdaFlowOut(lambdaCall, kind, pos, t, toJump, lastCall) and + getReturnPositionSimple(node, node.(ReturnNode).getKind()) = pos and + toReturn = true + ) + } + + pragma[nomagic] + predicate revLambdaFlowOutLambdaCall( + DataFlowCall lambdaCall, LambdaCallKind kind, OutNode out, DataFlowType t, boolean toJump, + DataFlowCall call, DataFlowCallOption lastCall + ) { + revLambdaFlow(lambdaCall, kind, out, t, _, toJump, lastCall) and + exists(ReturnKindExt rk | + out = rk.getAnOutNode(call) and + lambdaCall(call, _, _) + ) + } + + pragma[nomagic] + predicate revLambdaFlowOut( + DataFlowCall lambdaCall, LambdaCallKind kind, TReturnPositionSimple pos, DataFlowType t, + boolean toJump, DataFlowCallOption lastCall + ) { + exists(DataFlowCall call, OutNode out | + revLambdaFlow(lambdaCall, kind, out, t, _, toJump, lastCall) and + viableReturnPosOutNonLambda(call, pos, out) + or + // non-linear recursion + revLambdaFlowOutLambdaCall(lambdaCall, kind, out, t, toJump, call, lastCall) and + viableReturnPosOutLambda(call, _, pos, out) + ) + } + + pragma[nomagic] + predicate revLambdaFlowIn( + DataFlowCall lambdaCall, LambdaCallKind kind, ParameterNode p, DataFlowType t, boolean toJump, + DataFlowCallOption lastCall + ) { + revLambdaFlow(lambdaCall, kind, p, t, false, toJump, lastCall) + } +} + +private DataFlowCallable viableCallableExt(DataFlowCall call) { + result = viableCallable(call) + or + result = viableCallableLambda(call, _) +} + cached private module Cached { + /** + * Gets a viable target for the lambda call `call`. + * + * `lastCall` records the call required to reach `call` in order for the result + * to be a viable target, if any. + */ + cached + DataFlowCallable viableCallableLambda(DataFlowCall call, DataFlowCallOption lastCall) { + exists(Node creation, LambdaCallKind kind | + LambdaFlow::revLambdaFlow(call, kind, creation, _, _, _, lastCall) and + lambdaCreation(creation, kind, result) + ) + } + /** * Holds if `p` is the `i`th parameter of a viable dispatch target of `call`. * The instance parameter is considered to have index `-1`. */ pragma[nomagic] private predicate viableParam(DataFlowCall call, int i, ParameterNode p) { - p.isParameterOf(viableCallable(call), i) + p.isParameterOf(viableCallableExt(call), i) } /** @@ -52,7 +280,7 @@ private module Cached { pragma[nomagic] private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and + viableCallableExt(call) = result.getCallable() and kind = result.getKind() } @@ -317,6 +545,35 @@ private module Cached { cached private module DispatchWithCallContext { + /** + * Holds if the set of viable implementations that can be called by `call` + * might be improved by knowing the call context. + */ + pragma[nomagic] + private predicate mayBenefitFromCallContextExt(DataFlowCall call, DataFlowCallable callable) { + mayBenefitFromCallContext(call, callable) + or + callable = call.getEnclosingCallable() and + exists(viableCallableLambda(call, TDataFlowCallSome(_))) + } + + /** + * Gets a viable dispatch target of `call` in the context `ctx`. This is + * restricted to those `call`s for which a context might make a difference. + */ + pragma[nomagic] + private DataFlowCallable viableImplInCallContextExt(DataFlowCall call, DataFlowCall ctx) { + result = viableImplInCallContext(call, ctx) + or + result = viableCallableLambda(call, TDataFlowCallSome(ctx)) + or + exists(DataFlowCallable enclosing | + mayBenefitFromCallContextExt(call, enclosing) and + enclosing = viableCallableExt(ctx) and + result = viableCallableLambda(call, TDataFlowCallNone()) + ) + } + /** * Holds if the call context `ctx` reduces the set of viable run-time * dispatch targets of call `call` in `c`. @@ -324,10 +581,10 @@ private module Cached { cached predicate reducedViableImplInCallContext(DataFlowCall call, DataFlowCallable c, DataFlowCall ctx) { exists(int tgts, int ctxtgts | - mayBenefitFromCallContext(call, c) and - c = viableCallable(ctx) and - ctxtgts = count(viableImplInCallContext(call, ctx)) and - tgts = strictcount(viableCallable(call)) and + mayBenefitFromCallContextExt(call, c) and + c = viableCallableExt(ctx) and + ctxtgts = count(viableImplInCallContextExt(call, ctx)) and + tgts = strictcount(viableCallableExt(call)) and ctxtgts < tgts ) } @@ -339,7 +596,7 @@ private module Cached { */ cached DataFlowCallable prunedViableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { - result = viableImplInCallContext(call, ctx) and + result = viableImplInCallContextExt(call, ctx) and reducedViableImplInCallContext(call, _, ctx) } @@ -351,10 +608,10 @@ private module Cached { cached predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) { exists(int tgts, int ctxtgts | - mayBenefitFromCallContext(call, _) and - c = viableCallable(call) and - ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContext(call, ctx)) and - tgts = strictcount(DataFlowCall ctx | viableCallable(ctx) = call.getEnclosingCallable()) and + mayBenefitFromCallContextExt(call, _) and + c = viableCallableExt(call) and + ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContextExt(call, ctx)) and + tgts = strictcount(DataFlowCall ctx | viableCallableExt(ctx) = call.getEnclosingCallable()) and ctxtgts < tgts ) } @@ -367,7 +624,7 @@ private module Cached { */ cached DataFlowCallable prunedViableImplInCallContextReverse(DataFlowCall call, DataFlowCall ctx) { - result = viableImplInCallContext(call, ctx) and + result = viableImplInCallContextExt(call, ctx) and reducedViableImplInReturn(result, call) } } @@ -481,6 +738,11 @@ private module Cached { TBooleanNone() or TBooleanSome(boolean b) { b = true or b = false } + cached + newtype TDataFlowCallOption = + TDataFlowCallNone() or + TDataFlowCallSome(DataFlowCall call) + cached newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) } @@ -777,7 +1039,7 @@ ReturnPosition getReturnPosition(ReturnNodeExt ret) { bindingset[cc, callable] predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall call) { - cc instanceof CallContextAny and callable = viableCallable(call) + cc instanceof CallContextAny and callable = viableCallableExt(call) or exists(DataFlowCallable c0, DataFlowCall call0 | call0.getEnclosingCallable() = callable and @@ -791,14 +1053,14 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) { exists(DataFlowCall ctx | cc = TSpecificCall(ctx) | if reducedViableImplInCallContext(call, _, ctx) then result = prunedViableImplInCallContext(call, ctx) - else result = viableCallable(call) + else result = viableCallableExt(call) ) or - result = viableCallable(call) and cc instanceof CallContextSomeCall + result = viableCallableExt(call) and cc instanceof CallContextSomeCall or - result = viableCallable(call) and cc instanceof CallContextAny + result = viableCallableExt(call) and cc instanceof CallContextAny or - result = viableCallable(call) and cc instanceof CallContextReturn + result = viableCallableExt(call) and cc instanceof CallContextReturn } predicate read = readStep/3; @@ -812,6 +1074,19 @@ class BooleanOption extends TBooleanOption { } } +/** An optional `DataFlowCall`. */ +class DataFlowCallOption extends TDataFlowCallOption { + string toString() { + this = TDataFlowCallNone() and + result = "(none)" + or + exists(DataFlowCall call | + this = TDataFlowCallSome(call) and + result = call.toString() + ) + } +} + /** Content tagged with the type of a containing object. */ class TypedContent extends MkTypedContent { private Content c; diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index 958a434eeb1..86ef69a87b9 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -1605,3 +1605,14 @@ int accessPathLimit() { result = 5 } /** Holds if `n` should be hidden from path explanations. */ predicate nodeIsHidden(Node n) { none() } + +class LambdaCallKind = Unit; + +/** Holds if `creation` is an expression that creates a lambda of kind `kind` for `c`. */ +predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) { none() } + +/** Holds if `call` is a lambda call of kind `kind` where `receiver` is the lambda expression. */ +predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) { none() } + +/** Extra data-flow steps needed for lamba flow analysis. */ +predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() } From c684b74b3df89d67f9dace66f0b29c6f123960ae Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 16 Mar 2021 14:46:16 +0100 Subject: [PATCH 126/725] C#: Add async dataflow tests --- .../library-tests/dataflow/async/Async.cs | 50 +++++++++++++++++++ .../dataflow/async/Async.expected | 29 +++++++++++ .../library-tests/dataflow/async/Async.ql | 33 ++++++++++++ 3 files changed, 112 insertions(+) create mode 100644 csharp/ql/test/library-tests/dataflow/async/Async.cs create mode 100644 csharp/ql/test/library-tests/dataflow/async/Async.expected create mode 100644 csharp/ql/test/library-tests/dataflow/async/Async.ql diff --git a/csharp/ql/test/library-tests/dataflow/async/Async.cs b/csharp/ql/test/library-tests/dataflow/async/Async.cs new file mode 100644 index 00000000000..94adc7eb94a --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/async/Async.cs @@ -0,0 +1,50 @@ +using System.Threading.Tasks; + +class Test +{ + private void Sink(string s) + { + } + + public void TestNonAwait(string input) + { + Sink(Return(input)); // True positive + } + + private string Return(string x) + { + return x; + } + + public async Task TestAwait1(string input) + { + Sink(await ReturnAwait(input)); // False negative + } + + public async Task TestAwait2(string input) + { + var x = await ReturnAwait(input); + Sink(x); // False negative + } + + public void TestAwait3(string input) + { + Sink(ReturnAwait(input).Result); // False negative + } + + private async Task ReturnAwait(string x) + { + await Task.Delay(1); + return x; + } + + public void TestTask(string input) + { + Sink(ReturnTask(input).Result); // True positive + } + + private Task ReturnTask(string x) + { + return Task.FromResult(x); + } +} \ No newline at end of file diff --git a/csharp/ql/test/library-tests/dataflow/async/Async.expected b/csharp/ql/test/library-tests/dataflow/async/Async.expected new file mode 100644 index 00000000000..bb186ed405b --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/async/Async.expected @@ -0,0 +1,29 @@ +edges +| Async.cs:9:37:9:41 | input : String | Async.cs:11:21:11:25 | access to parameter input : String | +| Async.cs:11:21:11:25 | access to parameter input : String | Async.cs:11:14:11:26 | call to method Return | +| Async.cs:14:34:14:34 | x : String | Async.cs:16:16:16:16 | access to parameter x : String | +| Async.cs:16:16:16:16 | access to parameter x : String | Async.cs:11:14:11:26 | call to method Return | +| Async.cs:41:33:41:37 | input : String | Async.cs:43:25:43:29 | access to parameter input : String | +| Async.cs:43:14:43:30 | call to method ReturnTask [Result] : String | Async.cs:43:14:43:37 | access to property Result | +| Async.cs:43:25:43:29 | access to parameter input : String | Async.cs:43:14:43:30 | call to method ReturnTask [Result] : String | +| Async.cs:46:44:46:44 | x : String | Async.cs:48:32:48:32 | access to parameter x : String | +| Async.cs:48:16:48:33 | call to method FromResult [Result] : String | Async.cs:43:14:43:30 | call to method ReturnTask [Result] : String | +| Async.cs:48:32:48:32 | access to parameter x : String | Async.cs:48:16:48:33 | call to method FromResult [Result] : String | +nodes +| Async.cs:9:37:9:41 | input : String | semmle.label | input : String | +| Async.cs:11:14:11:26 | call to method Return | semmle.label | call to method Return | +| Async.cs:11:21:11:25 | access to parameter input : String | semmle.label | access to parameter input : String | +| Async.cs:14:34:14:34 | x : String | semmle.label | x : String | +| Async.cs:16:16:16:16 | access to parameter x : String | semmle.label | access to parameter x : String | +| Async.cs:41:33:41:37 | input : String | semmle.label | input : String | +| Async.cs:43:14:43:30 | call to method ReturnTask [Result] : String | semmle.label | call to method ReturnTask [Result] : String | +| Async.cs:43:14:43:37 | access to property Result | semmle.label | access to property Result | +| Async.cs:43:25:43:29 | access to parameter input : String | semmle.label | access to parameter input : String | +| Async.cs:46:44:46:44 | x : String | semmle.label | x : String | +| Async.cs:48:16:48:33 | call to method FromResult [Result] : String | semmle.label | call to method FromResult [Result] : String | +| Async.cs:48:32:48:32 | access to parameter x : String | semmle.label | access to parameter x : String | +#select +| Async.cs:11:14:11:26 | call to method Return | Async.cs:9:37:9:41 | input : String | Async.cs:11:14:11:26 | call to method Return | $@ flows to here and is used. | Async.cs:9:37:9:41 | input | User-provided value | +| Async.cs:11:14:11:26 | call to method Return | Async.cs:14:34:14:34 | x : String | Async.cs:11:14:11:26 | call to method Return | $@ flows to here and is used. | Async.cs:14:34:14:34 | x | User-provided value | +| Async.cs:43:14:43:37 | access to property Result | Async.cs:41:33:41:37 | input : String | Async.cs:43:14:43:37 | access to property Result | $@ flows to here and is used. | Async.cs:41:33:41:37 | input | User-provided value | +| Async.cs:43:14:43:37 | access to property Result | Async.cs:46:44:46:44 | x : String | Async.cs:43:14:43:37 | access to property Result | $@ flows to here and is used. | Async.cs:46:44:46:44 | x | User-provided value | diff --git a/csharp/ql/test/library-tests/dataflow/async/Async.ql b/csharp/ql/test/library-tests/dataflow/async/Async.ql new file mode 100644 index 00000000000..71799e22f8a --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/async/Async.ql @@ -0,0 +1,33 @@ +import csharp +import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph + +class MySink extends DataFlow::ExprNode { + MySink() { + exists(Method m, MethodCall mc | + mc.getTarget() = m and + m.getName() = "Sink" and + this.getExpr() = mc.getArgumentForName("s") + ) + } +} + +class MySource extends DataFlow::ParameterNode { + MySource() { + exists(Parameter p | p = this.getParameter() | + p = any(Class c | c.hasQualifiedName("Test")).getAMethod().getAParameter() + ) + } +} + +class MyConfig extends TaintTracking::Configuration { + MyConfig() { this = "MyConfig" } + + override predicate isSource(DataFlow::Node source) { source instanceof MySource } + + override predicate isSink(DataFlow::Node sink) { sink instanceof MySink } +} + +from MyConfig c, DataFlow::PathNode source, DataFlow::PathNode sink +where c.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "$@ flows to here and is used.", source.getNode(), + "User-provided value" From 732ef92830d9a3e148a3e1b06d10661677152eef Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 16 Mar 2021 15:18:00 +0100 Subject: [PATCH 127/725] C#: add store step for return statements inside async methods --- .../dataflow/internal/DataFlowPrivate.qll | 35 +++++++++++++++++++ .../library-tests/dataflow/async/Async.cs | 10 +++--- .../dataflow/async/Async.expected | 35 +++++++++++++++++++ 3 files changed, 75 insertions(+), 5 deletions(-) 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 5e3ac64f7c2..a140b48a423 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -632,6 +632,9 @@ private module Cached { TYieldReturnNode(ControlFlow::Nodes::ElementNode cfn) { any(Callable c).canYieldReturn(cfn.getElement()) } or + TAsyncReturnNode(ControlFlow::Nodes::ElementNode cfn) { + any(Callable c | c.(Modifiable).isAsync()).canReturn(cfn.getElement()) + } or TImplicitCapturedArgumentNode(ControlFlow::Nodes::ElementNode cfn, LocalScopeVariable v) { exists(Ssa::ExplicitDefinition def | def.isCapturedVariableDefinitionFlowIn(_, cfn, _) | v = def.getSourceVariable().getAssignable() @@ -783,6 +786,12 @@ private module Cached { c instanceof ElementContent ) or + exists(Expr e | + e = node1.asExpr() and + node2.(AsyncReturnNode).getReturnStmt().getExpr() = e and + c = getResultContent() + ) + or FlowSummaryImpl::Private::storeStep(node1, c, node2) } @@ -962,6 +971,8 @@ private module Cached { or n instanceof YieldReturnNode or + n instanceof AsyncReturnNode + or n instanceof ImplicitCapturedArgumentNode or n instanceof MallocNode @@ -1397,6 +1408,30 @@ private module ReturnNodes { override string toStringImpl() { result = yrs.toString() } } + /** + * A synthesized `return` node for returned expressions inside `async` methods. + */ + class AsyncReturnNode extends ReturnNode, NodeImpl, TAsyncReturnNode { + private ControlFlow::Nodes::ElementNode cfn; + private ReturnStmt rs; + + AsyncReturnNode() { this = TAsyncReturnNode(cfn) and rs.getExpr().getAControlFlowNode() = cfn } + + ReturnStmt getReturnStmt() { result = rs } + + override NormalReturnKind getKind() { any() } + + override Callable getEnclosingCallableImpl() { result = rs.getEnclosingCallable() } + + override Type getTypeImpl() { result = rs.getEnclosingCallable().getReturnType() } + + override ControlFlow::Node getControlFlowNodeImpl() { result = cfn } + + override Location getLocationImpl() { result = rs.getLocation() } + + override string toStringImpl() { result = rs.toString() } + } + /** * The value of a captured variable as an implicit return from a call, viewed * as a node in a data flow graph. diff --git a/csharp/ql/test/library-tests/dataflow/async/Async.cs b/csharp/ql/test/library-tests/dataflow/async/Async.cs index 94adc7eb94a..7040b5d4507 100644 --- a/csharp/ql/test/library-tests/dataflow/async/Async.cs +++ b/csharp/ql/test/library-tests/dataflow/async/Async.cs @@ -8,7 +8,7 @@ class Test public void TestNonAwait(string input) { - Sink(Return(input)); // True positive + Sink(Return(input)); } private string Return(string x) @@ -18,18 +18,18 @@ class Test public async Task TestAwait1(string input) { - Sink(await ReturnAwait(input)); // False negative + Sink(await ReturnAwait(input)); } public async Task TestAwait2(string input) { var x = await ReturnAwait(input); - Sink(x); // False negative + Sink(x); } public void TestAwait3(string input) { - Sink(ReturnAwait(input).Result); // False negative + Sink(ReturnAwait(input).Result); } private async Task ReturnAwait(string x) @@ -40,7 +40,7 @@ class Test public void TestTask(string input) { - Sink(ReturnTask(input).Result); // True positive + Sink(ReturnTask(input).Result); } private Task ReturnTask(string x) diff --git a/csharp/ql/test/library-tests/dataflow/async/Async.expected b/csharp/ql/test/library-tests/dataflow/async/Async.expected index bb186ed405b..7afc9cf0e9f 100644 --- a/csharp/ql/test/library-tests/dataflow/async/Async.expected +++ b/csharp/ql/test/library-tests/dataflow/async/Async.expected @@ -3,6 +3,20 @@ edges | Async.cs:11:21:11:25 | access to parameter input : String | Async.cs:11:14:11:26 | call to method Return | | Async.cs:14:34:14:34 | x : String | Async.cs:16:16:16:16 | access to parameter x : String | | Async.cs:16:16:16:16 | access to parameter x : String | Async.cs:11:14:11:26 | call to method Return | +| Async.cs:19:41:19:45 | input : String | Async.cs:21:32:21:36 | access to parameter input : String | +| Async.cs:21:20:21:37 | call to method ReturnAwait [Result] : String | Async.cs:21:14:21:37 | await ... | +| Async.cs:21:32:21:36 | access to parameter input : String | Async.cs:21:20:21:37 | call to method ReturnAwait [Result] : String | +| Async.cs:24:41:24:45 | input : String | Async.cs:26:35:26:39 | access to parameter input : String | +| Async.cs:26:17:26:40 | await ... : String | Async.cs:27:14:27:14 | access to local variable x | +| Async.cs:26:23:26:40 | call to method ReturnAwait [Result] : String | Async.cs:26:17:26:40 | await ... : String | +| Async.cs:26:35:26:39 | access to parameter input : String | Async.cs:26:23:26:40 | call to method ReturnAwait [Result] : String | +| Async.cs:30:35:30:39 | input : String | Async.cs:32:26:32:30 | access to parameter input : String | +| Async.cs:32:14:32:31 | call to method ReturnAwait [Result] : String | Async.cs:32:14:32:38 | access to property Result | +| Async.cs:32:26:32:30 | access to parameter input : String | Async.cs:32:14:32:31 | call to method ReturnAwait [Result] : String | +| Async.cs:35:51:35:51 | x : String | Async.cs:38:16:38:16 | access to parameter x : String | +| Async.cs:38:16:38:16 | access to parameter x : String | Async.cs:21:20:21:37 | call to method ReturnAwait [Result] : String | +| Async.cs:38:16:38:16 | access to parameter x : String | Async.cs:26:23:26:40 | call to method ReturnAwait [Result] : String | +| Async.cs:38:16:38:16 | access to parameter x : String | Async.cs:32:14:32:31 | call to method ReturnAwait [Result] : String | | Async.cs:41:33:41:37 | input : String | Async.cs:43:25:43:29 | access to parameter input : String | | Async.cs:43:14:43:30 | call to method ReturnTask [Result] : String | Async.cs:43:14:43:37 | access to property Result | | Async.cs:43:25:43:29 | access to parameter input : String | Async.cs:43:14:43:30 | call to method ReturnTask [Result] : String | @@ -15,6 +29,21 @@ nodes | Async.cs:11:21:11:25 | access to parameter input : String | semmle.label | access to parameter input : String | | Async.cs:14:34:14:34 | x : String | semmle.label | x : String | | Async.cs:16:16:16:16 | access to parameter x : String | semmle.label | access to parameter x : String | +| Async.cs:19:41:19:45 | input : String | semmle.label | input : String | +| Async.cs:21:14:21:37 | await ... | semmle.label | await ... | +| Async.cs:21:20:21:37 | call to method ReturnAwait [Result] : String | semmle.label | call to method ReturnAwait [Result] : String | +| Async.cs:21:32:21:36 | access to parameter input : String | semmle.label | access to parameter input : String | +| Async.cs:24:41:24:45 | input : String | semmle.label | input : String | +| Async.cs:26:17:26:40 | await ... : String | semmle.label | await ... : String | +| Async.cs:26:23:26:40 | call to method ReturnAwait [Result] : String | semmle.label | call to method ReturnAwait [Result] : String | +| Async.cs:26:35:26:39 | access to parameter input : String | semmle.label | access to parameter input : String | +| Async.cs:27:14:27:14 | access to local variable x | semmle.label | access to local variable x | +| Async.cs:30:35:30:39 | input : String | semmle.label | input : String | +| Async.cs:32:14:32:31 | call to method ReturnAwait [Result] : String | semmle.label | call to method ReturnAwait [Result] : String | +| Async.cs:32:14:32:38 | access to property Result | semmle.label | access to property Result | +| Async.cs:32:26:32:30 | access to parameter input : String | semmle.label | access to parameter input : String | +| Async.cs:35:51:35:51 | x : String | semmle.label | x : String | +| Async.cs:38:16:38:16 | access to parameter x : String | semmle.label | access to parameter x : String | | Async.cs:41:33:41:37 | input : String | semmle.label | input : String | | Async.cs:43:14:43:30 | call to method ReturnTask [Result] : String | semmle.label | call to method ReturnTask [Result] : String | | Async.cs:43:14:43:37 | access to property Result | semmle.label | access to property Result | @@ -25,5 +54,11 @@ nodes #select | Async.cs:11:14:11:26 | call to method Return | Async.cs:9:37:9:41 | input : String | Async.cs:11:14:11:26 | call to method Return | $@ flows to here and is used. | Async.cs:9:37:9:41 | input | User-provided value | | Async.cs:11:14:11:26 | call to method Return | Async.cs:14:34:14:34 | x : String | Async.cs:11:14:11:26 | call to method Return | $@ flows to here and is used. | Async.cs:14:34:14:34 | x | User-provided value | +| Async.cs:21:14:21:37 | await ... | Async.cs:19:41:19:45 | input : String | Async.cs:21:14:21:37 | await ... | $@ flows to here and is used. | Async.cs:19:41:19:45 | input | User-provided value | +| Async.cs:21:14:21:37 | await ... | Async.cs:35:51:35:51 | x : String | Async.cs:21:14:21:37 | await ... | $@ flows to here and is used. | Async.cs:35:51:35:51 | x | User-provided value | +| Async.cs:27:14:27:14 | access to local variable x | Async.cs:24:41:24:45 | input : String | Async.cs:27:14:27:14 | access to local variable x | $@ flows to here and is used. | Async.cs:24:41:24:45 | input | User-provided value | +| Async.cs:27:14:27:14 | access to local variable x | Async.cs:35:51:35:51 | x : String | Async.cs:27:14:27:14 | access to local variable x | $@ flows to here and is used. | Async.cs:35:51:35:51 | x | User-provided value | +| Async.cs:32:14:32:38 | access to property Result | Async.cs:30:35:30:39 | input : String | Async.cs:32:14:32:38 | access to property Result | $@ flows to here and is used. | Async.cs:30:35:30:39 | input | User-provided value | +| Async.cs:32:14:32:38 | access to property Result | Async.cs:35:51:35:51 | x : String | Async.cs:32:14:32:38 | access to property Result | $@ flows to here and is used. | Async.cs:35:51:35:51 | x | User-provided value | | Async.cs:43:14:43:37 | access to property Result | Async.cs:41:33:41:37 | input : String | Async.cs:43:14:43:37 | access to property Result | $@ flows to here and is used. | Async.cs:41:33:41:37 | input | User-provided value | | Async.cs:43:14:43:37 | access to property Result | Async.cs:46:44:46:44 | x : String | Async.cs:43:14:43:37 | access to property Result | $@ flows to here and is used. | Async.cs:46:44:46:44 | x | User-provided value | From aa2abf76baae17b76b9a85cfc13443c15b55b475 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 16 Mar 2021 16:17:27 +0100 Subject: [PATCH 128/725] Make ReturnNodes disjoint (normal, yield, async) --- .../code/csharp/dataflow/internal/DataFlowPrivate.qll | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) 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 a140b48a423..cc39631f8b5 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -1354,14 +1354,12 @@ abstract class ReturnNode extends Node { private module ReturnNodes { /** * A data-flow node that represents an expression returned by a callable, - * either using a (`yield`) `return` statement or an expression body (`=>`). + * either using a `return` statement or an expression body (`=>`). */ class ExprReturnNode extends ReturnNode, ExprNode { ExprReturnNode() { exists(DotNet::Callable c, DotNet::Expr e | e = this.getExpr() | - c.canReturn(e) - or - c.(Callable).canYieldReturn(e) + c.canReturn(e) and not c.(Modifiable).isAsync() ) } From 048c72a0f230e28b19ac84b5c816e5e3f24276ba Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 16 Mar 2021 16:20:04 +0100 Subject: [PATCH 129/725] C#: Remove YieldReturnKind --- .../dataflow/internal/DataFlowDispatch.qll | 6 ------ .../dataflow/internal/DataFlowPrivate.qll | 20 +------------------ 2 files changed, 1 insertion(+), 25 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll index c68ba38e0b5..ce6c9976ac8 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll @@ -82,7 +82,6 @@ private module Cached { cached newtype TReturnKind = TNormalReturnKind() { Stages::DataFlowStage::forceCachingInSameStage() } or - TYieldReturnKind() or TOutReturnKind(int i) { exists(Parameter p | callableReturnsOutOrRef(_, p, _) and p.isOut() | i = p.getPosition()) } or @@ -200,11 +199,6 @@ class NormalReturnKind extends ReturnKind, TNormalReturnKind { override string toString() { result = "return" } } -/** A value returned from a callable using a `yield return` statement. */ -class YieldReturnKind extends ReturnKind, TYieldReturnKind { - override string toString() { result = "yield return" } -} - /** A value returned from a callable using an `out` or a `ref` parameter. */ abstract class OutRefReturnKind extends ReturnKind { /** Gets the position of the `out`/`ref` parameter. */ 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 cc39631f8b5..061858ab316 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -1393,7 +1393,7 @@ private module ReturnNodes { YieldReturnStmt getYieldReturnStmt() { result = yrs } - override YieldReturnKind getKind() { any() } + override NormalReturnKind getKind() { any() } override Callable getEnclosingCallableImpl() { result = yrs.getEnclosingCallable() } @@ -1516,21 +1516,6 @@ private module OutNodes { result = TExplicitDelegateLikeCall(cfn, e) } - /** A valid return type for a method that uses `yield return`. */ - private class YieldReturnType extends Type { - YieldReturnType() { - exists(Type t | t = this.getUnboundDeclaration() | - t instanceof SystemCollectionsIEnumerableInterface - or - t instanceof SystemCollectionsIEnumeratorInterface - or - t instanceof SystemCollectionsGenericIEnumerableTInterface - or - t instanceof SystemCollectionsGenericIEnumeratorInterface - ) - } - } - /** * A data-flow node that reads a value returned directly by a callable, * either via a C# call or a CIL call. @@ -1551,9 +1536,6 @@ private module OutNodes { ( kind instanceof NormalReturnKind and not call.getExpr().getType() instanceof VoidType - or - kind instanceof YieldReturnKind and - call.getExpr().getType() instanceof YieldReturnType ) } } From 2541e9cb6a9d97b159d15d8f8deddbb3aecef3e2 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 16 Mar 2021 16:32:47 +0100 Subject: [PATCH 130/725] C#: Handle async data flow in expression bodied callables --- csharp/ql/src/semmle/code/csharp/Callable.qll | 7 ++++++- .../dataflow/internal/DataFlowPrivate.qll | 16 +++++++------- .../library-tests/dataflow/async/Async.cs | 4 +++- .../dataflow/async/Async.expected | 21 +++++++++++-------- 4 files changed, 29 insertions(+), 19 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/Callable.qll b/csharp/ql/src/semmle/code/csharp/Callable.qll index 6dc7cfced9b..83e1739be89 100644 --- a/csharp/ql/src/semmle/code/csharp/Callable.qll +++ b/csharp/ql/src/semmle/code/csharp/Callable.qll @@ -11,6 +11,7 @@ private import dotnet private import semmle.code.csharp.ExprOrStmtParent private import semmle.code.csharp.metrics.Complexity private import TypeRef +private import semmle.code.csharp.frameworks.system.threading.Tasks /** * An element that can be called. @@ -206,7 +207,11 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal exists(ReturnStmt ret | ret.getEnclosingCallable() = this | e = ret.getExpr()) or e = this.getExpressionBody() and - not this.getReturnType() instanceof VoidType + not this.getReturnType() instanceof VoidType and + ( + not this.(Modifiable).isAsync() or + not this.getReturnType() instanceof SystemThreadingTasksTaskClass + ) } /** Holds if this callable can yield return the expression `e`. */ 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 061858ab316..e816d376799 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -788,7 +788,7 @@ private module Cached { or exists(Expr e | e = node1.asExpr() and - node2.(AsyncReturnNode).getReturnStmt().getExpr() = e and + node2.(AsyncReturnNode).getExpr() = e and c = getResultContent() ) or @@ -1411,23 +1411,23 @@ private module ReturnNodes { */ class AsyncReturnNode extends ReturnNode, NodeImpl, TAsyncReturnNode { private ControlFlow::Nodes::ElementNode cfn; - private ReturnStmt rs; + private Expr expr; - AsyncReturnNode() { this = TAsyncReturnNode(cfn) and rs.getExpr().getAControlFlowNode() = cfn } + AsyncReturnNode() { this = TAsyncReturnNode(cfn) and expr = cfn.getElement() } - ReturnStmt getReturnStmt() { result = rs } + Expr getExpr() { result = expr } override NormalReturnKind getKind() { any() } - override Callable getEnclosingCallableImpl() { result = rs.getEnclosingCallable() } + override Callable getEnclosingCallableImpl() { result = expr.getEnclosingCallable() } - override Type getTypeImpl() { result = rs.getEnclosingCallable().getReturnType() } + override Type getTypeImpl() { result = expr.getEnclosingCallable().getReturnType() } override ControlFlow::Node getControlFlowNodeImpl() { result = cfn } - override Location getLocationImpl() { result = rs.getLocation() } + override Location getLocationImpl() { result = expr.getLocation() } - override string toStringImpl() { result = rs.toString() } + override string toStringImpl() { result = expr.toString() } } /** diff --git a/csharp/ql/test/library-tests/dataflow/async/Async.cs b/csharp/ql/test/library-tests/dataflow/async/Async.cs index 7040b5d4507..feb30fbbc49 100644 --- a/csharp/ql/test/library-tests/dataflow/async/Async.cs +++ b/csharp/ql/test/library-tests/dataflow/async/Async.cs @@ -29,7 +29,7 @@ class Test public void TestAwait3(string input) { - Sink(ReturnAwait(input).Result); + Sink(ReturnAwait2(input).Result); } private async Task ReturnAwait(string x) @@ -47,4 +47,6 @@ class Test { return Task.FromResult(x); } + + private async Task ReturnAwait2(string x) => x; } \ No newline at end of file diff --git a/csharp/ql/test/library-tests/dataflow/async/Async.expected b/csharp/ql/test/library-tests/dataflow/async/Async.expected index 7afc9cf0e9f..1b7ec20d98e 100644 --- a/csharp/ql/test/library-tests/dataflow/async/Async.expected +++ b/csharp/ql/test/library-tests/dataflow/async/Async.expected @@ -10,19 +10,20 @@ edges | Async.cs:26:17:26:40 | await ... : String | Async.cs:27:14:27:14 | access to local variable x | | Async.cs:26:23:26:40 | call to method ReturnAwait [Result] : String | Async.cs:26:17:26:40 | await ... : String | | Async.cs:26:35:26:39 | access to parameter input : String | Async.cs:26:23:26:40 | call to method ReturnAwait [Result] : String | -| Async.cs:30:35:30:39 | input : String | Async.cs:32:26:32:30 | access to parameter input : String | -| Async.cs:32:14:32:31 | call to method ReturnAwait [Result] : String | Async.cs:32:14:32:38 | access to property Result | -| Async.cs:32:26:32:30 | access to parameter input : String | Async.cs:32:14:32:31 | call to method ReturnAwait [Result] : String | +| Async.cs:30:35:30:39 | input : String | Async.cs:32:27:32:31 | access to parameter input : String | +| Async.cs:32:14:32:32 | call to method ReturnAwait2 [Result] : String | Async.cs:32:14:32:39 | access to property Result | +| Async.cs:32:27:32:31 | access to parameter input : String | Async.cs:32:14:32:32 | call to method ReturnAwait2 [Result] : String | | Async.cs:35:51:35:51 | x : String | Async.cs:38:16:38:16 | access to parameter x : String | | Async.cs:38:16:38:16 | access to parameter x : String | Async.cs:21:20:21:37 | call to method ReturnAwait [Result] : String | | Async.cs:38:16:38:16 | access to parameter x : String | Async.cs:26:23:26:40 | call to method ReturnAwait [Result] : String | -| Async.cs:38:16:38:16 | access to parameter x : String | Async.cs:32:14:32:31 | call to method ReturnAwait [Result] : String | | Async.cs:41:33:41:37 | input : String | Async.cs:43:25:43:29 | access to parameter input : String | | Async.cs:43:14:43:30 | call to method ReturnTask [Result] : String | Async.cs:43:14:43:37 | access to property Result | | Async.cs:43:25:43:29 | access to parameter input : String | Async.cs:43:14:43:30 | call to method ReturnTask [Result] : String | | Async.cs:46:44:46:44 | x : String | Async.cs:48:32:48:32 | access to parameter x : String | | Async.cs:48:16:48:33 | call to method FromResult [Result] : String | Async.cs:43:14:43:30 | call to method ReturnTask [Result] : String | | Async.cs:48:32:48:32 | access to parameter x : String | Async.cs:48:16:48:33 | call to method FromResult [Result] : String | +| Async.cs:51:52:51:52 | x : String | Async.cs:51:58:51:58 | access to parameter x : String | +| Async.cs:51:58:51:58 | access to parameter x : String | Async.cs:32:14:32:32 | call to method ReturnAwait2 [Result] : String | nodes | Async.cs:9:37:9:41 | input : String | semmle.label | input : String | | Async.cs:11:14:11:26 | call to method Return | semmle.label | call to method Return | @@ -39,9 +40,9 @@ nodes | Async.cs:26:35:26:39 | access to parameter input : String | semmle.label | access to parameter input : String | | Async.cs:27:14:27:14 | access to local variable x | semmle.label | access to local variable x | | Async.cs:30:35:30:39 | input : String | semmle.label | input : String | -| Async.cs:32:14:32:31 | call to method ReturnAwait [Result] : String | semmle.label | call to method ReturnAwait [Result] : String | -| Async.cs:32:14:32:38 | access to property Result | semmle.label | access to property Result | -| Async.cs:32:26:32:30 | access to parameter input : String | semmle.label | access to parameter input : String | +| Async.cs:32:14:32:32 | call to method ReturnAwait2 [Result] : String | semmle.label | call to method ReturnAwait2 [Result] : String | +| Async.cs:32:14:32:39 | access to property Result | semmle.label | access to property Result | +| Async.cs:32:27:32:31 | access to parameter input : String | semmle.label | access to parameter input : String | | Async.cs:35:51:35:51 | x : String | semmle.label | x : String | | Async.cs:38:16:38:16 | access to parameter x : String | semmle.label | access to parameter x : String | | Async.cs:41:33:41:37 | input : String | semmle.label | input : String | @@ -51,6 +52,8 @@ nodes | Async.cs:46:44:46:44 | x : String | semmle.label | x : String | | Async.cs:48:16:48:33 | call to method FromResult [Result] : String | semmle.label | call to method FromResult [Result] : String | | Async.cs:48:32:48:32 | access to parameter x : String | semmle.label | access to parameter x : String | +| Async.cs:51:52:51:52 | x : String | semmle.label | x : String | +| Async.cs:51:58:51:58 | access to parameter x : String | semmle.label | access to parameter x : String | #select | Async.cs:11:14:11:26 | call to method Return | Async.cs:9:37:9:41 | input : String | Async.cs:11:14:11:26 | call to method Return | $@ flows to here and is used. | Async.cs:9:37:9:41 | input | User-provided value | | Async.cs:11:14:11:26 | call to method Return | Async.cs:14:34:14:34 | x : String | Async.cs:11:14:11:26 | call to method Return | $@ flows to here and is used. | Async.cs:14:34:14:34 | x | User-provided value | @@ -58,7 +61,7 @@ nodes | Async.cs:21:14:21:37 | await ... | Async.cs:35:51:35:51 | x : String | Async.cs:21:14:21:37 | await ... | $@ flows to here and is used. | Async.cs:35:51:35:51 | x | User-provided value | | Async.cs:27:14:27:14 | access to local variable x | Async.cs:24:41:24:45 | input : String | Async.cs:27:14:27:14 | access to local variable x | $@ flows to here and is used. | Async.cs:24:41:24:45 | input | User-provided value | | Async.cs:27:14:27:14 | access to local variable x | Async.cs:35:51:35:51 | x : String | Async.cs:27:14:27:14 | access to local variable x | $@ flows to here and is used. | Async.cs:35:51:35:51 | x | User-provided value | -| Async.cs:32:14:32:38 | access to property Result | Async.cs:30:35:30:39 | input : String | Async.cs:32:14:32:38 | access to property Result | $@ flows to here and is used. | Async.cs:30:35:30:39 | input | User-provided value | -| Async.cs:32:14:32:38 | access to property Result | Async.cs:35:51:35:51 | x : String | Async.cs:32:14:32:38 | access to property Result | $@ flows to here and is used. | Async.cs:35:51:35:51 | x | User-provided value | +| Async.cs:32:14:32:39 | access to property Result | Async.cs:30:35:30:39 | input : String | Async.cs:32:14:32:39 | access to property Result | $@ flows to here and is used. | Async.cs:30:35:30:39 | input | User-provided value | +| Async.cs:32:14:32:39 | access to property Result | Async.cs:51:52:51:52 | x : String | Async.cs:32:14:32:39 | access to property Result | $@ flows to here and is used. | Async.cs:51:52:51:52 | x | User-provided value | | Async.cs:43:14:43:37 | access to property Result | Async.cs:41:33:41:37 | input : String | Async.cs:43:14:43:37 | access to property Result | $@ flows to here and is used. | Async.cs:41:33:41:37 | input | User-provided value | | Async.cs:43:14:43:37 | access to property Result | Async.cs:46:44:46:44 | x : String | Async.cs:43:14:43:37 | access to property Result | $@ flows to here and is used. | Async.cs:46:44:46:44 | x | User-provided value | From cd820917bc957497951fa9158fea990c6fb67025 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 16 Mar 2021 21:28:58 +0100 Subject: [PATCH 131/725] Remove duplicate yield return entries from global dataflow test --- .../dataflow/global/GetAnOutNode.expected | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected b/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected index 5b4957a19e9..318034455b7 100644 --- a/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected +++ b/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected @@ -1,11 +1,9 @@ | Capture.cs:33:9:33:40 | call to method Select | return | Capture.cs:33:9:33:40 | call to method Select | -| Capture.cs:33:9:33:40 | call to method Select | yield return | Capture.cs:33:9:33:40 | call to method Select | | Capture.cs:33:9:33:50 | call to method ToArray | return | Capture.cs:33:9:33:50 | call to method ToArray | | Capture.cs:71:9:71:21 | call to local function CaptureOut1 | captured sink30 | Capture.cs:71:9:71:21 | SSA call def(sink30) | | Capture.cs:83:9:83:21 | [transitive] call to local function CaptureOut2 | captured sink31 | Capture.cs:83:9:83:21 | SSA call def(sink31) | | Capture.cs:92:9:92:41 | [transitive] call to method Select | captured sink32 | Capture.cs:92:9:92:41 | SSA call def(sink32) | | Capture.cs:92:9:92:41 | call to method Select | return | Capture.cs:92:9:92:41 | call to method Select | -| Capture.cs:92:9:92:41 | call to method Select | yield return | Capture.cs:92:9:92:41 | call to method Select | | Capture.cs:92:9:92:51 | call to method ToArray | return | Capture.cs:92:9:92:51 | call to method ToArray | | Capture.cs:121:9:121:35 | [transitive] call to local function CaptureOutMultipleLambdas | captured nonSink0 | Capture.cs:121:9:121:35 | SSA call def(nonSink0) | | Capture.cs:121:9:121:35 | [transitive] call to local function CaptureOutMultipleLambdas | captured sink40 | Capture.cs:121:9:121:35 | SSA call def(sink40) | @@ -13,7 +11,6 @@ | Capture.cs:144:9:144:25 | [transitive] call to local function CaptureThrough2 | captured sink34 | Capture.cs:144:9:144:25 | SSA call def(sink34) | | Capture.cs:153:9:153:45 | [transitive] call to method Select | captured sink35 | Capture.cs:153:9:153:45 | SSA call def(sink35) | | Capture.cs:153:9:153:45 | call to method Select | return | Capture.cs:153:9:153:45 | call to method Select | -| Capture.cs:153:9:153:45 | call to method Select | yield return | Capture.cs:153:9:153:45 | call to method Select | | Capture.cs:153:9:153:55 | call to method ToArray | return | Capture.cs:153:9:153:55 | call to method ToArray | | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 | return | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 | | Capture.cs:168:9:168:32 | call to local function CaptureThrough5 | captured sink37 | Capture.cs:168:9:168:32 | SSA call def(sink37) | @@ -52,16 +49,12 @@ | GlobalDataFlow.cs:79:9:79:46 | call to method ReturnRef | out | GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) | | GlobalDataFlow.cs:79:9:79:46 | call to method ReturnRef | ref | GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) | | GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven | return | GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven | -| GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven | yield return | GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven | | GlobalDataFlow.cs:81:22:81:93 | call to method First | return | GlobalDataFlow.cs:81:22:81:93 | call to method First | | GlobalDataFlow.cs:83:22:83:87 | call to method Select | return | GlobalDataFlow.cs:83:22:83:87 | call to method Select | -| GlobalDataFlow.cs:83:22:83:87 | call to method Select | yield return | GlobalDataFlow.cs:83:22:83:87 | call to method Select | | GlobalDataFlow.cs:83:22:83:95 | call to method First | return | GlobalDataFlow.cs:83:22:83:95 | call to method First | | GlobalDataFlow.cs:85:22:85:128 | call to method Zip | return | GlobalDataFlow.cs:85:22:85:128 | call to method Zip | -| GlobalDataFlow.cs:85:22:85:128 | call to method Zip | yield return | GlobalDataFlow.cs:85:22:85:128 | call to method Zip | | GlobalDataFlow.cs:85:22:85:136 | call to method First | return | GlobalDataFlow.cs:85:22:85:136 | call to method First | | GlobalDataFlow.cs:87:22:87:128 | call to method Zip | return | GlobalDataFlow.cs:87:22:87:128 | call to method Zip | -| GlobalDataFlow.cs:87:22:87:128 | call to method Zip | yield return | GlobalDataFlow.cs:87:22:87:128 | call to method Zip | | GlobalDataFlow.cs:87:22:87:136 | call to method First | return | GlobalDataFlow.cs:87:22:87:136 | call to method First | | GlobalDataFlow.cs:89:22:89:110 | call to method Aggregate | return | GlobalDataFlow.cs:89:22:89:110 | call to method Aggregate | | GlobalDataFlow.cs:91:22:91:110 | call to method Aggregate | return | GlobalDataFlow.cs:91:22:91:110 | call to method Aggregate | @@ -83,16 +76,12 @@ | GlobalDataFlow.cs:111:9:111:49 | call to method ReturnRef | out | GlobalDataFlow.cs:111:30:111:34 | SSA def(sink1) | | GlobalDataFlow.cs:111:9:111:49 | call to method ReturnRef | ref | GlobalDataFlow.cs:111:30:111:34 | SSA def(sink1) | | GlobalDataFlow.cs:113:20:113:86 | call to method SelectEven | return | GlobalDataFlow.cs:113:20:113:86 | call to method SelectEven | -| GlobalDataFlow.cs:113:20:113:86 | call to method SelectEven | yield return | GlobalDataFlow.cs:113:20:113:86 | call to method SelectEven | | GlobalDataFlow.cs:113:20:113:94 | call to method First | return | GlobalDataFlow.cs:113:20:113:94 | call to method First | | GlobalDataFlow.cs:115:20:115:82 | call to method Select | return | GlobalDataFlow.cs:115:20:115:82 | call to method Select | -| GlobalDataFlow.cs:115:20:115:82 | call to method Select | yield return | GlobalDataFlow.cs:115:20:115:82 | call to method Select | | GlobalDataFlow.cs:115:20:115:90 | call to method First | return | GlobalDataFlow.cs:115:20:115:90 | call to method First | | GlobalDataFlow.cs:117:20:117:126 | call to method Zip | return | GlobalDataFlow.cs:117:20:117:126 | call to method Zip | -| GlobalDataFlow.cs:117:20:117:126 | call to method Zip | yield return | GlobalDataFlow.cs:117:20:117:126 | call to method Zip | | GlobalDataFlow.cs:117:20:117:134 | call to method First | return | GlobalDataFlow.cs:117:20:117:134 | call to method First | | GlobalDataFlow.cs:119:20:119:126 | call to method Zip | return | GlobalDataFlow.cs:119:20:119:126 | call to method Zip | -| GlobalDataFlow.cs:119:20:119:126 | call to method Zip | yield return | GlobalDataFlow.cs:119:20:119:126 | call to method Zip | | GlobalDataFlow.cs:119:20:119:134 | call to method First | return | GlobalDataFlow.cs:119:20:119:134 | call to method First | | GlobalDataFlow.cs:121:20:121:104 | call to method Aggregate | return | GlobalDataFlow.cs:121:20:121:104 | call to method Aggregate | | GlobalDataFlow.cs:123:20:123:109 | call to method Aggregate | return | GlobalDataFlow.cs:123:20:123:109 | call to method Aggregate | @@ -119,7 +108,6 @@ | GlobalDataFlow.cs:160:9:160:25 | call to method OutRef | ref | GlobalDataFlow.cs:160:20:160:24 | SSA def(sink8) | | GlobalDataFlow.cs:162:22:162:31 | call to method OutYield | qualifier | GlobalDataFlow.cs:162:22:162:31 | [post] this access | | GlobalDataFlow.cs:162:22:162:31 | call to method OutYield | return | GlobalDataFlow.cs:162:22:162:31 | call to method OutYield | -| GlobalDataFlow.cs:162:22:162:31 | call to method OutYield | yield return | GlobalDataFlow.cs:162:22:162:31 | call to method OutYield | | GlobalDataFlow.cs:162:22:162:39 | call to method First | return | GlobalDataFlow.cs:162:22:162:39 | call to method First | | GlobalDataFlow.cs:164:22:164:43 | call to method TaintedParam | return | GlobalDataFlow.cs:164:22:164:43 | call to method TaintedParam | | GlobalDataFlow.cs:168:20:168:27 | call to method NonOut | qualifier | GlobalDataFlow.cs:168:20:168:27 | [post] this access | @@ -132,7 +120,6 @@ | GlobalDataFlow.cs:172:9:172:31 | call to method NonOutRef | ref | GlobalDataFlow.cs:172:23:172:30 | SSA def(nonSink0) | | GlobalDataFlow.cs:174:20:174:32 | call to method NonOutYield | qualifier | GlobalDataFlow.cs:174:20:174:32 | [post] this access | | GlobalDataFlow.cs:174:20:174:32 | call to method NonOutYield | return | GlobalDataFlow.cs:174:20:174:32 | call to method NonOutYield | -| GlobalDataFlow.cs:174:20:174:32 | call to method NonOutYield | yield return | GlobalDataFlow.cs:174:20:174:32 | call to method NonOutYield | | GlobalDataFlow.cs:174:20:174:40 | call to method First | return | GlobalDataFlow.cs:174:20:174:40 | call to method First | | GlobalDataFlow.cs:176:20:176:44 | call to method NonTaintedParam | return | GlobalDataFlow.cs:176:20:176:44 | call to method NonTaintedParam | | GlobalDataFlow.cs:181:21:181:26 | delegate call | return | GlobalDataFlow.cs:181:21:181:26 | delegate call | @@ -151,26 +138,21 @@ | GlobalDataFlow.cs:209:41:209:77 | call to method AsQueryable | return | GlobalDataFlow.cs:209:41:209:77 | call to method AsQueryable | | GlobalDataFlow.cs:212:76:212:90 | call to method ReturnCheck2 | return | GlobalDataFlow.cs:212:76:212:90 | call to method ReturnCheck2 | | GlobalDataFlow.cs:213:22:213:39 | call to method Select | return | GlobalDataFlow.cs:213:22:213:39 | call to method Select | -| GlobalDataFlow.cs:213:22:213:39 | call to method Select | yield return | GlobalDataFlow.cs:213:22:213:39 | call to method Select | | GlobalDataFlow.cs:213:22:213:47 | call to method First | return | GlobalDataFlow.cs:213:22:213:47 | call to method First | | GlobalDataFlow.cs:215:22:215:39 | call to method Select | return | GlobalDataFlow.cs:215:22:215:39 | call to method Select | | GlobalDataFlow.cs:215:22:215:47 | call to method First | return | GlobalDataFlow.cs:215:22:215:47 | call to method First | | GlobalDataFlow.cs:217:22:217:49 | call to method Select | return | GlobalDataFlow.cs:217:22:217:49 | call to method Select | -| GlobalDataFlow.cs:217:22:217:49 | call to method Select | yield return | GlobalDataFlow.cs:217:22:217:49 | call to method Select | | GlobalDataFlow.cs:217:22:217:57 | call to method First | return | GlobalDataFlow.cs:217:22:217:57 | call to method First | | GlobalDataFlow.cs:222:76:222:92 | call to method NonReturnCheck | return | GlobalDataFlow.cs:222:76:222:92 | call to method NonReturnCheck | | GlobalDataFlow.cs:223:23:223:43 | call to method Select | return | GlobalDataFlow.cs:223:23:223:43 | call to method Select | -| GlobalDataFlow.cs:223:23:223:43 | call to method Select | yield return | GlobalDataFlow.cs:223:23:223:43 | call to method Select | | GlobalDataFlow.cs:223:23:223:51 | call to method First | return | GlobalDataFlow.cs:223:23:223:51 | call to method First | | GlobalDataFlow.cs:225:19:225:39 | call to method Select | return | GlobalDataFlow.cs:225:19:225:39 | call to method Select | | GlobalDataFlow.cs:225:19:225:47 | call to method First | return | GlobalDataFlow.cs:225:19:225:47 | call to method First | | GlobalDataFlow.cs:227:19:227:39 | call to method Select | return | GlobalDataFlow.cs:227:19:227:39 | call to method Select | -| GlobalDataFlow.cs:227:19:227:39 | call to method Select | yield return | GlobalDataFlow.cs:227:19:227:39 | call to method Select | | GlobalDataFlow.cs:227:19:227:47 | call to method First | return | GlobalDataFlow.cs:227:19:227:47 | call to method First | | GlobalDataFlow.cs:229:19:229:39 | call to method Select | return | GlobalDataFlow.cs:229:19:229:39 | call to method Select | | GlobalDataFlow.cs:229:19:229:47 | call to method First | return | GlobalDataFlow.cs:229:19:229:47 | call to method First | | GlobalDataFlow.cs:231:19:231:49 | call to method Select | return | GlobalDataFlow.cs:231:19:231:49 | call to method Select | -| GlobalDataFlow.cs:231:19:231:49 | call to method Select | yield return | GlobalDataFlow.cs:231:19:231:49 | call to method Select | | GlobalDataFlow.cs:231:19:231:57 | call to method First | return | GlobalDataFlow.cs:231:19:231:57 | call to method First | | GlobalDataFlow.cs:238:20:238:49 | call to method Run | return | GlobalDataFlow.cs:238:20:238:49 | call to method Run | | GlobalDataFlow.cs:239:22:239:32 | access to property Result | qualifier | GlobalDataFlow.cs:239:22:239:25 | [post] access to local variable task | From dd6b27df24180f7bcd0e40fc1ed996c301b451b5 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 16 Mar 2021 22:35:47 +0100 Subject: [PATCH 132/725] C++: Fix test annotation. --- cpp/ql/test/library-tests/dataflow/taint-tests/stringstream.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/stringstream.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/stringstream.cpp index 4d28955aaa0..fab96fc878d 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/stringstream.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/stringstream.cpp @@ -38,7 +38,7 @@ void test_stringstream_string(int amount) sink(ss2); // $ ast,ir sink(ss3); // $ ast MISSING: ir sink(ss4); // $ ast,ir - sink(ss5); // $ ast MISSIN,ir + sink(ss5); // $ ast,ir sink(ss1.str()); sink(ss2.str()); // $ ast,ir sink(ss3.str()); // $ ast MISSING: ir From 43fbcc1c8a19a6a02a0f304b5d22579aef96a996 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 16 Mar 2021 22:36:17 +0100 Subject: [PATCH 133/725] C++: Convert all the dataflow configurations to taint configurations. --- .../cpp/ir/dataflow/DefaultTaintTracking.qll | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) 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 7a4581cf31f..33473ebfb58 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll @@ -3,12 +3,12 @@ import semmle.code.cpp.security.Security private import semmle.code.cpp.ir.dataflow.DataFlow private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil private import semmle.code.cpp.ir.dataflow.DataFlow2 -private import semmle.code.cpp.ir.dataflow.DataFlow3 private import semmle.code.cpp.ir.IR private import semmle.code.cpp.ir.dataflow.internal.DataFlowDispatch as Dispatch private import semmle.code.cpp.controlflow.IRGuards private import semmle.code.cpp.models.interfaces.Taint private import semmle.code.cpp.models.interfaces.DataFlow +private import semmle.code.cpp.ir.dataflow.TaintTracking private import semmle.code.cpp.ir.dataflow.TaintTracking2 private import semmle.code.cpp.ir.dataflow.internal.ModelUtil @@ -67,23 +67,23 @@ private DataFlow::Node getNodeForExpr(Expr node) { not argv(node.(VariableAccess).getTarget()) } -private class DefaultTaintTrackingCfg extends DataFlow::Configuration { +private class DefaultTaintTrackingCfg extends TaintTracking::Configuration { DefaultTaintTrackingCfg() { this = "DefaultTaintTrackingCfg" } override predicate isSource(DataFlow::Node source) { source = getNodeForSource(_) } override predicate isSink(DataFlow::Node sink) { exists(adjustedSink(sink)) } - override predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) { + override predicate isAdditionalTaintStep(DataFlow::Node n1, DataFlow::Node n2) { commonTaintStep(n1, n2) } - override predicate isBarrier(DataFlow::Node node) { nodeIsBarrier(node) } + override predicate isSanitizer(DataFlow::Node node) { nodeIsBarrier(node) } - override predicate isBarrierIn(DataFlow::Node node) { nodeIsBarrierIn(node) } + override predicate isSanitizerIn(DataFlow::Node node) { nodeIsBarrierIn(node) } } -private class ToGlobalVarTaintTrackingCfg extends DataFlow::Configuration { +private class ToGlobalVarTaintTrackingCfg extends TaintTracking::Configuration { ToGlobalVarTaintTrackingCfg() { this = "GlobalVarTaintTrackingCfg" } override predicate isSource(DataFlow::Node source) { source = getNodeForSource(_) } @@ -92,7 +92,7 @@ private class ToGlobalVarTaintTrackingCfg extends DataFlow::Configuration { sink.asVariable() instanceof GlobalOrNamespaceVariable } - override predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) { + override predicate isAdditionalTaintStep(DataFlow::Node n1, DataFlow::Node n2) { commonTaintStep(n1, n2) or writesVariable(n1.asInstruction(), n2.asVariable().(GlobalOrNamespaceVariable)) @@ -100,12 +100,12 @@ private class ToGlobalVarTaintTrackingCfg extends DataFlow::Configuration { readsVariable(n2.asInstruction(), n1.asVariable().(GlobalOrNamespaceVariable)) } - override predicate isBarrier(DataFlow::Node node) { nodeIsBarrier(node) } + override predicate isSanitizer(DataFlow::Node node) { nodeIsBarrier(node) } - override predicate isBarrierIn(DataFlow::Node node) { nodeIsBarrierIn(node) } + override predicate isSanitizerIn(DataFlow::Node node) { nodeIsBarrierIn(node) } } -private class FromGlobalVarTaintTrackingCfg extends DataFlow3::Configuration { +private class FromGlobalVarTaintTrackingCfg extends TaintTracking2::Configuration { FromGlobalVarTaintTrackingCfg() { this = "FromGlobalVarTaintTrackingCfg" } override predicate isSource(DataFlow::Node source) { @@ -116,7 +116,7 @@ private class FromGlobalVarTaintTrackingCfg extends DataFlow3::Configuration { override predicate isSink(DataFlow::Node sink) { exists(adjustedSink(sink)) } - override predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) { + override predicate isAdditionalTaintStep(DataFlow::Node n1, DataFlow::Node n2) { commonTaintStep(n1, n2) or // Additional step for flow out of variables. There is no flow _into_ @@ -125,9 +125,9 @@ private class FromGlobalVarTaintTrackingCfg extends DataFlow3::Configuration { readsVariable(n2.asInstruction(), n1.asVariable()) } - override predicate isBarrier(DataFlow::Node node) { nodeIsBarrier(node) } + override predicate isSanitizer(DataFlow::Node node) { nodeIsBarrier(node) } - override predicate isBarrierIn(DataFlow::Node node) { nodeIsBarrierIn(node) } + override predicate isSanitizerIn(DataFlow::Node node) { nodeIsBarrierIn(node) } } private predicate readsVariable(LoadInstruction load, Variable var) { From 98204a15a6ad8c8dd5dfb42269bfdd153cfc1827 Mon Sep 17 00:00:00 2001 From: haby0 Date: Wed, 17 Mar 2021 15:28:04 +0800 Subject: [PATCH 134/725] Fix the problem --- .../Security/CWE/CWE-352/JsonStringLib.qll | 2 +- .../Security/CWE/CWE-352/JsonpInjection.java | 117 ++++++---- .../Security/CWE/CWE-352/JsonpInjection.qhelp | 11 +- .../Security/CWE/CWE-352/JsonpInjection.ql | 24 ++- .../CWE/CWE-352/JsonpInjectionLib.qll | 66 +++--- .../Security/CWE/CWE-598/SensitiveGetQuery.ql | 10 - .../semmle/code/java/frameworks/Servlets.qll | 11 + .../security/CWE-352/JsonpInjection.qlref | 1 - .../JsonpController.java | 105 +++++++-- .../JsonpInjection.expected | 87 ++++++++ .../JsonpInjection.qlref | 1 + .../JsonpInjectionServlet1.java | 0 .../JsonpInjectionServlet2.java | 0 .../RefererFilter.java | 0 .../CWE-352/JsonpInjectionWithFilter/options | 1 + .../JsonpController.java | 107 +++++++-- .../JsonpInjection.expected | 76 +++++++ .../JsonpInjection.qlref | 1 + .../options | 1 + .../JsonpController.java | 203 ++++++++++++++++++ .../JsonpInjection.expected | 92 ++++++++ .../JsonpInjection.qlref | 1 + .../JsonpInjectionServlet1.java | 0 .../JsonpInjectionServlet2.java | 0 .../options | 1 + .../CWE-352/JsonpInjection_1.expected | 60 ------ .../CWE-352/JsonpInjection_2.expected | 78 ------- .../CWE-352/JsonpInjection_3.expected | 66 ------ .../query-tests/security/CWE-352/Readme | 3 - .../security/CWE-352/RefererFilter.java | 43 ---- .../query-tests/security/CWE-352/options | 1 - .../core/annotation/AliasFor.java | 13 +- .../core/io/InputStreamSource.java | 8 + .../org/springframework/core/io/Resource.java | 46 ++++ .../org/springframework/lang/Nullable.java | 13 ++ .../springframework/util/FileCopyUtils.java | 53 +++++ .../org/springframework/util/StringUtils.java | 2 +- .../web/bind/annotation/GetMapping.java | 36 +++- .../web/bind/annotation/Mapping.java | 4 + .../web/bind/annotation/RequestMapping.java | 19 +- .../web/bind/annotation/RequestParam.java | 23 ++ .../web/bind/annotation/ResponseBody.java | 9 + .../web/multipart/MultipartFile.java | 38 ++++ .../javax/servlet/annotation/WebServlet.java | 30 +++ 44 files changed, 1075 insertions(+), 388 deletions(-) delete mode 100644 java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection.qlref rename java/ql/test/experimental/query-tests/security/CWE-352/{ => JsonpInjectionWithFilter}/JsonpController.java (54%) create mode 100644 java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithFilter/JsonpInjection.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithFilter/JsonpInjection.qlref rename java/ql/{src/experimental/Security/CWE/CWE-352 => test/experimental/query-tests/security/CWE-352/JsonpInjectionWithFilter}/JsonpInjectionServlet1.java (100%) rename java/ql/{src/experimental/Security/CWE/CWE-352 => test/experimental/query-tests/security/CWE-352/JsonpInjectionWithFilter}/JsonpInjectionServlet2.java (100%) rename java/ql/{src/experimental/Security/CWE/CWE-352 => test/experimental/query-tests/security/CWE-352/JsonpInjectionWithFilter}/RefererFilter.java (100%) create mode 100644 java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithFilter/options rename java/ql/{src/experimental/Security/CWE/CWE-352 => test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringController}/JsonpController.java (54%) create mode 100644 java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringController/JsonpInjection.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringController/JsonpInjection.qlref create mode 100644 java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringController/options create mode 100644 java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringControllerAndServlet/JsonpController.java create mode 100644 java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringControllerAndServlet/JsonpInjection.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringControllerAndServlet/JsonpInjection.qlref rename java/ql/test/experimental/query-tests/security/CWE-352/{ => JsonpInjectionWithSpringControllerAndServlet}/JsonpInjectionServlet1.java (100%) rename java/ql/test/experimental/query-tests/security/CWE-352/{ => JsonpInjectionWithSpringControllerAndServlet}/JsonpInjectionServlet2.java (100%) create mode 100644 java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringControllerAndServlet/options delete mode 100644 java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection_1.expected delete mode 100644 java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection_2.expected delete mode 100644 java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection_3.expected delete mode 100644 java/ql/test/experimental/query-tests/security/CWE-352/Readme delete mode 100644 java/ql/test/experimental/query-tests/security/CWE-352/RefererFilter.java delete mode 100644 java/ql/test/experimental/query-tests/security/CWE-352/options create mode 100644 java/ql/test/stubs/spring-core-5.3.2/org/springframework/core/io/InputStreamSource.java create mode 100644 java/ql/test/stubs/spring-core-5.3.2/org/springframework/core/io/Resource.java create mode 100644 java/ql/test/stubs/spring-core-5.3.2/org/springframework/lang/Nullable.java create mode 100644 java/ql/test/stubs/spring-core-5.3.2/org/springframework/util/FileCopyUtils.java create mode 100644 java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/bind/annotation/Mapping.java create mode 100644 java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/bind/annotation/RequestParam.java create mode 100644 java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/multipart/MultipartFile.java create mode 100644 java/ql/test/stubs/tomcat-embed-core-9.0.41/javax/servlet/annotation/WebServlet.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-352/JsonStringLib.qll b/java/ql/src/experimental/Security/CWE/CWE-352/JsonStringLib.qll index 0da8bc860d1..5cc52e97e33 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-352/JsonStringLib.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-352/JsonStringLib.qll @@ -3,7 +3,7 @@ import semmle.code.java.dataflow.DataFlow import semmle.code.java.dataflow.FlowSources import DataFlow::PathGraph -/** Json string type data */ +/** Json string type data. */ abstract class JsonpStringSource extends DataFlow::Node { } /** Convert to String using Gson library. */ diff --git a/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.java b/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.java index 8b4e7cc005e..7f479a8c023 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.java +++ b/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.java @@ -1,31 +1,39 @@ import com.alibaba.fastjson.JSONObject; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.Gson; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; import java.io.PrintWriter; import java.util.HashMap; -import java.util.Random; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.multipart.MultipartFile; @Controller public class JsonpInjection { -private static HashMap hashMap = new HashMap(); + + private static HashMap hashMap = new HashMap(); static { hashMap.put("username","admin"); hashMap.put("password","123456"); } + private String name = null; + @GetMapping(value = "jsonp1") @ResponseBody public String bad1(HttpServletRequest request) { String resultStr = null; String jsonpCallback = request.getParameter("jsonpCallback"); - Gson gson = new Gson(); String result = gson.toJson(hashMap); resultStr = jsonpCallback + "(" + result + ")"; @@ -37,9 +45,7 @@ private static HashMap hashMap = new HashMap(); public String bad2(HttpServletRequest request) { String resultStr = null; String jsonpCallback = request.getParameter("jsonpCallback"); - resultStr = jsonpCallback + "(" + JSONObject.toJSONString(hashMap) + ")"; - return resultStr; } @@ -67,7 +73,6 @@ private static HashMap hashMap = new HashMap(); @ResponseBody public void bad5(HttpServletRequest request, HttpServletResponse response) throws Exception { - response.setContentType("application/json"); String jsonpCallback = request.getParameter("jsonpCallback"); PrintWriter pw = null; Gson gson = new Gson(); @@ -83,7 +88,6 @@ private static HashMap hashMap = new HashMap(); @ResponseBody public void bad6(HttpServletRequest request, HttpServletResponse response) throws Exception { - response.setContentType("application/json"); String jsonpCallback = request.getParameter("jsonpCallback"); PrintWriter pw = null; ObjectMapper mapper = new ObjectMapper(); @@ -94,60 +98,96 @@ private static HashMap hashMap = new HashMap(); pw.println(resultStr); } - @GetMapping(value = "jsonp7") + @RequestMapping(value = "jsonp7", method = RequestMethod.GET) @ResponseBody - public String good(HttpServletRequest request) { + public String bad7(HttpServletRequest request) { String resultStr = null; String jsonpCallback = request.getParameter("jsonpCallback"); - - String val = ""; - Random random = new Random(); - for (int i = 0; i < 10; i++) { - val += String.valueOf(random.nextInt(10)); - } - // good - jsonpCallback = jsonpCallback + "_" + val; - String jsonStr = getJsonStr(hashMap); - resultStr = jsonpCallback + "(" + jsonStr + ")"; + Gson gson = new Gson(); + String result = gson.toJson(hashMap); + resultStr = jsonpCallback + "(" + result + ")"; return resultStr; } + @GetMapping(value = "jsonp8") @ResponseBody public String good1(HttpServletRequest request) { String resultStr = null; - String jsonpCallback = request.getParameter("jsonpCallback"); - String token = request.getParameter("token"); - - // good if (verifToken(token)){ - System.out.println(token); + String jsonpCallback = request.getParameter("jsonpCallback"); String jsonStr = getJsonStr(hashMap); resultStr = jsonpCallback + "(" + jsonStr + ")"; return resultStr; } - return "error"; } + @GetMapping(value = "jsonp9") @ResponseBody public String good2(HttpServletRequest request) { String resultStr = null; - String jsonpCallback = request.getParameter("jsonpCallback"); - - String referer = request.getHeader("Referer"); - - boolean result = verifReferer(referer); - // good + String token = request.getParameter("token"); + boolean result = verifToken(token); if (result){ - String jsonStr = getJsonStr(hashMap); - resultStr = jsonpCallback + "(" + jsonStr + ")"; - return resultStr; + return ""; } + String jsonpCallback = request.getParameter("jsonpCallback"); + String jsonStr = getJsonStr(hashMap); + resultStr = jsonpCallback + "(" + jsonStr + ")"; + return resultStr; + } - return "error"; + @RequestMapping(value = "jsonp10") + @ResponseBody + public String good3(HttpServletRequest request) { + JSONObject parameterObj = readToJSONObect(request); + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + String restr = JSONObject.toJSONString(hashMap); + resultStr = jsonpCallback + "(" + restr + ");"; + return resultStr; + } + + @RequestMapping(value = "jsonp11") + @ResponseBody + public String good4(@RequestParam("file") MultipartFile file,HttpServletRequest request) { + if(null == file){ + return "upload file error"; + } + String fileName = file.getOriginalFilename(); + System.out.println("file operations"); + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + String restr = JSONObject.toJSONString(hashMap); + resultStr = jsonpCallback + "(" + restr + ");"; + return resultStr; + } + + public static JSONObject readToJSONObect(HttpServletRequest request){ + String jsonText = readPostContent(request); + JSONObject jsonObj = JSONObject.parseObject(jsonText, JSONObject.class); + return jsonObj; + } + + public static String readPostContent(HttpServletRequest request){ + BufferedReader in= null; + String content = null; + String line = null; + try { + in = new BufferedReader(new InputStreamReader(request.getInputStream(),"UTF-8")); + StringBuilder buf = new StringBuilder(); + while ((line = in.readLine()) != null) { + buf.append(line); + } + content = buf.toString(); + } catch (IOException e) { + e.printStackTrace(); + } + String uri = request.getRequestURI(); + return content; } public static String getJsonStr(Object result) { @@ -160,11 +200,4 @@ private static HashMap hashMap = new HashMap(); } return true; } - - public static boolean verifReferer(String referer){ - if (!referer.startsWith("http://test.com/")){ - return false; - } - return true; - } } \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.qhelp b/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.qhelp index bb5d628ac0b..93c167d6c2c 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.qhelp +++ b/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.qhelp @@ -3,18 +3,21 @@ "qhelp.dtd"> -

    The software uses external input as the function name to wrap JSON data and return it to the client as a request response. When there is a cross-domain problem, -there is a problem of sensitive information leakage.

    +

    The software uses external input as the function name to wrap JSON data and returns it to the client as a request response. +When there is a cross-domain problem, the problem of sensitive information leakage may occur.

    -

    Adding `Referer` or random `token` verification processing can effectively prevent the leakage of sensitive information.

    +

    Adding Referer/Origin or random token verification processing can effectively prevent the leakage of sensitive information.

    -

    The following example shows the case of no verification processing and verification processing for the external input function name.

    +

    The following examples show the bad case and the good case respectively. Bad case, such as bad1 to bad7, +will cause information leakage problems when there are cross-domain problems. In a good case, for example, in the good1 +method and the good2 method, use the verifToken method to do the random token Verification can +solve the problem of information leakage caused by cross-domain.

    diff --git a/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.ql b/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.ql index f3ae25daa03..068469328ea 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.ql @@ -14,25 +14,25 @@ import java import JsonpInjectionLib import semmle.code.java.dataflow.FlowSources import semmle.code.java.deadcode.WebEntryPoints -import semmle.code.java.security.XSS import DataFlow::PathGraph /** Determine whether there is a verification method for the remote streaming source data flow path method. */ predicate existsFilterVerificationMethod() { - exists(MethodAccess ma,Node existsNode, Method m| + exists(MethodAccess ma, Node existsNode, Method m | ma.getMethod() instanceof VerificationMethodClass and existsNode.asExpr() = ma and - m = getAnMethod(existsNode.getEnclosingCallable()) and + m = getACallingCallableOrSelf(existsNode.getEnclosingCallable()) and isDoFilterMethod(m) ) } /** Determine whether there is a verification method for the remote streaming source data flow path method. */ predicate existsServletVerificationMethod(Node checkNode) { - exists(MethodAccess ma,Node existsNode| + exists(MethodAccess ma, Node existsNode | ma.getMethod() instanceof VerificationMethodClass and existsNode.asExpr() = ma and - getAnMethod(existsNode.getEnclosingCallable()) = getAnMethod(checkNode.getEnclosingCallable()) + getACallingCallableOrSelf(existsNode.getEnclosingCallable()) = + getACallingCallableOrSelf(checkNode.getEnclosingCallable()) ) } @@ -40,13 +40,15 @@ predicate existsServletVerificationMethod(Node checkNode) { class RequestResponseFlowConfig extends TaintTracking::Configuration { RequestResponseFlowConfig() { this = "RequestResponseFlowConfig" } - override predicate isSource(DataFlow::Node source) { - source instanceof RemoteFlowSource and - getAnMethod(source.getEnclosingCallable()) instanceof RequestGetMethod - } + override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } override predicate isSink(DataFlow::Node sink) { sink instanceof XssSink } + /** Eliminate the method of calling the node is not the get method. */ + override predicate isSanitizer(DataFlow::Node node) { + not getACallingCallableOrSelf(node.getEnclosingCallable()) instanceof RequestGetMethod + } + override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { exists(MethodAccess ma | isRequestGetParamMethod(ma) and pred.asExpr() = ma.getQualifier() and succ.asExpr() = ma @@ -60,5 +62,5 @@ where not existsFilterVerificationMethod() and conf.hasFlowPath(source, sink) and exists(JsonpInjectionFlowConfig jhfc | jhfc.hasFlowTo(sink.getNode())) -select sink.getNode(), source, sink, "Jsonp Injection query might include code from $@.", - source.getNode(), "this user input" \ No newline at end of file +select sink.getNode(), source, sink, "Jsonp response might include code from $@.", source.getNode(), + "this user input" diff --git a/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjectionLib.qll index b8964524a9f..d0e00bcb634 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjectionLib.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjectionLib.qll @@ -6,28 +6,25 @@ import semmle.code.java.dataflow.DataFlow import semmle.code.java.dataflow.FlowSources import semmle.code.java.frameworks.spring.SpringController -/** Taint-tracking configuration tracing flow from user-controllable function name jsonp data to output jsonp data. */ +/** Taint-tracking configuration tracing flow from untrusted inputs to verification of remote user input. */ class VerificationMethodFlowConfig extends TaintTracking::Configuration { VerificationMethodFlowConfig() { this = "VerificationMethodFlowConfig" } override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource } override predicate isSink(DataFlow::Node sink) { - exists(MethodAccess ma, BarrierGuard bg | + exists(MethodAccess ma | ma.getMethod().getAParameter().getName().regexpMatch("(?i).*(token|auth|referer|origin).*") and - bg = ma and - sink.asExpr() = ma.getAnArgument() + ma.getAnArgument() = sink.asExpr() ) } } -/** The parameter name of the method is `token`, `auth`, `referer`, `origin`. */ +/** The parameter names of this method are token/auth/referer/origin. */ class VerificationMethodClass extends Method { VerificationMethodClass() { - exists(MethodAccess ma, BarrierGuard bg, VerificationMethodFlowConfig vmfc, Node node | + exists(MethodAccess ma, VerificationMethodFlowConfig vmfc, Node node | this = ma.getMethod() and - this.getAParameter().getName().regexpMatch("(?i).*(token|auth|referer|origin).*") and - bg = ma and node.asExpr() = ma.getAnArgument() and vmfc.hasFlowTo(node) ) @@ -35,38 +32,43 @@ class VerificationMethodClass extends Method { } /** Get Callable by recursive method. */ -Callable getAnMethod(Callable call) { +Callable getACallingCallableOrSelf(Callable call) { result = call or - result = getAnMethod(call.getAReference().getEnclosingCallable()) + result = getACallingCallableOrSelf(call.getAReference().getEnclosingCallable()) } abstract class RequestGetMethod extends Method { } -/** Holds if `m` is a method of some override of `HttpServlet.doGet`. */ +/** Override method of `doGet` of `Servlet` subclass. */ private class ServletGetMethod extends RequestGetMethod { - ServletGetMethod() { - exists(Method m | - m = this and - isServletRequestMethod(m) and - m.getName() = "doGet" - ) + ServletGetMethod() { this instanceof DoGetServletMethod } +} + +/** The method of SpringController class processing `get` request. */ +abstract class SpringControllerGetMethod extends RequestGetMethod { } + +/** Method using `GetMapping` annotation in SpringController class. */ +class SpringControllerGetMappingGetMethod extends SpringControllerGetMethod { + SpringControllerGetMappingGetMethod() { + this.getAnAnnotation() + .getType() + .hasQualifiedName("org.springframework.web.bind.annotation", "GetMapping") } } -/** Holds if `m` is a method of some override of `HttpServlet.doGet`. */ -private class SpringControllerGetMethod extends RequestGetMethod { - SpringControllerGetMethod() { - exists(Annotation a | - a = this.getAnAnnotation() and - a.getType().hasQualifiedName("org.springframework.web.bind.annotation", "GetMapping") - ) - or - exists(Annotation a | - a = this.getAnAnnotation() and - a.getType().hasQualifiedName("org.springframework.web.bind.annotation", "RequestMapping") and - a.getValue("method").toString().regexpMatch("RequestMethod.GET|\\{...\\}") - ) +/** The method that uses the `RequestMapping` annotation in the SpringController class and only handles the get request. */ +class SpringControllerRequestMappingGetMethod extends SpringControllerGetMethod { + SpringControllerRequestMappingGetMethod() { + this.getAnAnnotation() + .getType() + .hasQualifiedName("org.springframework.web.bind.annotation", "RequestMapping") and + this.getAnAnnotation().getValue("method").toString().regexpMatch("RequestMethod.GET|\\{...\\}") and + not exists(MethodAccess ma | + ma.getMethod() instanceof ServletRequestGetBodyMethod and + this = getACallingCallableOrSelf(ma.getEnclosingCallable()) + ) and + not this.getAParamType().getName() = "MultipartFile" } } @@ -83,12 +85,12 @@ class JsonpInjectionExpr extends AddExpr { .regexpMatch("\"\\(\"") } - /** Get the jsonp function name of this expression */ + /** Get the jsonp function name of this expression. */ Expr getFunctionName() { result = getLeftOperand().(AddExpr).getLeftOperand().(AddExpr).getLeftOperand() } - /** Get the json data of this expression */ + /** Get the json data of this expression. */ Expr getJsonExpr() { result = getLeftOperand().(AddExpr).getRightOperand() } } diff --git a/java/ql/src/experimental/Security/CWE/CWE-598/SensitiveGetQuery.ql b/java/ql/src/experimental/Security/CWE/CWE-598/SensitiveGetQuery.ql index bc9850cfddb..c381595af14 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-598/SensitiveGetQuery.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-598/SensitiveGetQuery.ql @@ -23,16 +23,6 @@ class SensitiveInfoExpr extends Expr { } } -/** Holds if `m` is a method of some override of `HttpServlet.doGet`. */ -private predicate isGetServletMethod(Method m) { - isServletRequestMethod(m) and m.getName() = "doGet" -} - -/** The `doGet` method of `HttpServlet`. */ -class DoGetServletMethod extends Method { - DoGetServletMethod() { isGetServletMethod(this) } -} - /** Holds if `ma` is (perhaps indirectly) called from the `doGet` method of `HttpServlet`. */ predicate isReachableFromServletDoGet(MethodAccess ma) { ma.getEnclosingCallable() instanceof DoGetServletMethod diff --git a/java/ql/src/semmle/code/java/frameworks/Servlets.qll b/java/ql/src/semmle/code/java/frameworks/Servlets.qll index 5cccf62122f..7ac452affa9 100644 --- a/java/ql/src/semmle/code/java/frameworks/Servlets.qll +++ b/java/ql/src/semmle/code/java/frameworks/Servlets.qll @@ -354,9 +354,20 @@ class FilterChain extends Interface { /** Holds if `m` is a filter handler method (for example `doFilter`). */ predicate isDoFilterMethod(Method m) { + m.getName().matches("doFilter") and m.getDeclaringType() instanceof FilterClass and m.getNumberOfParameters() = 3 and m.getParameter(0).getType() instanceof ServletRequest and m.getParameter(1).getType() instanceof ServletResponse and m.getParameter(2).getType() instanceof FilterChain } + +/** Holds if `m` is a method of some override of `HttpServlet.doGet`. */ +predicate isGetServletMethod(Method m) { + isServletRequestMethod(m) and m.getName() = "doGet" +} + +/** The `doGet` method of `HttpServlet`. */ +class DoGetServletMethod extends Method { + DoGetServletMethod() { isGetServletMethod(this) } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection.qlref b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection.qlref deleted file mode 100644 index 6ad4b8acda7..00000000000 --- a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/CWE/CWE-352/JsonpInjection.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpController.java b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithFilter/JsonpController.java similarity index 54% rename from java/ql/test/experimental/query-tests/security/CWE-352/JsonpController.java rename to java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithFilter/JsonpController.java index cf860c75640..e5b5e70a38d 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpController.java +++ b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithFilter/JsonpController.java @@ -1,16 +1,24 @@ import com.alibaba.fastjson.JSONObject; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.Gson; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; import java.io.PrintWriter; import java.util.HashMap; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.multipart.MultipartFile; @Controller public class JsonpController { + private static HashMap hashMap = new HashMap(); static { @@ -18,13 +26,14 @@ public class JsonpController { hashMap.put("password","123456"); } + private String name = null; - @GetMapping(value = "jsonp1", produces="text/javascript") + + @GetMapping(value = "jsonp1") @ResponseBody public String bad1(HttpServletRequest request) { String resultStr = null; String jsonpCallback = request.getParameter("jsonpCallback"); - Gson gson = new Gson(); String result = gson.toJson(hashMap); resultStr = jsonpCallback + "(" + result + ")"; @@ -36,9 +45,7 @@ public class JsonpController { public String bad2(HttpServletRequest request) { String resultStr = null; String jsonpCallback = request.getParameter("jsonpCallback"); - resultStr = jsonpCallback + "(" + JSONObject.toJSONString(hashMap) + ")"; - return resultStr; } @@ -91,23 +98,98 @@ public class JsonpController { pw.println(resultStr); } - @GetMapping(value = "jsonp7") + @RequestMapping(value = "jsonp7", method = RequestMethod.GET) + @ResponseBody + public String bad7(HttpServletRequest request) { + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + Gson gson = new Gson(); + String result = gson.toJson(hashMap); + resultStr = jsonpCallback + "(" + result + ")"; + return resultStr; + } + + + @GetMapping(value = "jsonp8") @ResponseBody public String good1(HttpServletRequest request) { String resultStr = null; - String token = request.getParameter("token"); - if (verifToken(token)){ String jsonpCallback = request.getParameter("jsonpCallback"); String jsonStr = getJsonStr(hashMap); resultStr = jsonpCallback + "(" + jsonStr + ")"; return resultStr; } - return "error"; } + + @GetMapping(value = "jsonp9") + @ResponseBody + public String good2(HttpServletRequest request) { + String resultStr = null; + String token = request.getParameter("token"); + boolean result = verifToken(token); + if (result){ + return ""; + } + String jsonpCallback = request.getParameter("jsonpCallback"); + String jsonStr = getJsonStr(hashMap); + resultStr = jsonpCallback + "(" + jsonStr + ")"; + return resultStr; + } + + @RequestMapping(value = "jsonp10") + @ResponseBody + public String good3(HttpServletRequest request) { + JSONObject parameterObj = readToJSONObect(request); + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + String restr = JSONObject.toJSONString(hashMap); + resultStr = jsonpCallback + "(" + restr + ");"; + return resultStr; + } + + @RequestMapping(value = "jsonp11") + @ResponseBody + public String good4(@RequestParam("file") MultipartFile file,HttpServletRequest request) { + if(null == file){ + return "upload file error"; + } + String fileName = file.getOriginalFilename(); + System.out.println("file operations"); + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + String restr = JSONObject.toJSONString(hashMap); + resultStr = jsonpCallback + "(" + restr + ");"; + return resultStr; + } + + public static JSONObject readToJSONObect(HttpServletRequest request){ + String jsonText = readPostContent(request); + JSONObject jsonObj = JSONObject.parseObject(jsonText, JSONObject.class); + return jsonObj; + } + + public static String readPostContent(HttpServletRequest request){ + BufferedReader in= null; + String content = null; + String line = null; + try { + in = new BufferedReader(new InputStreamReader(request.getInputStream(),"UTF-8")); + StringBuilder buf = new StringBuilder(); + while ((line = in.readLine()) != null) { + buf.append(line); + } + content = buf.toString(); + } catch (IOException e) { + e.printStackTrace(); + } + String uri = request.getRequestURI(); + return content; + } + public static String getJsonStr(Object result) { return JSONObject.toJSONString(result); } @@ -118,11 +200,4 @@ public class JsonpController { } return true; } - - public static boolean verifReferer(String referer){ - if (!referer.startsWith("http://test.com/")){ - return false; - } - return true; - } } diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithFilter/JsonpInjection.expected b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithFilter/JsonpInjection.expected new file mode 100644 index 00000000000..501565f2b4e --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithFilter/JsonpInjection.expected @@ -0,0 +1,87 @@ +edges +| JsonpController.java:36:32:36:68 | getParameter(...) : String | JsonpController.java:40:16:40:24 | resultStr | +| JsonpController.java:39:21:39:54 | ... + ... : String | JsonpController.java:40:16:40:24 | resultStr | +| JsonpController.java:47:32:47:68 | getParameter(...) : String | JsonpController.java:49:16:49:24 | resultStr | +| JsonpController.java:48:21:48:80 | ... + ... : String | JsonpController.java:49:16:49:24 | resultStr | +| JsonpController.java:56:32:56:68 | getParameter(...) : String | JsonpController.java:59:16:59:24 | resultStr | +| JsonpController.java:58:21:58:55 | ... + ... : String | JsonpController.java:59:16:59:24 | resultStr | +| JsonpController.java:66:32:66:68 | getParameter(...) : String | JsonpController.java:69:16:69:24 | resultStr | +| JsonpController.java:68:21:68:54 | ... + ... : String | JsonpController.java:69:16:69:24 | resultStr | +| JsonpController.java:76:32:76:68 | getParameter(...) : String | JsonpController.java:84:20:84:28 | resultStr | +| JsonpController.java:83:21:83:54 | ... + ... : String | JsonpController.java:84:20:84:28 | resultStr | +| JsonpController.java:91:32:91:68 | getParameter(...) : String | JsonpController.java:98:20:98:28 | resultStr | +| JsonpController.java:97:21:97:54 | ... + ... : String | JsonpController.java:98:20:98:28 | resultStr | +| JsonpController.java:105:32:105:68 | getParameter(...) : String | JsonpController.java:109:16:109:24 | resultStr | +| JsonpController.java:108:21:108:54 | ... + ... : String | JsonpController.java:109:16:109:24 | resultStr | +| JsonpController.java:117:24:117:52 | getParameter(...) : String | JsonpController.java:118:24:118:28 | token | +| JsonpController.java:119:36:119:72 | getParameter(...) : String | JsonpController.java:122:20:122:28 | resultStr | +| JsonpController.java:121:25:121:59 | ... + ... : String | JsonpController.java:122:20:122:28 | resultStr | +| JsonpController.java:132:24:132:52 | getParameter(...) : String | JsonpController.java:133:37:133:41 | token | +| JsonpController.java:137:32:137:68 | getParameter(...) : String | JsonpController.java:140:16:140:24 | resultStr | +| JsonpController.java:139:21:139:55 | ... + ... : String | JsonpController.java:140:16:140:24 | resultStr | +| JsonpController.java:150:21:150:54 | ... + ... : String | JsonpController.java:151:16:151:24 | resultStr | +| JsonpController.java:165:21:165:54 | ... + ... : String | JsonpController.java:166:16:166:24 | resultStr | +| JsonpInjectionServlet1.java:31:32:31:64 | getParameter(...) : String | JsonpInjectionServlet1.java:45:24:45:32 | resultStr | +| JsonpInjectionServlet1.java:36:26:36:49 | getHeader(...) : String | JsonpInjectionServlet1.java:38:39:38:45 | referer | +| JsonpInjectionServlet1.java:44:25:44:62 | ... + ... : String | JsonpInjectionServlet1.java:45:24:45:32 | resultStr | +| JsonpInjectionServlet2.java:31:32:31:64 | getParameter(...) : String | JsonpInjectionServlet2.java:39:20:39:28 | resultStr | +| JsonpInjectionServlet2.java:38:21:38:54 | ... + ... : String | JsonpInjectionServlet2.java:39:20:39:28 | resultStr | +| RefererFilter.java:22:26:22:53 | getHeader(...) : String | RefererFilter.java:23:39:23:45 | refefer | +nodes +| JsonpController.java:36:32:36:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:39:21:39:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:40:16:40:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:40:16:40:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:47:32:47:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:48:21:48:80 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:49:16:49:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:49:16:49:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:56:32:56:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:58:21:58:55 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:59:16:59:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:59:16:59:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:66:32:66:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:68:21:68:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:69:16:69:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:69:16:69:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:76:32:76:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:83:21:83:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:84:20:84:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:84:20:84:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:91:32:91:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:97:21:97:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:98:20:98:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:98:20:98:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:105:32:105:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:108:21:108:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:109:16:109:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:109:16:109:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:117:24:117:52 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:118:24:118:28 | token | semmle.label | token | +| JsonpController.java:119:36:119:72 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:121:25:121:59 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:122:20:122:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:122:20:122:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:132:24:132:52 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:133:37:133:41 | token | semmle.label | token | +| JsonpController.java:137:32:137:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:139:21:139:55 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:140:16:140:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:140:16:140:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:150:21:150:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:151:16:151:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:165:21:165:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:166:16:166:24 | resultStr | semmle.label | resultStr | +| JsonpInjectionServlet1.java:31:32:31:64 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpInjectionServlet1.java:36:26:36:49 | getHeader(...) : String | semmle.label | getHeader(...) : String | +| JsonpInjectionServlet1.java:38:39:38:45 | referer | semmle.label | referer | +| JsonpInjectionServlet1.java:44:25:44:62 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpInjectionServlet1.java:45:24:45:32 | resultStr | semmle.label | resultStr | +| JsonpInjectionServlet1.java:45:24:45:32 | resultStr | semmle.label | resultStr | +| JsonpInjectionServlet2.java:31:32:31:64 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpInjectionServlet2.java:38:21:38:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpInjectionServlet2.java:39:20:39:28 | resultStr | semmle.label | resultStr | +| JsonpInjectionServlet2.java:39:20:39:28 | resultStr | semmle.label | resultStr | +| RefererFilter.java:22:26:22:53 | getHeader(...) : String | semmle.label | getHeader(...) : String | +| RefererFilter.java:23:39:23:45 | refefer | semmle.label | refefer | +#select diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithFilter/JsonpInjection.qlref b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithFilter/JsonpInjection.qlref new file mode 100644 index 00000000000..3f5fc450669 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithFilter/JsonpInjection.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-352/JsonpInjection.ql diff --git a/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjectionServlet1.java b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithFilter/JsonpInjectionServlet1.java similarity index 100% rename from java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjectionServlet1.java rename to java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithFilter/JsonpInjectionServlet1.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjectionServlet2.java b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithFilter/JsonpInjectionServlet2.java similarity index 100% rename from java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjectionServlet2.java rename to java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithFilter/JsonpInjectionServlet2.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-352/RefererFilter.java b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithFilter/RefererFilter.java similarity index 100% rename from java/ql/src/experimental/Security/CWE/CWE-352/RefererFilter.java rename to java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithFilter/RefererFilter.java diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithFilter/options b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithFilter/options new file mode 100644 index 00000000000..c53e31e467f --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithFilter/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../stubs/apache-http-4.4.13/:${testdir}/../../../../../stubs/servlet-api-2.4:${testdir}/../../../../../stubs/fastjson-1.2.74/:${testdir}/../../../../../stubs/gson-2.8.6/:${testdir}/../../../../../stubs/jackson-databind-2.10/:${testdir}/../../../../../stubs/spring-context-5.3.2/:${testdir}/../../../../../stubs/spring-web-5.3.2/:${testdir}/../../../../../stubs/spring-core-5.3.2/:${testdir}/../../../../../stubs/tomcat-embed-core-9.0.41/ diff --git a/java/ql/src/experimental/Security/CWE/CWE-352/JsonpController.java b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringController/JsonpController.java similarity index 54% rename from java/ql/src/experimental/Security/CWE/CWE-352/JsonpController.java rename to java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringController/JsonpController.java index 84a172a7aeb..e5b5e70a38d 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-352/JsonpController.java +++ b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringController/JsonpController.java @@ -1,16 +1,24 @@ import com.alibaba.fastjson.JSONObject; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.Gson; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; import java.io.PrintWriter; import java.util.HashMap; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.multipart.MultipartFile; @Controller public class JsonpController { + private static HashMap hashMap = new HashMap(); static { @@ -18,13 +26,14 @@ public class JsonpController { hashMap.put("password","123456"); } + private String name = null; - @GetMapping(value = "jsonp1", produces="text/javascript") + + @GetMapping(value = "jsonp1") @ResponseBody public String bad1(HttpServletRequest request) { String resultStr = null; String jsonpCallback = request.getParameter("jsonpCallback"); - Gson gson = new Gson(); String result = gson.toJson(hashMap); resultStr = jsonpCallback + "(" + result + ")"; @@ -36,9 +45,7 @@ public class JsonpController { public String bad2(HttpServletRequest request) { String resultStr = null; String jsonpCallback = request.getParameter("jsonpCallback"); - resultStr = jsonpCallback + "(" + JSONObject.toJSONString(hashMap) + ")"; - return resultStr; } @@ -91,23 +98,98 @@ public class JsonpController { pw.println(resultStr); } - @GetMapping(value = "jsonp7") + @RequestMapping(value = "jsonp7", method = RequestMethod.GET) + @ResponseBody + public String bad7(HttpServletRequest request) { + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + Gson gson = new Gson(); + String result = gson.toJson(hashMap); + resultStr = jsonpCallback + "(" + result + ")"; + return resultStr; + } + + + @GetMapping(value = "jsonp8") @ResponseBody public String good1(HttpServletRequest request) { String resultStr = null; - String token = request.getParameter("token"); - if (verifToken(token)){ String jsonpCallback = request.getParameter("jsonpCallback"); String jsonStr = getJsonStr(hashMap); resultStr = jsonpCallback + "(" + jsonStr + ")"; return resultStr; } - return "error"; } + + @GetMapping(value = "jsonp9") + @ResponseBody + public String good2(HttpServletRequest request) { + String resultStr = null; + String token = request.getParameter("token"); + boolean result = verifToken(token); + if (result){ + return ""; + } + String jsonpCallback = request.getParameter("jsonpCallback"); + String jsonStr = getJsonStr(hashMap); + resultStr = jsonpCallback + "(" + jsonStr + ")"; + return resultStr; + } + + @RequestMapping(value = "jsonp10") + @ResponseBody + public String good3(HttpServletRequest request) { + JSONObject parameterObj = readToJSONObect(request); + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + String restr = JSONObject.toJSONString(hashMap); + resultStr = jsonpCallback + "(" + restr + ");"; + return resultStr; + } + + @RequestMapping(value = "jsonp11") + @ResponseBody + public String good4(@RequestParam("file") MultipartFile file,HttpServletRequest request) { + if(null == file){ + return "upload file error"; + } + String fileName = file.getOriginalFilename(); + System.out.println("file operations"); + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + String restr = JSONObject.toJSONString(hashMap); + resultStr = jsonpCallback + "(" + restr + ");"; + return resultStr; + } + + public static JSONObject readToJSONObect(HttpServletRequest request){ + String jsonText = readPostContent(request); + JSONObject jsonObj = JSONObject.parseObject(jsonText, JSONObject.class); + return jsonObj; + } + + public static String readPostContent(HttpServletRequest request){ + BufferedReader in= null; + String content = null; + String line = null; + try { + in = new BufferedReader(new InputStreamReader(request.getInputStream(),"UTF-8")); + StringBuilder buf = new StringBuilder(); + while ((line = in.readLine()) != null) { + buf.append(line); + } + content = buf.toString(); + } catch (IOException e) { + e.printStackTrace(); + } + String uri = request.getRequestURI(); + return content; + } + public static String getJsonStr(Object result) { return JSONObject.toJSONString(result); } @@ -118,11 +200,4 @@ public class JsonpController { } return true; } - - public static boolean verifReferer(String referer){ - if (!referer.startsWith("http://test.com/")){ - return false; - } - return true; - } -} \ No newline at end of file +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringController/JsonpInjection.expected b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringController/JsonpInjection.expected new file mode 100644 index 00000000000..91d23cebbda --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringController/JsonpInjection.expected @@ -0,0 +1,76 @@ +edges +| JsonpController.java:36:32:36:68 | getParameter(...) : String | JsonpController.java:40:16:40:24 | resultStr | +| JsonpController.java:39:21:39:54 | ... + ... : String | JsonpController.java:40:16:40:24 | resultStr | +| JsonpController.java:47:32:47:68 | getParameter(...) : String | JsonpController.java:49:16:49:24 | resultStr | +| JsonpController.java:48:21:48:80 | ... + ... : String | JsonpController.java:49:16:49:24 | resultStr | +| JsonpController.java:56:32:56:68 | getParameter(...) : String | JsonpController.java:59:16:59:24 | resultStr | +| JsonpController.java:58:21:58:55 | ... + ... : String | JsonpController.java:59:16:59:24 | resultStr | +| JsonpController.java:66:32:66:68 | getParameter(...) : String | JsonpController.java:69:16:69:24 | resultStr | +| JsonpController.java:68:21:68:54 | ... + ... : String | JsonpController.java:69:16:69:24 | resultStr | +| JsonpController.java:76:32:76:68 | getParameter(...) : String | JsonpController.java:84:20:84:28 | resultStr | +| JsonpController.java:83:21:83:54 | ... + ... : String | JsonpController.java:84:20:84:28 | resultStr | +| JsonpController.java:91:32:91:68 | getParameter(...) : String | JsonpController.java:98:20:98:28 | resultStr | +| JsonpController.java:97:21:97:54 | ... + ... : String | JsonpController.java:98:20:98:28 | resultStr | +| JsonpController.java:105:32:105:68 | getParameter(...) : String | JsonpController.java:109:16:109:24 | resultStr | +| JsonpController.java:108:21:108:54 | ... + ... : String | JsonpController.java:109:16:109:24 | resultStr | +| JsonpController.java:117:24:117:52 | getParameter(...) : String | JsonpController.java:118:24:118:28 | token | +| JsonpController.java:119:36:119:72 | getParameter(...) : String | JsonpController.java:122:20:122:28 | resultStr | +| JsonpController.java:121:25:121:59 | ... + ... : String | JsonpController.java:122:20:122:28 | resultStr | +| JsonpController.java:132:24:132:52 | getParameter(...) : String | JsonpController.java:133:37:133:41 | token | +| JsonpController.java:137:32:137:68 | getParameter(...) : String | JsonpController.java:140:16:140:24 | resultStr | +| JsonpController.java:139:21:139:55 | ... + ... : String | JsonpController.java:140:16:140:24 | resultStr | +| JsonpController.java:150:21:150:54 | ... + ... : String | JsonpController.java:151:16:151:24 | resultStr | +| JsonpController.java:165:21:165:54 | ... + ... : String | JsonpController.java:166:16:166:24 | resultStr | +nodes +| JsonpController.java:36:32:36:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:39:21:39:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:40:16:40:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:40:16:40:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:47:32:47:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:48:21:48:80 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:49:16:49:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:49:16:49:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:56:32:56:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:58:21:58:55 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:59:16:59:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:59:16:59:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:66:32:66:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:68:21:68:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:69:16:69:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:69:16:69:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:76:32:76:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:83:21:83:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:84:20:84:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:84:20:84:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:91:32:91:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:97:21:97:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:98:20:98:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:98:20:98:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:105:32:105:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:108:21:108:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:109:16:109:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:109:16:109:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:117:24:117:52 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:118:24:118:28 | token | semmle.label | token | +| JsonpController.java:119:36:119:72 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:121:25:121:59 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:122:20:122:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:122:20:122:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:132:24:132:52 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:133:37:133:41 | token | semmle.label | token | +| JsonpController.java:137:32:137:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:139:21:139:55 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:140:16:140:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:140:16:140:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:150:21:150:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:151:16:151:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:165:21:165:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:166:16:166:24 | resultStr | semmle.label | resultStr | +#select +| JsonpController.java:40:16:40:24 | resultStr | JsonpController.java:36:32:36:68 | getParameter(...) : String | JsonpController.java:40:16:40:24 | resultStr | Jsonp response might include code from $@. | JsonpController.java:36:32:36:68 | getParameter(...) | this user input | +| JsonpController.java:49:16:49:24 | resultStr | JsonpController.java:47:32:47:68 | getParameter(...) : String | JsonpController.java:49:16:49:24 | resultStr | Jsonp response might include code from $@. | JsonpController.java:47:32:47:68 | getParameter(...) | this user input | +| JsonpController.java:59:16:59:24 | resultStr | JsonpController.java:56:32:56:68 | getParameter(...) : String | JsonpController.java:59:16:59:24 | resultStr | Jsonp response might include code from $@. | JsonpController.java:56:32:56:68 | getParameter(...) | this user input | +| JsonpController.java:69:16:69:24 | resultStr | JsonpController.java:66:32:66:68 | getParameter(...) : String | JsonpController.java:69:16:69:24 | resultStr | Jsonp response might include code from $@. | JsonpController.java:66:32:66:68 | getParameter(...) | this user input | +| JsonpController.java:84:20:84:28 | resultStr | JsonpController.java:76:32:76:68 | getParameter(...) : String | JsonpController.java:84:20:84:28 | resultStr | Jsonp response might include code from $@. | JsonpController.java:76:32:76:68 | getParameter(...) | this user input | +| JsonpController.java:98:20:98:28 | resultStr | JsonpController.java:91:32:91:68 | getParameter(...) : String | JsonpController.java:98:20:98:28 | resultStr | Jsonp response might include code from $@. | JsonpController.java:91:32:91:68 | getParameter(...) | this user input | +| JsonpController.java:109:16:109:24 | resultStr | JsonpController.java:105:32:105:68 | getParameter(...) : String | JsonpController.java:109:16:109:24 | resultStr | Jsonp response might include code from $@. | JsonpController.java:105:32:105:68 | getParameter(...) | this user input | diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringController/JsonpInjection.qlref b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringController/JsonpInjection.qlref new file mode 100644 index 00000000000..3f5fc450669 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringController/JsonpInjection.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-352/JsonpInjection.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringController/options b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringController/options new file mode 100644 index 00000000000..c53e31e467f --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringController/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../stubs/apache-http-4.4.13/:${testdir}/../../../../../stubs/servlet-api-2.4:${testdir}/../../../../../stubs/fastjson-1.2.74/:${testdir}/../../../../../stubs/gson-2.8.6/:${testdir}/../../../../../stubs/jackson-databind-2.10/:${testdir}/../../../../../stubs/spring-context-5.3.2/:${testdir}/../../../../../stubs/spring-web-5.3.2/:${testdir}/../../../../../stubs/spring-core-5.3.2/:${testdir}/../../../../../stubs/tomcat-embed-core-9.0.41/ diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringControllerAndServlet/JsonpController.java b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringControllerAndServlet/JsonpController.java new file mode 100644 index 00000000000..e5b5e70a38d --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringControllerAndServlet/JsonpController.java @@ -0,0 +1,203 @@ +import com.alibaba.fastjson.JSONObject; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.util.HashMap; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.multipart.MultipartFile; + +@Controller +public class JsonpController { + + private static HashMap hashMap = new HashMap(); + + static { + hashMap.put("username","admin"); + hashMap.put("password","123456"); + } + + private String name = null; + + + @GetMapping(value = "jsonp1") + @ResponseBody + public String bad1(HttpServletRequest request) { + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + Gson gson = new Gson(); + String result = gson.toJson(hashMap); + resultStr = jsonpCallback + "(" + result + ")"; + return resultStr; + } + + @GetMapping(value = "jsonp2") + @ResponseBody + public String bad2(HttpServletRequest request) { + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + resultStr = jsonpCallback + "(" + JSONObject.toJSONString(hashMap) + ")"; + return resultStr; + } + + @GetMapping(value = "jsonp3") + @ResponseBody + public String bad3(HttpServletRequest request) { + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + String jsonStr = getJsonStr(hashMap); + resultStr = jsonpCallback + "(" + jsonStr + ")"; + return resultStr; + } + + @GetMapping(value = "jsonp4") + @ResponseBody + public String bad4(HttpServletRequest request) { + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + String restr = JSONObject.toJSONString(hashMap); + resultStr = jsonpCallback + "(" + restr + ");"; + return resultStr; + } + + @GetMapping(value = "jsonp5") + @ResponseBody + public void bad5(HttpServletRequest request, + HttpServletResponse response) throws Exception { + String jsonpCallback = request.getParameter("jsonpCallback"); + PrintWriter pw = null; + Gson gson = new Gson(); + String result = gson.toJson(hashMap); + + String resultStr = null; + pw = response.getWriter(); + resultStr = jsonpCallback + "(" + result + ")"; + pw.println(resultStr); + } + + @GetMapping(value = "jsonp6") + @ResponseBody + public void bad6(HttpServletRequest request, + HttpServletResponse response) throws Exception { + String jsonpCallback = request.getParameter("jsonpCallback"); + PrintWriter pw = null; + ObjectMapper mapper = new ObjectMapper(); + String result = mapper.writeValueAsString(hashMap); + String resultStr = null; + pw = response.getWriter(); + resultStr = jsonpCallback + "(" + result + ")"; + pw.println(resultStr); + } + + @RequestMapping(value = "jsonp7", method = RequestMethod.GET) + @ResponseBody + public String bad7(HttpServletRequest request) { + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + Gson gson = new Gson(); + String result = gson.toJson(hashMap); + resultStr = jsonpCallback + "(" + result + ")"; + return resultStr; + } + + + @GetMapping(value = "jsonp8") + @ResponseBody + public String good1(HttpServletRequest request) { + String resultStr = null; + String token = request.getParameter("token"); + if (verifToken(token)){ + String jsonpCallback = request.getParameter("jsonpCallback"); + String jsonStr = getJsonStr(hashMap); + resultStr = jsonpCallback + "(" + jsonStr + ")"; + return resultStr; + } + return "error"; + } + + + @GetMapping(value = "jsonp9") + @ResponseBody + public String good2(HttpServletRequest request) { + String resultStr = null; + String token = request.getParameter("token"); + boolean result = verifToken(token); + if (result){ + return ""; + } + String jsonpCallback = request.getParameter("jsonpCallback"); + String jsonStr = getJsonStr(hashMap); + resultStr = jsonpCallback + "(" + jsonStr + ")"; + return resultStr; + } + + @RequestMapping(value = "jsonp10") + @ResponseBody + public String good3(HttpServletRequest request) { + JSONObject parameterObj = readToJSONObect(request); + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + String restr = JSONObject.toJSONString(hashMap); + resultStr = jsonpCallback + "(" + restr + ");"; + return resultStr; + } + + @RequestMapping(value = "jsonp11") + @ResponseBody + public String good4(@RequestParam("file") MultipartFile file,HttpServletRequest request) { + if(null == file){ + return "upload file error"; + } + String fileName = file.getOriginalFilename(); + System.out.println("file operations"); + String resultStr = null; + String jsonpCallback = request.getParameter("jsonpCallback"); + String restr = JSONObject.toJSONString(hashMap); + resultStr = jsonpCallback + "(" + restr + ");"; + return resultStr; + } + + public static JSONObject readToJSONObect(HttpServletRequest request){ + String jsonText = readPostContent(request); + JSONObject jsonObj = JSONObject.parseObject(jsonText, JSONObject.class); + return jsonObj; + } + + public static String readPostContent(HttpServletRequest request){ + BufferedReader in= null; + String content = null; + String line = null; + try { + in = new BufferedReader(new InputStreamReader(request.getInputStream(),"UTF-8")); + StringBuilder buf = new StringBuilder(); + while ((line = in.readLine()) != null) { + buf.append(line); + } + content = buf.toString(); + } catch (IOException e) { + e.printStackTrace(); + } + String uri = request.getRequestURI(); + return content; + } + + public static String getJsonStr(Object result) { + return JSONObject.toJSONString(result); + } + + public static boolean verifToken(String token){ + if (token != "xxxx"){ + return false; + } + return true; + } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringControllerAndServlet/JsonpInjection.expected b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringControllerAndServlet/JsonpInjection.expected new file mode 100644 index 00000000000..c2bcab77d4d --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringControllerAndServlet/JsonpInjection.expected @@ -0,0 +1,92 @@ +edges +| JsonpController.java:36:32:36:68 | getParameter(...) : String | JsonpController.java:40:16:40:24 | resultStr | +| JsonpController.java:39:21:39:54 | ... + ... : String | JsonpController.java:40:16:40:24 | resultStr | +| JsonpController.java:47:32:47:68 | getParameter(...) : String | JsonpController.java:49:16:49:24 | resultStr | +| JsonpController.java:48:21:48:80 | ... + ... : String | JsonpController.java:49:16:49:24 | resultStr | +| JsonpController.java:56:32:56:68 | getParameter(...) : String | JsonpController.java:59:16:59:24 | resultStr | +| JsonpController.java:58:21:58:55 | ... + ... : String | JsonpController.java:59:16:59:24 | resultStr | +| JsonpController.java:66:32:66:68 | getParameter(...) : String | JsonpController.java:69:16:69:24 | resultStr | +| JsonpController.java:68:21:68:54 | ... + ... : String | JsonpController.java:69:16:69:24 | resultStr | +| JsonpController.java:76:32:76:68 | getParameter(...) : String | JsonpController.java:84:20:84:28 | resultStr | +| JsonpController.java:83:21:83:54 | ... + ... : String | JsonpController.java:84:20:84:28 | resultStr | +| JsonpController.java:91:32:91:68 | getParameter(...) : String | JsonpController.java:98:20:98:28 | resultStr | +| JsonpController.java:97:21:97:54 | ... + ... : String | JsonpController.java:98:20:98:28 | resultStr | +| JsonpController.java:105:32:105:68 | getParameter(...) : String | JsonpController.java:109:16:109:24 | resultStr | +| JsonpController.java:108:21:108:54 | ... + ... : String | JsonpController.java:109:16:109:24 | resultStr | +| JsonpController.java:117:24:117:52 | getParameter(...) : String | JsonpController.java:118:24:118:28 | token | +| JsonpController.java:119:36:119:72 | getParameter(...) : String | JsonpController.java:122:20:122:28 | resultStr | +| JsonpController.java:121:25:121:59 | ... + ... : String | JsonpController.java:122:20:122:28 | resultStr | +| JsonpController.java:132:24:132:52 | getParameter(...) : String | JsonpController.java:133:37:133:41 | token | +| JsonpController.java:137:32:137:68 | getParameter(...) : String | JsonpController.java:140:16:140:24 | resultStr | +| JsonpController.java:139:21:139:55 | ... + ... : String | JsonpController.java:140:16:140:24 | resultStr | +| JsonpController.java:150:21:150:54 | ... + ... : String | JsonpController.java:151:16:151:24 | resultStr | +| JsonpController.java:165:21:165:54 | ... + ... : String | JsonpController.java:166:16:166:24 | resultStr | +| JsonpInjectionServlet1.java:31:32:31:64 | getParameter(...) : String | JsonpInjectionServlet1.java:45:24:45:32 | resultStr | +| JsonpInjectionServlet1.java:36:26:36:49 | getHeader(...) : String | JsonpInjectionServlet1.java:38:39:38:45 | referer | +| JsonpInjectionServlet1.java:44:25:44:62 | ... + ... : String | JsonpInjectionServlet1.java:45:24:45:32 | resultStr | +| JsonpInjectionServlet2.java:31:32:31:64 | getParameter(...) : String | JsonpInjectionServlet2.java:39:20:39:28 | resultStr | +| JsonpInjectionServlet2.java:38:21:38:54 | ... + ... : String | JsonpInjectionServlet2.java:39:20:39:28 | resultStr | +nodes +| JsonpController.java:36:32:36:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:39:21:39:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:40:16:40:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:40:16:40:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:47:32:47:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:48:21:48:80 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:49:16:49:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:49:16:49:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:56:32:56:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:58:21:58:55 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:59:16:59:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:59:16:59:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:66:32:66:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:68:21:68:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:69:16:69:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:69:16:69:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:76:32:76:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:83:21:83:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:84:20:84:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:84:20:84:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:91:32:91:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:97:21:97:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:98:20:98:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:98:20:98:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:105:32:105:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:108:21:108:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:109:16:109:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:109:16:109:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:117:24:117:52 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:118:24:118:28 | token | semmle.label | token | +| JsonpController.java:119:36:119:72 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:121:25:121:59 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:122:20:122:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:122:20:122:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:132:24:132:52 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:133:37:133:41 | token | semmle.label | token | +| JsonpController.java:137:32:137:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:139:21:139:55 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:140:16:140:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:140:16:140:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:150:21:150:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:151:16:151:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:165:21:165:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:166:16:166:24 | resultStr | semmle.label | resultStr | +| JsonpInjectionServlet1.java:31:32:31:64 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpInjectionServlet1.java:36:26:36:49 | getHeader(...) : String | semmle.label | getHeader(...) : String | +| JsonpInjectionServlet1.java:38:39:38:45 | referer | semmle.label | referer | +| JsonpInjectionServlet1.java:44:25:44:62 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpInjectionServlet1.java:45:24:45:32 | resultStr | semmle.label | resultStr | +| JsonpInjectionServlet1.java:45:24:45:32 | resultStr | semmle.label | resultStr | +| JsonpInjectionServlet2.java:31:32:31:64 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpInjectionServlet2.java:38:21:38:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpInjectionServlet2.java:39:20:39:28 | resultStr | semmle.label | resultStr | +| JsonpInjectionServlet2.java:39:20:39:28 | resultStr | semmle.label | resultStr | +#select +| JsonpController.java:40:16:40:24 | resultStr | JsonpController.java:36:32:36:68 | getParameter(...) : String | JsonpController.java:40:16:40:24 | resultStr | Jsonp response might include code from $@. | JsonpController.java:36:32:36:68 | getParameter(...) | this user input | +| JsonpController.java:49:16:49:24 | resultStr | JsonpController.java:47:32:47:68 | getParameter(...) : String | JsonpController.java:49:16:49:24 | resultStr | Jsonp response might include code from $@. | JsonpController.java:47:32:47:68 | getParameter(...) | this user input | +| JsonpController.java:59:16:59:24 | resultStr | JsonpController.java:56:32:56:68 | getParameter(...) : String | JsonpController.java:59:16:59:24 | resultStr | Jsonp response might include code from $@. | JsonpController.java:56:32:56:68 | getParameter(...) | this user input | +| JsonpController.java:69:16:69:24 | resultStr | JsonpController.java:66:32:66:68 | getParameter(...) : String | JsonpController.java:69:16:69:24 | resultStr | Jsonp response might include code from $@. | JsonpController.java:66:32:66:68 | getParameter(...) | this user input | +| JsonpController.java:84:20:84:28 | resultStr | JsonpController.java:76:32:76:68 | getParameter(...) : String | JsonpController.java:84:20:84:28 | resultStr | Jsonp response might include code from $@. | JsonpController.java:76:32:76:68 | getParameter(...) | this user input | +| JsonpController.java:98:20:98:28 | resultStr | JsonpController.java:91:32:91:68 | getParameter(...) : String | JsonpController.java:98:20:98:28 | resultStr | Jsonp response might include code from $@. | JsonpController.java:91:32:91:68 | getParameter(...) | this user input | +| JsonpController.java:109:16:109:24 | resultStr | JsonpController.java:105:32:105:68 | getParameter(...) : String | JsonpController.java:109:16:109:24 | resultStr | Jsonp response might include code from $@. | JsonpController.java:105:32:105:68 | getParameter(...) | this user input | +| JsonpInjectionServlet2.java:39:20:39:28 | resultStr | JsonpInjectionServlet2.java:31:32:31:64 | getParameter(...) : String | JsonpInjectionServlet2.java:39:20:39:28 | resultStr | Jsonp response might include code from $@. | JsonpInjectionServlet2.java:31:32:31:64 | getParameter(...) | this user input | diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringControllerAndServlet/JsonpInjection.qlref b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringControllerAndServlet/JsonpInjection.qlref new file mode 100644 index 00000000000..3f5fc450669 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringControllerAndServlet/JsonpInjection.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-352/JsonpInjection.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionServlet1.java b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringControllerAndServlet/JsonpInjectionServlet1.java similarity index 100% rename from java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionServlet1.java rename to java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringControllerAndServlet/JsonpInjectionServlet1.java diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionServlet2.java b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringControllerAndServlet/JsonpInjectionServlet2.java similarity index 100% rename from java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionServlet2.java rename to java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringControllerAndServlet/JsonpInjectionServlet2.java diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringControllerAndServlet/options b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringControllerAndServlet/options new file mode 100644 index 00000000000..c53e31e467f --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringControllerAndServlet/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../stubs/apache-http-4.4.13/:${testdir}/../../../../../stubs/servlet-api-2.4:${testdir}/../../../../../stubs/fastjson-1.2.74/:${testdir}/../../../../../stubs/gson-2.8.6/:${testdir}/../../../../../stubs/jackson-databind-2.10/:${testdir}/../../../../../stubs/spring-context-5.3.2/:${testdir}/../../../../../stubs/spring-web-5.3.2/:${testdir}/../../../../../stubs/spring-core-5.3.2/:${testdir}/../../../../../stubs/tomcat-embed-core-9.0.41/ diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection_1.expected b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection_1.expected deleted file mode 100644 index a89d03b67a7..00000000000 --- a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection_1.expected +++ /dev/null @@ -1,60 +0,0 @@ -edges -| JsonpController.java:26:32:26:68 | getParameter(...) : String | JsonpController.java:31:16:31:24 | resultStr | -| JsonpController.java:30:21:30:54 | ... + ... : String | JsonpController.java:31:16:31:24 | resultStr | -| JsonpController.java:38:32:38:68 | getParameter(...) : String | JsonpController.java:42:16:42:24 | resultStr | -| JsonpController.java:40:21:40:80 | ... + ... : String | JsonpController.java:42:16:42:24 | resultStr | -| JsonpController.java:49:32:49:68 | getParameter(...) : String | JsonpController.java:52:16:52:24 | resultStr | -| JsonpController.java:51:21:51:55 | ... + ... : String | JsonpController.java:52:16:52:24 | resultStr | -| JsonpController.java:59:32:59:68 | getParameter(...) : String | JsonpController.java:62:16:62:24 | resultStr | -| JsonpController.java:61:21:61:54 | ... + ... : String | JsonpController.java:62:16:62:24 | resultStr | -| JsonpController.java:69:32:69:68 | getParameter(...) : String | JsonpController.java:77:20:77:28 | resultStr | -| JsonpController.java:76:21:76:54 | ... + ... : String | JsonpController.java:77:20:77:28 | resultStr | -| JsonpController.java:84:32:84:68 | getParameter(...) : String | JsonpController.java:91:20:91:28 | resultStr | -| JsonpController.java:90:21:90:54 | ... + ... : String | JsonpController.java:91:20:91:28 | resultStr | -| JsonpController.java:99:24:99:52 | getParameter(...) : String | JsonpController.java:101:24:101:28 | token | -| JsonpController.java:102:36:102:72 | getParameter(...) : String | JsonpController.java:105:20:105:28 | resultStr | -| JsonpController.java:104:25:104:59 | ... + ... : String | JsonpController.java:105:20:105:28 | resultStr | -nodes -| JsonpController.java:26:32:26:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:30:21:30:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:31:16:31:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:31:16:31:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:38:32:38:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:40:21:40:80 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:42:16:42:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:42:16:42:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:49:32:49:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:51:21:51:55 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:52:16:52:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:52:16:52:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:59:32:59:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:61:21:61:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:62:16:62:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:62:16:62:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:69:32:69:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:76:21:76:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:77:20:77:28 | resultStr | semmle.label | resultStr | -| JsonpController.java:77:20:77:28 | resultStr | semmle.label | resultStr | -| JsonpController.java:84:32:84:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:90:21:90:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:91:20:91:28 | resultStr | semmle.label | resultStr | -| JsonpController.java:91:20:91:28 | resultStr | semmle.label | resultStr | -| JsonpController.java:99:24:99:52 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:101:24:101:28 | token | semmle.label | token | -| JsonpController.java:102:36:102:72 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:104:25:104:59 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:105:20:105:28 | resultStr | semmle.label | resultStr | -| JsonpController.java:105:20:105:28 | resultStr | semmle.label | resultStr | -#select -| JsonpController.java:31:16:31:24 | resultStr | JsonpController.java:26:32:26:68 | getParameter(...) : String | JsonpController.java:31:16:31:24 | - resultStr | Jsonp Injection query might include code from $@. | JsonpController.java:26:32:26:68 | getParameter(...) | this user input | -| JsonpController.java:42:16:42:24 | resultStr | JsonpController.java:38:32:38:68 | getParameter(...) : String | JsonpController.java:42:16:42:24 | - resultStr | Jsonp Injection query might include code from $@. | JsonpController.java:38:32:38:68 | getParameter(...) | this user input | -| JsonpController.java:52:16:52:24 | resultStr | JsonpController.java:49:32:49:68 | getParameter(...) : String | JsonpController.java:52:16:52:24 | - resultStr | Jsonp Injection query might include code from $@. | JsonpController.java:49:32:49:68 | getParameter(...) | this user input | -| JsonpController.java:62:16:62:24 | resultStr | JsonpController.java:59:32:59:68 | getParameter(...) : String | JsonpController.java:62:16:62:24 | - resultStr | Jsonp Injection query might include code from $@. | JsonpController.java:59:32:59:68 | getParameter(...) | this user input | -| JsonpController.java:77:20:77:28 | resultStr | JsonpController.java:69:32:69:68 | getParameter(...) : String | JsonpController.java:77:20:77:28 | - resultStr | Jsonp Injection query might include code from $@. | JsonpController.java:69:32:69:68 | getParameter(...) | this user input | -| JsonpController.java:91:20:91:28 | resultStr | JsonpController.java:84:32:84:68 | getParameter(...) : String | JsonpController.java:91:20:91:28 | - resultStr | Jsonp Injection query might include code from $@. | JsonpController.java:84:32:84:68 | getParameter(...) | this user input | \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection_2.expected b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection_2.expected deleted file mode 100644 index 4b12308a212..00000000000 --- a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection_2.expected +++ /dev/null @@ -1,78 +0,0 @@ -edges -| JsonpController.java:26:32:26:68 | getParameter(...) : String | JsonpController.java:31:16:31:24 | resultStr | -| JsonpController.java:30:21:30:54 | ... + ... : String | JsonpController.java:31:16:31:24 | resultStr | -| JsonpController.java:38:32:38:68 | getParameter(...) : String | JsonpController.java:42:16:42:24 | resultStr | -| JsonpController.java:40:21:40:80 | ... + ... : String | JsonpController.java:42:16:42:24 | resultStr | -| JsonpController.java:49:32:49:68 | getParameter(...) : String | JsonpController.java:52:16:52:24 | resultStr | -| JsonpController.java:51:21:51:55 | ... + ... : String | JsonpController.java:52:16:52:24 | resultStr | -| JsonpController.java:59:32:59:68 | getParameter(...) : String | JsonpController.java:62:16:62:24 | resultStr | -| JsonpController.java:61:21:61:54 | ... + ... : String | JsonpController.java:62:16:62:24 | resultStr | -| JsonpController.java:69:32:69:68 | getParameter(...) : String | JsonpController.java:77:20:77:28 | resultStr | -| JsonpController.java:76:21:76:54 | ... + ... : String | JsonpController.java:77:20:77:28 | resultStr | -| JsonpController.java:84:32:84:68 | getParameter(...) : String | JsonpController.java:91:20:91:28 | resultStr | -| JsonpController.java:90:21:90:54 | ... + ... : String | JsonpController.java:91:20:91:28 | resultStr | -| JsonpController.java:99:24:99:52 | getParameter(...) : String | JsonpController.java:101:24:101:28 | token | -| JsonpController.java:102:36:102:72 | getParameter(...) : String | JsonpController.java:105:20:105:28 | resultStr | -| JsonpController.java:104:25:104:59 | ... + ... : String | JsonpController.java:105:20:105:28 | resultStr | -| JsonpInjectionServlet1.java:31:32:31:64 | getParameter(...) : String | JsonpInjectionServlet1.java:45:24:45:32 | resultStr | -| JsonpInjectionServlet1.java:36:26:36:49 | getHeader(...) : String | JsonpInjectionServlet1.java:38:39:38:45 | referer | -| JsonpInjectionServlet1.java:44:25:44:62 | ... + ... : String | JsonpInjectionServlet1.java:45:24:45:32 | resultStr | -| JsonpInjectionServlet2.java:31:32:31:64 | getParameter(...) : String | JsonpInjectionServlet2.java:39:20:39:28 | resultStr | -| JsonpInjectionServlet2.java:38:21:38:54 | ... + ... : String | JsonpInjectionServlet2.java:39:20:39:28 | resultStr | -nodes -| JsonpController.java:26:32:26:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:30:21:30:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:31:16:31:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:31:16:31:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:38:32:38:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:40:21:40:80 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:42:16:42:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:42:16:42:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:49:32:49:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:51:21:51:55 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:52:16:52:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:52:16:52:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:59:32:59:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:61:21:61:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:62:16:62:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:62:16:62:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:69:32:69:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:76:21:76:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:77:20:77:28 | resultStr | semmle.label | resultStr | -| JsonpController.java:77:20:77:28 | resultStr | semmle.label | resultStr | -| JsonpController.java:84:32:84:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:90:21:90:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:91:20:91:28 | resultStr | semmle.label | resultStr | -| JsonpController.java:91:20:91:28 | resultStr | semmle.label | resultStr | -| JsonpController.java:99:24:99:52 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:101:24:101:28 | token | semmle.label | token | -| JsonpController.java:102:36:102:72 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:104:25:104:59 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:105:20:105:28 | resultStr | semmle.label | resultStr | -| JsonpController.java:105:20:105:28 | resultStr | semmle.label | resultStr | -| JsonpInjectionServlet1.java:31:32:31:64 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpInjectionServlet1.java:36:26:36:49 | getHeader(...) : String | semmle.label | getHeader(...) : String | -| JsonpInjectionServlet1.java:38:39:38:45 | referer | semmle.label | referer | -| JsonpInjectionServlet1.java:44:25:44:62 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpInjectionServlet1.java:45:24:45:32 | resultStr | semmle.label | resultStr | -| JsonpInjectionServlet1.java:45:24:45:32 | resultStr | semmle.label | resultStr | -| JsonpInjectionServlet2.java:31:32:31:64 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpInjectionServlet2.java:38:21:38:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpInjectionServlet2.java:39:20:39:28 | resultStr | semmle.label | resultStr | -| JsonpInjectionServlet2.java:39:20:39:28 | resultStr | semmle.label | resultStr | -#select -| JsonpController.java:31:16:31:24 | resultStr | JsonpController.java:26:32:26:68 | getParameter(...) : String | JsonpController.java:31:16:31:24 | - resultStr | Jsonp Injection query might include code from $@. | JsonpController.java:26:32:26:68 | getParameter(...) | this user input | -| JsonpController.java:42:16:42:24 | resultStr | JsonpController.java:38:32:38:68 | getParameter(...) : String | JsonpController.java:42:16:42:24 | - resultStr | Jsonp Injection query might include code from $@. | JsonpController.java:38:32:38:68 | getParameter(...) | this user input | -| JsonpController.java:52:16:52:24 | resultStr | JsonpController.java:49:32:49:68 | getParameter(...) : String | JsonpController.java:52:16:52:24 | - resultStr | Jsonp Injection query might include code from $@. | JsonpController.java:49:32:49:68 | getParameter(...) | this user input | -| JsonpController.java:62:16:62:24 | resultStr | JsonpController.java:59:32:59:68 | getParameter(...) : String | JsonpController.java:62:16:62:24 | - resultStr | Jsonp Injection query might include code from $@. | JsonpController.java:59:32:59:68 | getParameter(...) | this user input | -| JsonpController.java:77:20:77:28 | resultStr | JsonpController.java:69:32:69:68 | getParameter(...) : String | JsonpController.java:77:20:77:28 | - resultStr | Jsonp Injection query might include code from $@. | JsonpController.java:69:32:69:68 | getParameter(...) | this user input | -| JsonpController.java:91:20:91:28 | resultStr | JsonpController.java:84:32:84:68 | getParameter(...) : String | JsonpController.java:91:20:91:28 | - resultStr | Jsonp Injection query might include code from $@. | JsonpController.java:84:32:84:68 | getParameter(...) | this user input | -| JsonpInjectionServlet2.java:39:20:39:28 | resultStr | JsonpInjectionServlet2.java:31:32:31:64 | getParameter(...) : String | JsonpInjectionServle -t2.java:39:20:39:28 | resultStr | Jsonp Injection query might include code from $@. | JsonpInjectionServlet2.java:31:32:31:64 | getParameter(...) | - this user input | \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection_3.expected b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection_3.expected deleted file mode 100644 index 8e33ca6984c..00000000000 --- a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection_3.expected +++ /dev/null @@ -1,66 +0,0 @@ -edges -| JsonpController.java:26:32:26:68 | getParameter(...) : String | JsonpController.java:31:16:31:24 | resultStr | -| JsonpController.java:30:21:30:54 | ... + ... : String | JsonpController.java:31:16:31:24 | resultStr | -| JsonpController.java:38:32:38:68 | getParameter(...) : String | JsonpController.java:42:16:42:24 | resultStr | -| JsonpController.java:40:21:40:80 | ... + ... : String | JsonpController.java:42:16:42:24 | resultStr | -| JsonpController.java:49:32:49:68 | getParameter(...) : String | JsonpController.java:52:16:52:24 | resultStr | -| JsonpController.java:51:21:51:55 | ... + ... : String | JsonpController.java:52:16:52:24 | resultStr | -| JsonpController.java:59:32:59:68 | getParameter(...) : String | JsonpController.java:62:16:62:24 | resultStr | -| JsonpController.java:61:21:61:54 | ... + ... : String | JsonpController.java:62:16:62:24 | resultStr | -| JsonpController.java:69:32:69:68 | getParameter(...) : String | JsonpController.java:77:20:77:28 | resultStr | -| JsonpController.java:76:21:76:54 | ... + ... : String | JsonpController.java:77:20:77:28 | resultStr | -| JsonpController.java:84:32:84:68 | getParameter(...) : String | JsonpController.java:91:20:91:28 | resultStr | -| JsonpController.java:90:21:90:54 | ... + ... : String | JsonpController.java:91:20:91:28 | resultStr | -| JsonpController.java:99:24:99:52 | getParameter(...) : String | JsonpController.java:101:24:101:28 | token | -| JsonpController.java:102:36:102:72 | getParameter(...) : String | JsonpController.java:105:20:105:28 | resultStr | -| JsonpController.java:104:25:104:59 | ... + ... : String | JsonpController.java:105:20:105:28 | resultStr | -| JsonpInjectionServlet1.java:31:32:31:64 | getParameter(...) : String | JsonpInjectionServlet1.java:45:24:45:32 | resultStr | -| JsonpInjectionServlet1.java:36:26:36:49 | getHeader(...) : String | JsonpInjectionServlet1.java:38:39:38:45 | referer | -| JsonpInjectionServlet1.java:44:25:44:62 | ... + ... : String | JsonpInjectionServlet1.java:45:24:45:32 | resultStr | -| JsonpInjectionServlet2.java:31:32:31:64 | getParameter(...) : String | JsonpInjectionServlet2.java:39:20:39:28 | resultStr | -| JsonpInjectionServlet2.java:38:21:38:54 | ... + ... : String | JsonpInjectionServlet2.java:39:20:39:28 | resultStr | -| RefererFilter.java:22:26:22:53 | getHeader(...) : String | RefererFilter.java:23:39:23:45 | refefer | -nodes -| JsonpController.java:26:32:26:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:30:21:30:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:31:16:31:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:31:16:31:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:38:32:38:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:40:21:40:80 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:42:16:42:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:42:16:42:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:49:32:49:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:51:21:51:55 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:52:16:52:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:52:16:52:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:59:32:59:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:61:21:61:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:62:16:62:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:62:16:62:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:69:32:69:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:76:21:76:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:77:20:77:28 | resultStr | semmle.label | resultStr | -| JsonpController.java:77:20:77:28 | resultStr | semmle.label | resultStr | -| JsonpController.java:84:32:84:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:90:21:90:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:91:20:91:28 | resultStr | semmle.label | resultStr | -| JsonpController.java:91:20:91:28 | resultStr | semmle.label | resultStr | -| JsonpController.java:99:24:99:52 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:101:24:101:28 | token | semmle.label | token | -| JsonpController.java:102:36:102:72 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:104:25:104:59 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:105:20:105:28 | resultStr | semmle.label | resultStr | -| JsonpController.java:105:20:105:28 | resultStr | semmle.label | resultStr | -| JsonpInjectionServlet1.java:31:32:31:64 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpInjectionServlet1.java:36:26:36:49 | getHeader(...) : String | semmle.label | getHeader(...) : String | -| JsonpInjectionServlet1.java:38:39:38:45 | referer | semmle.label | referer | -| JsonpInjectionServlet1.java:44:25:44:62 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpInjectionServlet1.java:45:24:45:32 | resultStr | semmle.label | resultStr | -| JsonpInjectionServlet1.java:45:24:45:32 | resultStr | semmle.label | resultStr | -| JsonpInjectionServlet2.java:31:32:31:64 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpInjectionServlet2.java:38:21:38:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpInjectionServlet2.java:39:20:39:28 | resultStr | semmle.label | resultStr | -| JsonpInjectionServlet2.java:39:20:39:28 | resultStr | semmle.label | resultStr | -| RefererFilter.java:22:26:22:53 | getHeader(...) : String | semmle.label | getHeader(...) : String | -| RefererFilter.java:23:39:23:45 | refefer | semmle.label | refefer | -#select \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/Readme b/java/ql/test/experimental/query-tests/security/CWE-352/Readme deleted file mode 100644 index 15715d6187c..00000000000 --- a/java/ql/test/experimental/query-tests/security/CWE-352/Readme +++ /dev/null @@ -1,3 +0,0 @@ -1. The JsonpInjection_1.expected result is obtained through the test of `JsonpController.java`. -2. The JsonpInjection_2.expected result is obtained through the test of `JsonpController.java`, `JsonpInjectionServlet1.java`, `JsonpInjectionServlet2.java`. -3. The JsonpInjection_3.expected result is obtained through the test of `JsonpController.java`, `JsonpInjectionServlet1.java`, `JsonpInjectionServlet2.java`, `RefererFilter.java`. \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/RefererFilter.java b/java/ql/test/experimental/query-tests/security/CWE-352/RefererFilter.java deleted file mode 100644 index 97444932ae1..00000000000 --- a/java/ql/test/experimental/query-tests/security/CWE-352/RefererFilter.java +++ /dev/null @@ -1,43 +0,0 @@ -import java.io.IOException; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.springframework.util.StringUtils; - -public class RefererFilter implements Filter { - - @Override - public void init(FilterConfig filterConfig) throws ServletException { - } - - @Override - public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { - HttpServletRequest request = (HttpServletRequest) servletRequest; - HttpServletResponse response = (HttpServletResponse) servletResponse; - String refefer = request.getHeader("Referer"); - boolean result = verifReferer(refefer); - if (result){ - filterChain.doFilter(servletRequest, servletResponse); - } - response.sendError(444, "Referer xxx."); - } - - @Override - public void destroy() { - } - - public static boolean verifReferer(String referer){ - if (StringUtils.isEmpty(referer)){ - return false; - } - if (referer.startsWith("http://www.baidu.com/")){ - return true; - } - return false; - } -} diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/options b/java/ql/test/experimental/query-tests/security/CWE-352/options deleted file mode 100644 index 3676b8e38b6..00000000000 --- a/java/ql/test/experimental/query-tests/security/CWE-352/options +++ /dev/null @@ -1 +0,0 @@ -//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/apache-http-4.4.13/:${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/fastjson-1.2.74/:${testdir}/../../../../stubs/gson-2.8.6/:${testdir}/../../../../stubs/jackson-databind-2.10/:${testdir}/../../../../stubs/springframework-5.2.3/:${testdir}/../../../../stubs/spring-context-5.3.2/:${testdir}/../../../../stubs/spring-web-5.3.2/:${testdir}/../../../../stubs/spring-core-5.3.2/ diff --git a/java/ql/test/stubs/spring-core-5.3.2/org/springframework/core/annotation/AliasFor.java b/java/ql/test/stubs/spring-core-5.3.2/org/springframework/core/annotation/AliasFor.java index 3a823fade5b..edfe917400b 100644 --- a/java/ql/test/stubs/spring-core-5.3.2/org/springframework/core/annotation/AliasFor.java +++ b/java/ql/test/stubs/spring-core-5.3.2/org/springframework/core/annotation/AliasFor.java @@ -1,10 +1,21 @@ package org.springframework.core.annotation; +import java.lang.annotation.Annotation; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD}) +@Documented public @interface AliasFor { @AliasFor("attribute") String value() default ""; @AliasFor("value") String attribute() default ""; - + + Class annotation() default Annotation.class; } diff --git a/java/ql/test/stubs/spring-core-5.3.2/org/springframework/core/io/InputStreamSource.java b/java/ql/test/stubs/spring-core-5.3.2/org/springframework/core/io/InputStreamSource.java new file mode 100644 index 00000000000..372d06cc738 --- /dev/null +++ b/java/ql/test/stubs/spring-core-5.3.2/org/springframework/core/io/InputStreamSource.java @@ -0,0 +1,8 @@ +package org.springframework.core.io; + +import java.io.IOException; +import java.io.InputStream; + +public interface InputStreamSource { + InputStream getInputStream() throws IOException; +} diff --git a/java/ql/test/stubs/spring-core-5.3.2/org/springframework/core/io/Resource.java b/java/ql/test/stubs/spring-core-5.3.2/org/springframework/core/io/Resource.java new file mode 100644 index 00000000000..6bd357f2228 --- /dev/null +++ b/java/ql/test/stubs/spring-core-5.3.2/org/springframework/core/io/Resource.java @@ -0,0 +1,46 @@ +package org.springframework.core.io; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URL; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; +import org.springframework.lang.Nullable; + +public interface Resource extends InputStreamSource { + boolean exists(); + + default boolean isReadable() { + return this.exists(); + } + + default boolean isOpen() { + return false; + } + + default boolean isFile() { + return false; + } + + URL getURL() throws IOException; + + URI getURI() throws IOException; + + File getFile() throws IOException; + + default ReadableByteChannel readableChannel() throws IOException { + return null; + } + + long contentLength() throws IOException; + + long lastModified() throws IOException; + + Resource createRelative(String var1) throws IOException; + + @Nullable + String getFilename(); + + String getDescription(); +} diff --git a/java/ql/test/stubs/spring-core-5.3.2/org/springframework/lang/Nullable.java b/java/ql/test/stubs/spring-core-5.3.2/org/springframework/lang/Nullable.java new file mode 100644 index 00000000000..44bdae10fda --- /dev/null +++ b/java/ql/test/stubs/spring-core-5.3.2/org/springframework/lang/Nullable.java @@ -0,0 +1,13 @@ +package org.springframework.lang; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface Nullable { +} diff --git a/java/ql/test/stubs/spring-core-5.3.2/org/springframework/util/FileCopyUtils.java b/java/ql/test/stubs/spring-core-5.3.2/org/springframework/util/FileCopyUtils.java new file mode 100644 index 00000000000..78d384d7266 --- /dev/null +++ b/java/ql/test/stubs/spring-core-5.3.2/org/springframework/util/FileCopyUtils.java @@ -0,0 +1,53 @@ +package org.springframework.util; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.Closeable; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.StringWriter; +import java.io.Writer; +import java.nio.file.Files; +import org.springframework.lang.Nullable; + +public abstract class FileCopyUtils { + public static final int BUFFER_SIZE = 4096; + + public FileCopyUtils() { + } + + public static int copy(File in, File out) throws IOException { + return 1; + } + + public static void copy(byte[] in, File out) throws IOException {} + + public static byte[] copyToByteArray(File in) throws IOException { + return null; + } + + public static int copy(InputStream in, OutputStream out) throws IOException { + return 1; + } + + public static void copy(byte[] in, OutputStream out) throws IOException {} + + public static byte[] copyToByteArray(@Nullable InputStream in) throws IOException { + return null; + } + + public static int copy(Reader in, Writer out) throws IOException { + return 1; + } + + public static void copy(String in, Writer out) throws IOException {} + + public static String copyToString(@Nullable Reader in) throws IOException { + return null; + } + + private static void close(Closeable closeable) {} +} diff --git a/java/ql/test/stubs/spring-core-5.3.2/org/springframework/util/StringUtils.java b/java/ql/test/stubs/spring-core-5.3.2/org/springframework/util/StringUtils.java index 6ee07f84593..6ea27bbffa2 100644 --- a/java/ql/test/stubs/spring-core-5.3.2/org/springframework/util/StringUtils.java +++ b/java/ql/test/stubs/spring-core-5.3.2/org/springframework/util/StringUtils.java @@ -5,4 +5,4 @@ public abstract class StringUtils { public static boolean isEmpty(Object str) { return str == null || "".equals(str); } -} \ No newline at end of file +} diff --git a/java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/bind/annotation/GetMapping.java b/java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/bind/annotation/GetMapping.java index 1190be7b879..541c7cd4e21 100644 --- a/java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/bind/annotation/GetMapping.java +++ b/java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/bind/annotation/GetMapping.java @@ -1,19 +1,51 @@ package org.springframework.web.bind.annotation; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; import org.springframework.core.annotation.AliasFor; -@RequestMapping +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@RequestMapping( + method = {RequestMethod.GET} +) public @interface GetMapping { - + @AliasFor( + annotation = RequestMapping.class + ) String name() default ""; + @AliasFor( + annotation = RequestMapping.class + ) String[] value() default {}; + @AliasFor( + annotation = RequestMapping.class + ) String[] path() default {}; + @AliasFor( + annotation = RequestMapping.class + ) String[] params() default {}; + @AliasFor( + annotation = RequestMapping.class + ) + String[] headers() default {}; + + @AliasFor( + annotation = RequestMapping.class + ) String[] consumes() default {}; + @AliasFor( + annotation = RequestMapping.class + ) String[] produces() default {}; } diff --git a/java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/bind/annotation/Mapping.java b/java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/bind/annotation/Mapping.java new file mode 100644 index 00000000000..5f269bbcbb8 --- /dev/null +++ b/java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/bind/annotation/Mapping.java @@ -0,0 +1,4 @@ +package org.springframework.web.bind.annotation; + +public @interface Mapping { +} diff --git a/java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/bind/annotation/RequestMapping.java b/java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/bind/annotation/RequestMapping.java index ddb36bce4c0..ed692a03063 100644 --- a/java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/bind/annotation/RequestMapping.java +++ b/java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/bind/annotation/RequestMapping.java @@ -1,15 +1,32 @@ package org.springframework.web.bind.annotation; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; import org.springframework.core.annotation.AliasFor; +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Mapping public @interface RequestMapping { String name() default ""; @AliasFor("path") String[] value() default {}; - + @AliasFor("value") String[] path() default {}; RequestMethod[] method() default {}; + + String[] params() default {}; + + String[] headers() default {}; + + String[] consumes() default {}; + + String[] produces() default {}; } diff --git a/java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/bind/annotation/RequestParam.java b/java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/bind/annotation/RequestParam.java new file mode 100644 index 00000000000..56094811c37 --- /dev/null +++ b/java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/bind/annotation/RequestParam.java @@ -0,0 +1,23 @@ +package org.springframework.web.bind.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import org.springframework.core.annotation.AliasFor; + +@Target({ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RequestParam { + @AliasFor("name") + String value() default ""; + + @AliasFor("value") + String name() default ""; + + boolean required() default true; + + String defaultValue() default "\n\t\t\n\t\t\n\ue000\ue001\ue002\n\t\t\t\t\n"; +} diff --git a/java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/bind/annotation/ResponseBody.java b/java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/bind/annotation/ResponseBody.java index b2134009968..4f21b6daaaf 100644 --- a/java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/bind/annotation/ResponseBody.java +++ b/java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/bind/annotation/ResponseBody.java @@ -1,4 +1,13 @@ package org.springframework.web.bind.annotation; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented public @interface ResponseBody { } diff --git a/java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/multipart/MultipartFile.java b/java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/multipart/MultipartFile.java new file mode 100644 index 00000000000..93ea3439fed --- /dev/null +++ b/java/ql/test/stubs/spring-web-5.3.2/org/springframework/web/multipart/MultipartFile.java @@ -0,0 +1,38 @@ +package org.springframework.web.multipart; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import org.springframework.core.io.InputStreamSource; +import org.springframework.core.io.Resource; +import org.springframework.lang.Nullable; +import org.springframework.util.FileCopyUtils; + +public interface MultipartFile extends InputStreamSource { + String getName(); + + @Nullable + String getOriginalFilename(); + + @Nullable + String getContentType(); + + boolean isEmpty(); + + long getSize(); + + byte[] getBytes() throws IOException; + + InputStream getInputStream() throws IOException; + + default Resource getResource() { + return null; + } + + void transferTo(File var1) throws IOException, IllegalStateException; + + default void transferTo(Path dest) throws IOException, IllegalStateException { + } +} diff --git a/java/ql/test/stubs/tomcat-embed-core-9.0.41/javax/servlet/annotation/WebServlet.java b/java/ql/test/stubs/tomcat-embed-core-9.0.41/javax/servlet/annotation/WebServlet.java new file mode 100644 index 00000000000..cc255efc00f --- /dev/null +++ b/java/ql/test/stubs/tomcat-embed-core-9.0.41/javax/servlet/annotation/WebServlet.java @@ -0,0 +1,30 @@ +package javax.servlet.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface WebServlet { + String name() default ""; + + String[] value() default {}; + + String[] urlPatterns() default {}; + + int loadOnStartup() default -1; + + boolean asyncSupported() default false; + + String smallIcon() default ""; + + String largeIcon() default ""; + + String description() default ""; + + String displayName() default ""; +} From 15206fd2ce3d53168caa2d0250c2b9036dccfca9 Mon Sep 17 00:00:00 2001 From: haby0 Date: Wed, 17 Mar 2021 15:52:05 +0800 Subject: [PATCH 135/725] JsonpInjection.ql autoformatted --- java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.ql b/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.ql index 068469328ea..eb4fe4e5b66 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.ql @@ -46,7 +46,7 @@ class RequestResponseFlowConfig extends TaintTracking::Configuration { /** Eliminate the method of calling the node is not the get method. */ override predicate isSanitizer(DataFlow::Node node) { - not getACallingCallableOrSelf(node.getEnclosingCallable()) instanceof RequestGetMethod + not getACallingCallableOrSelf(node.getEnclosingCallable()) instanceof RequestGetMethod } override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { From 0b1705f302d17e933124e3a2b3f22aae5d164f96 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Wed, 17 Mar 2021 09:25:57 +0100 Subject: [PATCH 136/725] C#: Adjust Callable::canReturn to handle Task-like async return types --- csharp/ql/src/semmle/code/csharp/Callable.qll | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/Callable.qll b/csharp/ql/src/semmle/code/csharp/Callable.qll index 83e1739be89..111702bac48 100644 --- a/csharp/ql/src/semmle/code/csharp/Callable.qll +++ b/csharp/ql/src/semmle/code/csharp/Callable.qll @@ -11,7 +11,6 @@ private import dotnet private import semmle.code.csharp.ExprOrStmtParent private import semmle.code.csharp.metrics.Complexity private import TypeRef -private import semmle.code.csharp.frameworks.system.threading.Tasks /** * An element that can be called. @@ -210,7 +209,7 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal not this.getReturnType() instanceof VoidType and ( not this.(Modifiable).isAsync() or - not this.getReturnType() instanceof SystemThreadingTasksTaskClass + this.getReturnType() instanceof Generic ) } From 78843882f90a4f167dfab4bc3aec4a80501e6872 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Fri, 12 Mar 2021 12:51:00 +0100 Subject: [PATCH 137/725] C#: Upgrade nuget packages --- csharp/autobuilder/Semmle.Autobuild.CSharp/DotNetRule.cs | 2 +- .../Semmle.Autobuild.CSharp/Semmle.Autobuild.CSharp.csproj | 4 ++-- .../Semmle.Autobuild.Shared/Semmle.Autobuild.Shared.csproj | 2 +- .../Semmle.Extraction.CSharp.Standalone.csproj | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/csharp/autobuilder/Semmle.Autobuild.CSharp/DotNetRule.cs b/csharp/autobuilder/Semmle.Autobuild.CSharp/DotNetRule.cs index 93f0a630d1e..8787406c104 100644 --- a/csharp/autobuilder/Semmle.Autobuild.CSharp/DotNetRule.cs +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp/DotNetRule.cs @@ -145,7 +145,7 @@ namespace Semmle.Autobuild.CSharp try { var o = JObject.Parse(File.ReadAllText(path)); - version = (string)o["sdk"]["version"]; + version = (string)(o?["sdk"]?["version"]!); } catch // lgtm[cs/catch-of-all-exceptions] { diff --git a/csharp/autobuilder/Semmle.Autobuild.CSharp/Semmle.Autobuild.CSharp.csproj b/csharp/autobuilder/Semmle.Autobuild.CSharp/Semmle.Autobuild.CSharp.csproj index b02b1a3fef1..60291bfc308 100644 --- a/csharp/autobuilder/Semmle.Autobuild.CSharp/Semmle.Autobuild.CSharp.csproj +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp/Semmle.Autobuild.CSharp.csproj @@ -17,8 +17,8 @@ - - + + diff --git a/csharp/autobuilder/Semmle.Autobuild.Shared/Semmle.Autobuild.Shared.csproj b/csharp/autobuilder/Semmle.Autobuild.Shared/Semmle.Autobuild.Shared.csproj index 5f59b205527..ae1c61bc992 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Shared/Semmle.Autobuild.Shared.csproj +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/Semmle.Autobuild.Shared.csproj @@ -14,7 +14,7 @@ - + diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Semmle.Extraction.CSharp.Standalone.csproj b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Semmle.Extraction.CSharp.Standalone.csproj index adf51941ad7..aed85473e7c 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Semmle.Extraction.CSharp.Standalone.csproj +++ b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Semmle.Extraction.CSharp.Standalone.csproj @@ -23,7 +23,7 @@ - + From 2f3869f41bfdfd272e73d5e1314a30950be0d3a5 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 16 Mar 2021 23:45:36 +0100 Subject: [PATCH 138/725] add model for puppeteer --- javascript/ql/src/javascript.qll | 1 + .../javascript/frameworks/Puppeteer.qll | 125 ++++++++++++++++++ .../dataflow/TaintedPathCustomizations.qll | 14 ++ .../ClientRequests/ClientRequests.expected | 6 + .../frameworks/ClientRequests/puppeteer.ts | 20 +++ .../frameworks/ClientRequests/tsconfig.json | 1 + .../CWE-022/TaintedPath/TaintedPath.expected | 41 ++++++ .../Security/CWE-022/TaintedPath/pupeteer.js | 18 +++ 8 files changed, 226 insertions(+) create mode 100644 javascript/ql/src/semmle/javascript/frameworks/Puppeteer.qll create mode 100644 javascript/ql/test/library-tests/frameworks/ClientRequests/puppeteer.ts create mode 100644 javascript/ql/test/library-tests/frameworks/ClientRequests/tsconfig.json create mode 100644 javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/pupeteer.js diff --git a/javascript/ql/src/javascript.qll b/javascript/ql/src/javascript.qll index b3664fce00e..66dccd8cddd 100644 --- a/javascript/ql/src/javascript.qll +++ b/javascript/ql/src/javascript.qll @@ -102,6 +102,7 @@ import semmle.javascript.frameworks.Next import semmle.javascript.frameworks.NoSQL import semmle.javascript.frameworks.PkgCloud import semmle.javascript.frameworks.PropertyProjection +import semmle.javascript.frameworks.Puppeteer import semmle.javascript.frameworks.React import semmle.javascript.frameworks.ReactNative import semmle.javascript.frameworks.Request diff --git a/javascript/ql/src/semmle/javascript/frameworks/Puppeteer.qll b/javascript/ql/src/semmle/javascript/frameworks/Puppeteer.qll new file mode 100644 index 00000000000..94f644ebb94 --- /dev/null +++ b/javascript/ql/src/semmle/javascript/frameworks/Puppeteer.qll @@ -0,0 +1,125 @@ +import javascript + +/** + * Classes and predicates modelling the `puppeteer` library. + */ +module Puppeteer { + /** + * A reference to a module import of puppeteer. + */ + private API::Node puppeteer() { result = API::moduleImport(["puppeteer", "puppeteer-core"]) } + + private class BrowserTypeEntryPoint extends API::EntryPoint { + BrowserTypeEntryPoint() { this = "PuppeteerBrowserTypeEntryPoint" } + + override DataFlow::SourceNode getAUse() { result.hasUnderlyingType("puppeteer", "Browser") } + + override DataFlow::Node getARhs() { none() } + } + + /** + * A reference to a `Browser` from puppeteer. + */ + private API::Node browser() { + result = API::root().getASuccessor(any(BrowserTypeEntryPoint b)) + or + result = puppeteer().getMember(["launch", "connect"]).getReturn().getPromised() + or + result = [page(), context(), target()].getMember("browser").getReturn() + } + + private class PageTypeEntryPoint extends API::EntryPoint { + PageTypeEntryPoint() { this = "PuppeteerPageTypeEntryPoint" } + + override DataFlow::SourceNode getAUse() { result.hasUnderlyingType("puppeteer", "Page") } + + override DataFlow::Node getARhs() { none() } + } + + /** + * A reference to a `Page` from puppeteer. + */ + API::Node page() { + result = API::root().getASuccessor(any(PageTypeEntryPoint b)) + or + result = [browser(), context()].getMember("newPage").getReturn().getPromised() + or + result = [browser(), context()].getMember("pages").getReturn().getPromised().getUnknownMember() + or + result = target().getMember("page").getReturn().getPromised() + } + + private class TargetTypeEntryPoint extends API::EntryPoint { + TargetTypeEntryPoint() { this = "PuppeteerTargetTypeEntryPoint" } + + override DataFlow::SourceNode getAUse() { result.hasUnderlyingType("puppeteer", "Target") } + + override DataFlow::Node getARhs() { none() } + } + + /** + * A reference to a `Target` from puppeteer. + */ + private API::Node target() { + result = API::root().getASuccessor(any(TargetTypeEntryPoint b)) + or + result = [page(), browser()].getMember("target").getReturn() + or + result = context().getMember("targets").getReturn().getUnknownMember() + or + result = target().getMember("opener").getReturn() + } + + private class ContextTypeEntryPoint extends API::EntryPoint { + ContextTypeEntryPoint() { this = "PuppeteerContextTypeEntryPoint" } + + override DataFlow::SourceNode getAUse() { + result.hasUnderlyingType("puppeteer", "BrowserContext") + } + + override DataFlow::Node getARhs() { none() } + } + + /** + * A reference to a `BrowserContext` from puppeteer. + */ + private API::Node context() { + result = API::root().getASuccessor(any(ContextTypeEntryPoint b)) + or + result = [page(), target()].getMember("browserContext").getReturn() + or + result = browser().getMember("browserContexts").getReturn().getUnknownMember() + or + result = browser().getMember("createIncognitoBrowserContext").getReturn().getPromised() + or + result = browser().getMember("defaultBrowserContext").getReturn() + } + + /** + * A call requesting a `Page` to navigate to some url, seen as a `ClientRequest`. + */ + private class PuppeteerGotoCall extends ClientRequest::Range, API::InvokeNode { + PuppeteerGotoCall() { this = page().getMember("goto").getACall() } + + override DataFlow::Node getUrl() { result = getArgument(0) } + + override DataFlow::Node getHost() { none() } + + override DataFlow::Node getADataNode() { none() } + } + + /** + * A call requesting a `Page` to load a stylesheet or script, seen as a `ClientRequest`. + */ + private class PuppeteerLoadResourceCall extends ClientRequest::Range, API::InvokeNode { + PuppeteerLoadResourceCall() { + this = page().getMember(["addStyleTag", "addScriptTag"]).getACall() + } + + override DataFlow::Node getUrl() { result = getParameter(0).getMember("url").getARhs() } + + override DataFlow::Node getHost() { none() } + + override DataFlow::Node getADataNode() { none() } + } +} diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll index 095a2e072c1..80c4346bace 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll @@ -631,6 +631,20 @@ module TaintedPath { SendPathSink() { this = DataFlow::moduleImport("send").getACall().getArgument(1) } } + /** + * A path argument given to a `Page` in puppeteer, specifying where a pdf/screenshot should be saved. + */ + private class PuppeteerPath extends TaintedPath::Sink { + PuppeteerPath() { + this = + Puppeteer::page() + .getMember(["pdf", "screenshot"]) + .getParameter(0) + .getMember("path") + .getARhs() + } + } + /** * Holds if there is a step `src -> dst` mapping `srclabel` to `dstlabel` relevant for path traversal vulnerabilities. */ diff --git a/javascript/ql/test/library-tests/frameworks/ClientRequests/ClientRequests.expected b/javascript/ql/test/library-tests/frameworks/ClientRequests/ClientRequests.expected index 2bf2d305cb0..e1cdc2dc000 100644 --- a/javascript/ql/test/library-tests/frameworks/ClientRequests/ClientRequests.expected +++ b/javascript/ql/test/library-tests/frameworks/ClientRequests/ClientRequests.expected @@ -5,6 +5,9 @@ test_ClientRequest | apollo.js:17:1:17:34 | new Pre ... yurl"}) | | apollo.js:20:1:20:77 | createN ... phql'}) | | apollo.js:23:1:23:31 | new Web ... wsUri}) | +| puppeteer.ts:6:11:6:42 | page.go ... e.com') | +| puppeteer.ts:8:5:8:61 | page.ad ... css" }) | +| puppeteer.ts:18:30:18:50 | page.go ... estUrl) | | tst.js:11:5:11:16 | request(url) | | tst.js:13:5:13:20 | request.get(url) | | tst.js:15:5:15:23 | request.delete(url) | @@ -136,6 +139,9 @@ test_getUrl | apollo.js:17:1:17:34 | new Pre ... yurl"}) | apollo.js:17:26:17:32 | "myurl" | | apollo.js:20:1:20:77 | createN ... phql'}) | apollo.js:20:30:20:75 | 'https: ... raphql' | | apollo.js:23:1:23:31 | new Web ... wsUri}) | apollo.js:23:25:23:29 | wsUri | +| puppeteer.ts:6:11:6:42 | page.go ... e.com') | puppeteer.ts:6:21:6:41 | 'https: ... le.com' | +| puppeteer.ts:8:5:8:61 | page.ad ... css" }) | puppeteer.ts:8:29:8:58 | "http:/ ... le.css" | +| puppeteer.ts:18:30:18:50 | page.go ... estUrl) | puppeteer.ts:18:40:18:49 | requestUrl | | tst.js:11:5:11:16 | request(url) | tst.js:11:13:11:15 | url | | tst.js:13:5:13:20 | request.get(url) | tst.js:13:17:13:19 | url | | tst.js:15:5:15:23 | request.delete(url) | tst.js:15:20:15:22 | url | diff --git a/javascript/ql/test/library-tests/frameworks/ClientRequests/puppeteer.ts b/javascript/ql/test/library-tests/frameworks/ClientRequests/puppeteer.ts new file mode 100644 index 00000000000..5f630f1a691 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/ClientRequests/puppeteer.ts @@ -0,0 +1,20 @@ +import * as puppeteer from 'puppeteer'; + +(async () => { + const browser = await puppeteer.launch(); + const page = await browser.newPage(); + await page.goto('https://example.com'); + + page.addStyleTag({ url: "http://example.org/style.css" }) +})(); + +class Renderer { + private browser: puppeteer.Browser; + constructor(browser: puppeteer.Browser) { + this.browser = browser; + } + async foo(requestUrl: string): Promise { + const page = await this.browser.newPage(); + let response = await page.goto(requestUrl); + } +} \ No newline at end of file diff --git a/javascript/ql/test/library-tests/frameworks/ClientRequests/tsconfig.json b/javascript/ql/test/library-tests/frameworks/ClientRequests/tsconfig.json new file mode 100644 index 00000000000..9e26dfeeb6e --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/ClientRequests/tsconfig.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected index 7e4ab1a0427..0b1fe929968 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected @@ -2168,6 +2168,24 @@ nodes | other-fs-libraries.js:42:53:42:56 | path | | other-fs-libraries.js:42:53:42:56 | path | | other-fs-libraries.js:42:53:42:56 | path | +| pupeteer.js:5:9:5:71 | tainted | +| pupeteer.js:5:9:5:71 | tainted | +| pupeteer.js:5:9:5:71 | tainted | +| pupeteer.js:5:19:5:71 | "dir/" ... t.data" | +| pupeteer.js:5:19:5:71 | "dir/" ... t.data" | +| pupeteer.js:5:19:5:71 | "dir/" ... t.data" | +| pupeteer.js:5:28:5:53 | parseTo ... t).name | +| pupeteer.js:5:28:5:53 | parseTo ... t).name | +| pupeteer.js:5:28:5:53 | parseTo ... t).name | +| pupeteer.js:5:28:5:53 | parseTo ... t).name | +| pupeteer.js:9:28:9:34 | tainted | +| pupeteer.js:9:28:9:34 | tainted | +| pupeteer.js:9:28:9:34 | tainted | +| pupeteer.js:9:28:9:34 | tainted | +| pupeteer.js:13:37:13:43 | tainted | +| pupeteer.js:13:37:13:43 | tainted | +| pupeteer.js:13:37:13:43 | tainted | +| pupeteer.js:13:37:13:43 | tainted | | tainted-access-paths.js:6:7:6:48 | path | | tainted-access-paths.js:6:7:6:48 | path | | tainted-access-paths.js:6:7:6:48 | path | @@ -6403,6 +6421,27 @@ edges | other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | | other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | | other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| pupeteer.js:5:9:5:71 | tainted | pupeteer.js:9:28:9:34 | tainted | +| pupeteer.js:5:9:5:71 | tainted | pupeteer.js:9:28:9:34 | tainted | +| pupeteer.js:5:9:5:71 | tainted | pupeteer.js:9:28:9:34 | tainted | +| pupeteer.js:5:9:5:71 | tainted | pupeteer.js:9:28:9:34 | tainted | +| pupeteer.js:5:9:5:71 | tainted | pupeteer.js:9:28:9:34 | tainted | +| pupeteer.js:5:9:5:71 | tainted | pupeteer.js:9:28:9:34 | tainted | +| pupeteer.js:5:9:5:71 | tainted | pupeteer.js:13:37:13:43 | tainted | +| pupeteer.js:5:9:5:71 | tainted | pupeteer.js:13:37:13:43 | tainted | +| pupeteer.js:5:9:5:71 | tainted | pupeteer.js:13:37:13:43 | tainted | +| pupeteer.js:5:9:5:71 | tainted | pupeteer.js:13:37:13:43 | tainted | +| pupeteer.js:5:9:5:71 | tainted | pupeteer.js:13:37:13:43 | tainted | +| pupeteer.js:5:9:5:71 | tainted | pupeteer.js:13:37:13:43 | tainted | +| pupeteer.js:5:19:5:71 | "dir/" ... t.data" | pupeteer.js:5:9:5:71 | tainted | +| pupeteer.js:5:19:5:71 | "dir/" ... t.data" | pupeteer.js:5:9:5:71 | tainted | +| pupeteer.js:5:19:5:71 | "dir/" ... t.data" | pupeteer.js:5:9:5:71 | tainted | +| pupeteer.js:5:28:5:53 | parseTo ... t).name | pupeteer.js:5:19:5:71 | "dir/" ... t.data" | +| pupeteer.js:5:28:5:53 | parseTo ... t).name | pupeteer.js:5:19:5:71 | "dir/" ... t.data" | +| pupeteer.js:5:28:5:53 | parseTo ... t).name | pupeteer.js:5:19:5:71 | "dir/" ... t.data" | +| pupeteer.js:5:28:5:53 | parseTo ... t).name | pupeteer.js:5:19:5:71 | "dir/" ... t.data" | +| pupeteer.js:5:28:5:53 | parseTo ... t).name | pupeteer.js:5:19:5:71 | "dir/" ... t.data" | +| pupeteer.js:5:28:5:53 | parseTo ... t).name | pupeteer.js:5:19:5:71 | "dir/" ... t.data" | | tainted-access-paths.js:6:7:6:48 | path | tainted-access-paths.js:8:19:8:22 | path | | tainted-access-paths.js:6:7:6:48 | path | tainted-access-paths.js:8:19:8:22 | path | | tainted-access-paths.js:6:7:6:48 | path | tainted-access-paths.js:8:19:8:22 | path | @@ -8007,6 +8046,8 @@ edges | other-fs-libraries.js:40:35:40:38 | path | other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:40:35:40:38 | path | This path depends on $@. | other-fs-libraries.js:38:24:38:30 | req.url | a user-provided value | | other-fs-libraries.js:41:50:41:53 | path | other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:41:50:41:53 | path | This path depends on $@. | other-fs-libraries.js:38:24:38:30 | req.url | a user-provided value | | other-fs-libraries.js:42:53:42:56 | path | other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:42:53:42:56 | path | This path depends on $@. | other-fs-libraries.js:38:24:38:30 | req.url | a user-provided value | +| pupeteer.js:9:28:9:34 | tainted | pupeteer.js:5:28:5:53 | parseTo ... t).name | pupeteer.js:9:28:9:34 | tainted | This path depends on $@. | pupeteer.js:5:28:5:53 | parseTo ... t).name | a user-provided value | +| pupeteer.js:13:37:13:43 | tainted | pupeteer.js:5:28:5:53 | parseTo ... t).name | pupeteer.js:13:37:13:43 | tainted | This path depends on $@. | pupeteer.js:5:28:5:53 | parseTo ... t).name | a user-provided value | | tainted-access-paths.js:8:19:8:22 | path | tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:8:19:8:22 | path | This path depends on $@. | tainted-access-paths.js:6:24:6:30 | req.url | a user-provided value | | tainted-access-paths.js:12:19:12:25 | obj.sub | tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:12:19:12:25 | obj.sub | This path depends on $@. | tainted-access-paths.js:6:24:6:30 | req.url | a user-provided value | | tainted-access-paths.js:26:19:26:26 | obj.sub3 | tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:26:19:26:26 | obj.sub3 | This path depends on $@. | tainted-access-paths.js:6:24:6:30 | req.url | a user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/pupeteer.js b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/pupeteer.js new file mode 100644 index 00000000000..363b2f014c7 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/pupeteer.js @@ -0,0 +1,18 @@ +const puppeteer = require('puppeteer'); +const parseTorrent = require('parse-torrent'); + +(async () => { + let tainted = "dir/" + parseTorrent(torrent).name + ".torrent.data"; + + const browser = await puppeteer.launch(); + const page = await browser.newPage(); + await page.pdf({ path: tainted, format: 'a4' }); + + const pages = await browser.pages(); + for (let i = 0; i < something(); i++) { + pages[i].screenshot({ path: tainted }); + } + + await browser.close(); +})(); + From 8975c3a7ce678c4e715a8a1222e7b41697595411 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 17 Mar 2021 00:00:19 +0100 Subject: [PATCH 139/725] broaden which types are recognized by API-graphs --- .../ql/src/semmle/javascript/ApiGraphs.qll | 18 +++++++- .../javascript/frameworks/Puppeteer.qll | 42 ++----------------- 2 files changed, 21 insertions(+), 39 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/ApiGraphs.qll b/javascript/ql/src/semmle/javascript/ApiGraphs.qll index 6c8c9533557..fd955cf00ab 100644 --- a/javascript/ql/src/semmle/javascript/ApiGraphs.qll +++ b/javascript/ql/src/semmle/javascript/ApiGraphs.qll @@ -317,6 +317,8 @@ module API { tn.hasQualifiedName(moduleName, exportedName) and result = Impl::MkCanonicalNameUse(tn).(Node).getInstance() ) + or + result = Impl::MkHasUnderlyingType(moduleName, exportedName) } } @@ -413,6 +415,13 @@ module API { not n.isRoot() and isUsed(n) } or + /** + * An instance of a TypeScript type, identified by name of the type-annotation. + * This API node is exclusively used by `API::Node::ofType`. + */ + MkHasUnderlyingType(string moduleName, string exportName) { + any(TypeAnnotation n).hasQualifiedName(moduleName, exportName) + } or MkSyntheticCallbackArg(DataFlow::Node src, int bound, DataFlow::InvokeNode nd) { trackUseNode(src, true, bound).flowsTo(nd.getCalleeNode()) } @@ -423,7 +432,8 @@ module API { MkModuleExport or MkClassInstance or MkAsyncFuncResult or MkDef or MkCanonicalNameDef or MkSyntheticCallbackArg; - class TUse = MkModuleUse or MkModuleImport or MkUse or MkCanonicalNameUse; + class TUse = + MkModuleUse or MkModuleImport or MkUse or MkCanonicalNameUse or MkHasUnderlyingType; private predicate hasSemantics(DataFlow::Node nd) { not nd.getTopLevel().isExterns() } @@ -678,6 +688,12 @@ module API { nd = MkUse(ref) or exists(CanonicalName n | nd = MkCanonicalNameUse(n) | ref.asExpr() = n.getAnAccess()) + or + exists(string moduleName, string exportsName | + nd = MkHasUnderlyingType(moduleName, exportsName) + | + ref.(DataFlow::SourceNode).hasUnderlyingType(moduleName, exportsName) + ) } /** Holds if module `m` exports `rhs`. */ diff --git a/javascript/ql/src/semmle/javascript/frameworks/Puppeteer.qll b/javascript/ql/src/semmle/javascript/frameworks/Puppeteer.qll index 94f644ebb94..e60a447cd07 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Puppeteer.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Puppeteer.qll @@ -9,38 +9,22 @@ module Puppeteer { */ private API::Node puppeteer() { result = API::moduleImport(["puppeteer", "puppeteer-core"]) } - private class BrowserTypeEntryPoint extends API::EntryPoint { - BrowserTypeEntryPoint() { this = "PuppeteerBrowserTypeEntryPoint" } - - override DataFlow::SourceNode getAUse() { result.hasUnderlyingType("puppeteer", "Browser") } - - override DataFlow::Node getARhs() { none() } - } - /** * A reference to a `Browser` from puppeteer. */ private API::Node browser() { - result = API::root().getASuccessor(any(BrowserTypeEntryPoint b)) + result = API::Node::ofType("puppeteer", "Browser") or result = puppeteer().getMember(["launch", "connect"]).getReturn().getPromised() or result = [page(), context(), target()].getMember("browser").getReturn() } - private class PageTypeEntryPoint extends API::EntryPoint { - PageTypeEntryPoint() { this = "PuppeteerPageTypeEntryPoint" } - - override DataFlow::SourceNode getAUse() { result.hasUnderlyingType("puppeteer", "Page") } - - override DataFlow::Node getARhs() { none() } - } - /** * A reference to a `Page` from puppeteer. */ API::Node page() { - result = API::root().getASuccessor(any(PageTypeEntryPoint b)) + result = API::Node::ofType("puppeteer", "Page") or result = [browser(), context()].getMember("newPage").getReturn().getPromised() or @@ -49,19 +33,11 @@ module Puppeteer { result = target().getMember("page").getReturn().getPromised() } - private class TargetTypeEntryPoint extends API::EntryPoint { - TargetTypeEntryPoint() { this = "PuppeteerTargetTypeEntryPoint" } - - override DataFlow::SourceNode getAUse() { result.hasUnderlyingType("puppeteer", "Target") } - - override DataFlow::Node getARhs() { none() } - } - /** * A reference to a `Target` from puppeteer. */ private API::Node target() { - result = API::root().getASuccessor(any(TargetTypeEntryPoint b)) + result = API::Node::ofType("puppeteer", "Target") or result = [page(), browser()].getMember("target").getReturn() or @@ -70,21 +46,11 @@ module Puppeteer { result = target().getMember("opener").getReturn() } - private class ContextTypeEntryPoint extends API::EntryPoint { - ContextTypeEntryPoint() { this = "PuppeteerContextTypeEntryPoint" } - - override DataFlow::SourceNode getAUse() { - result.hasUnderlyingType("puppeteer", "BrowserContext") - } - - override DataFlow::Node getARhs() { none() } - } - /** * A reference to a `BrowserContext` from puppeteer. */ private API::Node context() { - result = API::root().getASuccessor(any(ContextTypeEntryPoint b)) + result = API::Node::ofType("puppeteer", "BrowserContext") or result = [page(), target()].getMember("browserContext").getReturn() or From edb0f7717760c4b2b8cb0208b60de81b7b15d669 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 17 Mar 2021 10:05:36 +0100 Subject: [PATCH 140/725] add missing qldoc --- .../ql/src/semmle/javascript/frameworks/Puppeteer.qll | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Puppeteer.qll b/javascript/ql/src/semmle/javascript/frameworks/Puppeteer.qll index e60a447cd07..84c2351b600 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Puppeteer.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Puppeteer.qll @@ -1,7 +1,11 @@ +/** + * Provides classes and predicates for reasoning about [puppeteer](https://www.npmjs.com/package/puppeteer). + */ + import javascript /** - * Classes and predicates modelling the `puppeteer` library. + * Classes and predicates modelling the [puppeteer](https://www.npmjs.com/package/puppeteer) library. */ module Puppeteer { /** From d1602d538ea437cf59bca5c31cdcf6fe8d9a74b5 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 17 Mar 2021 10:06:41 +0100 Subject: [PATCH 141/725] add change note --- javascript/change-notes/2021-03-17-puppeteer.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 javascript/change-notes/2021-03-17-puppeteer.md diff --git a/javascript/change-notes/2021-03-17-puppeteer.md b/javascript/change-notes/2021-03-17-puppeteer.md new file mode 100644 index 00000000000..84e8fadd9b7 --- /dev/null +++ b/javascript/change-notes/2021-03-17-puppeteer.md @@ -0,0 +1,4 @@ +lgtm,codescanning +* URIs used in the puppeteer library are now recognized as sinks for `js/request-forgery`. + Affected packages are + [puppeteer](https://www.npmjs.com/package/puppeteer) \ No newline at end of file From 96124266800de6683872968269245ffbbd5e8b16 Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Tue, 16 Mar 2021 12:56:40 +0000 Subject: [PATCH 142/725] C++: Initial file-related metric queries. This adds a library `FailedExtractions.qll` that classifies extractor errors and provides a unified interface for both recoverable and irrecoverable extractor errors. This interface is then used by the new diagnostic queries to list successfully extracted files, as well as files that encountered an extraction error. --- cpp/ql/src/Diagnostics/FailedExtractions.ql | 16 +++ cpp/ql/src/Diagnostics/FailedExtractions.qll | 114 ++++++++++++++++++ .../src/Diagnostics/SuccessfulExtractions.ql | 15 +++ 3 files changed, 145 insertions(+) create mode 100644 cpp/ql/src/Diagnostics/FailedExtractions.ql create mode 100644 cpp/ql/src/Diagnostics/FailedExtractions.qll create mode 100644 cpp/ql/src/Diagnostics/SuccessfulExtractions.ql diff --git a/cpp/ql/src/Diagnostics/FailedExtractions.ql b/cpp/ql/src/Diagnostics/FailedExtractions.ql new file mode 100644 index 00000000000..6a3d7daae4c --- /dev/null +++ b/cpp/ql/src/Diagnostics/FailedExtractions.ql @@ -0,0 +1,16 @@ +/** + * @name Failed extractions + * @description Gives the command-line of compilations for which extraction did not run to completion. + * @kind diagnostic + * @id cpp/diagnostics/failed-extractions + */ + +import cpp +import FailedExtractions + +from ExtractionError error +where + error instanceof ExtractionUnknownError or + exists(error.getFile().getRelativePath()) +select error, "Extracting file $@ failed with $@ (at $@)", error.getFile(), error.getErrorMessage(), + error.getLocation(), error.getSeverity() diff --git a/cpp/ql/src/Diagnostics/FailedExtractions.qll b/cpp/ql/src/Diagnostics/FailedExtractions.qll new file mode 100644 index 00000000000..808c4d7d386 --- /dev/null +++ b/cpp/ql/src/Diagnostics/FailedExtractions.qll @@ -0,0 +1,114 @@ +import cpp + +/** + * The class of errors upon we mark a file as non-successfully extracted. + */ +class ReportableError extends Diagnostic { + ReportableError() { + ( + this instanceof CompilerDiscretionaryError or + this instanceof CompilerError or + this instanceof CompilerCatastrophe + ) and + // If the extractor encounters an error in a compilation, it always emits a + // catch-all diagnostic "There was an error during this compilation", to ensure + // that the error makes it to the database. + // This error doesn't have a file path attached to it, and is thus + // useless for us to report. Furthermore, in the common case, we will have a + // proper diagnostic for this error we can show. + // Instead, we synthesize `TUnknownError` if this is the only error that we can show to the user. + not this.getFile().getAbsolutePath() = "" + } +} + +newtype TExtractionError = + TReportableError(ReportableError err) or + TCompilationFailed(Compilation c, File f) { + f = c.getAFileCompiled() and not c.normalTermination() + } or + // Report generic extractor errors only if we haven't seen any other error-level diagnostic + TUnknownError(CompilerError err) { not exists(ReportableError e) } + +class ExtractionError extends TExtractionError { + string toString() { none() } + + string getErrorMessage() { none() } + + File getFile() { none() } + + Location getLocation() { none() } + + int getSeverity() { + // Unfortunately, we can't distinguish between errors and fatal errors in SARIF, + // so all errors have severity 2. + result = 2 + } +} + +/** + * An irrecoverable extraction failure, where extraction was unable to finish. + * This can be caused by a multitude of reasons, for example: + * - hitting a frontend assertion + * - crashing due to dereferencing an invalid pointer + * - stack overflow + * - out of memory + */ +class ExtractionIrrecoverableError extends ExtractionError, TCompilationFailed { + Compilation c; + File f; + + ExtractionIrrecoverableError() { this = TCompilationFailed(c, f) } + + override string toString() { + result = "Irrecoverable extraction error: " + c.toString() + " in " + f.toString() + } + + override string getErrorMessage() { + result = + "Irrecoverable compilation failure, check logs/build-tracer.log in the database directory for more information." + } + + override File getFile() { result = f } + + override Location getLocation() { result = f.getLocation() } +} + +/** + * A recoverable extraction error. + * These are compiler errors from the frontend. + * Upon encountering one of these, we still continue extraction, but the + * database will be incomplete for that file. + */ +class ExtractionRecoverableError extends ExtractionError, TReportableError { + ReportableError err; + + ExtractionRecoverableError() { this = TReportableError(err) } + + override string toString() { result = "Recoverable extraction error: " + err } + + override string getErrorMessage() { result = err.getFullMessage() } + + override File getFile() { result = err.getFile() } + + override Location getLocation() { result = err.getLocation() } +} + +/** + * An unknown error happened during extraction. + * These are only displayed if we know that we encountered an error during extraction, + * but, for some reason, failed to emit a proper diagnostic with location information + * and error message. + */ +class ExtractionUnknownError extends ExtractionError, TUnknownError { + CompilerError err; + + ExtractionUnknownError() { this = TUnknownError(err) } + + override string toString() { result = "Unknown extraction error: " + err } + + override string getErrorMessage() { result = err.getFullMessage() } + + override File getFile() { result = err.getFile() } + + override Location getLocation() { result = err.getLocation() } +} diff --git a/cpp/ql/src/Diagnostics/SuccessfulExtractions.ql b/cpp/ql/src/Diagnostics/SuccessfulExtractions.ql new file mode 100644 index 00000000000..cf5ec56a493 --- /dev/null +++ b/cpp/ql/src/Diagnostics/SuccessfulExtractions.ql @@ -0,0 +1,15 @@ +/** + * @name Successfully extracted files. + * @description Lists all files in the database that were extracted without encountering an error. + * @kind diagnostic + * @id cpp/diagnostics/successfully-extracted-files + */ + +import cpp +import FailedExtractions + +from File f +where + not exists(ExtractionError e | e.getFile() = f) and + exists(f.getRelativePath()) +select f From 4c4fc05553616b354d3f660d546077874d888071 Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Tue, 16 Mar 2021 16:23:21 +0100 Subject: [PATCH 143/725] C++: Make toString deterministic for tests. --- cpp/ql/src/Diagnostics/FailedExtractions.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/Diagnostics/FailedExtractions.qll b/cpp/ql/src/Diagnostics/FailedExtractions.qll index 808c4d7d386..951dda23396 100644 --- a/cpp/ql/src/Diagnostics/FailedExtractions.qll +++ b/cpp/ql/src/Diagnostics/FailedExtractions.qll @@ -60,7 +60,7 @@ class ExtractionIrrecoverableError extends ExtractionError, TCompilationFailed { ExtractionIrrecoverableError() { this = TCompilationFailed(c, f) } override string toString() { - result = "Irrecoverable extraction error: " + c.toString() + " in " + f.toString() + result = "Irrecoverable extraction error while compiling " + f.toString() } override string getErrorMessage() { From 5e4e853ffb3f41c25493d7f891c9d32bdc6b7c22 Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Tue, 16 Mar 2021 16:27:13 +0100 Subject: [PATCH 144/725] C++: Add missing QLDoc. --- cpp/ql/src/Diagnostics/FailedExtractions.qll | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/Diagnostics/FailedExtractions.qll b/cpp/ql/src/Diagnostics/FailedExtractions.qll index 951dda23396..5fd371204ec 100644 --- a/cpp/ql/src/Diagnostics/FailedExtractions.qll +++ b/cpp/ql/src/Diagnostics/FailedExtractions.qll @@ -21,7 +21,7 @@ class ReportableError extends Diagnostic { } } -newtype TExtractionError = +private newtype TExtractionError = TReportableError(ReportableError err) or TCompilationFailed(Compilation c, File f) { f = c.getAFileCompiled() and not c.normalTermination() @@ -29,15 +29,22 @@ newtype TExtractionError = // Report generic extractor errors only if we haven't seen any other error-level diagnostic TUnknownError(CompilerError err) { not exists(ReportableError e) } +/** + * Superclass for the extraction error hierarchy. + */ class ExtractionError extends TExtractionError { string toString() { none() } + /** Gets the error message for this error. */ string getErrorMessage() { none() } + /** Gets the file this error occured in. */ File getFile() { none() } + /** Gets the location this error occured in. */ Location getLocation() { none() } + /** Gets the SARIF severity of this error. */ int getSeverity() { // Unfortunately, we can't distinguish between errors and fatal errors in SARIF, // so all errors have severity 2. From 144dcf1b5e51f51865b56864fb6e61316dcdee09 Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Tue, 16 Mar 2021 16:37:31 +0100 Subject: [PATCH 145/725] C++: Include empty message for SuccessfulExtractions.ql. --- cpp/ql/src/Diagnostics/SuccessfulExtractions.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/Diagnostics/SuccessfulExtractions.ql b/cpp/ql/src/Diagnostics/SuccessfulExtractions.ql index cf5ec56a493..4331b768934 100644 --- a/cpp/ql/src/Diagnostics/SuccessfulExtractions.ql +++ b/cpp/ql/src/Diagnostics/SuccessfulExtractions.ql @@ -12,4 +12,4 @@ from File f where not exists(ExtractionError e | e.getFile() = f) and exists(f.getRelativePath()) -select f +select f, "" From 3914a93504bb92bb514fe74cb609662f683f290b Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 17 Mar 2021 11:56:59 +0100 Subject: [PATCH 146/725] C++: Remove commonTaintStep from DefaultTaintTracking. --- .../cpp/ir/dataflow/DefaultTaintTracking.qll | 209 ------------------ 1 file changed, 209 deletions(-) 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 33473ebfb58..7b97bc738f4 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll @@ -74,10 +74,6 @@ private class DefaultTaintTrackingCfg extends TaintTracking::Configuration { override predicate isSink(DataFlow::Node sink) { exists(adjustedSink(sink)) } - override predicate isAdditionalTaintStep(DataFlow::Node n1, DataFlow::Node n2) { - commonTaintStep(n1, n2) - } - override predicate isSanitizer(DataFlow::Node node) { nodeIsBarrier(node) } override predicate isSanitizerIn(DataFlow::Node node) { nodeIsBarrierIn(node) } @@ -93,8 +89,6 @@ private class ToGlobalVarTaintTrackingCfg extends TaintTracking::Configuration { } override predicate isAdditionalTaintStep(DataFlow::Node n1, DataFlow::Node n2) { - commonTaintStep(n1, n2) - or writesVariable(n1.asInstruction(), n2.asVariable().(GlobalOrNamespaceVariable)) or readsVariable(n2.asInstruction(), n1.asVariable().(GlobalOrNamespaceVariable)) @@ -117,8 +111,6 @@ private class FromGlobalVarTaintTrackingCfg extends TaintTracking2::Configuratio override predicate isSink(DataFlow::Node sink) { exists(adjustedSink(sink)) } override predicate isAdditionalTaintStep(DataFlow::Node n1, DataFlow::Node n2) { - commonTaintStep(n1, n2) - or // Additional step for flow out of variables. There is no flow _into_ // variables in this configuration, so this step only serves to take flow // out of a variable that's a source. @@ -227,207 +219,6 @@ private predicate nodeIsBarrierIn(DataFlow::Node node) { ) } -cached -private predicate commonTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) { - operandToInstructionTaintStep(fromNode.asOperand(), toNode.asInstruction()) - or - instructionToOperandTaintStep(fromNode.asInstruction(), toNode.asOperand()) -} - -private predicate instructionToOperandTaintStep(Instruction fromInstr, Operand toOperand) { - // Propagate flow from the definition of an operand to the operand, even when the overlap is inexact. - // We only do this in certain cases: - // 1. The instruction's result must not be conflated, and - // 2. The instruction's result type is one the types where we expect element-to-object flow. Currently - // this is array types and union types. This matches the other two cases of element-to-object flow in - // `DefaultTaintTracking`. - toOperand.getAnyDef() = fromInstr and - not fromInstr.isResultConflated() and - ( - fromInstr.getResultType() instanceof ArrayType or - fromInstr.getResultType() instanceof Union - ) - or - exists(ReadSideEffectInstruction readInstr | - fromInstr = readInstr.getArgumentDef() and - toOperand = readInstr.getSideEffectOperand() - ) -} - -private predicate operandToInstructionTaintStep(Operand fromOperand, Instruction toInstr) { - // Expressions computed from tainted data are also tainted - exists(CallInstruction call, int argIndex | call = toInstr | - isPureFunction(call.getStaticCallTarget().getName()) and - fromOperand = getACallArgumentOrIndirection(call, argIndex) and - forall(Operand argOperand | argOperand = call.getAnArgumentOperand() | - argOperand = getACallArgumentOrIndirection(call, argIndex) or - predictableInstruction(argOperand.getAnyDef()) - ) and - // flow through `strlen` tends to cause dubious results, if the length is - // bounded. - not call.getStaticCallTarget().getName() = "strlen" - ) - or - // Flow from argument to return value - toInstr = - any(CallInstruction call | - exists(int indexIn | - modelTaintToReturnValue(call.getStaticCallTarget(), indexIn) and - fromOperand = getACallArgumentOrIndirection(call, indexIn) and - not predictableOnlyFlow(call.getStaticCallTarget().getName()) - ) - ) - or - // Flow from input argument to output argument - // TODO: This won't work in practice as long as all aliased memory is tracked - // together in a single virtual variable. - // TODO: Will this work on the test for `TaintedPath.ql`, where the output arg - // is a pointer addition expression? - toInstr = - any(WriteSideEffectInstruction outInstr | - exists(CallInstruction call, int indexIn, int indexOut | - modelTaintToParameter(call.getStaticCallTarget(), indexIn, indexOut) and - fromOperand = getACallArgumentOrIndirection(call, indexIn) and - outInstr.getIndex() = indexOut and - outInstr.getPrimaryInstruction() = call - ) - ) - or - // Flow through pointer dereference - toInstr.(LoadInstruction).getSourceAddressOperand() = fromOperand - or - // Flow through partial reads of arrays and unions - toInstr.(LoadInstruction).getSourceValueOperand() = fromOperand and - exists(Instruction fromInstr | fromInstr = fromOperand.getAnyDef() | - not fromInstr.isResultConflated() and - ( - fromInstr.getResultType() instanceof ArrayType or - fromInstr.getResultType() instanceof Union - ) - ) - or - // Unary instructions tend to preserve enough information in practice that we - // want taint to flow through. - // The exception is `FieldAddressInstruction`. Together with the rule for - // `LoadInstruction` above and for `ChiInstruction` below, flow through - // `FieldAddressInstruction` could cause flow into one field to come out an - // unrelated field. This would happen across function boundaries, where the IR - // would not be able to match loads to stores. - toInstr.(UnaryInstruction).getUnaryOperand() = fromOperand and - ( - not toInstr instanceof FieldAddressInstruction - or - toInstr.(FieldAddressInstruction).getField().getDeclaringType() instanceof Union - ) - or - // Flow from an element to an array or union that contains it. - toInstr.(ChiInstruction).getPartialOperand() = fromOperand and - not toInstr.isResultConflated() and - exists(Type t | toInstr.getResultLanguageType().hasType(t, false) | - t instanceof Union - or - t instanceof ArrayType - ) - or - exists(BinaryInstruction bin | - bin = toInstr and - predictableInstruction(toInstr.getAnOperand().getDef()) and - fromOperand = toInstr.getAnOperand() - ) - or - // This is part of the translation of `a[i]`, where we want taint to flow - // from `a`. - toInstr.(PointerAddInstruction).getLeftOperand() = fromOperand - or - // Until we have flow through indirections across calls, we'll take flow out - // of the indirection and into the argument. - // When we get proper flow through indirections across calls, this code can be - // moved to `adjusedSink` or possibly into the `DataFlow::ExprNode` class. - exists(ReadSideEffectInstruction read | - read.getSideEffectOperand() = fromOperand and - read.getArgumentDef() = toInstr - ) - or - // Until we have from through indirections across calls, we'll take flow out - // of the parameter and into its indirection. - // `InitializeIndirectionInstruction` only has a single operand: the address of the - // value whose indirection we are initializing. When initializing an indirection of a parameter `p`, - // the IR looks like this: - // ``` - // m1 = InitializeParameter[p] : &r1 - // r2 = Load[p] : r2, m1 - // m3 = InitializeIndirection[p] : &r2 - // ``` - // So by having flow from `r2` to `m3` we're enabling flow from `m1` to `m3`. This relies on the - // `LoadOperand`'s overlap being exact. - toInstr.(InitializeIndirectionInstruction).getAnOperand() = fromOperand -} - -/** - * Returns the index of the side effect instruction corresponding to the specified function output, - * if one exists. - */ -private int getWriteSideEffectIndex(FunctionOutput output) { - output.isParameterDeref(result) - or - output.isQualifierObject() and result = -1 -} - -/** - * Get an operand that goes into argument `argumentIndex` of `call`. This - * can be either directly or through one pointer indirection. - */ -private Operand getACallArgumentOrIndirection(CallInstruction call, int argumentIndex) { - result = call.getPositionalArgumentOperand(argumentIndex) - or - exists(ReadSideEffectInstruction readSE | - // TODO: why are read side effect operands imprecise? - result = readSE.getSideEffectOperand() and - readSE.getPrimaryInstruction() = call and - readSE.getIndex() = argumentIndex - ) -} - -private predicate modelTaintToParameter(Function f, int parameterIn, int parameterOut) { - exists(FunctionInput modelIn, FunctionOutput modelOut | - ( - f.(DataFlowFunction).hasDataFlow(modelIn, modelOut) - or - f.(TaintFunction).hasTaintFlow(modelIn, modelOut) - ) and - (modelIn.isParameter(parameterIn) or modelIn.isParameterDeref(parameterIn)) and - parameterOut = getWriteSideEffectIndex(modelOut) - ) -} - -private predicate modelTaintToReturnValue(Function f, int parameterIn) { - // Taint flow from parameter to return value - exists(FunctionInput modelIn, FunctionOutput modelOut | - f.(TaintFunction).hasTaintFlow(modelIn, modelOut) and - (modelIn.isParameter(parameterIn) or modelIn.isParameterDeref(parameterIn)) and - (modelOut.isReturnValue() or modelOut.isReturnValueDeref()) - ) - or - // Data flow (not taint flow) to where the return value points. For the time - // being we will conflate pointers and objects in taint tracking. - exists(FunctionInput modelIn, FunctionOutput modelOut | - f.(DataFlowFunction).hasDataFlow(modelIn, modelOut) and - (modelIn.isParameter(parameterIn) or modelIn.isParameterDeref(parameterIn)) and - modelOut.isReturnValueDeref() - ) - or - // Taint flow from one argument to another and data flow from an argument to a - // return value. This happens in functions like `strcat` and `memcpy`. We - // could model this flow in two separate steps, but that would add reverse - // flow from the write side-effect to the call instruction, which may not be - // desirable. - exists(int parameterMid, InParameter modelMid, OutReturnValue returnOut | - modelTaintToParameter(f, parameterIn, parameterMid) and - modelMid.isParameter(parameterMid) and - f.(DataFlowFunction).hasDataFlow(modelMid, returnOut) - ) -} - private Element adjustedSink(DataFlow::Node sink) { // TODO: is it more appropriate to use asConvertedExpr here and avoid // `getConversion*`? Or will that cause us to miss some cases where there's From 7019878775ceef8dba6dfaf64cdd35031c4f1845 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Wed, 17 Mar 2021 12:18:28 +0100 Subject: [PATCH 147/725] Upgrade nuget package in Semmle.Autobuild.Cpp.csproj --- .../Semmle.Autobuild.Cpp/Semmle.Autobuild.Cpp.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/autobuilder/Semmle.Autobuild.Cpp/Semmle.Autobuild.Cpp.csproj b/cpp/autobuilder/Semmle.Autobuild.Cpp/Semmle.Autobuild.Cpp.csproj index 68cfef57b3d..1d6459d77e3 100644 --- a/cpp/autobuilder/Semmle.Autobuild.Cpp/Semmle.Autobuild.Cpp.csproj +++ b/cpp/autobuilder/Semmle.Autobuild.Cpp/Semmle.Autobuild.Cpp.csproj @@ -17,7 +17,7 @@ - + From 5e0601fe1fe7cd5642881ce3217269467d6700d1 Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Wed, 17 Mar 2021 12:28:03 +0100 Subject: [PATCH 148/725] C++: Address review comments. --- ...dCompilations.ql => AbortedExtractions.ql} | 8 ++-- cpp/ql/src/Diagnostics/FailedExtractions.ql | 6 +-- cpp/ql/src/Diagnostics/FailedExtractions.qll | 44 ++++++++++++------- .../src/Diagnostics/SuccessfulExtractions.ql | 4 +- cpp/ql/src/semmle/code/cpp/Diagnostics.qll | 3 ++ 5 files changed, 41 insertions(+), 24 deletions(-) rename cpp/ql/src/Diagnostics/{FailedCompilations.ql => AbortedExtractions.ql} (71%) diff --git a/cpp/ql/src/Diagnostics/FailedCompilations.ql b/cpp/ql/src/Diagnostics/AbortedExtractions.ql similarity index 71% rename from cpp/ql/src/Diagnostics/FailedCompilations.ql rename to cpp/ql/src/Diagnostics/AbortedExtractions.ql index 8af1b0250c0..5bab529b23e 100644 --- a/cpp/ql/src/Diagnostics/FailedCompilations.ql +++ b/cpp/ql/src/Diagnostics/AbortedExtractions.ql @@ -1,8 +1,8 @@ /** - * @name Failed compiler invocations. - * @description Gives the command-line of compilations for which extraction did not run to completion. + * @name Aborted extractor invocations + * @description Gives the command line of compilations for which extraction did not run to completion. * @kind diagnostic - * @id cpp/diagnostics/failed-compilations + * @id cpp/diagnostics/aborted-extractions */ import cpp @@ -19,4 +19,4 @@ string describe(Compilation c) { from Compilation c where not c.normalTermination() -select c, "Extraction failed for " + describe(c), 2 +select c, "Extraction aborted for " + describe(c), 2 diff --git a/cpp/ql/src/Diagnostics/FailedExtractions.ql b/cpp/ql/src/Diagnostics/FailedExtractions.ql index 6a3d7daae4c..52b07ca2559 100644 --- a/cpp/ql/src/Diagnostics/FailedExtractions.ql +++ b/cpp/ql/src/Diagnostics/FailedExtractions.ql @@ -1,6 +1,6 @@ /** * @name Failed extractions - * @description Gives the command-line of compilations for which extraction did not run to completion. + * @description List all files in the source code directory with extraction errors. * @kind diagnostic * @id cpp/diagnostics/failed-extractions */ @@ -12,5 +12,5 @@ from ExtractionError error where error instanceof ExtractionUnknownError or exists(error.getFile().getRelativePath()) -select error, "Extracting file $@ failed with $@ (at $@)", error.getFile(), error.getErrorMessage(), - error.getLocation(), error.getSeverity() +select error, "Extracting failed in " + error.getFile() + " with error " + error.getErrorMessage(), + error.getSeverity() diff --git a/cpp/ql/src/Diagnostics/FailedExtractions.qll b/cpp/ql/src/Diagnostics/FailedExtractions.qll index 5fd371204ec..36bf264aa90 100644 --- a/cpp/ql/src/Diagnostics/FailedExtractions.qll +++ b/cpp/ql/src/Diagnostics/FailedExtractions.qll @@ -1,7 +1,24 @@ import cpp +/* + * A note about how the C/C++ extractor emits diagnostics: + * When the extractor frontend encounters an error, it emits a diagnostic message, + * that includes a message, location and severity. + * However, that process is best-effort and may fail (e.g. due to lack of memory). + * Thus, if the extractor emitted at least one diagnostic of severity discretionary + * error (or higher), it *also* emits a simple "There was an error during this compilation" + * error diagnostic, without location information. + * In the common case, this means that a file with one (or more) errors also gets + * the catch-all diagnostic. + * This diagnostic has the empty string as file path. + * We filter out these useless diagnostics if there is at least one error-level diagnostic + * for the affected compilation in the database. + * Otherwise, we show it to, to indicate that something went wrong, and we + * don't know what exactly happened. + */ + /** - * The class of errors upon we mark a file as non-successfully extracted. + * An error that, if present, leads to a file being marked as non-successfully extracted. */ class ReportableError extends Diagnostic { ReportableError() { @@ -10,13 +27,7 @@ class ReportableError extends Diagnostic { this instanceof CompilerError or this instanceof CompilerCatastrophe ) and - // If the extractor encounters an error in a compilation, it always emits a - // catch-all diagnostic "There was an error during this compilation", to ensure - // that the error makes it to the database. - // This error doesn't have a file path attached to it, and is thus - // useless for us to report. Furthermore, in the common case, we will have a - // proper diagnostic for this error we can show. - // Instead, we synthesize `TUnknownError` if this is the only error that we can show to the user. + // Filter for the catch-all diagnostic, see note above. not this.getFile().getAbsolutePath() = "" } } @@ -26,8 +37,11 @@ private newtype TExtractionError = TCompilationFailed(Compilation c, File f) { f = c.getAFileCompiled() and not c.normalTermination() } or - // Report generic extractor errors only if we haven't seen any other error-level diagnostic - TUnknownError(CompilerError err) { not exists(ReportableError e) } + // Show the catch-all diagnostic (see note above) only if we haven't seen any other error-level diagnostic + // for that compilation + TUnknownError(CompilerError err) { + not exists(ReportableError e | e.getCompilation() = err.getCompilation()) + } /** * Superclass for the extraction error hierarchy. @@ -53,26 +67,26 @@ class ExtractionError extends TExtractionError { } /** - * An irrecoverable extraction failure, where extraction was unable to finish. + * An unrecoverable extraction error, where extraction was unable to finish. * This can be caused by a multitude of reasons, for example: * - hitting a frontend assertion * - crashing due to dereferencing an invalid pointer * - stack overflow * - out of memory */ -class ExtractionIrrecoverableError extends ExtractionError, TCompilationFailed { +class ExtractionUnrecoverableError extends ExtractionError, TCompilationFailed { Compilation c; File f; - ExtractionIrrecoverableError() { this = TCompilationFailed(c, f) } + ExtractionUnrecoverableError() { this = TCompilationFailed(c, f) } override string toString() { - result = "Irrecoverable extraction error while compiling " + f.toString() + result = "Unrecoverable extraction error while compiling " + f.toString() } override string getErrorMessage() { result = - "Irrecoverable compilation failure, check logs/build-tracer.log in the database directory for more information." + "Unrecoverable compilation failure; check logs/build-tracer.log in the database directory for more information." } override File getFile() { result = f } diff --git a/cpp/ql/src/Diagnostics/SuccessfulExtractions.ql b/cpp/ql/src/Diagnostics/SuccessfulExtractions.ql index 4331b768934..380f1ce8bbe 100644 --- a/cpp/ql/src/Diagnostics/SuccessfulExtractions.ql +++ b/cpp/ql/src/Diagnostics/SuccessfulExtractions.ql @@ -1,6 +1,6 @@ /** - * @name Successfully extracted files. - * @description Lists all files in the database that were extracted without encountering an error. + * @name Successfully extracted files + * @description Lists all files in the source code directory that were extracted without encountering an error. * @kind diagnostic * @id cpp/diagnostics/successfully-extracted-files */ diff --git a/cpp/ql/src/semmle/code/cpp/Diagnostics.qll b/cpp/ql/src/semmle/code/cpp/Diagnostics.qll index 79074fa8657..9ad38d4e4be 100644 --- a/cpp/ql/src/semmle/code/cpp/Diagnostics.qll +++ b/cpp/ql/src/semmle/code/cpp/Diagnostics.qll @@ -6,6 +6,9 @@ import semmle.code.cpp.Location /** A compiler-generated error, warning or remark. */ class Diagnostic extends Locatable, @diagnostic { + /** Gets the compilation that generated this diagnostic. */ + Compilation getCompilation() { diagnostic_for(underlyingElement(this), result, _, _) } + /** * Gets the severity of the message, on a range from 1 to 5: 1=remark, * 2=warning, 3=discretionary error, 4=error, 5=catastrophic error. From 135a6713e83e9c7d099d0369aea952988c8b5ec1 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Wed, 17 Mar 2021 14:42:50 +0100 Subject: [PATCH 149/725] Python, doc: References to section on API graphs. --- .../codeql-language-guides/analyzing-data-flow-in-python.rst | 2 ++ docs/codeql/codeql-language-guides/codeql-for-python.rst | 2 ++ .../codeql-language-guides/codeql-library-for-python.rst | 5 +---- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/codeql/codeql-language-guides/analyzing-data-flow-in-python.rst b/docs/codeql/codeql-language-guides/analyzing-data-flow-in-python.rst index 068e925534e..6e35c78a5a4 100644 --- a/docs/codeql/codeql-language-guides/analyzing-data-flow-in-python.rst +++ b/docs/codeql/codeql-language-guides/analyzing-data-flow-in-python.rst @@ -99,6 +99,8 @@ Python has builtin functionality for reading and writing files, such as the func ➤ `See this in the query console on LGTM.com `__. Two of the demo projects make use of this low-level API. +Notice the use of the ``API`` module for referring to library functions. It is further described in ":doc:`Using API graphs in Python `." + Unfortunately this will only give the expression in the argument, not the values which could be passed to it. So we use local data flow to find all expressions that flow into the argument: .. code-block:: ql diff --git a/docs/codeql/codeql-language-guides/codeql-for-python.rst b/docs/codeql/codeql-language-guides/codeql-for-python.rst index 3504b1fb2c3..0d4fe4d17b3 100644 --- a/docs/codeql/codeql-language-guides/codeql-for-python.rst +++ b/docs/codeql/codeql-language-guides/codeql-for-python.rst @@ -21,6 +21,8 @@ Experiment and learn how to write effective and efficient queries for CodeQL dat - :doc:`Analyzing data flow in Python `: You can use CodeQL to track the flow of data through a Python program to places where the data is used. +- :doc:`Using API graphs in Python `: API graphs are a uniform interface for referring to functions, classes, and methods defined in external libraries. + - :doc:`Functions in Python `: You can use syntactic classes from the standard CodeQL library to find Python functions and identify calls to them. - :doc:`Expressions and statements in Python `: You can use syntactic classes from the CodeQL library to explore how Python expressions and statements are used in a codebase. diff --git a/docs/codeql/codeql-language-guides/codeql-library-for-python.rst b/docs/codeql/codeql-language-guides/codeql-library-for-python.rst index 3f546dad1d0..ed5cf8b1deb 100644 --- a/docs/codeql/codeql-language-guides/codeql-library-for-python.rst +++ b/docs/codeql/codeql-language-guides/codeql-library-for-python.rst @@ -23,10 +23,7 @@ The CodeQL library for Python incorporates a large number of classes. Each class - **Data flow** - classes that represent entities from the data flow graphs. - **API graphs** - classes that represent entities from the API graphs. -The first two categories are described below. See ":doc:`Analyzing data flow in Python `" for a description of data flow and associated classes. - -.. - and [TO COME IN FUTURE PR] for a description of API graphs and their use. +The first two categories are described below. See ":doc:`Analyzing data flow in Python `" for a description of data flow and associated classes and ":doc:`Using API graphs in Python `" for a description of API graphs and their use. Syntactic classes ----------------- From f04ac87091e2f069e0769cf705b3ec45202b31df Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Wed, 17 Mar 2021 15:04:07 +0100 Subject: [PATCH 150/725] Python, doc: Include new section in toc --- docs/codeql/codeql-language-guides/codeql-for-python.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/codeql/codeql-language-guides/codeql-for-python.rst b/docs/codeql/codeql-language-guides/codeql-for-python.rst index 0d4fe4d17b3..15b0c4a84f8 100644 --- a/docs/codeql/codeql-language-guides/codeql-for-python.rst +++ b/docs/codeql/codeql-language-guides/codeql-for-python.rst @@ -11,6 +11,7 @@ Experiment and learn how to write effective and efficient queries for CodeQL dat basic-query-for-python-code codeql-library-for-python analyzing-data-flow-in-python + using-api-graphs-in-python functions-in-python expressions-and-statements-in-python analyzing-control-flow-in-python From 4d856d4461179f2e22f0655344d95d915453b443 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Fri, 12 Mar 2021 18:04:13 +0100 Subject: [PATCH 151/725] Python: Add small api enhancements determined useful during documentation work. --- .../2021-03-12-small-api-enhancements.md | 5 + .../dataflow/new/internal/DataFlowPublic.qll | 108 ++------------- .../dataflow/new/internal/LocalSources.qll | 131 ++++++++++++++++++ 3 files changed, 146 insertions(+), 98 deletions(-) create mode 100644 python/change-notes/2021-03-12-small-api-enhancements.md create mode 100644 python/ql/src/semmle/python/dataflow/new/internal/LocalSources.qll diff --git a/python/change-notes/2021-03-12-small-api-enhancements.md b/python/change-notes/2021-03-12-small-api-enhancements.md new file mode 100644 index 00000000000..f75a91e548a --- /dev/null +++ b/python/change-notes/2021-03-12-small-api-enhancements.md @@ -0,0 +1,5 @@ +lgtm,codescanning +* Make `ParameterNode` extend `LocalSourceNode`, thus making members like `flowsTo` available. +* Add member predicate `taintFlowsTo` to `LocalSourceNode` facilitating smoother syntax for local taint tracking. +* Add member `getALocalTaintSource` to `DataFlow::Node` facilitating smoother syntax for local taint tracking. +* Add predicate `parameterNode` to map from a `Parameter` to a data-flow node. diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll index 7b75fd70f2a..aa69f829b9f 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll @@ -6,6 +6,7 @@ private import python private import DataFlowPrivate import semmle.python.dataflow.new.TypeTracker import Attributes +import LocalSources private import semmle.python.essa.SsaCompute /** @@ -138,6 +139,11 @@ class Node extends TNode { * Gets a local source node from which data may flow to this node in zero or more local steps. */ LocalSourceNode getALocalSource() { result.flowsTo(this) } + + /** + * Gets a local source node from which data may flow to this node in zero or more local steps. + */ + LocalSourceNode getALocalTaintSource() { result.taintFlowsTo(this) } } /** A data-flow node corresponding to an SSA variable. */ @@ -215,7 +221,7 @@ ExprNode exprNode(DataFlowExpr e) { result.getNode().getNode() = e } * The value of a parameter at function entry, viewed as a node in a data * flow graph. */ -class ParameterNode extends CfgNode { +class ParameterNode extends CfgNode, LocalSourceNode { ParameterDefinition def; ParameterNode() { @@ -237,6 +243,9 @@ class ParameterNode extends CfgNode { Parameter getParameter() { result = def.getParameter() } } +/** Gets a node corresponding to parameter `p`. */ +ParameterNode parameterNode(Parameter p) { result.getParameter() = p } + /** A data flow node that represents a call argument. */ class ArgumentNode extends Node { ArgumentNode() { this = any(DataFlowCall c).getArg(_) } @@ -467,103 +476,6 @@ class BarrierGuard extends GuardNode { } } -/** - * A data flow node that is a source of local flow. This includes things like - * - Expressions - * - Function parameters - */ -class LocalSourceNode extends Node { - LocalSourceNode() { - not simpleLocalFlowStep+(any(CfgNode n), this) and - not this instanceof ModuleVariableNode - or - this = any(ModuleVariableNode mvn).getARead() - } - - /** Holds if this `LocalSourceNode` can flow to `nodeTo` in one or more local flow steps. */ - pragma[inline] - predicate flowsTo(Node nodeTo) { Cached::hasLocalSource(nodeTo, this) } - - /** - * Gets a reference (read or write) of attribute `attrName` on this node. - */ - AttrRef getAnAttributeReference(string attrName) { Cached::namedAttrRef(this, attrName, result) } - - /** - * Gets a read of attribute `attrName` on this node. - */ - AttrRead getAnAttributeRead(string attrName) { result = getAnAttributeReference(attrName) } - - /** - * Gets a reference (read or write) of any attribute on this node. - */ - AttrRef getAnAttributeReference() { - Cached::namedAttrRef(this, _, result) - or - Cached::dynamicAttrRef(this, result) - } - - /** - * Gets a read of any attribute on this node. - */ - AttrRead getAnAttributeRead() { result = getAnAttributeReference() } - - /** - * Gets a call to this node. - */ - CallCfgNode getACall() { Cached::call(this, result) } -} - -cached -private module Cached { - /** - * Holds if `source` is a `LocalSourceNode` that can reach `sink` via local flow steps. - * - * The slightly backwards parametering ordering is to force correct indexing. - */ - cached - predicate hasLocalSource(Node sink, Node source) { - // Declaring `source` to be a `SourceNode` currently causes a redundant check in the - // recursive case, so instead we check it explicitly here. - source = sink and - source instanceof LocalSourceNode - or - exists(Node mid | - hasLocalSource(mid, source) and - simpleLocalFlowStep(mid, sink) - ) - } - - /** - * Holds if `base` flows to the base of `ref` and `ref` has attribute name `attr`. - */ - cached - predicate namedAttrRef(LocalSourceNode base, string attr, AttrRef ref) { - base.flowsTo(ref.getObject()) and - ref.getAttributeName() = attr - } - - /** - * Holds if `base` flows to the base of `ref` and `ref` has no known attribute name. - */ - cached - predicate dynamicAttrRef(LocalSourceNode base, AttrRef ref) { - base.flowsTo(ref.getObject()) and - not exists(ref.getAttributeName()) - } - - /** - * Holds if `func` flows to the callee of `call`. - */ - cached - predicate call(LocalSourceNode func, CallCfgNode call) { - exists(CfgNode n | - func.flowsTo(n) and - n = call.getFunction() - ) - } -} - /** * Algebraic datatype for tracking data content associated with values. * Content can be collection elements or object attributes. diff --git a/python/ql/src/semmle/python/dataflow/new/internal/LocalSources.qll b/python/ql/src/semmle/python/dataflow/new/internal/LocalSources.qll new file mode 100644 index 00000000000..a84fed4824a --- /dev/null +++ b/python/ql/src/semmle/python/dataflow/new/internal/LocalSources.qll @@ -0,0 +1,131 @@ +/** + * Provides support for intra-procedural tracking of a customizable + * set of data flow nodes. + * + * Note that unlike `TypeTracker.qll`, this library only performs + * local tracking within a function. + */ + +import python +import DataFlowPublic +private import DataFlowPrivate +private import TaintTrackingPublic + +/** + * A data flow node that is a source of local flow. This includes things like + * - Expressions + * - Function parameters + */ +class LocalSourceNode extends Node { + LocalSourceNode() { + not simpleLocalFlowStep+(any(CfgNode n), this) and + not this instanceof ModuleVariableNode + or + this = any(ModuleVariableNode mvn).getARead() + } + + /** Holds if this `LocalSourceNode` can flow to `nodeTo` in one or more local flow steps. */ + pragma[inline] + predicate flowsTo(Node nodeTo) { Cached::hasLocalSource(nodeTo, this) } + + /** Holds if this `LocalSourceNode` can flow to `nodeTo` in one or more local taint steps. */ + pragma[inline] + predicate taintFlowsTo(Node nodeTo) { Cached::hasLocalTaintSource(nodeTo, this) } + + /** + * Gets a reference (read or write) of attribute `attrName` on this node. + */ + AttrRef getAnAttributeReference(string attrName) { Cached::namedAttrRef(this, attrName, result) } + + /** + * Gets a read of attribute `attrName` on this node. + */ + AttrRead getAnAttributeRead(string attrName) { result = getAnAttributeReference(attrName) } + + /** + * Gets a reference (read or write) of any attribute on this node. + */ + AttrRef getAnAttributeReference() { + Cached::namedAttrRef(this, _, result) + or + Cached::dynamicAttrRef(this, result) + } + + /** + * Gets a read of any attribute on this node. + */ + AttrRead getAnAttributeRead() { result = getAnAttributeReference() } + + /** + * Gets a call to this node. + */ + CallCfgNode getACall() { Cached::call(this, result) } +} + +cached +private module Cached { + /** + * Holds if `source` is a `LocalSourceNode` that can reach `sink` via local flow steps. + * + * The slightly backwards parametering ordering is to force correct indexing. + */ + cached + predicate hasLocalSource(Node sink, Node source) { + // Declaring `source` to be a `SourceNode` currently causes a redundant check in the + // recursive case, so instead we check it explicitly here. + source = sink and + source instanceof LocalSourceNode + or + exists(Node mid | + hasLocalSource(mid, source) and + simpleLocalFlowStep(mid, sink) + ) + } + + /** + * Holds if `source` is a `LocalSourceNode` that can reach `sink` via local taint steps. + * + * The slightly backwards parametering ordering is to force correct indexing. + */ + cached + predicate hasLocalTaintSource(Node sink, Node source) { + // Declaring `source` to be a `SourceNode` currently causes a redundant check in the + // recursive case, so instead we check it explicitly here. + source = sink and + source instanceof LocalSourceNode + or + exists(Node mid | + hasLocalTaintSource(mid, source) and + localTaintStep(mid, sink) + ) + } + + /** + * Holds if `base` flows to the base of `ref` and `ref` has attribute name `attr`. + */ + cached + predicate namedAttrRef(LocalSourceNode base, string attr, AttrRef ref) { + base.flowsTo(ref.getObject()) and + ref.getAttributeName() = attr + } + + /** + * Holds if `base` flows to the base of `ref` and `ref` has no known attribute name. + */ + cached + predicate dynamicAttrRef(LocalSourceNode base, AttrRef ref) { + base.flowsTo(ref.getObject()) and + not exists(ref.getAttributeName()) + } + + /** + * Holds if `func` flows to the callee of `call`. + */ + cached + predicate call(LocalSourceNode func, CallCfgNode call) { + exists(CfgNode n | + func.flowsTo(n) and + n = call.getFunction() + ) + } +} From 63b732ce1f78b2639b796b2ccc12bffae03bef23 Mon Sep 17 00:00:00 2001 From: yoff Date: Fri, 12 Mar 2021 18:36:20 +0100 Subject: [PATCH 152/725] Apply suggestions from code review Co-authored-by: Taus --- .../semmle/python/dataflow/new/internal/DataFlowPublic.qll | 2 +- .../src/semmle/python/dataflow/new/internal/LocalSources.qll | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll index aa69f829b9f..aac5f501263 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll @@ -141,7 +141,7 @@ class Node extends TNode { LocalSourceNode getALocalSource() { result.flowsTo(this) } /** - * Gets a local source node from which data may flow to this node in zero or more local steps. + * Gets a local source node from which data may flow to this node in zero or more local taint-flow steps. */ LocalSourceNode getALocalTaintSource() { result.taintFlowsTo(this) } } diff --git a/python/ql/src/semmle/python/dataflow/new/internal/LocalSources.qll b/python/ql/src/semmle/python/dataflow/new/internal/LocalSources.qll index a84fed4824a..26d731061b4 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/LocalSources.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/LocalSources.qll @@ -71,7 +71,7 @@ private module Cached { */ cached predicate hasLocalSource(Node sink, Node source) { - // Declaring `source` to be a `SourceNode` currently causes a redundant check in the + // Declaring `source` to be a `LocalSourceNode` currently causes a redundant check in the // recursive case, so instead we check it explicitly here. source = sink and source instanceof LocalSourceNode @@ -89,7 +89,7 @@ private module Cached { */ cached predicate hasLocalTaintSource(Node sink, Node source) { - // Declaring `source` to be a `SourceNode` currently causes a redundant check in the + // Declaring `source` to be a `LocalSourceNode` currently causes a redundant check in the // recursive case, so instead we check it explicitly here. source = sink and source instanceof LocalSourceNode From 8f467003d257dd018c0d3034ff077e90ed7f68dc Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Fri, 12 Mar 2021 18:45:09 +0100 Subject: [PATCH 153/725] Python: More review suggestions --- python/change-notes/2021-03-12-small-api-enhancements.md | 7 +++---- .../semmle/python/dataflow/new/internal/DataFlowPublic.qll | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/python/change-notes/2021-03-12-small-api-enhancements.md b/python/change-notes/2021-03-12-small-api-enhancements.md index f75a91e548a..ce7421cde7c 100644 --- a/python/change-notes/2021-03-12-small-api-enhancements.md +++ b/python/change-notes/2021-03-12-small-api-enhancements.md @@ -1,5 +1,4 @@ lgtm,codescanning -* Make `ParameterNode` extend `LocalSourceNode`, thus making members like `flowsTo` available. -* Add member predicate `taintFlowsTo` to `LocalSourceNode` facilitating smoother syntax for local taint tracking. -* Add member `getALocalTaintSource` to `DataFlow::Node` facilitating smoother syntax for local taint tracking. -* Add predicate `parameterNode` to map from a `Parameter` to a data-flow node. +* The class ParameterNode now extends LocalSourceNode, thus making methods like flowsTo available. +* Local taint tracking can now be performed using the `taintFlowsTo` method on the `LocalSourceNode` class. Conversely, the new member predicate `getALocalTaintSource` can be called on a `DataFlow::Node` to obtain a `LocalSourceNode` from which taint can be tracked locally to that data-flow node. +* The new predicate `parameterNode` can now be used to map from a `Parameter` to a data-flow node. diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll index aac5f501263..e802373a527 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll @@ -136,7 +136,7 @@ class Node extends TNode { LocalSourceNode backtrack(TypeBackTracker t2, TypeBackTracker t) { t2 = t.step(result, this) } /** - * Gets a local source node from which data may flow to this node in zero or more local steps. + * Gets a local source node from which data may flow to this node in zero or more local data-flow steps. */ LocalSourceNode getALocalSource() { result.flowsTo(this) } From b3ff3f7ee7f0838f43c29417033c89322b77dcb2 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Fri, 12 Mar 2021 18:59:49 +0100 Subject: [PATCH 154/725] =?UTF-8?q?Python=C3=86=20adjust=20test=20expectat?= =?UTF-8?q?ions=20I=20suspect=20it=20has=20to=20do=20with=20ParameterNode?= =?UTF-8?q?=20being=20a=20LocalSourceNode,=20but=20I=20really=20have=20no?= =?UTF-8?q?=20idea...?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ql/test/2/library-tests/locations/general/Locations.expected | 1 + .../ql/test/3/library-tests/locations/general/Locations.expected | 1 + 2 files changed, 2 insertions(+) diff --git a/python/ql/test/2/library-tests/locations/general/Locations.expected b/python/ql/test/2/library-tests/locations/general/Locations.expected index 3c74898d80f..c6473cb2cc2 100644 --- a/python/ql/test/2/library-tests/locations/general/Locations.expected +++ b/python/ql/test/2/library-tests/locations/general/Locations.expected @@ -55,6 +55,7 @@ | Dict | 46 | 54 | 46 | 55 | | Dict | 48 | 9 | 48 | 19 | | DictUnpacking | 46 | 52 | 46 | 55 | +| DjangoViewClassHelper | 4 | 1 | 4 | 8 | | Ellipsis | 7 | 7 | 7 | 9 | | Ellipsis | 50 | 14 | 50 | 16 | | ExceptStmt | 32 | 9 | 32 | 31 | diff --git a/python/ql/test/3/library-tests/locations/general/Locations.expected b/python/ql/test/3/library-tests/locations/general/Locations.expected index 8da184f747e..70217f5117a 100644 --- a/python/ql/test/3/library-tests/locations/general/Locations.expected +++ b/python/ql/test/3/library-tests/locations/general/Locations.expected @@ -44,6 +44,7 @@ | Dict | 46 | 54 | 46 | 55 | | Dict | 48 | 9 | 48 | 19 | | DictUnpacking | 46 | 52 | 46 | 55 | +| DjangoViewClassHelper | 4 | 1 | 4 | 8 | | Ellipsis | 7 | 7 | 7 | 9 | | Ellipsis | 50 | 14 | 50 | 16 | | ExceptStmt | 32 | 9 | 32 | 31 | From bf5259096e291c3e254a2790a103e4a12b6149ed Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 17 Mar 2021 14:34:30 +0000 Subject: [PATCH 155/725] JS: Update cheat sheet --- .../data-flow-cheat-sheet-for-javascript.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/codeql/codeql-language-guides/data-flow-cheat-sheet-for-javascript.rst b/docs/codeql/codeql-language-guides/data-flow-cheat-sheet-for-javascript.rst index 92eb35d4d2e..09b821ad9e7 100644 --- a/docs/codeql/codeql-language-guides/data-flow-cheat-sheet-for-javascript.rst +++ b/docs/codeql/codeql-language-guides/data-flow-cheat-sheet-for-javascript.rst @@ -63,7 +63,7 @@ Classes and member predicates in the ``DataFlow::`` module: - `getAnInstantiation `__ -- find ``new``-calls with this as the callee - `getAnInvocation `__ -- find calls or ``new``-calls with this as the callee - `getAMethodCall `__ -- find method calls with this as the receiver - - `getAMemberCall `__ -- find calls with a member of this as the receiver + - `getAMemberCall `__ -- find calls with a member of this as the callee - `getAPropertyRead `__ -- find property reads with this as the base - `getAPropertyWrite `__ -- find property writes with this as the base - `getAPropertySource `__ -- find nodes flowing into a property of this node @@ -109,12 +109,14 @@ StringOps module - StringOps::`StartsWith `__ -- check if a string starts with something - StringOps::`EndsWith `__ -- check if a string ends with something - StringOps::`Includes `__ -- check if a string contains something +- StringOps::`RegExpTest `__ -- check if a string matches a RegExp Utility -------- - `ExtendCall `__ -- call that copies properties from one object to another - `JsonParserCall `__ -- call that deserializes a JSON string +- `JsonStringifyCall `__ -- call that serializes a JSON string - `PropertyProjection `__ -- call that extracts nested properties by name System and Network From 4f635841796d98b03b1803c486e14420dd612f4d Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 17 Mar 2021 15:55:58 +0100 Subject: [PATCH 156/725] Docs: Highlight that Configuration is not DataFlow::Configuration I made that mistake when just reading it over (DOH). I think that calling it MyConfiguration makes it a bit more clear that this is a configuration class you wrote yourself :D --- docs/codeql/writing-codeql-queries/creating-path-queries.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/codeql/writing-codeql-queries/creating-path-queries.rst b/docs/codeql/writing-codeql-queries/creating-path-queries.rst index 11d72b8baf1..836e7d19585 100644 --- a/docs/codeql/writing-codeql-queries/creating-path-queries.rst +++ b/docs/codeql/writing-codeql-queries/creating-path-queries.rst @@ -58,7 +58,7 @@ You should use the following template: import DataFlow::PathGraph ... - from Configuration config, DataFlow::PathNode source, DataFlow::PathNode sink + from MyConfiguration config, DataFlow::PathNode source, DataFlow::PathNode sink where config.hasFlowPath(source, sink) select sink.getNode(), source, sink, "" @@ -66,7 +66,7 @@ Where: - ``DataFlow::Pathgraph`` is the path graph module you need to import from the standard CodeQL libraries. - ``source`` and ``sink`` are nodes on the `path graph `__, and ``DataFlow::PathNode`` is their type. -- ``Configuration`` is a class containing the predicates which define how data may flow between the ``source`` and the ``sink``. +- ``MyConfiguration`` is a class containing the predicates which define how data may flow between the ``source`` and the ``sink``. The following sections describe the main requirements for a valid path query. From d426f1efaf37aa44ab1ea2dfacaa23da9d8005ff Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 17 Mar 2021 16:01:20 +0100 Subject: [PATCH 157/725] Docs: Highlight need for explicit import of DataFlow lib at least in some langauges --- docs/codeql/writing-codeql-queries/creating-path-queries.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/codeql/writing-codeql-queries/creating-path-queries.rst b/docs/codeql/writing-codeql-queries/creating-path-queries.rst index 836e7d19585..60723f488e1 100644 --- a/docs/codeql/writing-codeql-queries/creating-path-queries.rst +++ b/docs/codeql/writing-codeql-queries/creating-path-queries.rst @@ -55,6 +55,8 @@ You should use the following template: */ import + // For some languages (Java/C++/Python) you need to explicitly import the data flow library, such as + // import semmle.code.java.dataflow.DataFlow import DataFlow::PathGraph ... From 3995ff322d6426aceacc48e15b27338f5990fb9d Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 17 Mar 2021 13:08:42 +0100 Subject: [PATCH 158/725] add models for `koa-route` and `koa-router` --- .../src/semmle/javascript/frameworks/Koa.qll | 126 ++++++++++++++++-- .../Security/CWE-918/RequestForgery.expected | 27 ++++ .../test/query-tests/Security/CWE-918/tst.js | 20 ++- 3 files changed, 162 insertions(+), 11 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Koa.qll b/javascript/ql/src/semmle/javascript/frameworks/Koa.qll index 325afacea10..112203cb26d 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Koa.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Koa.qll @@ -36,18 +36,11 @@ module Koa { /** * A Koa route handler. */ - class RouteHandler extends HTTP::Servers::StandardRouteHandler, DataFlow::ValueNode { - Function function; - - RouteHandler() { - function = astNode and - any(RouteSetup setup).getARouteHandler() = this - } - + abstract class RouteHandler extends HTTP::Servers::StandardRouteHandler, DataFlow::SourceNode { /** * Gets the parameter of the route handler that contains the context object. */ - Parameter getContextParameter() { result = function.getParameter(0) } + Parameter getContextParameter() { result = getAFunctionValue().getFunction().getParameter(0) } /** * Gets an expression that contains the "context" object of @@ -70,6 +63,35 @@ module Koa { * object of a route handler invocation. */ Expr getARequestOrContextExpr() { result = getARequestExpr() or result = getAContextExpr() } + + /** + * Gets a reference to a request parameter defined by this route handler. + */ + DataFlow::Node getARequestParameterAccess() { + none() // overriden in subclasses. + } + + /** + * Gets the dataflow node that is given to a `RouteSetup` to register the handler. + */ + abstract DataFlow::SourceNode getRouteHandlerRegistration(); + } + + /** + * A koa route handler registered directly with a route-setup. + * Like: + * ```JavaScript + * var route = require('koa-route'); + * var app = new Koa(); + * app.use((context, next) => { + * ... + * }); + * ``` + */ + private class StandardRouteHandler extends RouteHandler { + StandardRouteHandler() { any(RouteSetup setup).getARouteHandler() = this } + + override DataFlow::SourceNode getRouteHandlerRegistration() { result = this } } /** @@ -100,6 +122,77 @@ module Koa { } } + /** + * A Koa route handler registered using a routing library. + * + * Example of what that could look like: + * ```JavaScript + * const router = require('koa-router')(); + * const Koa = require('koa'); + * const app = new Koa(); + * router.get('/', async (ctx, next) => { + * // route handler stuff + * }); + * app.use(router.routes()); + * ``` + */ + private class RoutedRouteHandler extends RouteHandler, DataFlow::SourceNode { + DataFlow::InvokeNode router; + DataFlow::MethodCallNode call; + + RoutedRouteHandler() { + router = DataFlow::moduleImport(["@koa/router", "koa-router"]).getAnInvocation() and + call = router.getAMethodCall*() and + call.getMethodName() = + [ + "use", "get", "post", "put", "link", "unlink", "delete", "del", "head", "options", + "patch", "all" + ] and + this.flowsTo(call.getArgument(any(int i | i >= 1))) + } + + override DataFlow::SourceNode getRouteHandlerRegistration() { + result = call + or + result = router.getAMethodCall("routes") + } + } + + /** + * A route handler registered using the `koa-route` library. + * + * Example of how `koa-route` can be used: + * ```JavaScript + * var route = require('koa-route'); + * var Koa = require('koa'); + * var app = new Koa(); + * + * app.use(route.get('/pets', (context, param1, param2, param3, ...params) => { + * // route handler stuff + * })); + */ + class KoaRouteHandler extends RouteHandler, DataFlow::SourceNode { + DataFlow::CallNode call; + + KoaRouteHandler() { + call = + DataFlow::moduleMember("koa-route", + [ + "all", "acl", "bind", "checkout", "connect", "copy", "delete", "del", "get", "head", + "link", "lock", "msearch", "merge", "mkactivity", "mkcalendar", "mkcol", "move", + "notify", "options", "patch", "post", "propfind", "proppatch", "purge", "put", "rebind", + "report", "search", "subscribe", "trace", "unbind", "unlink", "unlock", "unsubscribe" + ]).getACall() and + this.flowsTo(call.getArgument(1)) + } + + override DataFlow::Node getARequestParameterAccess() { + result = call.getABoundCallbackParameter(1, any(int i | i >= 1)) + } + + override DataFlow::SourceNode getRouteHandlerRegistration() { result = call } + } + /** * A Koa request source, that is, an access to the `request` property * of a context object. @@ -189,6 +282,9 @@ module Koa { kind = "parameter" and this = getAQueryParameterAccess(rh) or + kind = "parameter" and + this = rh.getARequestParameterAccess() + or exists(Expr e | rh.getARequestOrContextExpr() = e | // `ctx.request.url`, `ctx.request.originalUrl`, or `ctx.request.href` exists(string propName | @@ -202,6 +298,10 @@ module Koa { propName = "href" ) or + // params, when handler is registered by `koa-router` or similar. + kind = "parameter" and + this.asExpr().(PropAccess).accesses(e, "params") + or // `ctx.request.body` e instanceof RequestExpr and kind = "body" and @@ -285,7 +385,13 @@ module Koa { getMethodName() = "use" } - override DataFlow::SourceNode getARouteHandler() { result.flowsToExpr(getArgument(0)) } + override DataFlow::SourceNode getARouteHandler() { + // `StandardRouteHandler` uses this predicate in it's charpred, so making this predicate return a `RouteHandler` would give an empty recursion. + result.flowsToExpr(getArgument(0)) + or + // For the route-handlers that does not depend on this predicate in their charpred. + result.(RouteHandler).getRouteHandlerRegistration().flowsToExpr(getArgument(0)) + } override Expr getServer() { result = server } } diff --git a/javascript/ql/test/query-tests/Security/CWE-918/RequestForgery.expected b/javascript/ql/test/query-tests/Security/CWE-918/RequestForgery.expected index 06a55b512a0..7d21bc4e033 100644 --- a/javascript/ql/test/query-tests/Security/CWE-918/RequestForgery.expected +++ b/javascript/ql/test/query-tests/Security/CWE-918/RequestForgery.expected @@ -57,6 +57,18 @@ nodes | tst.js:74:29:74:35 | req.url | | tst.js:76:19:76:25 | tainted | | tst.js:76:19:76:25 | tainted | +| tst.js:83:38:83:43 | param1 | +| tst.js:83:38:83:43 | param1 | +| tst.js:84:19:84:24 | param1 | +| tst.js:84:19:84:24 | param1 | +| tst.js:91:19:91:28 | ctx.params | +| tst.js:91:19:91:28 | ctx.params | +| tst.js:91:19:91:32 | ctx.params.foo | +| tst.js:91:19:91:32 | ctx.params.foo | +| tst.js:93:19:93:28 | ctx.params | +| tst.js:93:19:93:28 | ctx.params | +| tst.js:93:19:93:32 | ctx.params.foo | +| tst.js:93:19:93:32 | ctx.params.foo | edges | tst.js:14:9:14:52 | tainted | tst.js:18:13:18:19 | tainted | | tst.js:14:9:14:52 | tainted | tst.js:18:13:18:19 | tainted | @@ -113,6 +125,18 @@ edges | tst.js:74:19:74:52 | url.par ... ery.url | tst.js:74:9:74:52 | tainted | | tst.js:74:29:74:35 | req.url | tst.js:74:19:74:42 | url.par ... , true) | | tst.js:74:29:74:35 | req.url | tst.js:74:19:74:42 | url.par ... , true) | +| tst.js:83:38:83:43 | param1 | tst.js:84:19:84:24 | param1 | +| tst.js:83:38:83:43 | param1 | tst.js:84:19:84:24 | param1 | +| tst.js:83:38:83:43 | param1 | tst.js:84:19:84:24 | param1 | +| tst.js:83:38:83:43 | param1 | tst.js:84:19:84:24 | param1 | +| tst.js:91:19:91:28 | ctx.params | tst.js:91:19:91:32 | ctx.params.foo | +| tst.js:91:19:91:28 | ctx.params | tst.js:91:19:91:32 | ctx.params.foo | +| tst.js:91:19:91:28 | ctx.params | tst.js:91:19:91:32 | ctx.params.foo | +| tst.js:91:19:91:28 | ctx.params | tst.js:91:19:91:32 | ctx.params.foo | +| tst.js:93:19:93:28 | ctx.params | tst.js:93:19:93:32 | ctx.params.foo | +| tst.js:93:19:93:28 | ctx.params | tst.js:93:19:93:32 | ctx.params.foo | +| tst.js:93:19:93:28 | ctx.params | tst.js:93:19:93:32 | ctx.params.foo | +| tst.js:93:19:93:28 | ctx.params | tst.js:93:19:93:32 | ctx.params.foo | #select | tst.js:18:5:18:20 | request(tainted) | tst.js:14:29:14:35 | req.url | tst.js:18:13:18:19 | tainted | The $@ of this request depends on $@. | tst.js:18:13:18:19 | tainted | URL | tst.js:14:29:14:35 | req.url | a user-provided value | | tst.js:20:5:20:24 | request.get(tainted) | tst.js:14:29:14:35 | req.url | tst.js:20:17:20:23 | tainted | The $@ of this request depends on $@. | tst.js:20:17:20:23 | tainted | URL | tst.js:14:29:14:35 | req.url | a user-provided value | @@ -130,3 +154,6 @@ edges | tst.js:64:3:64:38 | client. ... inted}) | tst.js:58:29:58:35 | req.url | tst.js:64:30:64:36 | tainted | The $@ of this request depends on $@. | tst.js:64:30:64:36 | tainted | URL | tst.js:58:29:58:35 | req.url | a user-provided value | | tst.js:68:3:68:38 | client. ... inted}) | tst.js:58:29:58:35 | req.url | tst.js:68:30:68:36 | tainted | The $@ of this request depends on $@. | tst.js:68:30:68:36 | tainted | URL | tst.js:58:29:58:35 | req.url | a user-provided value | | tst.js:76:5:76:26 | JSDOM.f ... ainted) | tst.js:74:29:74:35 | req.url | tst.js:76:19:76:25 | tainted | The $@ of this request depends on $@. | tst.js:76:19:76:25 | tainted | URL | tst.js:74:29:74:35 | req.url | a user-provided value | +| tst.js:84:5:84:25 | JSDOM.f ... param1) | tst.js:83:38:83:43 | param1 | tst.js:84:19:84:24 | param1 | The $@ of this request depends on $@. | tst.js:84:19:84:24 | param1 | URL | tst.js:83:38:83:43 | param1 | a user-provided value | +| tst.js:91:5:91:33 | JSDOM.f ... ms.foo) | tst.js:91:19:91:28 | ctx.params | tst.js:91:19:91:32 | ctx.params.foo | The $@ of this request depends on $@. | tst.js:91:19:91:32 | ctx.params.foo | URL | tst.js:91:19:91:28 | ctx.params | a user-provided value | +| tst.js:93:5:93:33 | JSDOM.f ... ms.foo) | tst.js:93:19:93:28 | ctx.params | tst.js:93:19:93:32 | ctx.params.foo | The $@ of this request depends on $@. | tst.js:93:19:93:32 | ctx.params.foo | URL | tst.js:93:19:93:28 | ctx.params | a user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-918/tst.js b/javascript/ql/test/query-tests/Security/CWE-918/tst.js index d5951f648b4..0cf66758fc0 100644 --- a/javascript/ql/test/query-tests/Security/CWE-918/tst.js +++ b/javascript/ql/test/query-tests/Security/CWE-918/tst.js @@ -74,4 +74,22 @@ var server = http.createServer(async function(req, res) { var tainted = url.parse(req.url, true).query.url; JSDOM.fromURL(tainted); // NOT OK -}); \ No newline at end of file +}); + +var route = require('koa-route'); +var Koa = require('koa'); +var app = new Koa(); + +app.use(route.get('/pets', (context, param1, param2, param3) => { + JSDOM.fromURL(param1); // NOT OK +})); + + +const router = require('koa-router')(); +const app = new Koa(); +router.get('/', async (ctx, next) => { + JSDOM.fromURL(ctx.params.foo); // NOT OK +}).post('/', async (ctx, next) => { + JSDOM.fromURL(ctx.params.foo); // NOT OK +}); +app.use(router.routes()); From b2d6982318c18dcf47f56972448e08202cb27271 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 17 Mar 2021 13:10:03 +0100 Subject: [PATCH 159/725] add change note --- javascript/change-notes/2021-03-17-koa-route.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 javascript/change-notes/2021-03-17-koa-route.md diff --git a/javascript/change-notes/2021-03-17-koa-route.md b/javascript/change-notes/2021-03-17-koa-route.md new file mode 100644 index 00000000000..15b1d862c9a --- /dev/null +++ b/javascript/change-notes/2021-03-17-koa-route.md @@ -0,0 +1,5 @@ +lgtm,codescanning +* Route handlers registered using koa routing libraries are recognized as a source of remote user input. + Affected packages are + [koa-route](https://www.npmjs.com/package/koa-route), and + [koa-router](https://www.npmjs.com/package/koa-router) From 40ec23cf13767dce637ab1e9ba715b221bb63b62 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 18 Mar 2021 10:47:38 +0100 Subject: [PATCH 160/725] refactor MkHasUnderlyingType to use Label::instance() --- .../ql/src/semmle/javascript/ApiGraphs.qll | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/ApiGraphs.qll b/javascript/ql/src/semmle/javascript/ApiGraphs.qll index fd955cf00ab..a494a9e335e 100644 --- a/javascript/ql/src/semmle/javascript/ApiGraphs.qll +++ b/javascript/ql/src/semmle/javascript/ApiGraphs.qll @@ -318,7 +318,7 @@ module API { result = Impl::MkCanonicalNameUse(tn).(Node).getInstance() ) or - result = Impl::MkHasUnderlyingType(moduleName, exportedName) + result = Impl::MkHasUnderlyingType(moduleName, exportedName).(Node).getInstance() } } @@ -416,7 +416,7 @@ module API { isUsed(n) } or /** - * An instance of a TypeScript type, identified by name of the type-annotation. + * A TypeScript type, identified by name of the type-annotation. * This API node is exclusively used by `API::Node::ofType`. */ MkHasUnderlyingType(string moduleName, string exportName) { @@ -649,6 +649,12 @@ module API { ref = getANodeWithType(tn) ) or + exists(string moduleName, string exportName | + base = MkHasUnderlyingType(moduleName, exportName) and + lbl = Label::instance() and + ref.(DataFlow::SourceNode).hasUnderlyingType(moduleName, exportName) + ) + or exists(DataFlow::InvokeNode call | base = MkSyntheticCallbackArg(_, _, call) and lbl = Label::parameter(1) and @@ -688,12 +694,6 @@ module API { nd = MkUse(ref) or exists(CanonicalName n | nd = MkCanonicalNameUse(n) | ref.asExpr() = n.getAnAccess()) - or - exists(string moduleName, string exportsName | - nd = MkHasUnderlyingType(moduleName, exportsName) - | - ref.(DataFlow::SourceNode).hasUnderlyingType(moduleName, exportsName) - ) } /** Holds if module `m` exports `rhs`. */ From 8b931626ceafa7948d9c8d2ba3d18ea1e0d48897 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 18 Mar 2021 11:04:08 +0100 Subject: [PATCH 161/725] add edge from root type MkHasUnderlyingType --- javascript/ql/src/semmle/javascript/ApiGraphs.qll | 8 ++++++++ javascript/ql/test/ApiGraphs/typed/NodeOfType.expected | 1 + javascript/ql/test/ApiGraphs/typed/index.ts | 8 ++++++++ 3 files changed, 17 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/ApiGraphs.qll b/javascript/ql/src/semmle/javascript/ApiGraphs.qll index a494a9e335e..1ab8234cb78 100644 --- a/javascript/ql/src/semmle/javascript/ApiGraphs.qll +++ b/javascript/ql/src/semmle/javascript/ApiGraphs.qll @@ -386,6 +386,8 @@ module API { imports(_, m) or m = any(CanonicalName n | isUsed(n)).getExternalModuleName() + or + any(TypeAnnotation n).hasQualifiedName(m, _) } or MkClassInstance(DataFlow::ClassNode cls) { cls = trackDefNode(_) and hasSemantics(cls) } or MkAsyncFuncResult(DataFlow::FunctionNode f) { @@ -902,6 +904,12 @@ module API { succ in [mkCanonicalNameDef(cn2), mkCanonicalNameUse(cn2)] ) or + exists(string moduleName, string exportName | + pred = MkModuleImport(moduleName) and + lbl = Label::member(exportName) and + succ = MkHasUnderlyingType(moduleName, exportName) + ) + or exists(DataFlow::Node nd, DataFlow::FunctionNode f | pred = MkDef(nd) and f = trackDefNode(nd) and diff --git a/javascript/ql/test/ApiGraphs/typed/NodeOfType.expected b/javascript/ql/test/ApiGraphs/typed/NodeOfType.expected index 4513f16cfc3..09fd4b89242 100644 --- a/javascript/ql/test/ApiGraphs/typed/NodeOfType.expected +++ b/javascript/ql/test/ApiGraphs/typed/NodeOfType.expected @@ -1,3 +1,4 @@ | mongodb | Collection | index.ts:14:3:14:17 | getCollection() | | mongoose | Model | index.ts:22:3:22:20 | getMongooseModel() | | mongoose | Query | index.ts:23:3:23:20 | getMongooseQuery() | +| puppeteer | Browser | index.ts:30:22:30:33 | this.browser | diff --git a/javascript/ql/test/ApiGraphs/typed/index.ts b/javascript/ql/test/ApiGraphs/typed/index.ts index 8f1338d95c2..0b35d1582d9 100644 --- a/javascript/ql/test/ApiGraphs/typed/index.ts +++ b/javascript/ql/test/ApiGraphs/typed/index.ts @@ -22,3 +22,11 @@ app.post("/find", (req, res) => { getMongooseModel().find({ id: v }); /* def (parameter 0 (member find (instance (member Model (member exports (module mongoose)))))) */ getMongooseQuery().find({ id: v }); /* def (parameter 0 (member find (instance (member Query (member exports (module mongoose)))))) */ }); + +import * as puppeteer from 'puppeteer'; +class Renderer { + private browser: puppeteer.Browser; + foo(): void { + const page = this.browser.newPage(); /* use (instance (member Browser (member exports (module puppeteer)))) */ + } +} \ No newline at end of file From 45a1fc6a969f429859e8080afde1d1122394dc8d Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 18 Mar 2021 11:20:22 +0100 Subject: [PATCH 162/725] Python: Add link to better PyYAML docs I found this randomly --- python/ql/src/semmle/python/frameworks/Yaml.qll | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/python/ql/src/semmle/python/frameworks/Yaml.qll b/python/ql/src/semmle/python/frameworks/Yaml.qll index 7e9d7f100e9..ec3a21379da 100644 --- a/python/ql/src/semmle/python/frameworks/Yaml.qll +++ b/python/ql/src/semmle/python/frameworks/Yaml.qll @@ -1,6 +1,10 @@ /** - * Provides classes modeling security-relevant aspects of the PyYAML package - * https://pyyaml.org/wiki/PyYAMLDocumentation (obtained via `import yaml`). + * Provides classes modeling security-relevant aspects of the PyYAML package (obtained + * via `import yaml`) + * + * See + * - https://pyyaml.org/wiki/PyYAMLDocumentation + * - https://pyyaml.docsforge.com/master/documentation/ */ private import python @@ -8,6 +12,14 @@ private import semmle.python.dataflow.new.DataFlow private import semmle.python.dataflow.new.RemoteFlowSources private import semmle.python.Concepts +/** + * Provides classes modeling security-relevant aspects of the PyYAML package (obtained + * via `import yaml`) + * + * See + * - https://pyyaml.org/wiki/PyYAMLDocumentation + * - https://pyyaml.docsforge.com/master/documentation/ + */ private module Yaml { /** Gets a reference to the `yaml` module. */ private DataFlow::Node yaml(DataFlow::TypeTracker t) { From 14e9bda5de10ef5a1c6dd96692d083f4e0f16025 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 18 Mar 2021 11:35:17 +0100 Subject: [PATCH 163/725] Python: Refactor PyYAML tests a bit --- .../library-tests/frameworks/yaml/Decoding.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/python/ql/test/experimental/library-tests/frameworks/yaml/Decoding.py b/python/ql/test/experimental/library-tests/frameworks/yaml/Decoding.py index 816d91d9068..7d5bcde1503 100644 --- a/python/ql/test/experimental/library-tests/frameworks/yaml/Decoding.py +++ b/python/ql/test/experimental/library-tests/frameworks/yaml/Decoding.py @@ -1,15 +1,18 @@ import yaml -from yaml import SafeLoader +# Unsafe: yaml.load(payload) # $decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML decodeMayExecuteInput -yaml.load(payload, SafeLoader) # $ decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML -yaml.load(payload, Loader=SafeLoader) # $decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML -yaml.load(payload, Loader=yaml.BaseLoader) # $decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML - -yaml.safe_load(payload) # $ decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML +yaml.load(payload, yaml.Loader) # $decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML decodeMayExecuteInput yaml.unsafe_load(payload) # $ decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML decodeMayExecuteInput yaml.full_load(payload) # $ decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML decodeMayExecuteInput +# Safe +yaml.load(payload, yaml.SafeLoader) # $ decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML +yaml.load(payload, Loader=yaml.SafeLoader) # $decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML +yaml.load(payload, yaml.BaseLoader) # $decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML +yaml.safe_load(payload) # $ decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML + +# load_all variants yaml.load_all(payload) # $ decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML decodeMayExecuteInput yaml.safe_load_all(payload) # $ decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML yaml.unsafe_load_all(payload) # $ decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML decodeMayExecuteInput From 17d7ba80496ac5c4abb29e44d0a4a8c106407c90 Mon Sep 17 00:00:00 2001 From: Porcuiney Hairs Date: Tue, 2 Feb 2021 23:58:32 +0530 Subject: [PATCH 164/725] Add Log Injection Vulnerability --- .../Security/CWE/CWE-117/LogInjection.qhelp | 49 ++++++++++++++ .../Security/CWE/CWE-117/LogInjection.ql | 67 +++++++++++++++++++ .../Security/CWE/CWE-117/LogInjectionBad.java | 24 +++++++ .../CWE/CWE-117/LogInjectionGood.java | 25 +++++++ .../Security/CWE/CWE-532/SensitiveInfoLog.ql | 31 ++------- .../experimental/semmle/code/java/Logging.qll | 30 +++++++++ 6 files changed, 199 insertions(+), 27 deletions(-) create mode 100644 java/ql/src/experimental/Security/CWE/CWE-117/LogInjection.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-117/LogInjection.ql create mode 100644 java/ql/src/experimental/Security/CWE/CWE-117/LogInjectionBad.java create mode 100644 java/ql/src/experimental/Security/CWE/CWE-117/LogInjectionGood.java create mode 100644 java/ql/src/experimental/semmle/code/java/Logging.qll diff --git a/java/ql/src/experimental/Security/CWE/CWE-117/LogInjection.qhelp b/java/ql/src/experimental/Security/CWE/CWE-117/LogInjection.qhelp new file mode 100644 index 00000000000..4ad7b2d5380 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-117/LogInjection.qhelp @@ -0,0 +1,49 @@ + + + + + + +

    If unsanitized user input is written to a log entry, a malicious user may be able to forge new log entries.

    + +

    Forgery can occur if a user provides some input creating the appearance of multiple + log entries. This can include unescaped new-line characters, or HTML or other markup.

    +
    + + +

    +User input should be suitably sanitized before it is logged. +

    +

    +If the log entries are plain text then line breaks should be removed from user input, using for example +String replace(char oldChar, char newChar) or similar. Care should also be taken that user input is clearly marked +in log entries, and that a malicious user cannot cause confusion in other ways. +

    +

    +For log entries that will be displayed in HTML, user input should be HTML encoded before being logged, to prevent forgery and +other forms of HTML injection. +

    + +
    + + +

    In the example, a username, provided by the user, is logged using logger.warn (from org.slf4j.Logger). + In the first case (/bad endpoint), the username is logged without any sanitization. + If a malicious user provides Guest'%0AUser:'Admin as a username parameter, + the log entry will be split into two separate lines, where the first line will be User:'Guest' and the second one will be User:'Admin'. +

    + + +

    In the second case (/good endpoint), matches() is used to ensure the user input only has alphanumeric characters. + If a malicious user provides `Guest'%0AUser:'Admin` as a username parameter, + the log entry will not be split into two separate lines, resulting in a single line User:'Guest'User:'Admin'.

    + + +
    + + +
  • OWASP: Log Injection.
  • +
    +
    diff --git a/java/ql/src/experimental/Security/CWE/CWE-117/LogInjection.ql b/java/ql/src/experimental/Security/CWE/CWE-117/LogInjection.ql new file mode 100644 index 00000000000..440c39b77e8 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-117/LogInjection.ql @@ -0,0 +1,67 @@ +/** + * @name Log Injection + * @description Building log entries from user-controlled data is vulnerable to + * insertion of forged log entries by a malicious user. + * @kind path-problem + * @problem.severity error + * @precision high + * @id java/log-injection + * @tags security + * external/cwe/cwe-117 + */ + +import java +import DataFlow::PathGraph +import experimental.semmle.code.java.Logging +import semmle.code.java.dataflow.FlowSources + +/** + * A taint-tracking configuration for tracking untrusted user input used in log entries. + */ +private class LogInjectionConfiguration extends TaintTracking::Configuration { + LogInjectionConfiguration() { this = "Log Injection" } + + override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } + + override predicate isSink(DataFlow::Node sink) { + sink.asExpr() = any(LoggingCall c).getALogArgument() + } + + override predicate isSanitizer(DataFlow::Node node) { + node.getType() instanceof BoxedType or node.getType() instanceof PrimitiveType + } + + override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { + guard instanceof StrCheckSanitizerGuard + } +} + +/** + * Models any regex or equality check as a sanitizer guard. + * Assumes any check on the taint to be a valid sanitizing check. + */ +private class StrCheckSanitizerGuard extends DataFlow::BarrierGuard { + StrCheckSanitizerGuard() { + exists(Method m | + m.getDeclaringType().hasQualifiedName("java.util.regex", "Pattern") and + m.hasName("matches") + or + m.getDeclaringType() instanceof TypeString and + m.hasName([ + "startsWith", "regionMatches", "matches", "equals", "equalsIgnoreCase", "endsWith", + "contentEquals", "contains" + ]) + | + m.getAReference() = this + ) + } + + override predicate checks(Expr e, boolean branch) { + e = this.(MethodAccess).getQualifier() and branch = true + } +} + +from LogInjectionConfiguration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "$@ flows to log entry.", source.getNode(), + "User-provided value" diff --git a/java/ql/src/experimental/Security/CWE/CWE-117/LogInjectionBad.java b/java/ql/src/experimental/Security/CWE/CWE-117/LogInjectionBad.java new file mode 100644 index 00000000000..620b9801631 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-117/LogInjectionBad.java @@ -0,0 +1,24 @@ +package com.example.restservice; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class LogInjection { + + private final Logger log = LoggerFactory.getLogger(LogInjection.class); + + // /bad?username=Guest'%0AUser:'Admin + @GetMapping("/bad") + public String bad(@RequestParam(value = "username", defaultValue = "name") String username) { + log.warn("User:'{}'", username); + // The logging call above would result in multiple log entries as shown below: + // User:'Guest' + // User:'Admin' + return username; + } +} + diff --git a/java/ql/src/experimental/Security/CWE/CWE-117/LogInjectionGood.java b/java/ql/src/experimental/Security/CWE/CWE-117/LogInjectionGood.java new file mode 100644 index 00000000000..2ed683a2760 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-117/LogInjectionGood.java @@ -0,0 +1,25 @@ +package com.example.restservice; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class LogInjection { + + private final Logger log = LoggerFactory.getLogger(LogInjection.class); + + // /good?username=Guest'%0AUser:'Admin + @GetMapping("/good") + public String good(@RequestParam(value = "username", defaultValue = "name") String username) { + // The regex check here, allows only alphanumeric characters to pass. + // Hence, does not result in log injection + if (username.matches("\w*")) { + log.warn("User:'{}'", username); + + return username; + } + } +} diff --git a/java/ql/src/experimental/Security/CWE/CWE-532/SensitiveInfoLog.ql b/java/ql/src/experimental/Security/CWE/CWE-532/SensitiveInfoLog.ql index 15690b7c32b..853bbb6bace 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-532/SensitiveInfoLog.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-532/SensitiveInfoLog.ql @@ -10,6 +10,7 @@ import java import semmle.code.java.dataflow.TaintTracking import semmle.code.java.security.SensitiveActions +import experimental.semmle.code.java.Logging import DataFlow import PathGraph @@ -27,38 +28,14 @@ class CredentialExpr extends Expr { } } -/** Class of popular logging utilities * */ -class LoggerType extends RefType { - LoggerType() { - this.hasQualifiedName("org.apache.log4j", "Category") or //Log4J - this.hasQualifiedName("org.apache.logging.log4j", "Logger") or //Log4J 2 - this.hasQualifiedName("org.slf4j", "Logger") or //SLF4j and Gradle Logging - this.hasQualifiedName("org.jboss.logging", "BasicLogger") or //JBoss Logging - this.hasQualifiedName("org.jboss.logging", "Logger") or //JBoss Logging (`org.jboss.logging.Logger` in some implementations like JBoss Application Server 4.0.4 did not implement `BasicLogger`) - this.hasQualifiedName("org.apache.commons.logging", "Log") or //Apache Commons Logging - this.hasQualifiedName("org.scijava.log", "Logger") //SciJava Logging - } -} - -predicate isSensitiveLoggingSink(DataFlow::Node sink) { - exists(MethodAccess ma | - ma.getMethod().getDeclaringType() instanceof LoggerType and - ( - ma.getMethod().hasName("debug") or - ma.getMethod().hasName("trace") or - ma.getMethod().hasName("debugf") or - ma.getMethod().hasName("debugv") - ) and //Check low priority log levels which are more likely to be real issues to reduce false positives - sink.asExpr() = ma.getAnArgument() - ) -} - class LoggerConfiguration extends DataFlow::Configuration { LoggerConfiguration() { this = "Logger Configuration" } override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof CredentialExpr } - override predicate isSink(DataFlow::Node sink) { isSensitiveLoggingSink(sink) } + override predicate isSink(DataFlow::Node sink) { + exists(LoggingCall c | sink.asExpr() = c.getALogArgument()) + } override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { TaintTracking::localTaintStep(node1, node2) diff --git a/java/ql/src/experimental/semmle/code/java/Logging.qll b/java/ql/src/experimental/semmle/code/java/Logging.qll new file mode 100644 index 00000000000..6e50dc163bc --- /dev/null +++ b/java/ql/src/experimental/semmle/code/java/Logging.qll @@ -0,0 +1,30 @@ +/** + * Provides classes and predicates for working with loggers. + */ + +import java + +/** Models a call to a logging method. */ +class LoggingCall extends MethodAccess { + LoggingCall() { + exists(RefType t, Method m | + t.hasQualifiedName("org.apache.log4j", "Category") or // Log4j 1 + t.hasQualifiedName("org.apache.logging.log4j", ["Logger", "LogBuilder"]) or // Log4j 2 + t.hasQualifiedName("org.apache.commons.logging", "Log") or + // JBoss Logging (`org.jboss.logging.Logger` in some implementations like JBoss Application Server 4.0.4 did not implement `BasicLogger`) + t.hasQualifiedName("org.jboss.logging", ["BasicLogger", "Logger"]) or + t.hasQualifiedName("org.slf4j.spi", "LoggingEventBuilder") or + t.hasQualifiedName("org.slf4j", "Logger") or + t.hasQualifiedName("org.scijava.log", "Logger") or + t.hasQualifiedName("java.lang", "System$Logger") or + t.hasQualifiedName("java.util.logging","Logger") + | + m.getDeclaringType().(RefType).extendsOrImplements*(t) and + m.getReturnType() instanceof VoidType and + this = m.getAReference() + ) + } + + /** Returns an argument which would be logged by this call. */ + Argument getALogArgument() { result = this.getArgument(_) } +} From d0c82d3756e78678e981b301215d0f7120acb4ce Mon Sep 17 00:00:00 2001 From: Porcuiney Hairs Date: Wed, 3 Mar 2021 03:42:21 +0530 Subject: [PATCH 165/725] Add flogger and android logging support --- java/ql/src/experimental/semmle/code/java/Logging.qll | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/java/ql/src/experimental/semmle/code/java/Logging.qll b/java/ql/src/experimental/semmle/code/java/Logging.qll index 6e50dc163bc..c99334cdedd 100644 --- a/java/ql/src/experimental/semmle/code/java/Logging.qll +++ b/java/ql/src/experimental/semmle/code/java/Logging.qll @@ -9,17 +9,22 @@ class LoggingCall extends MethodAccess { LoggingCall() { exists(RefType t, Method m | t.hasQualifiedName("org.apache.log4j", "Category") or // Log4j 1 - t.hasQualifiedName("org.apache.logging.log4j", ["Logger", "LogBuilder"]) or // Log4j 2 + t.hasQualifiedName("org.apache.logging.log4j", ["Logger", "LogBuilder"]) or // Log4j 2 t.hasQualifiedName("org.apache.commons.logging", "Log") or // JBoss Logging (`org.jboss.logging.Logger` in some implementations like JBoss Application Server 4.0.4 did not implement `BasicLogger`) t.hasQualifiedName("org.jboss.logging", ["BasicLogger", "Logger"]) or t.hasQualifiedName("org.slf4j.spi", "LoggingEventBuilder") or t.hasQualifiedName("org.slf4j", "Logger") or t.hasQualifiedName("org.scijava.log", "Logger") or + t.hasQualifiedName("com.google.common.flogger", "LoggingApi") or t.hasQualifiedName("java.lang", "System$Logger") or - t.hasQualifiedName("java.util.logging","Logger") + t.hasQualifiedName("java.util.logging", "Logger") or + t.hasQualifiedName("android.util.Log", _) | - m.getDeclaringType().(RefType).extendsOrImplements*(t) and + ( + m.getDeclaringType().getASourceSupertype*() = t or + m.getDeclaringType().(RefType).extendsOrImplements*(t) + ) and m.getReturnType() instanceof VoidType and this = m.getAReference() ) From f27d2bdf6d3ebbb37bb006d249494b96cfafadf9 Mon Sep 17 00:00:00 2001 From: porcupineyhairs <61983466+porcupineyhairs@users.noreply.github.com> Date: Wed, 3 Mar 2021 12:36:01 +0530 Subject: [PATCH 166/725] Update java/ql/src/experimental/semmle/code/java/Logging.qll Co-authored-by: Marcono1234 --- java/ql/src/experimental/semmle/code/java/Logging.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/src/experimental/semmle/code/java/Logging.qll b/java/ql/src/experimental/semmle/code/java/Logging.qll index c99334cdedd..7a70cd8149b 100644 --- a/java/ql/src/experimental/semmle/code/java/Logging.qll +++ b/java/ql/src/experimental/semmle/code/java/Logging.qll @@ -19,7 +19,7 @@ class LoggingCall extends MethodAccess { t.hasQualifiedName("com.google.common.flogger", "LoggingApi") or t.hasQualifiedName("java.lang", "System$Logger") or t.hasQualifiedName("java.util.logging", "Logger") or - t.hasQualifiedName("android.util.Log", _) + t.hasQualifiedName("android.util", "Log") | ( m.getDeclaringType().getASourceSupertype*() = t or From 84c9137152a4533393bea86292debb3dad1b4fff Mon Sep 17 00:00:00 2001 From: Porcuiney Hairs Date: Wed, 3 Mar 2021 17:27:56 +0530 Subject: [PATCH 167/725] Include suggestions from review --- java/ql/src/experimental/semmle/code/java/Logging.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/src/experimental/semmle/code/java/Logging.qll b/java/ql/src/experimental/semmle/code/java/Logging.qll index 7a70cd8149b..b3444972710 100644 --- a/java/ql/src/experimental/semmle/code/java/Logging.qll +++ b/java/ql/src/experimental/semmle/code/java/Logging.qll @@ -23,7 +23,7 @@ class LoggingCall extends MethodAccess { | ( m.getDeclaringType().getASourceSupertype*() = t or - m.getDeclaringType().(RefType).extendsOrImplements*(t) + m.getDeclaringType().extendsOrImplements*(t) ) and m.getReturnType() instanceof VoidType and this = m.getAReference() From a88c3682ff429dddb09dfd826c9c5efb4bc2c593 Mon Sep 17 00:00:00 2001 From: Porcuiney Hairs Date: Thu, 18 Mar 2021 16:11:27 +0530 Subject: [PATCH 168/725] remove sanitiserGuards --- .../Security/CWE/CWE-117/LogInjection.ql | 29 ------------------- 1 file changed, 29 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-117/LogInjection.ql b/java/ql/src/experimental/Security/CWE/CWE-117/LogInjection.ql index 440c39b77e8..7183c74b5bf 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-117/LogInjection.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-117/LogInjection.ql @@ -30,35 +30,6 @@ private class LogInjectionConfiguration extends TaintTracking::Configuration { override predicate isSanitizer(DataFlow::Node node) { node.getType() instanceof BoxedType or node.getType() instanceof PrimitiveType } - - override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { - guard instanceof StrCheckSanitizerGuard - } -} - -/** - * Models any regex or equality check as a sanitizer guard. - * Assumes any check on the taint to be a valid sanitizing check. - */ -private class StrCheckSanitizerGuard extends DataFlow::BarrierGuard { - StrCheckSanitizerGuard() { - exists(Method m | - m.getDeclaringType().hasQualifiedName("java.util.regex", "Pattern") and - m.hasName("matches") - or - m.getDeclaringType() instanceof TypeString and - m.hasName([ - "startsWith", "regionMatches", "matches", "equals", "equalsIgnoreCase", "endsWith", - "contentEquals", "contains" - ]) - | - m.getAReference() = this - ) - } - - override predicate checks(Expr e, boolean branch) { - e = this.(MethodAccess).getQualifier() and branch = true - } } from LogInjectionConfiguration cfg, DataFlow::PathNode source, DataFlow::PathNode sink From 5ec8511d50c96fac2909dfba39424fac79c9df89 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 18 Mar 2021 11:47:46 +0100 Subject: [PATCH 169/725] Python: Port PyYAML model to API graphs --- .../ql/src/semmle/python/frameworks/Yaml.qll | 76 ++----------------- 1 file changed, 7 insertions(+), 69 deletions(-) diff --git a/python/ql/src/semmle/python/frameworks/Yaml.qll b/python/ql/src/semmle/python/frameworks/Yaml.qll index ec3a21379da..8240dd21378 100644 --- a/python/ql/src/semmle/python/frameworks/Yaml.qll +++ b/python/ql/src/semmle/python/frameworks/Yaml.qll @@ -11,6 +11,7 @@ private import python private import semmle.python.dataflow.new.DataFlow private import semmle.python.dataflow.new.RemoteFlowSources private import semmle.python.Concepts +private import semmle.python.ApiGraphs /** * Provides classes modeling security-relevant aspects of the PyYAML package (obtained @@ -20,70 +21,7 @@ private import semmle.python.Concepts * - https://pyyaml.org/wiki/PyYAMLDocumentation * - https://pyyaml.docsforge.com/master/documentation/ */ -private module Yaml { - /** Gets a reference to the `yaml` module. */ - private DataFlow::Node yaml(DataFlow::TypeTracker t) { - t.start() and - result = DataFlow::importNode("yaml") - or - exists(DataFlow::TypeTracker t2 | result = yaml(t2).track(t2, t)) - } - - /** Gets a reference to the `yaml` module. */ - DataFlow::Node yaml() { result = yaml(DataFlow::TypeTracker::end()) } - - /** Provides models for the `yaml` module. */ - module yaml { - /** - * Gets a reference to the attribute `attr_name` of the `yaml` module. - * WARNING: Only holds for a few predefined attributes. - * - * For example, using `attr_name = "load"` will get all uses of `yaml.load`. - */ - private DataFlow::Node yaml_attr(DataFlow::TypeTracker t, string attr_name) { - attr_name in [ - // functions - "load", "load_all", "full_load", "full_load_all", "unsafe_load", "unsafe_load_all", - "safe_load", "safe_load_all", - // Classes - "SafeLoader", "BaseLoader" - ] and - ( - t.start() and - result = DataFlow::importNode("yaml." + attr_name) - or - t.startInAttr(attr_name) and - result = yaml() - ) - or - // Due to bad performance when using normal setup with `yaml_attr(t2, attr_name).track(t2, t)` - // we have inlined that code and forced a join - exists(DataFlow::TypeTracker t2 | - exists(DataFlow::StepSummary summary | - yaml_attr_first_join(t2, attr_name, result, summary) and - t = t2.append(summary) - ) - ) - } - - pragma[nomagic] - private predicate yaml_attr_first_join( - DataFlow::TypeTracker t2, string attr_name, DataFlow::Node res, DataFlow::StepSummary summary - ) { - DataFlow::StepSummary::step(yaml_attr(t2, attr_name), res, summary) - } - - /** - * Gets a reference to the attribute `attr_name` of the `yaml` module. - * WARNING: Only holds for a few predefined attributes. - * - * For example, using `attr_name = "load"` will get all uses of `yaml.load`. - */ - DataFlow::Node yaml_attr(string attr_name) { - result = yaml_attr(DataFlow::TypeTracker::end(), attr_name) - } - } -} +private module Yaml { } /** * A call to any of the loading functions in `yaml` (`load`, `load_all`, `full_load`, @@ -91,7 +29,7 @@ private module Yaml { * * See https://pyyaml.org/wiki/PyYAMLDocumentation (you will have to scroll down). */ -private class YamlLoadCall extends Decoding::Range, DataFlow::CfgNode { +private class YamlLoadCall extends Decoding::Range, DataFlow::CallCfgNode { override CallNode node; string func_name; @@ -100,7 +38,7 @@ private class YamlLoadCall extends Decoding::Range, DataFlow::CfgNode { "load", "load_all", "full_load", "full_load_all", "unsafe_load", "unsafe_load_all", "safe_load", "safe_load_all" ] and - node.getFunction() = Yaml::yaml::yaml_attr(func_name).asCfgNode() + this = API::moduleImport("yaml").getMember(func_name).getACall() } /** @@ -117,13 +55,13 @@ private class YamlLoadCall extends Decoding::Range, DataFlow::CfgNode { // If the `Loader` is not set to either `SafeLoader` or `BaseLoader` or not set at all, // then the default loader will be used, which is not safe. not exists(DataFlow::Node loader_arg | - loader_arg.asCfgNode() in [node.getArg(1), node.getArgByName("Loader")] + loader_arg in [this.getArg(1), this.getArgByName("Loader")] | - loader_arg = Yaml::yaml::yaml_attr(["SafeLoader", "BaseLoader"]) + loader_arg = API::moduleImport("yaml").getMember(["SafeLoader", "BaseLoader"]).getAUse() ) } - override DataFlow::Node getAnInput() { result.asCfgNode() = node.getArg(0) } + override DataFlow::Node getAnInput() { result = this.getArg(0) } override DataFlow::Node getOutput() { result = this } From 25b15d74709e912f97ca7d461552eb5681c4ca50 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 18 Mar 2021 11:48:30 +0100 Subject: [PATCH 170/725] Python: Move PyYAML modeling classes within module For now, this is how we're trying to structure things -- all in all it doesn't matter too much, since everything is still marked as private. --- .../ql/src/semmle/python/frameworks/Yaml.qll | 84 +++++++++---------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/python/ql/src/semmle/python/frameworks/Yaml.qll b/python/ql/src/semmle/python/frameworks/Yaml.qll index 8240dd21378..1bf5c517ec8 100644 --- a/python/ql/src/semmle/python/frameworks/Yaml.qll +++ b/python/ql/src/semmle/python/frameworks/Yaml.qll @@ -21,49 +21,49 @@ private import semmle.python.ApiGraphs * - https://pyyaml.org/wiki/PyYAMLDocumentation * - https://pyyaml.docsforge.com/master/documentation/ */ -private module Yaml { } - -/** - * A call to any of the loading functions in `yaml` (`load`, `load_all`, `full_load`, - * `full_load_all`, `unsafe_load`, `unsafe_load_all`, `safe_load`, `safe_load_all`) - * - * See https://pyyaml.org/wiki/PyYAMLDocumentation (you will have to scroll down). - */ -private class YamlLoadCall extends Decoding::Range, DataFlow::CallCfgNode { - override CallNode node; - string func_name; - - YamlLoadCall() { - func_name in [ - "load", "load_all", "full_load", "full_load_all", "unsafe_load", "unsafe_load_all", - "safe_load", "safe_load_all" - ] and - this = API::moduleImport("yaml").getMember(func_name).getACall() - } - +private module Yaml { /** - * This function was thought safe from the 5.1 release in 2017, when the default loader was changed to `FullLoader`. - * In 2020 new exploits were found, meaning it's not safe. The Current plan is to change the default to `SafeLoader` in release 6.0 - * (as explained in https://github.com/yaml/pyyaml/issues/420#issuecomment-696752389). - * Until 6.0 is released, we will mark `yaml.load` as possibly leading to arbitrary code execution. - * See https://github.com/yaml/pyyaml/wiki/PyYAML-yaml.load(input)-Deprecation for more details. + * A call to any of the loading functions in `yaml` (`load`, `load_all`, `full_load`, + * `full_load_all`, `unsafe_load`, `unsafe_load_all`, `safe_load`, `safe_load_all`) + * + * See https://pyyaml.org/wiki/PyYAMLDocumentation (you will have to scroll down). */ - override predicate mayExecuteInput() { - func_name in ["full_load", "full_load_all", "unsafe_load", "unsafe_load_all"] - or - func_name in ["load", "load_all"] and - // If the `Loader` is not set to either `SafeLoader` or `BaseLoader` or not set at all, - // then the default loader will be used, which is not safe. - not exists(DataFlow::Node loader_arg | - loader_arg in [this.getArg(1), this.getArgByName("Loader")] - | - loader_arg = API::moduleImport("yaml").getMember(["SafeLoader", "BaseLoader"]).getAUse() - ) + private class YamlLoadCall extends Decoding::Range, DataFlow::CallCfgNode { + override CallNode node; + string func_name; + + YamlLoadCall() { + func_name in [ + "load", "load_all", "full_load", "full_load_all", "unsafe_load", "unsafe_load_all", + "safe_load", "safe_load_all" + ] and + this = API::moduleImport("yaml").getMember(func_name).getACall() + } + + /** + * This function was thought safe from the 5.1 release in 2017, when the default loader was changed to `FullLoader`. + * In 2020 new exploits were found, meaning it's not safe. The Current plan is to change the default to `SafeLoader` in release 6.0 + * (as explained in https://github.com/yaml/pyyaml/issues/420#issuecomment-696752389). + * Until 6.0 is released, we will mark `yaml.load` as possibly leading to arbitrary code execution. + * See https://github.com/yaml/pyyaml/wiki/PyYAML-yaml.load(input)-Deprecation for more details. + */ + override predicate mayExecuteInput() { + func_name in ["full_load", "full_load_all", "unsafe_load", "unsafe_load_all"] + or + func_name in ["load", "load_all"] and + // If the `Loader` is not set to either `SafeLoader` or `BaseLoader` or not set at all, + // then the default loader will be used, which is not safe. + not exists(DataFlow::Node loader_arg | + loader_arg in [this.getArg(1), this.getArgByName("Loader")] + | + loader_arg = API::moduleImport("yaml").getMember(["SafeLoader", "BaseLoader"]).getAUse() + ) + } + + override DataFlow::Node getAnInput() { result = this.getArg(0) } + + override DataFlow::Node getOutput() { result = this } + + override string getFormat() { result = "YAML" } } - - override DataFlow::Node getAnInput() { result = this.getArg(0) } - - override DataFlow::Node getOutput() { result = this } - - override string getFormat() { result = "YAML" } } From 54e6f51512e99279ea249c6553168a65d604c618 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 18 Mar 2021 11:49:33 +0100 Subject: [PATCH 171/725] Python: Add example of C-based PyYAML loaders ``` In [6]: yaml.load("!!python/object/new:os.system [echo EXPLOIT!]", yaml.CLoader) EXPLOIT! Out[6]: 0 ``` --- .../experimental/library-tests/frameworks/yaml/Decoding.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/python/ql/test/experimental/library-tests/frameworks/yaml/Decoding.py b/python/ql/test/experimental/library-tests/frameworks/yaml/Decoding.py index 7d5bcde1503..80360648391 100644 --- a/python/ql/test/experimental/library-tests/frameworks/yaml/Decoding.py +++ b/python/ql/test/experimental/library-tests/frameworks/yaml/Decoding.py @@ -17,3 +17,9 @@ yaml.load_all(payload) # $ decodeInput=payload decodeOutput=Attribute() decodeFo yaml.safe_load_all(payload) # $ decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML yaml.unsafe_load_all(payload) # $ decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML decodeMayExecuteInput yaml.full_load_all(payload) # $ decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML decodeMayExecuteInput + +# C-based loaders with `libyaml` +yaml.load(payload, yaml.CLoader) # $ decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML decodeMayExecuteInput +yaml.load(payload, yaml.CFullLoader) # $ decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML decodeMayExecuteInput +yaml.load(payload, yaml.CSafeLoader) # $decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML SPURIOUS: decodeMayExecuteInput +yaml.load(payload, yaml.CBaseLoader) # $decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML SPURIOUS: decodeMayExecuteInput From 42b2c3ed52e529c72f815844d8aaf01f937320d7 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 18 Mar 2021 11:55:01 +0100 Subject: [PATCH 172/725] Python: Model C-based loaders for PyYAML Not really that important. But easy to do while I was working on this library. --- .../change-notes/2021-03-18-yaml-handle-C-based-loaders.md | 2 ++ python/ql/src/semmle/python/frameworks/Yaml.qll | 5 ++++- .../experimental/library-tests/frameworks/yaml/Decoding.py | 4 ++-- 3 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 python/change-notes/2021-03-18-yaml-handle-C-based-loaders.md diff --git a/python/change-notes/2021-03-18-yaml-handle-C-based-loaders.md b/python/change-notes/2021-03-18-yaml-handle-C-based-loaders.md new file mode 100644 index 00000000000..054d10dbb0b --- /dev/null +++ b/python/change-notes/2021-03-18-yaml-handle-C-based-loaders.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* Improved modeling of the `PyYAML` PyPI package, so we now correctly treat `CSafeLoader` and `CBaseLoader` as being safe loaders that can not lead to code execution. diff --git a/python/ql/src/semmle/python/frameworks/Yaml.qll b/python/ql/src/semmle/python/frameworks/Yaml.qll index 1bf5c517ec8..f7ac0a9fda7 100644 --- a/python/ql/src/semmle/python/frameworks/Yaml.qll +++ b/python/ql/src/semmle/python/frameworks/Yaml.qll @@ -56,7 +56,10 @@ private module Yaml { not exists(DataFlow::Node loader_arg | loader_arg in [this.getArg(1), this.getArgByName("Loader")] | - loader_arg = API::moduleImport("yaml").getMember(["SafeLoader", "BaseLoader"]).getAUse() + loader_arg = + API::moduleImport("yaml") + .getMember(["SafeLoader", "BaseLoader", "CSafeLoader", "CBaseLoader"]) + .getAUse() ) } diff --git a/python/ql/test/experimental/library-tests/frameworks/yaml/Decoding.py b/python/ql/test/experimental/library-tests/frameworks/yaml/Decoding.py index 80360648391..a9369d6ec3d 100644 --- a/python/ql/test/experimental/library-tests/frameworks/yaml/Decoding.py +++ b/python/ql/test/experimental/library-tests/frameworks/yaml/Decoding.py @@ -21,5 +21,5 @@ yaml.full_load_all(payload) # $ decodeInput=payload decodeOutput=Attribute() dec # C-based loaders with `libyaml` yaml.load(payload, yaml.CLoader) # $ decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML decodeMayExecuteInput yaml.load(payload, yaml.CFullLoader) # $ decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML decodeMayExecuteInput -yaml.load(payload, yaml.CSafeLoader) # $decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML SPURIOUS: decodeMayExecuteInput -yaml.load(payload, yaml.CBaseLoader) # $decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML SPURIOUS: decodeMayExecuteInput +yaml.load(payload, yaml.CSafeLoader) # $decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML +yaml.load(payload, yaml.CBaseLoader) # $decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML From d998d06b942911cae3cdae9d5a21e65abe33dbf6 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 18 Mar 2021 13:37:18 +0100 Subject: [PATCH 173/725] add link to source in alert-message for js/shell-command-constructed-from-input --- .../src/Security/CWE-078/UnsafeShellCommandConstruction.ql | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.ql b/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.ql index f5d5113634d..1b4d5523ba4 100644 --- a/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.ql +++ b/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.ql @@ -18,6 +18,6 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, Sink sinkNode where cfg.hasFlowPath(source, sink) and sinkNode = sink.getNode() -select sinkNode.getAlertLocation(), source, sink, "$@ based on library input is later used in $@.", - sinkNode.getAlertLocation(), sinkNode.getSinkType(), sinkNode.getCommandExecution(), - "shell command" +select sinkNode.getAlertLocation(), source, sink, "$@ based on $@ is later used in $@.", + sinkNode.getAlertLocation(), sinkNode.getSinkType(), source.getNode(), "library input", + sinkNode.getCommandExecution(), "shell command" From add0c88530970a200c60aa91fb24259df5d4fe26 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 18 Mar 2021 13:39:12 +0100 Subject: [PATCH 174/725] loosen the requirement that the `package.json` file must be the top-most `package.json` --- .../src/semmle/javascript/PackageExports.qll | 27 +++---------------- 1 file changed, 3 insertions(+), 24 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/PackageExports.qll b/javascript/ql/src/semmle/javascript/PackageExports.qll index bdb0c297411..9de6a7780b1 100644 --- a/javascript/ql/src/semmle/javascript/PackageExports.qll +++ b/javascript/ql/src/semmle/javascript/PackageExports.qll @@ -17,33 +17,12 @@ DataFlow::ParameterNode getALibraryInputParameter() { } /** - * Gets the number of occurrences of "/" in `path`. - */ -bindingset[path] -private int countSlashes(string path) { result = count(path.splitAt("/")) - 1 } - -/** - * Gets the topmost named package.json that appears in the project. - * - * There can be multiple results if the there exists multiple package.json that are equally deeply nested in the folder structure. - * Results are limited to package.json files that are at most nested 2 directories deep. - */ -PackageJSON getTopmostPackageJSON() { - result = - min(PackageJSON j | - countSlashes(j.getFile().getRelativePath()) <= 3 and - exists(j.getPackageName()) - | - j order by countSlashes(j.getFile().getRelativePath()) - ) -} - -/** - * Gets a value exported by the main module from one of the topmost `package.json` files (see `getTopmostPackageJSON`). + * Gets a value exported by the main module from a named `package.json` file. * The value is either directly the `module.exports` value, a nested property of `module.exports`, or a method on an exported class. */ private DataFlow::Node getAValueExportedByPackage() { - result = getAnExportFromModule(getTopmostPackageJSON().getMainModule()) + result = + getAnExportFromModule(any(PackageJSON pack | exists(pack.getPackageName())).getMainModule()) or result = getAValueExportedByPackage().(DataFlow::PropWrite).getRhs() or From c0bb169342f7561ce7d50ee1ed07b030aad252fa Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 18 Mar 2021 13:41:36 +0100 Subject: [PATCH 175/725] recognize a `src/index.js` file as a main module for a package --- .../ql/src/semmle/javascript/NodeModuleResolutionImpl.qll | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/NodeModuleResolutionImpl.qll b/javascript/ql/src/semmle/javascript/NodeModuleResolutionImpl.qll index 01b01f1ac04..60ccf7216c9 100644 --- a/javascript/ql/src/semmle/javascript/NodeModuleResolutionImpl.qll +++ b/javascript/ql/src/semmle/javascript/NodeModuleResolutionImpl.qll @@ -96,8 +96,11 @@ File resolveMainModule(PackageJSON pkg, int priority) { ) ) or - result = - tryExtensions(pkg.getFile().getParentContainer(), "index", priority - prioritiesPerCandidate()) + exists(Folder folder | folder = pkg.getFile().getParentContainer() | + result = + tryExtensions([folder, folder.getChildContainer("src")], "index", + priority - prioritiesPerCandidate()) + ) } /** From 67a5831ac09f26971965d7eb65fd3520dd653e54 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 18 Mar 2021 13:59:44 +0100 Subject: [PATCH 176/725] update expected output --- .../PackageExports/tests.expected | 3 - .../library-tests/PackageExports/tests.ql | 2 - .../UnsafeShellCommandConstruction.expected | 132 ++++++++++-------- .../Security/CWE-078/lib/subLib/index.js | 2 +- 4 files changed, 76 insertions(+), 63 deletions(-) diff --git a/javascript/ql/test/library-tests/PackageExports/tests.expected b/javascript/ql/test/library-tests/PackageExports/tests.expected index 648226a0d13..1d46e149521 100644 --- a/javascript/ql/test/library-tests/PackageExports/tests.expected +++ b/javascript/ql/test/library-tests/PackageExports/tests.expected @@ -1,6 +1,3 @@ -getTopmostPackageJSON -| absent_main/package.json:1:1:4:1 | {\\n " ... t.js"\\n} | -| lib1/package.json:1:1:4:1 | {\\n " ... n.js"\\n} | getALibraryInputParameter | lib1/foo.js:3:44:3:44 | d | | lib1/main.js:6:17:6:17 | a | diff --git a/javascript/ql/test/library-tests/PackageExports/tests.ql b/javascript/ql/test/library-tests/PackageExports/tests.ql index 1a23e8d24d9..08ce8bcd068 100644 --- a/javascript/ql/test/library-tests/PackageExports/tests.ql +++ b/javascript/ql/test/library-tests/PackageExports/tests.ql @@ -1,8 +1,6 @@ import javascript import semmle.javascript.PackageExports as Exports -query PackageJSON getTopmostPackageJSON() { result = Exports::getTopmostPackageJSON() } - query DataFlow::Node getALibraryInputParameter() { result = Exports::getALibraryInputParameter() } query DataFlow::Node getAnExportedValue(Module mod, string name) { diff --git a/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction.expected b/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction.expected index 2d707e1a693..f4ed7e6d10b 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction.expected @@ -205,6 +205,14 @@ nodes | lib/lib.js:405:39:405:42 | name | | lib/lib.js:406:22:406:25 | name | | lib/lib.js:406:22:406:25 | name | +| lib/subLib/index.js:3:28:3:31 | name | +| lib/subLib/index.js:3:28:3:31 | name | +| lib/subLib/index.js:4:22:4:25 | name | +| lib/subLib/index.js:4:22:4:25 | name | +| lib/subLib/index.js:7:32:7:35 | name | +| lib/subLib/index.js:7:32:7:35 | name | +| lib/subLib/index.js:8:22:8:25 | name | +| lib/subLib/index.js:8:22:8:25 | name | edges | lib/lib2.js:3:28:3:31 | name | lib/lib2.js:4:22:4:25 | name | | lib/lib2.js:3:28:3:31 | name | lib/lib2.js:4:22:4:25 | name | @@ -444,61 +452,71 @@ edges | lib/lib.js:405:39:405:42 | name | lib/lib.js:406:22:406:25 | name | | lib/lib.js:405:39:405:42 | name | lib/lib.js:406:22:406:25 | name | | lib/lib.js:405:39:405:42 | name | lib/lib.js:406:22:406:25 | name | +| lib/subLib/index.js:3:28:3:31 | name | lib/subLib/index.js:4:22:4:25 | name | +| lib/subLib/index.js:3:28:3:31 | name | lib/subLib/index.js:4:22:4:25 | name | +| lib/subLib/index.js:3:28:3:31 | name | lib/subLib/index.js:4:22:4:25 | name | +| lib/subLib/index.js:3:28:3:31 | name | lib/subLib/index.js:4:22:4:25 | name | +| lib/subLib/index.js:7:32:7:35 | name | lib/subLib/index.js:8:22:8:25 | name | +| lib/subLib/index.js:7:32:7:35 | name | lib/subLib/index.js:8:22:8:25 | name | +| lib/subLib/index.js:7:32:7:35 | name | lib/subLib/index.js:8:22:8:25 | name | +| lib/subLib/index.js:7:32:7:35 | name | lib/subLib/index.js:8:22:8:25 | name | #select -| lib/lib2.js:4:10:4:25 | "rm -rf " + name | lib/lib2.js:3:28:3:31 | name | lib/lib2.js:4:22:4:25 | name | $@ based on library input is later used in $@. | lib/lib2.js:4:10:4:25 | "rm -rf " + name | String concatenation | lib/lib2.js:4:2:4:26 | cp.exec ... + name) | shell command | -| lib/lib2.js:8:10:8:25 | "rm -rf " + name | lib/lib2.js:7:32:7:35 | name | lib/lib2.js:8:22:8:25 | name | $@ based on library input is later used in $@. | lib/lib2.js:8:10:8:25 | "rm -rf " + name | String concatenation | lib/lib2.js:8:2:8:26 | cp.exec ... + name) | shell command | -| lib/lib.js:4:10:4:25 | "rm -rf " + name | lib/lib.js:3:28:3:31 | name | lib/lib.js:4:22:4:25 | name | $@ based on library input is later used in $@. | lib/lib.js:4:10:4:25 | "rm -rf " + name | String concatenation | lib/lib.js:4:2:4:26 | cp.exec ... + name) | shell command | -| lib/lib.js:11:10:11:25 | "rm -rf " + name | lib/lib.js:10:32:10:35 | name | lib/lib.js:11:22:11:25 | name | $@ based on library input is later used in $@. | lib/lib.js:11:10:11:25 | "rm -rf " + name | String concatenation | lib/lib.js:11:2:11:26 | cp.exec ... + name) | shell command | -| lib/lib.js:15:10:15:25 | "rm -rf " + name | lib/lib.js:14:36:14:39 | name | lib/lib.js:15:22:15:25 | name | $@ based on library input is later used in $@. | lib/lib.js:15:10:15:25 | "rm -rf " + name | String concatenation | lib/lib.js:15:2:15:26 | cp.exec ... + name) | shell command | -| lib/lib.js:20:10:20:25 | "rm -rf " + name | lib/lib.js:19:34:19:37 | name | lib/lib.js:20:22:20:25 | name | $@ based on library input is later used in $@. | lib/lib.js:20:10:20:25 | "rm -rf " + name | String concatenation | lib/lib.js:20:2:20:26 | cp.exec ... + name) | shell command | -| lib/lib.js:27:10:27:25 | "rm -rf " + name | lib/lib.js:26:35:26:38 | name | lib/lib.js:27:22:27:25 | name | $@ based on library input is later used in $@. | lib/lib.js:27:10:27:25 | "rm -rf " + name | String concatenation | lib/lib.js:27:2:27:26 | cp.exec ... + name) | shell command | -| lib/lib.js:35:11:35:26 | "rm -rf " + name | lib/lib.js:34:14:34:17 | name | lib/lib.js:35:23:35:26 | name | $@ based on library input is later used in $@. | lib/lib.js:35:11:35:26 | "rm -rf " + name | String concatenation | lib/lib.js:35:3:35:27 | cp.exec ... + name) | shell command | -| lib/lib.js:38:11:38:26 | "rm -rf " + name | lib/lib.js:37:13:37:16 | name | lib/lib.js:38:23:38:26 | name | $@ based on library input is later used in $@. | lib/lib.js:38:11:38:26 | "rm -rf " + name | String concatenation | lib/lib.js:38:3:38:27 | cp.exec ... + name) | shell command | -| lib/lib.js:41:11:41:26 | "rm -rf " + name | lib/lib.js:40:6:40:9 | name | lib/lib.js:41:23:41:26 | name | $@ based on library input is later used in $@. | lib/lib.js:41:11:41:26 | "rm -rf " + name | String concatenation | lib/lib.js:41:3:41:27 | cp.exec ... + name) | shell command | -| lib/lib.js:50:35:50:50 | "rm -rf " + name | lib/lib.js:49:31:49:34 | name | lib/lib.js:50:47:50:50 | name | $@ based on library input is later used in $@. | lib/lib.js:50:35:50:50 | "rm -rf " + name | String concatenation | lib/lib.js:50:2:50:51 | require ... + name) | shell command | -| lib/lib.js:54:13:54:28 | "rm -rf " + name | lib/lib.js:53:33:53:36 | name | lib/lib.js:54:25:54:28 | name | $@ based on library input is later used in $@. | lib/lib.js:54:13:54:28 | "rm -rf " + name | String concatenation | lib/lib.js:55:2:55:14 | cp.exec(cmd1) | shell command | -| lib/lib.js:57:13:57:28 | "rm -rf " + name | lib/lib.js:53:33:53:36 | name | lib/lib.js:57:25:57:28 | name | $@ based on library input is later used in $@. | lib/lib.js:57:13:57:28 | "rm -rf " + name | String concatenation | lib/lib.js:59:3:59:14 | cp.exec(cmd) | shell command | -| lib/lib.js:65:10:65:25 | "rm -rf " + name | lib/lib.js:64:41:64:44 | name | lib/lib.js:65:22:65:25 | name | $@ based on library input is later used in $@. | lib/lib.js:65:10:65:25 | "rm -rf " + name | String concatenation | lib/lib.js:65:2:65:26 | cp.exec ... + name) | shell command | -| lib/lib.js:71:10:71:31 | "cat /f ... + name | lib/lib.js:64:41:64:44 | name | lib/lib.js:71:28:71:31 | name | $@ based on library input is later used in $@. | lib/lib.js:71:10:71:31 | "cat /f ... + name | String concatenation | lib/lib.js:71:2:71:32 | cp.exec ... + name) | shell command | -| lib/lib.js:73:10:73:31 | "cat \\" ... + "\\"" | lib/lib.js:64:41:64:44 | name | lib/lib.js:73:21:73:24 | name | $@ based on library input is later used in $@. | lib/lib.js:73:10:73:31 | "cat \\" ... + "\\"" | String concatenation | lib/lib.js:73:2:73:32 | cp.exec ... + "\\"") | shell command | -| lib/lib.js:75:10:75:29 | "cat '" + name + "'" | lib/lib.js:64:41:64:44 | name | lib/lib.js:75:20:75:23 | name | $@ based on library input is later used in $@. | lib/lib.js:75:10:75:29 | "cat '" + name + "'" | String concatenation | lib/lib.js:75:2:75:30 | cp.exec ... + "'") | shell command | -| lib/lib.js:77:10:77:37 | "cat '/ ... e + "'" | lib/lib.js:64:41:64:44 | name | lib/lib.js:77:28:77:31 | name | $@ based on library input is later used in $@. | lib/lib.js:77:10:77:37 | "cat '/ ... e + "'" | String concatenation | lib/lib.js:77:2:77:38 | cp.exec ... + "'") | shell command | -| lib/lib.js:83:10:83:25 | "rm -rf " + name | lib/lib.js:82:35:82:38 | name | lib/lib.js:83:22:83:25 | name | $@ based on library input is later used in $@. | lib/lib.js:83:10:83:25 | "rm -rf " + name | String concatenation | lib/lib.js:83:2:83:26 | cp.exec ... + name) | shell command | -| lib/lib.js:86:13:86:16 | name | lib/lib.js:82:35:82:38 | name | lib/lib.js:86:13:86:16 | name | $@ based on library input is later used in $@. | lib/lib.js:86:13:86:16 | name | Array element | lib/lib.js:87:2:87:25 | cp.exec ... n(" ")) | shell command | -| lib/lib.js:89:21:89:24 | name | lib/lib.js:82:35:82:38 | name | lib/lib.js:89:21:89:24 | name | $@ based on library input is later used in $@. | lib/lib.js:89:21:89:24 | name | Array element | lib/lib.js:89:2:89:36 | cp.exec ... n(" ")) | shell command | -| lib/lib.js:91:21:91:38 | "\\"" + name + "\\"" | lib/lib.js:82:35:82:38 | name | lib/lib.js:91:21:91:38 | "\\"" + name + "\\"" | $@ based on library input is later used in $@. | lib/lib.js:91:21:91:38 | "\\"" + name + "\\"" | Array element | lib/lib.js:91:2:91:50 | cp.exec ... n(" ")) | shell command | -| lib/lib.js:98:35:98:38 | name | lib/lib.js:97:35:97:38 | name | lib/lib.js:98:35:98:38 | name | $@ based on library input is later used in $@. | lib/lib.js:98:35:98:38 | name | Formatted string | lib/lib.js:98:2:98:40 | cp.exec ... name)) | shell command | -| lib/lib.js:100:37:100:40 | name | lib/lib.js:97:35:97:38 | name | lib/lib.js:100:37:100:40 | name | $@ based on library input is later used in $@. | lib/lib.js:100:37:100:40 | name | Formatted string | lib/lib.js:100:2:100:42 | cp.exec ... name)) | shell command | -| lib/lib.js:102:46:102:49 | name | lib/lib.js:97:35:97:38 | name | lib/lib.js:102:46:102:49 | name | $@ based on library input is later used in $@. | lib/lib.js:102:46:102:49 | name | Formatted string | lib/lib.js:102:2:102:51 | cp.exec ... name)) | shell command | -| lib/lib.js:108:41:108:44 | name | lib/lib.js:97:35:97:38 | name | lib/lib.js:108:41:108:44 | name | $@ based on library input is later used in $@. | lib/lib.js:108:41:108:44 | name | Formatted string | lib/lib.js:108:2:108:46 | cp.exec ... name)) | shell command | -| lib/lib.js:112:10:112:25 | "rm -rf " + name | lib/lib.js:111:34:111:37 | name | lib/lib.js:112:22:112:25 | name | $@ based on library input is later used in $@. | lib/lib.js:112:10:112:25 | "rm -rf " + name | String concatenation | lib/lib.js:112:2:112:26 | cp.exec ... + name) | shell command | -| lib/lib.js:121:10:121:25 | "rm -rf " + name | lib/lib.js:120:33:120:36 | name | lib/lib.js:121:22:121:25 | name | $@ based on library input is later used in $@. | lib/lib.js:121:10:121:25 | "rm -rf " + name | String concatenation | lib/lib.js:121:2:121:26 | cp.exec ... + name) | shell command | -| lib/lib.js:131:11:131:26 | "rm -rf " + name | lib/lib.js:130:6:130:9 | name | lib/lib.js:131:23:131:26 | name | $@ based on library input is later used in $@. | lib/lib.js:131:11:131:26 | "rm -rf " + name | String concatenation | lib/lib.js:131:3:131:27 | cp.exec ... + name) | shell command | -| lib/lib.js:149:12:149:27 | "rm -rf " + name | lib/lib.js:148:37:148:40 | name | lib/lib.js:149:24:149:27 | name | $@ based on library input is later used in $@. | lib/lib.js:149:12:149:27 | "rm -rf " + name | String concatenation | lib/lib.js:152:2:152:23 | cp.spaw ... gs, cb) | shell command | -| lib/lib.js:161:13:161:28 | "rm -rf " + name | lib/lib.js:155:38:155:41 | name | lib/lib.js:161:25:161:28 | name | $@ based on library input is later used in $@. | lib/lib.js:161:13:161:28 | "rm -rf " + name | String concatenation | lib/lib.js:163:2:167:2 | cp.spaw ... t' }\\n\\t) | shell command | -| lib/lib.js:173:10:173:23 | "fo \| " + name | lib/lib.js:170:41:170:44 | name | lib/lib.js:173:20:173:23 | name | $@ based on library input is later used in $@. | lib/lib.js:173:10:173:23 | "fo \| " + name | String concatenation | lib/lib.js:173:2:173:24 | cp.exec ... + name) | shell command | -| lib/lib.js:182:10:182:27 | "rm -rf " + broken | lib/lib.js:177:38:177:41 | name | lib/lib.js:182:22:182:27 | broken | $@ based on library input is later used in $@. | lib/lib.js:182:10:182:27 | "rm -rf " + broken | String concatenation | lib/lib.js:182:2:182:28 | cp.exec ... broken) | shell command | -| lib/lib.js:187:10:187:25 | "rm -rf " + name | lib/lib.js:186:34:186:37 | name | lib/lib.js:187:22:187:25 | name | $@ based on library input is later used in $@. | lib/lib.js:187:10:187:25 | "rm -rf " + name | String concatenation | lib/lib.js:187:2:187:26 | cp.exec ... + name) | shell command | -| lib/lib.js:190:11:190:26 | "rm -rf " + name | lib/lib.js:186:34:186:37 | name | lib/lib.js:190:23:190:26 | name | $@ based on library input is later used in $@. | lib/lib.js:190:11:190:26 | "rm -rf " + name | String concatenation | lib/lib.js:190:3:190:27 | cp.exec ... + name) | shell command | -| lib/lib.js:197:10:197:25 | "rm -rf " + name | lib/lib.js:196:45:196:48 | name | lib/lib.js:197:22:197:25 | name | $@ based on library input is later used in $@. | lib/lib.js:197:10:197:25 | "rm -rf " + name | String concatenation | lib/lib.js:197:2:197:26 | cp.exec ... + name) | shell command | -| lib/lib.js:200:11:200:26 | "rm -rf " + name | lib/lib.js:196:45:196:48 | name | lib/lib.js:200:23:200:26 | name | $@ based on library input is later used in $@. | lib/lib.js:200:11:200:26 | "rm -rf " + name | String concatenation | lib/lib.js:200:3:200:27 | cp.exec ... + name) | shell command | -| lib/lib.js:207:10:207:25 | "rm -rf " + name | lib/lib.js:206:45:206:48 | name | lib/lib.js:207:22:207:25 | name | $@ based on library input is later used in $@. | lib/lib.js:207:10:207:25 | "rm -rf " + name | String concatenation | lib/lib.js:207:2:207:26 | cp.exec ... + name) | shell command | -| lib/lib.js:212:11:212:26 | "rm -rf " + name | lib/lib.js:206:45:206:48 | name | lib/lib.js:212:23:212:26 | name | $@ based on library input is later used in $@. | lib/lib.js:212:11:212:26 | "rm -rf " + name | String concatenation | lib/lib.js:212:3:212:27 | cp.exec ... + name) | shell command | -| lib/lib.js:217:10:217:25 | "rm -rf " + name | lib/lib.js:216:39:216:42 | name | lib/lib.js:217:22:217:25 | name | $@ based on library input is later used in $@. | lib/lib.js:217:10:217:25 | "rm -rf " + name | String concatenation | lib/lib.js:217:2:217:26 | cp.exec ... + name) | shell command | -| lib/lib.js:220:11:220:26 | "rm -rf " + name | lib/lib.js:216:39:216:42 | name | lib/lib.js:220:23:220:26 | name | $@ based on library input is later used in $@. | lib/lib.js:220:11:220:26 | "rm -rf " + name | String concatenation | lib/lib.js:220:3:220:27 | cp.exec ... + name) | shell command | -| lib/lib.js:224:10:224:25 | "rm -rf " + name | lib/lib.js:216:39:216:42 | name | lib/lib.js:224:22:224:25 | name | $@ based on library input is later used in $@. | lib/lib.js:224:10:224:25 | "rm -rf " + name | String concatenation | lib/lib.js:224:2:224:26 | cp.exec ... + name) | shell command | -| lib/lib.js:228:10:228:25 | "rm -rf " + name | lib/lib.js:227:39:227:42 | name | lib/lib.js:228:22:228:25 | name | $@ based on library input is later used in $@. | lib/lib.js:228:10:228:25 | "rm -rf " + name | String concatenation | lib/lib.js:228:2:228:26 | cp.exec ... + name) | shell command | -| lib/lib.js:236:10:236:25 | "rm -rf " + name | lib/lib.js:227:39:227:42 | name | lib/lib.js:236:22:236:25 | name | $@ based on library input is later used in $@. | lib/lib.js:236:10:236:25 | "rm -rf " + name | String concatenation | lib/lib.js:236:2:236:26 | cp.exec ... + name) | shell command | -| lib/lib.js:249:10:249:25 | "rm -rf " + name | lib/lib.js:248:42:248:45 | name | lib/lib.js:249:22:249:25 | name | $@ based on library input is later used in $@. | lib/lib.js:249:10:249:25 | "rm -rf " + name | String concatenation | lib/lib.js:249:2:249:26 | cp.exec ... + name) | shell command | -| lib/lib.js:258:10:258:25 | "rm -rf " + name | lib/lib.js:257:35:257:38 | name | lib/lib.js:258:22:258:25 | name | $@ based on library input is later used in $@. | lib/lib.js:258:10:258:25 | "rm -rf " + name | String concatenation | lib/lib.js:258:2:258:26 | cp.exec ... + name) | shell command | -| lib/lib.js:261:11:261:33 | "rm -rf ... + name | lib/lib.js:257:35:257:38 | name | lib/lib.js:261:30:261:33 | name | $@ based on library input is later used in $@. | lib/lib.js:261:11:261:33 | "rm -rf ... + name | String concatenation | lib/lib.js:261:3:261:34 | cp.exec ... + name) | shell command | -| lib/lib.js:268:10:268:32 | "rm -rf ... version | lib/lib.js:267:46:267:48 | obj | lib/lib.js:268:22:268:32 | obj.version | $@ based on library input is later used in $@. | lib/lib.js:268:10:268:32 | "rm -rf ... version | String concatenation | lib/lib.js:268:2:268:33 | cp.exec ... ersion) | shell command | -| lib/lib.js:277:11:277:30 | "rm -rf " + opts.bla | lib/lib.js:276:8:276:11 | opts | lib/lib.js:277:23:277:30 | opts.bla | $@ based on library input is later used in $@. | lib/lib.js:277:11:277:30 | "rm -rf " + opts.bla | String concatenation | lib/lib.js:277:3:277:31 | cp.exec ... ts.bla) | shell command | -| lib/lib.js:308:11:308:26 | "rm -rf " + name | lib/lib.js:307:39:307:42 | name | lib/lib.js:308:23:308:26 | name | $@ based on library input is later used in $@. | lib/lib.js:308:11:308:26 | "rm -rf " + name | String concatenation | lib/lib.js:308:3:308:27 | cp.exec ... + name) | shell command | -| lib/lib.js:315:10:315:25 | "rm -rf " + name | lib/lib.js:314:40:314:43 | name | lib/lib.js:315:22:315:25 | name | $@ based on library input is later used in $@. | lib/lib.js:315:10:315:25 | "rm -rf " + name | String concatenation | lib/lib.js:315:2:315:26 | cp.exec ... + name) | shell command | -| lib/lib.js:320:11:320:26 | "rm -rf " + name | lib/lib.js:314:40:314:43 | name | lib/lib.js:320:23:320:26 | name | $@ based on library input is later used in $@. | lib/lib.js:320:11:320:26 | "rm -rf " + name | String concatenation | lib/lib.js:320:3:320:27 | cp.exec ... + name) | shell command | -| lib/lib.js:325:12:325:51 | "MyWind ... " + arg | lib/lib.js:324:40:324:42 | arg | lib/lib.js:325:49:325:51 | arg | $@ based on library input is later used in $@. | lib/lib.js:325:12:325:51 | "MyWind ... " + arg | String concatenation | lib/lib.js:326:2:326:13 | cp.exec(cmd) | shell command | -| lib/lib.js:340:10:340:26 | "rm -rf " + id(n) | lib/lib.js:339:39:339:39 | n | lib/lib.js:340:22:340:26 | id(n) | $@ based on library input is later used in $@. | lib/lib.js:340:10:340:26 | "rm -rf " + id(n) | String concatenation | lib/lib.js:340:2:340:27 | cp.exec ... id(n)) | shell command | -| lib/lib.js:351:10:351:27 | "rm -rf " + unsafe | lib/lib.js:349:29:349:34 | unsafe | lib/lib.js:351:22:351:27 | unsafe | $@ based on library input is later used in $@. | lib/lib.js:351:10:351:27 | "rm -rf " + unsafe | String concatenation | lib/lib.js:351:2:351:28 | cp.exec ... unsafe) | shell command | -| lib/lib.js:366:17:366:56 | "learn ... + model | lib/lib.js:360:20:360:23 | opts | lib/lib.js:366:28:366:42 | this.learn_args | $@ based on library input is later used in $@. | lib/lib.js:366:17:366:56 | "learn ... + model | String concatenation | lib/lib.js:367:3:367:18 | cp.exec(command) | shell command | -| lib/lib.js:406:10:406:25 | "rm -rf " + name | lib/lib.js:405:39:405:42 | name | lib/lib.js:406:22:406:25 | name | $@ based on library input is later used in $@. | lib/lib.js:406:10:406:25 | "rm -rf " + name | String concatenation | lib/lib.js:406:2:406:26 | cp.exec ... + name) | shell command | +| lib/lib2.js:4:10:4:25 | "rm -rf " + name | lib/lib2.js:3:28:3:31 | name | lib/lib2.js:4:22:4:25 | name | $@ based on $@ is later used in $@. | lib/lib2.js:4:10:4:25 | "rm -rf " + name | String concatenation | lib/lib2.js:3:28:3:31 | name | library input | lib/lib2.js:4:2:4:26 | cp.exec ... + name) | shell command | +| lib/lib2.js:8:10:8:25 | "rm -rf " + name | lib/lib2.js:7:32:7:35 | name | lib/lib2.js:8:22:8:25 | name | $@ based on $@ is later used in $@. | lib/lib2.js:8:10:8:25 | "rm -rf " + name | String concatenation | lib/lib2.js:7:32:7:35 | name | library input | lib/lib2.js:8:2:8:26 | cp.exec ... + name) | shell command | +| lib/lib.js:4:10:4:25 | "rm -rf " + name | lib/lib.js:3:28:3:31 | name | lib/lib.js:4:22:4:25 | name | $@ based on $@ is later used in $@. | lib/lib.js:4:10:4:25 | "rm -rf " + name | String concatenation | lib/lib.js:3:28:3:31 | name | library input | lib/lib.js:4:2:4:26 | cp.exec ... + name) | shell command | +| lib/lib.js:11:10:11:25 | "rm -rf " + name | lib/lib.js:10:32:10:35 | name | lib/lib.js:11:22:11:25 | name | $@ based on $@ is later used in $@. | lib/lib.js:11:10:11:25 | "rm -rf " + name | String concatenation | lib/lib.js:10:32:10:35 | name | library input | lib/lib.js:11:2:11:26 | cp.exec ... + name) | shell command | +| lib/lib.js:15:10:15:25 | "rm -rf " + name | lib/lib.js:14:36:14:39 | name | lib/lib.js:15:22:15:25 | name | $@ based on $@ is later used in $@. | lib/lib.js:15:10:15:25 | "rm -rf " + name | String concatenation | lib/lib.js:14:36:14:39 | name | library input | lib/lib.js:15:2:15:26 | cp.exec ... + name) | shell command | +| lib/lib.js:20:10:20:25 | "rm -rf " + name | lib/lib.js:19:34:19:37 | name | lib/lib.js:20:22:20:25 | name | $@ based on $@ is later used in $@. | lib/lib.js:20:10:20:25 | "rm -rf " + name | String concatenation | lib/lib.js:19:34:19:37 | name | library input | lib/lib.js:20:2:20:26 | cp.exec ... + name) | shell command | +| lib/lib.js:27:10:27:25 | "rm -rf " + name | lib/lib.js:26:35:26:38 | name | lib/lib.js:27:22:27:25 | name | $@ based on $@ is later used in $@. | lib/lib.js:27:10:27:25 | "rm -rf " + name | String concatenation | lib/lib.js:26:35:26:38 | name | library input | lib/lib.js:27:2:27:26 | cp.exec ... + name) | shell command | +| lib/lib.js:35:11:35:26 | "rm -rf " + name | lib/lib.js:34:14:34:17 | name | lib/lib.js:35:23:35:26 | name | $@ based on $@ is later used in $@. | lib/lib.js:35:11:35:26 | "rm -rf " + name | String concatenation | lib/lib.js:34:14:34:17 | name | library input | lib/lib.js:35:3:35:27 | cp.exec ... + name) | shell command | +| lib/lib.js:38:11:38:26 | "rm -rf " + name | lib/lib.js:37:13:37:16 | name | lib/lib.js:38:23:38:26 | name | $@ based on $@ is later used in $@. | lib/lib.js:38:11:38:26 | "rm -rf " + name | String concatenation | lib/lib.js:37:13:37:16 | name | library input | lib/lib.js:38:3:38:27 | cp.exec ... + name) | shell command | +| lib/lib.js:41:11:41:26 | "rm -rf " + name | lib/lib.js:40:6:40:9 | name | lib/lib.js:41:23:41:26 | name | $@ based on $@ is later used in $@. | lib/lib.js:41:11:41:26 | "rm -rf " + name | String concatenation | lib/lib.js:40:6:40:9 | name | library input | lib/lib.js:41:3:41:27 | cp.exec ... + name) | shell command | +| lib/lib.js:50:35:50:50 | "rm -rf " + name | lib/lib.js:49:31:49:34 | name | lib/lib.js:50:47:50:50 | name | $@ based on $@ is later used in $@. | lib/lib.js:50:35:50:50 | "rm -rf " + name | String concatenation | lib/lib.js:49:31:49:34 | name | library input | lib/lib.js:50:2:50:51 | require ... + name) | shell command | +| lib/lib.js:54:13:54:28 | "rm -rf " + name | lib/lib.js:53:33:53:36 | name | lib/lib.js:54:25:54:28 | name | $@ based on $@ is later used in $@. | lib/lib.js:54:13:54:28 | "rm -rf " + name | String concatenation | lib/lib.js:53:33:53:36 | name | library input | lib/lib.js:55:2:55:14 | cp.exec(cmd1) | shell command | +| lib/lib.js:57:13:57:28 | "rm -rf " + name | lib/lib.js:53:33:53:36 | name | lib/lib.js:57:25:57:28 | name | $@ based on $@ is later used in $@. | lib/lib.js:57:13:57:28 | "rm -rf " + name | String concatenation | lib/lib.js:53:33:53:36 | name | library input | lib/lib.js:59:3:59:14 | cp.exec(cmd) | shell command | +| lib/lib.js:65:10:65:25 | "rm -rf " + name | lib/lib.js:64:41:64:44 | name | lib/lib.js:65:22:65:25 | name | $@ based on $@ is later used in $@. | lib/lib.js:65:10:65:25 | "rm -rf " + name | String concatenation | lib/lib.js:64:41:64:44 | name | library input | lib/lib.js:65:2:65:26 | cp.exec ... + name) | shell command | +| lib/lib.js:71:10:71:31 | "cat /f ... + name | lib/lib.js:64:41:64:44 | name | lib/lib.js:71:28:71:31 | name | $@ based on $@ is later used in $@. | lib/lib.js:71:10:71:31 | "cat /f ... + name | String concatenation | lib/lib.js:64:41:64:44 | name | library input | lib/lib.js:71:2:71:32 | cp.exec ... + name) | shell command | +| lib/lib.js:73:10:73:31 | "cat \\" ... + "\\"" | lib/lib.js:64:41:64:44 | name | lib/lib.js:73:21:73:24 | name | $@ based on $@ is later used in $@. | lib/lib.js:73:10:73:31 | "cat \\" ... + "\\"" | String concatenation | lib/lib.js:64:41:64:44 | name | library input | lib/lib.js:73:2:73:32 | cp.exec ... + "\\"") | shell command | +| lib/lib.js:75:10:75:29 | "cat '" + name + "'" | lib/lib.js:64:41:64:44 | name | lib/lib.js:75:20:75:23 | name | $@ based on $@ is later used in $@. | lib/lib.js:75:10:75:29 | "cat '" + name + "'" | String concatenation | lib/lib.js:64:41:64:44 | name | library input | lib/lib.js:75:2:75:30 | cp.exec ... + "'") | shell command | +| lib/lib.js:77:10:77:37 | "cat '/ ... e + "'" | lib/lib.js:64:41:64:44 | name | lib/lib.js:77:28:77:31 | name | $@ based on $@ is later used in $@. | lib/lib.js:77:10:77:37 | "cat '/ ... e + "'" | String concatenation | lib/lib.js:64:41:64:44 | name | library input | lib/lib.js:77:2:77:38 | cp.exec ... + "'") | shell command | +| lib/lib.js:83:10:83:25 | "rm -rf " + name | lib/lib.js:82:35:82:38 | name | lib/lib.js:83:22:83:25 | name | $@ based on $@ is later used in $@. | lib/lib.js:83:10:83:25 | "rm -rf " + name | String concatenation | lib/lib.js:82:35:82:38 | name | library input | lib/lib.js:83:2:83:26 | cp.exec ... + name) | shell command | +| lib/lib.js:86:13:86:16 | name | lib/lib.js:82:35:82:38 | name | lib/lib.js:86:13:86:16 | name | $@ based on $@ is later used in $@. | lib/lib.js:86:13:86:16 | name | Array element | lib/lib.js:82:35:82:38 | name | library input | lib/lib.js:87:2:87:25 | cp.exec ... n(" ")) | shell command | +| lib/lib.js:89:21:89:24 | name | lib/lib.js:82:35:82:38 | name | lib/lib.js:89:21:89:24 | name | $@ based on $@ is later used in $@. | lib/lib.js:89:21:89:24 | name | Array element | lib/lib.js:82:35:82:38 | name | library input | lib/lib.js:89:2:89:36 | cp.exec ... n(" ")) | shell command | +| lib/lib.js:91:21:91:38 | "\\"" + name + "\\"" | lib/lib.js:82:35:82:38 | name | lib/lib.js:91:21:91:38 | "\\"" + name + "\\"" | $@ based on $@ is later used in $@. | lib/lib.js:91:21:91:38 | "\\"" + name + "\\"" | Array element | lib/lib.js:82:35:82:38 | name | library input | lib/lib.js:91:2:91:50 | cp.exec ... n(" ")) | shell command | +| lib/lib.js:98:35:98:38 | name | lib/lib.js:97:35:97:38 | name | lib/lib.js:98:35:98:38 | name | $@ based on $@ is later used in $@. | lib/lib.js:98:35:98:38 | name | Formatted string | lib/lib.js:97:35:97:38 | name | library input | lib/lib.js:98:2:98:40 | cp.exec ... name)) | shell command | +| lib/lib.js:100:37:100:40 | name | lib/lib.js:97:35:97:38 | name | lib/lib.js:100:37:100:40 | name | $@ based on $@ is later used in $@. | lib/lib.js:100:37:100:40 | name | Formatted string | lib/lib.js:97:35:97:38 | name | library input | lib/lib.js:100:2:100:42 | cp.exec ... name)) | shell command | +| lib/lib.js:102:46:102:49 | name | lib/lib.js:97:35:97:38 | name | lib/lib.js:102:46:102:49 | name | $@ based on $@ is later used in $@. | lib/lib.js:102:46:102:49 | name | Formatted string | lib/lib.js:97:35:97:38 | name | library input | lib/lib.js:102:2:102:51 | cp.exec ... name)) | shell command | +| lib/lib.js:108:41:108:44 | name | lib/lib.js:97:35:97:38 | name | lib/lib.js:108:41:108:44 | name | $@ based on $@ is later used in $@. | lib/lib.js:108:41:108:44 | name | Formatted string | lib/lib.js:97:35:97:38 | name | library input | lib/lib.js:108:2:108:46 | cp.exec ... name)) | shell command | +| lib/lib.js:112:10:112:25 | "rm -rf " + name | lib/lib.js:111:34:111:37 | name | lib/lib.js:112:22:112:25 | name | $@ based on $@ is later used in $@. | lib/lib.js:112:10:112:25 | "rm -rf " + name | String concatenation | lib/lib.js:111:34:111:37 | name | library input | lib/lib.js:112:2:112:26 | cp.exec ... + name) | shell command | +| lib/lib.js:121:10:121:25 | "rm -rf " + name | lib/lib.js:120:33:120:36 | name | lib/lib.js:121:22:121:25 | name | $@ based on $@ is later used in $@. | lib/lib.js:121:10:121:25 | "rm -rf " + name | String concatenation | lib/lib.js:120:33:120:36 | name | library input | lib/lib.js:121:2:121:26 | cp.exec ... + name) | shell command | +| lib/lib.js:131:11:131:26 | "rm -rf " + name | lib/lib.js:130:6:130:9 | name | lib/lib.js:131:23:131:26 | name | $@ based on $@ is later used in $@. | lib/lib.js:131:11:131:26 | "rm -rf " + name | String concatenation | lib/lib.js:130:6:130:9 | name | library input | lib/lib.js:131:3:131:27 | cp.exec ... + name) | shell command | +| lib/lib.js:149:12:149:27 | "rm -rf " + name | lib/lib.js:148:37:148:40 | name | lib/lib.js:149:24:149:27 | name | $@ based on $@ is later used in $@. | lib/lib.js:149:12:149:27 | "rm -rf " + name | String concatenation | lib/lib.js:148:37:148:40 | name | library input | lib/lib.js:152:2:152:23 | cp.spaw ... gs, cb) | shell command | +| lib/lib.js:161:13:161:28 | "rm -rf " + name | lib/lib.js:155:38:155:41 | name | lib/lib.js:161:25:161:28 | name | $@ based on $@ is later used in $@. | lib/lib.js:161:13:161:28 | "rm -rf " + name | String concatenation | lib/lib.js:155:38:155:41 | name | library input | lib/lib.js:163:2:167:2 | cp.spaw ... t' }\\n\\t) | shell command | +| lib/lib.js:173:10:173:23 | "fo \| " + name | lib/lib.js:170:41:170:44 | name | lib/lib.js:173:20:173:23 | name | $@ based on $@ is later used in $@. | lib/lib.js:173:10:173:23 | "fo \| " + name | String concatenation | lib/lib.js:170:41:170:44 | name | library input | lib/lib.js:173:2:173:24 | cp.exec ... + name) | shell command | +| lib/lib.js:182:10:182:27 | "rm -rf " + broken | lib/lib.js:177:38:177:41 | name | lib/lib.js:182:22:182:27 | broken | $@ based on $@ is later used in $@. | lib/lib.js:182:10:182:27 | "rm -rf " + broken | String concatenation | lib/lib.js:177:38:177:41 | name | library input | lib/lib.js:182:2:182:28 | cp.exec ... broken) | shell command | +| lib/lib.js:187:10:187:25 | "rm -rf " + name | lib/lib.js:186:34:186:37 | name | lib/lib.js:187:22:187:25 | name | $@ based on $@ is later used in $@. | lib/lib.js:187:10:187:25 | "rm -rf " + name | String concatenation | lib/lib.js:186:34:186:37 | name | library input | lib/lib.js:187:2:187:26 | cp.exec ... + name) | shell command | +| lib/lib.js:190:11:190:26 | "rm -rf " + name | lib/lib.js:186:34:186:37 | name | lib/lib.js:190:23:190:26 | name | $@ based on $@ is later used in $@. | lib/lib.js:190:11:190:26 | "rm -rf " + name | String concatenation | lib/lib.js:186:34:186:37 | name | library input | lib/lib.js:190:3:190:27 | cp.exec ... + name) | shell command | +| lib/lib.js:197:10:197:25 | "rm -rf " + name | lib/lib.js:196:45:196:48 | name | lib/lib.js:197:22:197:25 | name | $@ based on $@ is later used in $@. | lib/lib.js:197:10:197:25 | "rm -rf " + name | String concatenation | lib/lib.js:196:45:196:48 | name | library input | lib/lib.js:197:2:197:26 | cp.exec ... + name) | shell command | +| lib/lib.js:200:11:200:26 | "rm -rf " + name | lib/lib.js:196:45:196:48 | name | lib/lib.js:200:23:200:26 | name | $@ based on $@ is later used in $@. | lib/lib.js:200:11:200:26 | "rm -rf " + name | String concatenation | lib/lib.js:196:45:196:48 | name | library input | lib/lib.js:200:3:200:27 | cp.exec ... + name) | shell command | +| lib/lib.js:207:10:207:25 | "rm -rf " + name | lib/lib.js:206:45:206:48 | name | lib/lib.js:207:22:207:25 | name | $@ based on $@ is later used in $@. | lib/lib.js:207:10:207:25 | "rm -rf " + name | String concatenation | lib/lib.js:206:45:206:48 | name | library input | lib/lib.js:207:2:207:26 | cp.exec ... + name) | shell command | +| lib/lib.js:212:11:212:26 | "rm -rf " + name | lib/lib.js:206:45:206:48 | name | lib/lib.js:212:23:212:26 | name | $@ based on $@ is later used in $@. | lib/lib.js:212:11:212:26 | "rm -rf " + name | String concatenation | lib/lib.js:206:45:206:48 | name | library input | lib/lib.js:212:3:212:27 | cp.exec ... + name) | shell command | +| lib/lib.js:217:10:217:25 | "rm -rf " + name | lib/lib.js:216:39:216:42 | name | lib/lib.js:217:22:217:25 | name | $@ based on $@ is later used in $@. | lib/lib.js:217:10:217:25 | "rm -rf " + name | String concatenation | lib/lib.js:216:39:216:42 | name | library input | lib/lib.js:217:2:217:26 | cp.exec ... + name) | shell command | +| lib/lib.js:220:11:220:26 | "rm -rf " + name | lib/lib.js:216:39:216:42 | name | lib/lib.js:220:23:220:26 | name | $@ based on $@ is later used in $@. | lib/lib.js:220:11:220:26 | "rm -rf " + name | String concatenation | lib/lib.js:216:39:216:42 | name | library input | lib/lib.js:220:3:220:27 | cp.exec ... + name) | shell command | +| lib/lib.js:224:10:224:25 | "rm -rf " + name | lib/lib.js:216:39:216:42 | name | lib/lib.js:224:22:224:25 | name | $@ based on $@ is later used in $@. | lib/lib.js:224:10:224:25 | "rm -rf " + name | String concatenation | lib/lib.js:216:39:216:42 | name | library input | lib/lib.js:224:2:224:26 | cp.exec ... + name) | shell command | +| lib/lib.js:228:10:228:25 | "rm -rf " + name | lib/lib.js:227:39:227:42 | name | lib/lib.js:228:22:228:25 | name | $@ based on $@ is later used in $@. | lib/lib.js:228:10:228:25 | "rm -rf " + name | String concatenation | lib/lib.js:227:39:227:42 | name | library input | lib/lib.js:228:2:228:26 | cp.exec ... + name) | shell command | +| lib/lib.js:236:10:236:25 | "rm -rf " + name | lib/lib.js:227:39:227:42 | name | lib/lib.js:236:22:236:25 | name | $@ based on $@ is later used in $@. | lib/lib.js:236:10:236:25 | "rm -rf " + name | String concatenation | lib/lib.js:227:39:227:42 | name | library input | lib/lib.js:236:2:236:26 | cp.exec ... + name) | shell command | +| lib/lib.js:249:10:249:25 | "rm -rf " + name | lib/lib.js:248:42:248:45 | name | lib/lib.js:249:22:249:25 | name | $@ based on $@ is later used in $@. | lib/lib.js:249:10:249:25 | "rm -rf " + name | String concatenation | lib/lib.js:248:42:248:45 | name | library input | lib/lib.js:249:2:249:26 | cp.exec ... + name) | shell command | +| lib/lib.js:258:10:258:25 | "rm -rf " + name | lib/lib.js:257:35:257:38 | name | lib/lib.js:258:22:258:25 | name | $@ based on $@ is later used in $@. | lib/lib.js:258:10:258:25 | "rm -rf " + name | String concatenation | lib/lib.js:257:35:257:38 | name | library input | lib/lib.js:258:2:258:26 | cp.exec ... + name) | shell command | +| lib/lib.js:261:11:261:33 | "rm -rf ... + name | lib/lib.js:257:35:257:38 | name | lib/lib.js:261:30:261:33 | name | $@ based on $@ is later used in $@. | lib/lib.js:261:11:261:33 | "rm -rf ... + name | String concatenation | lib/lib.js:257:35:257:38 | name | library input | lib/lib.js:261:3:261:34 | cp.exec ... + name) | shell command | +| lib/lib.js:268:10:268:32 | "rm -rf ... version | lib/lib.js:267:46:267:48 | obj | lib/lib.js:268:22:268:32 | obj.version | $@ based on $@ is later used in $@. | lib/lib.js:268:10:268:32 | "rm -rf ... version | String concatenation | lib/lib.js:267:46:267:48 | obj | library input | lib/lib.js:268:2:268:33 | cp.exec ... ersion) | shell command | +| lib/lib.js:277:11:277:30 | "rm -rf " + opts.bla | lib/lib.js:276:8:276:11 | opts | lib/lib.js:277:23:277:30 | opts.bla | $@ based on $@ is later used in $@. | lib/lib.js:277:11:277:30 | "rm -rf " + opts.bla | String concatenation | lib/lib.js:276:8:276:11 | opts | library input | lib/lib.js:277:3:277:31 | cp.exec ... ts.bla) | shell command | +| lib/lib.js:308:11:308:26 | "rm -rf " + name | lib/lib.js:307:39:307:42 | name | lib/lib.js:308:23:308:26 | name | $@ based on $@ is later used in $@. | lib/lib.js:308:11:308:26 | "rm -rf " + name | String concatenation | lib/lib.js:307:39:307:42 | name | library input | lib/lib.js:308:3:308:27 | cp.exec ... + name) | shell command | +| lib/lib.js:315:10:315:25 | "rm -rf " + name | lib/lib.js:314:40:314:43 | name | lib/lib.js:315:22:315:25 | name | $@ based on $@ is later used in $@. | lib/lib.js:315:10:315:25 | "rm -rf " + name | String concatenation | lib/lib.js:314:40:314:43 | name | library input | lib/lib.js:315:2:315:26 | cp.exec ... + name) | shell command | +| lib/lib.js:320:11:320:26 | "rm -rf " + name | lib/lib.js:314:40:314:43 | name | lib/lib.js:320:23:320:26 | name | $@ based on $@ is later used in $@. | lib/lib.js:320:11:320:26 | "rm -rf " + name | String concatenation | lib/lib.js:314:40:314:43 | name | library input | lib/lib.js:320:3:320:27 | cp.exec ... + name) | shell command | +| lib/lib.js:325:12:325:51 | "MyWind ... " + arg | lib/lib.js:324:40:324:42 | arg | lib/lib.js:325:49:325:51 | arg | $@ based on $@ is later used in $@. | lib/lib.js:325:12:325:51 | "MyWind ... " + arg | String concatenation | lib/lib.js:324:40:324:42 | arg | library input | lib/lib.js:326:2:326:13 | cp.exec(cmd) | shell command | +| lib/lib.js:340:10:340:26 | "rm -rf " + id(n) | lib/lib.js:339:39:339:39 | n | lib/lib.js:340:22:340:26 | id(n) | $@ based on $@ is later used in $@. | lib/lib.js:340:10:340:26 | "rm -rf " + id(n) | String concatenation | lib/lib.js:339:39:339:39 | n | library input | lib/lib.js:340:2:340:27 | cp.exec ... id(n)) | shell command | +| lib/lib.js:351:10:351:27 | "rm -rf " + unsafe | lib/lib.js:349:29:349:34 | unsafe | lib/lib.js:351:22:351:27 | unsafe | $@ based on $@ is later used in $@. | lib/lib.js:351:10:351:27 | "rm -rf " + unsafe | String concatenation | lib/lib.js:349:29:349:34 | unsafe | library input | lib/lib.js:351:2:351:28 | cp.exec ... unsafe) | shell command | +| lib/lib.js:366:17:366:56 | "learn ... + model | lib/lib.js:360:20:360:23 | opts | lib/lib.js:366:28:366:42 | this.learn_args | $@ based on $@ is later used in $@. | lib/lib.js:366:17:366:56 | "learn ... + model | String concatenation | lib/lib.js:360:20:360:23 | opts | library input | lib/lib.js:367:3:367:18 | cp.exec(command) | shell command | +| lib/lib.js:406:10:406:25 | "rm -rf " + name | lib/lib.js:405:39:405:42 | name | lib/lib.js:406:22:406:25 | name | $@ based on $@ is later used in $@. | lib/lib.js:406:10:406:25 | "rm -rf " + name | String concatenation | lib/lib.js:405:39:405:42 | name | library input | lib/lib.js:406:2:406:26 | cp.exec ... + name) | shell command | +| lib/subLib/index.js:4:10:4:25 | "rm -rf " + name | lib/subLib/index.js:3:28:3:31 | name | lib/subLib/index.js:4:22:4:25 | name | $@ based on $@ is later used in $@. | lib/subLib/index.js:4:10:4:25 | "rm -rf " + name | String concatenation | lib/subLib/index.js:3:28:3:31 | name | library input | lib/subLib/index.js:4:2:4:26 | cp.exec ... + name) | shell command | +| lib/subLib/index.js:8:10:8:25 | "rm -rf " + name | lib/subLib/index.js:7:32:7:35 | name | lib/subLib/index.js:8:22:8:25 | name | $@ based on $@ is later used in $@. | lib/subLib/index.js:8:10:8:25 | "rm -rf " + name | String concatenation | lib/subLib/index.js:7:32:7:35 | name | library input | lib/subLib/index.js:8:2:8:26 | cp.exec ... + name) | shell command | diff --git a/javascript/ql/test/query-tests/Security/CWE-078/lib/subLib/index.js b/javascript/ql/test/query-tests/Security/CWE-078/lib/subLib/index.js index c101df07d02..325a652c9b5 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/lib/subLib/index.js +++ b/javascript/ql/test/query-tests/Security/CWE-078/lib/subLib/index.js @@ -1,7 +1,7 @@ var cp = require("child_process") module.exports = function (name) { - cp.exec("rm -rf " + name); // OK - this file belongs in a sub-"module", and is not the primary exported module. + cp.exec("rm -rf " + name); // NOT OK - functions exported as part of a submodule are also flagged. }; module.exports.foo = function (name) { From 0e98ea0c1034c9338dbd5d4434b5b31744c20fb1 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 18 Mar 2021 14:09:08 +0100 Subject: [PATCH 177/725] remove spurious import of PackageExports --- javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll | 2 -- 1 file changed, 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll index d05c2194c94..9894dd119df 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll @@ -646,8 +646,6 @@ module NodeJSLib { } } - private import semmle.javascript.PackageExports as Exports - /** * A direct step from an named export to a property-read reading the exported value. */ From 38a9c71380e952e81ccde62e339e8f54ef412cda Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 18 Mar 2021 14:30:10 +0100 Subject: [PATCH 178/725] Apply suggestions from code review Co-authored-by: Asger F --- .../ql/src/semmle/javascript/frameworks/Koa.qll | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Koa.qll b/javascript/ql/src/semmle/javascript/frameworks/Koa.qll index 112203cb26d..4372a7480ba 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Koa.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Koa.qll @@ -72,9 +72,9 @@ module Koa { } /** - * Gets the dataflow node that is given to a `RouteSetup` to register the handler. + * Gets a dataflow node that can be given to a `RouteSetup` to register the handler. */ - abstract DataFlow::SourceNode getRouteHandlerRegistration(); + abstract DataFlow::SourceNode getARouteHandlerRegistrationObject(); } /** @@ -91,7 +91,7 @@ module Koa { private class StandardRouteHandler extends RouteHandler { StandardRouteHandler() { any(RouteSetup setup).getARouteHandler() = this } - override DataFlow::SourceNode getRouteHandlerRegistration() { result = this } + override DataFlow::SourceNode getARouteHandlerRegistrationObject() { result = this } } /** @@ -136,7 +136,7 @@ module Koa { * app.use(router.routes()); * ``` */ - private class RoutedRouteHandler extends RouteHandler, DataFlow::SourceNode { + private class RoutedRouteHandler extends RouteHandler { DataFlow::InvokeNode router; DataFlow::MethodCallNode call; @@ -151,7 +151,7 @@ module Koa { this.flowsTo(call.getArgument(any(int i | i >= 1))) } - override DataFlow::SourceNode getRouteHandlerRegistration() { + override DataFlow::SourceNode getARouteHandlerRegistrationObject() { result = call or result = router.getAMethodCall("routes") @@ -171,7 +171,7 @@ module Koa { * // route handler stuff * })); */ - class KoaRouteHandler extends RouteHandler, DataFlow::SourceNode { + class KoaRouteHandler extends RouteHandler { DataFlow::CallNode call; KoaRouteHandler() { @@ -190,7 +190,7 @@ module Koa { result = call.getABoundCallbackParameter(1, any(int i | i >= 1)) } - override DataFlow::SourceNode getRouteHandlerRegistration() { result = call } + override DataFlow::SourceNode getARouteHandlerRegistrationObject() { result = call } } /** @@ -390,7 +390,7 @@ module Koa { result.flowsToExpr(getArgument(0)) or // For the route-handlers that does not depend on this predicate in their charpred. - result.(RouteHandler).getRouteHandlerRegistration().flowsToExpr(getArgument(0)) + result.(RouteHandler).getARouteHandlerRegistrationObject().flowsToExpr(getArgument(0)) } override Expr getServer() { result = server } From f94f82a0dc442a96165a5b38b5c975e84f502c7a Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 18 Mar 2021 14:35:10 +0100 Subject: [PATCH 179/725] use getAChainedMethodCall --- .../ql/src/semmle/javascript/frameworks/Koa.qll | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Koa.qll b/javascript/ql/src/semmle/javascript/frameworks/Koa.qll index 4372a7480ba..59d256cdba2 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Koa.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Koa.qll @@ -142,12 +142,12 @@ module Koa { RoutedRouteHandler() { router = DataFlow::moduleImport(["@koa/router", "koa-router"]).getAnInvocation() and - call = router.getAMethodCall*() and - call.getMethodName() = - [ - "use", "get", "post", "put", "link", "unlink", "delete", "del", "head", "options", - "patch", "all" - ] and + call = + router + .getAChainedMethodCall([ + "use", "get", "post", "put", "link", "unlink", "delete", "del", "head", "options", + "patch", "all" + ]) and this.flowsTo(call.getArgument(any(int i | i >= 1))) } From af5a61782cbaf151c3328faffded5cc36e183483 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 18 Mar 2021 14:51:11 +0100 Subject: [PATCH 180/725] also look for main modules in a `lib` folder --- .../ql/src/semmle/javascript/NodeModuleResolutionImpl.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/NodeModuleResolutionImpl.qll b/javascript/ql/src/semmle/javascript/NodeModuleResolutionImpl.qll index 60ccf7216c9..84538e9925a 100644 --- a/javascript/ql/src/semmle/javascript/NodeModuleResolutionImpl.qll +++ b/javascript/ql/src/semmle/javascript/NodeModuleResolutionImpl.qll @@ -98,7 +98,7 @@ File resolveMainModule(PackageJSON pkg, int priority) { or exists(Folder folder | folder = pkg.getFile().getParentContainer() | result = - tryExtensions([folder, folder.getChildContainer("src")], "index", + tryExtensions([folder, folder.getChildContainer(["src", "lib"])], "index", priority - prioritiesPerCandidate()) ) } From 7180a1ed5253a8a7368a1abc03af261764500576 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 18 Mar 2021 15:16:31 +0100 Subject: [PATCH 181/725] add `Type` to `MkHasUnderlyingType` --- javascript/ql/src/semmle/javascript/ApiGraphs.qll | 2 ++ 1 file changed, 2 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/ApiGraphs.qll b/javascript/ql/src/semmle/javascript/ApiGraphs.qll index 1ab8234cb78..d9d4d0e80fa 100644 --- a/javascript/ql/src/semmle/javascript/ApiGraphs.qll +++ b/javascript/ql/src/semmle/javascript/ApiGraphs.qll @@ -423,6 +423,8 @@ module API { */ MkHasUnderlyingType(string moduleName, string exportName) { any(TypeAnnotation n).hasQualifiedName(moduleName, exportName) + or + any(Type t).hasUnderlyingType(moduleName, exportName) } or MkSyntheticCallbackArg(DataFlow::Node src, int bound, DataFlow::InvokeNode nd) { trackUseNode(src, true, bound).flowsTo(nd.getCalleeNode()) From ed8e0fb593143677c6ab2a0440fe1c5a5eb35d11 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 18 Mar 2021 15:34:17 +0100 Subject: [PATCH 182/725] remove CannonicalName API nodes --- .../ql/src/semmle/javascript/ApiGraphs.qll | 74 +------------------ 1 file changed, 2 insertions(+), 72 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/ApiGraphs.qll b/javascript/ql/src/semmle/javascript/ApiGraphs.qll index d9d4d0e80fa..5b3e2ed5f09 100644 --- a/javascript/ql/src/semmle/javascript/ApiGraphs.qll +++ b/javascript/ql/src/semmle/javascript/ApiGraphs.qll @@ -313,11 +313,6 @@ module API { module Node { /** Gets a node whose type has the given qualified name. */ Node ofType(string moduleName, string exportedName) { - exists(TypeName tn | - tn.hasQualifiedName(moduleName, exportedName) and - result = Impl::MkCanonicalNameUse(tn).(Node).getInstance() - ) - or result = Impl::MkHasUnderlyingType(moduleName, exportedName).(Node).getInstance() } } @@ -395,28 +390,6 @@ module API { } or MkDef(DataFlow::Node nd) { rhs(_, _, nd) } or MkUse(DataFlow::Node nd) { use(_, _, nd) } or - /** - * A TypeScript canonical name that is defined somewhere, and that isn't a module root. - * (Module roots are represented by `MkModuleExport` nodes instead.) - * - * For most purposes, you probably want to use the `mkCanonicalNameDef` predicate instead of - * this constructor. - */ - MkCanonicalNameDef(CanonicalName n) { - not n.isRoot() and - isDefined(n) - } or - /** - * A TypeScript canonical name that is used somewhere, and that isn't a module root. - * (Module roots are represented by `MkModuleImport` nodes instead.) - * - * For most purposes, you probably want to use the `mkCanonicalNameUse` predicate instead of - * this constructor. - */ - MkCanonicalNameUse(CanonicalName n) { - not n.isRoot() and - isUsed(n) - } or /** * A TypeScript type, identified by name of the type-annotation. * This API node is exclusively used by `API::Node::ofType`. @@ -433,11 +406,9 @@ module API { class TDef = MkModuleDef or TNonModuleDef; class TNonModuleDef = - MkModuleExport or MkClassInstance or MkAsyncFuncResult or MkDef or MkCanonicalNameDef or - MkSyntheticCallbackArg; + MkModuleExport or MkClassInstance or MkAsyncFuncResult or MkDef or MkSyntheticCallbackArg; - class TUse = - MkModuleUse or MkModuleImport or MkUse or MkCanonicalNameUse or MkHasUnderlyingType; + class TUse = MkModuleUse or MkModuleImport or MkUse or MkHasUnderlyingType; private predicate hasSemantics(DataFlow::Node nd) { not nd.getTopLevel().isExterns() } @@ -474,20 +445,6 @@ module API { ) } - /** An API-graph node representing definitions of the canonical name `cn`. */ - private TApiNode mkCanonicalNameDef(CanonicalName cn) { - if cn.isModuleRoot() - then result = MkModuleExport(cn.getExternalModuleName()) - else result = MkCanonicalNameDef(cn) - } - - /** An API-graph node representing uses of the canonical name `cn`. */ - private TApiNode mkCanonicalNameUse(CanonicalName cn) { - if cn.isModuleRoot() - then result = MkModuleImport(cn.getExternalModuleName()) - else result = MkCanonicalNameUse(cn) - } - /** * Holds if `rhs` is the right-hand side of a definition of a node that should have an * incoming edge from `base` labeled `lbl` in the API graph. @@ -591,11 +548,6 @@ module API { exists(string m | nd = MkModuleExport(m) | exports(m, rhs)) or nd = MkDef(rhs) - or - exists(CanonicalName n | nd = MkCanonicalNameDef(n) | - rhs = n.(Namespace).getADefinition().flow() or - rhs = n.(CanonicalFunctionName).getADefinition().flow() - ) } /** @@ -647,12 +599,6 @@ module API { ref = cls.getConstructor().getParameter(i) ) or - exists(TypeName tn | - base = MkCanonicalNameUse(tn) and - lbl = Label::instance() and - ref = getANodeWithType(tn) - ) - or exists(string moduleName, string exportName | base = MkHasUnderlyingType(moduleName, exportName) and lbl = Label::instance() and @@ -696,8 +642,6 @@ module API { ) or nd = MkUse(ref) - or - exists(CanonicalName n | nd = MkCanonicalNameUse(n) | ref.asExpr() = n.getAnAccess()) } /** Holds if module `m` exports `rhs`. */ @@ -852,13 +796,6 @@ module API { result = awaited(call, DataFlow::TypeTracker::end()) } - private DataFlow::SourceNode getANodeWithType(TypeName tn) { - exists(string moduleName, string typeName | - tn.hasQualifiedName(moduleName, typeName) and - result.hasUnderlyingType(moduleName, typeName) - ) - } - /** * Holds if there is an edge from `pred` to `succ` in the API graph that is labeled with `lbl`. */ @@ -899,13 +836,6 @@ module API { succ = MkClassInstance(trackDefNode(def)) ) or - exists(CanonicalName cn1, string n, CanonicalName cn2 | - pred in [mkCanonicalNameDef(cn1), mkCanonicalNameUse(cn1)] and - cn2 = cn1.getChild(n) and - lbl = Label::member(n) and - succ in [mkCanonicalNameDef(cn2), mkCanonicalNameUse(cn2)] - ) - or exists(string moduleName, string exportName | pred = MkModuleImport(moduleName) and lbl = Label::member(exportName) and From 58617c5c59f495cd6031204d2c4d0baf872494d8 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 17 Mar 2021 19:44:24 +0100 Subject: [PATCH 183/725] recognize client websockets as ClientRequests --- .../javascript/frameworks/WebSocket.qll | 22 ++++++++++++++++++- .../ClientRequests/ClientRequests.expected | 4 ++++ .../frameworks/ClientRequests/tst.js | 12 +++++++++- .../Security/CWE-918/RequestForgery.expected | 16 ++++++++++++++ .../test/query-tests/Security/CWE-918/tst.js | 7 ++++++ 5 files changed, 59 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/WebSocket.qll b/javascript/ql/src/semmle/javascript/frameworks/WebSocket.qll index 8d4cb9b7126..fc3f1135d06 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/WebSocket.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/WebSocket.qll @@ -81,7 +81,7 @@ module ClientWebSocket { /** * A client WebSocket instance. */ - class ClientSocket extends EventEmitter::Range, DataFlow::SourceNode { + class ClientSocket extends EventEmitter::Range, DataFlow::NewNode, ClientRequest::Range { SocketClass socketClass; ClientSocket() { this = socketClass.getAnInstantiation() } @@ -90,6 +90,26 @@ module ClientWebSocket { * Gets the WebSocket library name. */ LibraryName getLibrary() { result = socketClass.getLibrary() } + + override DataFlow::Node getUrl() { result = getArgument(0) } + + override DataFlow::Node getHost() { none() } + + override DataFlow::Node getADataNode() { + exists(SendNode send | + send.getEmitter() = this and + result = send.getSentItem(_) + ) + } + + override DataFlow::Node getAResponseDataNode(string responseType, boolean promise) { + responseType = "json" and + promise = false and + exists(WebSocketReceiveNode receiver | + receiver.getEmitter() = this and + result = receiver.getReceivedItem(_) + ) + } } /** diff --git a/javascript/ql/test/library-tests/frameworks/ClientRequests/ClientRequests.expected b/javascript/ql/test/library-tests/frameworks/ClientRequests/ClientRequests.expected index 2bf2d305cb0..2ee9976ce3b 100644 --- a/javascript/ql/test/library-tests/frameworks/ClientRequests/ClientRequests.expected +++ b/javascript/ql/test/library-tests/frameworks/ClientRequests/ClientRequests.expected @@ -83,6 +83,7 @@ test_ClientRequest | tst.js:269:13:269:48 | httpPro ... ptions) | | tst.js:271:3:271:61 | proxy.w ... 080' }) | | tst.js:274:1:283:2 | httpPro ... true\\n}) | +| tst.js:286:20:286:55 | new Web ... :8080') | test_getADataNode | tst.js:53:5:53:23 | axios({data: data}) | tst.js:53:18:53:21 | data | | tst.js:57:5:57:39 | axios.p ... data2}) | tst.js:57:19:57:23 | data1 | @@ -121,6 +122,7 @@ test_getADataNode | tst.js:249:1:251:2 | form.su ... e();\\n}) | tst.js:246:26:246:43 | Buffer.from("foo") | | tst.js:249:1:251:2 | form.su ... e();\\n}) | tst.js:247:24:247:68 | request ... o.png') | | tst.js:257:1:262:2 | form.su ... rs()\\n}) | tst.js:255:25:255:35 | 'new_value' | +| tst.js:286:20:286:55 | new Web ... :8080') | tst.js:288:21:288:35 | 'Hello Server!' | test_getHost | tst.js:87:5:87:39 | http.ge ... host}) | tst.js:87:34:87:37 | host | | tst.js:89:5:89:23 | axios({host: host}) | tst.js:89:18:89:21 | host | @@ -218,6 +220,7 @@ test_getUrl | tst.js:267:1:267:61 | httpPro ... 9000'}) | tst.js:267:37:267:59 | 'http:/ ... t:9000' | | tst.js:271:3:271:61 | proxy.w ... 080' }) | tst.js:271:33:271:58 | 'http:/ ... m:8080' | | tst.js:274:1:283:2 | httpPro ... true\\n}) | tst.js:275:13:281:5 | {\\n ... ,\\n } | +| tst.js:286:20:286:55 | new Web ... :8080') | tst.js:286:34:286:54 | 'ws://l ... t:8080' | test_getAResponseDataNode | tst.js:19:5:19:23 | requestPromise(url) | tst.js:19:5:19:23 | requestPromise(url) | text | true | | tst.js:21:5:21:23 | superagent.get(url) | tst.js:21:5:21:23 | superagent.get(url) | stream | true | @@ -284,3 +287,4 @@ test_getAResponseDataNode | tst.js:231:5:233:6 | needle. ... \\n }) | tst.js:231:50:231:53 | body | json | false | | tst.js:235:5:237:6 | needle. ... \\n }) | tst.js:235:67:235:70 | resp | fetch.response | false | | tst.js:235:5:237:6 | needle. ... \\n }) | tst.js:235:73:235:76 | body | json | false | +| tst.js:286:20:286:55 | new Web ... :8080') | tst.js:291:44:291:53 | event.data | json | false | diff --git a/javascript/ql/test/library-tests/frameworks/ClientRequests/tst.js b/javascript/ql/test/library-tests/frameworks/ClientRequests/tst.js index 4003fd1b0a3..bc15565c072 100644 --- a/javascript/ql/test/library-tests/frameworks/ClientRequests/tst.js +++ b/javascript/ql/test/library-tests/frameworks/ClientRequests/tst.js @@ -280,4 +280,14 @@ httpProxy.createProxyServer({ passphrase: 'password', }, changeOrigin: true -}).listen(8000); \ No newline at end of file +}).listen(8000); + +function webSocket() { + const socket = new WebSocket('ws://localhost:8080'); + socket.addEventListener('open', function (event) { + socket.send('Hello Server!'); + }); + socket.addEventListener('message', function (event) { + console.log("Data from server: " + event.data); + }); +} \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Security/CWE-918/RequestForgery.expected b/javascript/ql/test/query-tests/Security/CWE-918/RequestForgery.expected index 06a55b512a0..4e24efd2a5d 100644 --- a/javascript/ql/test/query-tests/Security/CWE-918/RequestForgery.expected +++ b/javascript/ql/test/query-tests/Security/CWE-918/RequestForgery.expected @@ -57,6 +57,14 @@ nodes | tst.js:74:29:74:35 | req.url | | tst.js:76:19:76:25 | tainted | | tst.js:76:19:76:25 | tainted | +| tst.js:81:9:81:52 | tainted | +| tst.js:81:19:81:42 | url.par ... , true) | +| tst.js:81:19:81:48 | url.par ... ).query | +| tst.js:81:19:81:52 | url.par ... ery.url | +| tst.js:81:29:81:35 | req.url | +| tst.js:81:29:81:35 | req.url | +| tst.js:83:19:83:25 | tainted | +| tst.js:83:19:83:25 | tainted | edges | tst.js:14:9:14:52 | tainted | tst.js:18:13:18:19 | tainted | | tst.js:14:9:14:52 | tainted | tst.js:18:13:18:19 | tainted | @@ -113,6 +121,13 @@ edges | tst.js:74:19:74:52 | url.par ... ery.url | tst.js:74:9:74:52 | tainted | | tst.js:74:29:74:35 | req.url | tst.js:74:19:74:42 | url.par ... , true) | | tst.js:74:29:74:35 | req.url | tst.js:74:19:74:42 | url.par ... , true) | +| tst.js:81:9:81:52 | tainted | tst.js:83:19:83:25 | tainted | +| tst.js:81:9:81:52 | tainted | tst.js:83:19:83:25 | tainted | +| tst.js:81:19:81:42 | url.par ... , true) | tst.js:81:19:81:48 | url.par ... ).query | +| tst.js:81:19:81:48 | url.par ... ).query | tst.js:81:19:81:52 | url.par ... ery.url | +| tst.js:81:19:81:52 | url.par ... ery.url | tst.js:81:9:81:52 | tainted | +| tst.js:81:29:81:35 | req.url | tst.js:81:19:81:42 | url.par ... , true) | +| tst.js:81:29:81:35 | req.url | tst.js:81:19:81:42 | url.par ... , true) | #select | tst.js:18:5:18:20 | request(tainted) | tst.js:14:29:14:35 | req.url | tst.js:18:13:18:19 | tainted | The $@ of this request depends on $@. | tst.js:18:13:18:19 | tainted | URL | tst.js:14:29:14:35 | req.url | a user-provided value | | tst.js:20:5:20:24 | request.get(tainted) | tst.js:14:29:14:35 | req.url | tst.js:20:17:20:23 | tainted | The $@ of this request depends on $@. | tst.js:20:17:20:23 | tainted | URL | tst.js:14:29:14:35 | req.url | a user-provided value | @@ -130,3 +145,4 @@ edges | tst.js:64:3:64:38 | client. ... inted}) | tst.js:58:29:58:35 | req.url | tst.js:64:30:64:36 | tainted | The $@ of this request depends on $@. | tst.js:64:30:64:36 | tainted | URL | tst.js:58:29:58:35 | req.url | a user-provided value | | tst.js:68:3:68:38 | client. ... inted}) | tst.js:58:29:58:35 | req.url | tst.js:68:30:68:36 | tainted | The $@ of this request depends on $@. | tst.js:68:30:68:36 | tainted | URL | tst.js:58:29:58:35 | req.url | a user-provided value | | tst.js:76:5:76:26 | JSDOM.f ... ainted) | tst.js:74:29:74:35 | req.url | tst.js:76:19:76:25 | tainted | The $@ of this request depends on $@. | tst.js:76:19:76:25 | tainted | URL | tst.js:74:29:74:35 | req.url | a user-provided value | +| tst.js:83:5:83:26 | new Web ... ainted) | tst.js:81:29:81:35 | req.url | tst.js:83:19:83:25 | tainted | The $@ of this request depends on $@. | tst.js:83:19:83:25 | tainted | URL | tst.js:81:29:81:35 | req.url | a user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-918/tst.js b/javascript/ql/test/query-tests/Security/CWE-918/tst.js index d5951f648b4..5464375cb62 100644 --- a/javascript/ql/test/query-tests/Security/CWE-918/tst.js +++ b/javascript/ql/test/query-tests/Security/CWE-918/tst.js @@ -74,4 +74,11 @@ var server = http.createServer(async function(req, res) { var tainted = url.parse(req.url, true).query.url; JSDOM.fromURL(tainted); // NOT OK +}); + +import {JSDOM} from "jsdom"; +var server = http.createServer(async function(req, res) { + var tainted = url.parse(req.url, true).query.url; + + new WebSocket(tainted); // NOT OK }); \ No newline at end of file From 28ad6675788bd73a6a25bfc198cc780f8fb821ac Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 18 Mar 2021 19:40:46 +0100 Subject: [PATCH 184/725] add model for async-execute --- .../javascript/frameworks/SystemCommandExecutors.qll | 12 +++++++++--- .../CWE-078/UnsafeShellCommandConstruction.expected | 9 +++++++++ .../ql/test/query-tests/Security/CWE-078/lib/lib.js | 5 +++++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/SystemCommandExecutors.qll b/javascript/ql/src/semmle/javascript/frameworks/SystemCommandExecutors.qll index 913f7fd7205..ce445cfd174 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/SystemCommandExecutors.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/SystemCommandExecutors.qll @@ -43,9 +43,15 @@ private predicate execApi(string mod, int cmdArg, int optionsArg, boolean shell) ) or shell = true and - mod = "exec" and - optionsArg = -2 and - cmdArg = 0 + ( + mod = "exec" and + optionsArg = -2 and + cmdArg = 0 + or + mod = "async-execute" and + optionsArg = 1 and + cmdArg = 0 + ) } private class SystemCommandExecutors extends SystemCommandExecution, DataFlow::InvokeNode { diff --git a/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction.expected b/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction.expected index 2d707e1a693..ee6ebd939da 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction.expected @@ -205,6 +205,10 @@ nodes | lib/lib.js:405:39:405:42 | name | | lib/lib.js:406:22:406:25 | name | | lib/lib.js:406:22:406:25 | name | +| lib/lib.js:413:39:413:42 | name | +| lib/lib.js:413:39:413:42 | name | +| lib/lib.js:414:24:414:27 | name | +| lib/lib.js:414:24:414:27 | name | edges | lib/lib2.js:3:28:3:31 | name | lib/lib2.js:4:22:4:25 | name | | lib/lib2.js:3:28:3:31 | name | lib/lib2.js:4:22:4:25 | name | @@ -444,6 +448,10 @@ edges | lib/lib.js:405:39:405:42 | name | lib/lib.js:406:22:406:25 | name | | lib/lib.js:405:39:405:42 | name | lib/lib.js:406:22:406:25 | name | | lib/lib.js:405:39:405:42 | name | lib/lib.js:406:22:406:25 | name | +| lib/lib.js:413:39:413:42 | name | lib/lib.js:414:24:414:27 | name | +| lib/lib.js:413:39:413:42 | name | lib/lib.js:414:24:414:27 | name | +| lib/lib.js:413:39:413:42 | name | lib/lib.js:414:24:414:27 | name | +| lib/lib.js:413:39:413:42 | name | lib/lib.js:414:24:414:27 | name | #select | lib/lib2.js:4:10:4:25 | "rm -rf " + name | lib/lib2.js:3:28:3:31 | name | lib/lib2.js:4:22:4:25 | name | $@ based on library input is later used in $@. | lib/lib2.js:4:10:4:25 | "rm -rf " + name | String concatenation | lib/lib2.js:4:2:4:26 | cp.exec ... + name) | shell command | | lib/lib2.js:8:10:8:25 | "rm -rf " + name | lib/lib2.js:7:32:7:35 | name | lib/lib2.js:8:22:8:25 | name | $@ based on library input is later used in $@. | lib/lib2.js:8:10:8:25 | "rm -rf " + name | String concatenation | lib/lib2.js:8:2:8:26 | cp.exec ... + name) | shell command | @@ -502,3 +510,4 @@ edges | lib/lib.js:351:10:351:27 | "rm -rf " + unsafe | lib/lib.js:349:29:349:34 | unsafe | lib/lib.js:351:22:351:27 | unsafe | $@ based on library input is later used in $@. | lib/lib.js:351:10:351:27 | "rm -rf " + unsafe | String concatenation | lib/lib.js:351:2:351:28 | cp.exec ... unsafe) | shell command | | lib/lib.js:366:17:366:56 | "learn ... + model | lib/lib.js:360:20:360:23 | opts | lib/lib.js:366:28:366:42 | this.learn_args | $@ based on library input is later used in $@. | lib/lib.js:366:17:366:56 | "learn ... + model | String concatenation | lib/lib.js:367:3:367:18 | cp.exec(command) | shell command | | lib/lib.js:406:10:406:25 | "rm -rf " + name | lib/lib.js:405:39:405:42 | name | lib/lib.js:406:22:406:25 | name | $@ based on library input is later used in $@. | lib/lib.js:406:10:406:25 | "rm -rf " + name | String concatenation | lib/lib.js:406:2:406:26 | cp.exec ... + name) | shell command | +| lib/lib.js:414:12:414:27 | "rm -rf " + name | lib/lib.js:413:39:413:42 | name | lib/lib.js:414:24:414:27 | name | $@ based on library input is later used in $@. | lib/lib.js:414:12:414:27 | "rm -rf " + name | String concatenation | lib/lib.js:414:2:414:28 | asyncEx ... + name) | shell command | diff --git a/javascript/ql/test/query-tests/Security/CWE-078/lib/lib.js b/javascript/ql/test/query-tests/Security/CWE-078/lib/lib.js index d1a885438ff..e492c1b04ce 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/lib/lib.js +++ b/javascript/ql/test/query-tests/Security/CWE-078/lib/lib.js @@ -408,3 +408,8 @@ module.exports.sanitizer3 = function (name) { var sanitized = yetAnohterSanitizer(name); cp.exec("rm -rf " + sanitized); // OK } + +var asyncExec = require("async-execute"); +module.exports.asyncStuff = function (name) { + asyncExec("rm -rf " + name); // NOT OK +} \ No newline at end of file From d489d63b8e78af348b9e3cfae7354efcbd826c5d Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 18 Mar 2021 20:54:33 +0100 Subject: [PATCH 185/725] recognize object transformations in module.exports when looking for library inputs --- .../src/semmle/javascript/PackageExports.qll | 57 ++++++++++++++++++- .../javascript/dataflow/TypeTracking.qll | 6 ++ .../UnsafeShellCommandConstruction.expected | 9 +++ .../query-tests/Security/CWE-078/lib/lib.js | 29 +++++++++- 4 files changed, 99 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/PackageExports.qll b/javascript/ql/src/semmle/javascript/PackageExports.qll index bdb0c297411..5a0a7ddcc0f 100644 --- a/javascript/ql/src/semmle/javascript/PackageExports.qll +++ b/javascript/ql/src/semmle/javascript/PackageExports.qll @@ -42,7 +42,7 @@ PackageJSON getTopmostPackageJSON() { * Gets a value exported by the main module from one of the topmost `package.json` files (see `getTopmostPackageJSON`). * The value is either directly the `module.exports` value, a nested property of `module.exports`, or a method on an exported class. */ -private DataFlow::Node getAValueExportedByPackage() { +DataFlow::Node getAValueExportedByPackage() { result = getAnExportFromModule(getTopmostPackageJSON().getMainModule()) or result = getAValueExportedByPackage().(DataFlow::PropWrite).getRhs() @@ -70,6 +70,61 @@ private DataFlow::Node getAValueExportedByPackage() { result = cla.getAStaticMethod() or result = cla.getConstructor() ) + or + // ***** + // Various standard library methods for transforming exported objects. + // ***** + // + // Object.defineProperties + exists(DataFlow::MethodCallNode call | + call = DataFlow::globalVarRef("Object").getAMethodCall("defineProperties") and + [call, call.getArgument(0)] = getAValueExportedByPackage() and + result = call.getArgument(any(int i | i > 0)) + ) + or + // Object.defineProperty + exists(DataFlow::MethodCallNode call | + call = DataFlow::globalVarRef("Object").getAMethodCall("defineProperty") and + [call, call.getArgument(0)] = getAValueExportedByPackage() + | + result = call.getArgument(2).getALocalSource().getAPropertyReference("value") + or + result = + call.getArgument(2) + .getALocalSource() + .getAPropertyReference("get") + .(DataFlow::FunctionNode) + .getAReturn() + ) + or + // Object.assign + exists(DataFlow::MethodCallNode assign | + assign = DataFlow::globalVarRef("Object").getAMethodCall("assign") + | + getAValueExportedByPackage() = [assign, assign.getArgument(0)] and + result = assign.getAnArgument() + ) + or + // Array.prototype.{map, reduce, entries, values} + exists(DataFlow::MethodCallNode map | + map.getMethodName() = ["map", "reduce", "entries", "values"] and + map = getAValueExportedByPackage() + | + result = map.getArgument(0).getABoundFunctionValue(_).getAReturn() + or + // assuming that the receiver of the call is somehow exported + result = map.getReceiver() + ) + or + // Object.{fromEntries, freeze, entries, values} + exists(DataFlow::MethodCallNode freeze | + freeze = + DataFlow::globalVarRef("Object") + .getAMethodCall(["fromEntries", "freeze", "entries", "values"]) + | + freeze = getAValueExportedByPackage() and + result = freeze.getArgument(0) + ) } /** diff --git a/javascript/ql/src/semmle/javascript/dataflow/TypeTracking.qll b/javascript/ql/src/semmle/javascript/dataflow/TypeTracking.qll index 0996fc5c0ac..7facab07ff1 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TypeTracking.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TypeTracking.qll @@ -252,6 +252,12 @@ class TypeBackTracker extends TTypeBackTracker { */ predicate start() { hasReturn = false and prop = "" } + /** + * Holds if this is the starting point of type backtracking, and the value is in the property named `propName`. + * The type tracking only ends after the property has been stored. + */ + predicate isInProp(PropertyName propName) { hasReturn = false and prop = propName } + /** * Holds if this is the end point of type tracking. */ diff --git a/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction.expected b/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction.expected index ee6ebd939da..29a83580ad1 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction.expected @@ -209,6 +209,10 @@ nodes | lib/lib.js:413:39:413:42 | name | | lib/lib.js:414:24:414:27 | name | | lib/lib.js:414:24:414:27 | name | +| lib/lib.js:418:20:418:23 | name | +| lib/lib.js:418:20:418:23 | name | +| lib/lib.js:419:25:419:28 | name | +| lib/lib.js:419:25:419:28 | name | edges | lib/lib2.js:3:28:3:31 | name | lib/lib2.js:4:22:4:25 | name | | lib/lib2.js:3:28:3:31 | name | lib/lib2.js:4:22:4:25 | name | @@ -452,6 +456,10 @@ edges | lib/lib.js:413:39:413:42 | name | lib/lib.js:414:24:414:27 | name | | lib/lib.js:413:39:413:42 | name | lib/lib.js:414:24:414:27 | name | | lib/lib.js:413:39:413:42 | name | lib/lib.js:414:24:414:27 | name | +| lib/lib.js:418:20:418:23 | name | lib/lib.js:419:25:419:28 | name | +| lib/lib.js:418:20:418:23 | name | lib/lib.js:419:25:419:28 | name | +| lib/lib.js:418:20:418:23 | name | lib/lib.js:419:25:419:28 | name | +| lib/lib.js:418:20:418:23 | name | lib/lib.js:419:25:419:28 | name | #select | lib/lib2.js:4:10:4:25 | "rm -rf " + name | lib/lib2.js:3:28:3:31 | name | lib/lib2.js:4:22:4:25 | name | $@ based on library input is later used in $@. | lib/lib2.js:4:10:4:25 | "rm -rf " + name | String concatenation | lib/lib2.js:4:2:4:26 | cp.exec ... + name) | shell command | | lib/lib2.js:8:10:8:25 | "rm -rf " + name | lib/lib2.js:7:32:7:35 | name | lib/lib2.js:8:22:8:25 | name | $@ based on library input is later used in $@. | lib/lib2.js:8:10:8:25 | "rm -rf " + name | String concatenation | lib/lib2.js:8:2:8:26 | cp.exec ... + name) | shell command | @@ -511,3 +519,4 @@ edges | lib/lib.js:366:17:366:56 | "learn ... + model | lib/lib.js:360:20:360:23 | opts | lib/lib.js:366:28:366:42 | this.learn_args | $@ based on library input is later used in $@. | lib/lib.js:366:17:366:56 | "learn ... + model | String concatenation | lib/lib.js:367:3:367:18 | cp.exec(command) | shell command | | lib/lib.js:406:10:406:25 | "rm -rf " + name | lib/lib.js:405:39:405:42 | name | lib/lib.js:406:22:406:25 | name | $@ based on library input is later used in $@. | lib/lib.js:406:10:406:25 | "rm -rf " + name | String concatenation | lib/lib.js:406:2:406:26 | cp.exec ... + name) | shell command | | lib/lib.js:414:12:414:27 | "rm -rf " + name | lib/lib.js:413:39:413:42 | name | lib/lib.js:414:24:414:27 | name | $@ based on library input is later used in $@. | lib/lib.js:414:12:414:27 | "rm -rf " + name | String concatenation | lib/lib.js:414:2:414:28 | asyncEx ... + name) | shell command | +| lib/lib.js:419:13:419:28 | "rm -rf " + name | lib/lib.js:418:20:418:23 | name | lib/lib.js:419:25:419:28 | name | $@ based on library input is later used in $@. | lib/lib.js:419:13:419:28 | "rm -rf " + name | String concatenation | lib/lib.js:419:3:419:29 | asyncEx ... + name) | shell command | diff --git a/javascript/ql/test/query-tests/Security/CWE-078/lib/lib.js b/javascript/ql/test/query-tests/Security/CWE-078/lib/lib.js index e492c1b04ce..a645788aa72 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/lib/lib.js +++ b/javascript/ql/test/query-tests/Security/CWE-078/lib/lib.js @@ -412,4 +412,31 @@ module.exports.sanitizer3 = function (name) { var asyncExec = require("async-execute"); module.exports.asyncStuff = function (name) { asyncExec("rm -rf " + name); // NOT OK -} \ No newline at end of file +} + +const myFuncs = { + myFunc: function (name) { + asyncExec("rm -rf " + name); // NOT OK + } +}; + +module.exports.blabity = {}; + +Object.defineProperties( + module.exports.blabity, + Object.assign( + {}, + Object.entries(myFuncs).reduce( + (props, [ key, value ]) => Object.assign( + props, + { + [key]: { + value, + configurable: true, + }, + }, + ), + {} + ) + ) +); From 20f0b3329aa1f59d8b6e9217a8785a04388b722b Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Wed, 17 Mar 2021 09:55:52 +0100 Subject: [PATCH 186/725] C#: Fix code quality issues reported by code scanning --- .../Semmle.Extraction.CSharp/Entities/CachedSymbol.cs | 9 +++------ .../Entities/Expressions/ImplicitCast.cs | 2 +- .../Entities/Expressions/MemberAccess.cs | 2 +- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/CachedSymbol.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/CachedSymbol.cs index f7f18ff4c25..d6fb0d65e5d 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/CachedSymbol.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/CachedSymbol.cs @@ -151,13 +151,10 @@ namespace Semmle.Extraction.CSharp.Entities if (handleProp is null) { var underlyingSymbolProp = GetPropertyInfo(Symbol, "UnderlyingSymbol"); - if (underlyingSymbolProp is not null) + if (underlyingSymbolProp?.GetValue(Symbol) is object underlying) { - if (underlyingSymbolProp.GetValue(Symbol) is object underlying) - { - handleProp = GetPropertyInfo(underlying, "Handle"); - handleObj = underlying; - } + handleProp = GetPropertyInfo(underlying, "Handle"); + handleObj = underlying; } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitCast.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitCast.cs index a6995adc30f..2d617cdb1b9 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitCast.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitCast.cs @@ -3,7 +3,7 @@ using Semmle.Extraction.Kinds; namespace Semmle.Extraction.CSharp.Entities.Expressions { - internal class ImplicitCast : Expression + internal sealed class ImplicitCast : Expression { public Expression Expr { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/MemberAccess.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/MemberAccess.cs index 0de154509c8..426145e2d27 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/MemberAccess.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/MemberAccess.cs @@ -4,7 +4,7 @@ using Semmle.Extraction.Kinds; namespace Semmle.Extraction.CSharp.Entities.Expressions { - internal class MemberAccess : Expression + internal sealed class MemberAccess : Expression { private MemberAccess(ExpressionNodeInfo info, ExpressionSyntax qualifier, ISymbol? target) : base(info) { From 7543f10593dfe5bd3aaea1572d1c9135aff49b31 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 19 Mar 2021 09:53:25 +0100 Subject: [PATCH 187/725] Python: Reorganize PyYAML tests a bit --- .../library-tests/frameworks/yaml/Decoding.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/python/ql/test/experimental/library-tests/frameworks/yaml/Decoding.py b/python/ql/test/experimental/library-tests/frameworks/yaml/Decoding.py index a9369d6ec3d..987ea76552a 100644 --- a/python/ql/test/experimental/library-tests/frameworks/yaml/Decoding.py +++ b/python/ql/test/experimental/library-tests/frameworks/yaml/Decoding.py @@ -6,20 +6,32 @@ yaml.load(payload, yaml.Loader) # $decodeInput=payload decodeOutput=Attribute() yaml.unsafe_load(payload) # $ decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML decodeMayExecuteInput yaml.full_load(payload) # $ decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML decodeMayExecuteInput -# Safe +# Safe: yaml.load(payload, yaml.SafeLoader) # $ decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML yaml.load(payload, Loader=yaml.SafeLoader) # $decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML yaml.load(payload, yaml.BaseLoader) # $decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML yaml.safe_load(payload) # $ decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML +################################################################################ # load_all variants +################################################################################ + +# Unsafe: yaml.load_all(payload) # $ decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML decodeMayExecuteInput -yaml.safe_load_all(payload) # $ decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML yaml.unsafe_load_all(payload) # $ decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML decodeMayExecuteInput yaml.full_load_all(payload) # $ decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML decodeMayExecuteInput +# Safe: +yaml.safe_load_all(payload) # $ decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML + +################################################################################ # C-based loaders with `libyaml` +################################################################################ + +# Unsafe: yaml.load(payload, yaml.CLoader) # $ decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML decodeMayExecuteInput yaml.load(payload, yaml.CFullLoader) # $ decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML decodeMayExecuteInput + +# Safe: yaml.load(payload, yaml.CSafeLoader) # $decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML yaml.load(payload, yaml.CBaseLoader) # $decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML From e90fb1a225661dce835ac3d4683e824439b37b41 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 19 Mar 2021 10:09:33 +0100 Subject: [PATCH 188/725] reuse classes modelling standard library functions --- .../src/semmle/javascript/PackageExports.qll | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/PackageExports.qll b/javascript/ql/src/semmle/javascript/PackageExports.qll index 5a0a7ddcc0f..c8807043487 100644 --- a/javascript/ql/src/semmle/javascript/PackageExports.qll +++ b/javascript/ql/src/semmle/javascript/PackageExports.qll @@ -83,14 +83,13 @@ DataFlow::Node getAValueExportedByPackage() { ) or // Object.defineProperty - exists(DataFlow::MethodCallNode call | - call = DataFlow::globalVarRef("Object").getAMethodCall("defineProperty") and - [call, call.getArgument(0)] = getAValueExportedByPackage() + exists(CallToObjectDefineProperty call | + [call, call.getBaseObject()] = getAValueExportedByPackage() | - result = call.getArgument(2).getALocalSource().getAPropertyReference("value") + result = call.getPropertyDescriptor().getALocalSource().getAPropertyReference("value") or result = - call.getArgument(2) + call.getPropertyDescriptor() .getALocalSource() .getAPropertyReference("get") .(DataFlow::FunctionNode) @@ -98,11 +97,9 @@ DataFlow::Node getAValueExportedByPackage() { ) or // Object.assign - exists(DataFlow::MethodCallNode assign | - assign = DataFlow::globalVarRef("Object").getAMethodCall("assign") - | - getAValueExportedByPackage() = [assign, assign.getArgument(0)] and - result = assign.getAnArgument() + exists(ExtendCall assign | + getAValueExportedByPackage() = [assign, assign.getDestinationOperand()] and + result = assign.getASourceOperand() ) or // Array.prototype.{map, reduce, entries, values} @@ -120,7 +117,7 @@ DataFlow::Node getAValueExportedByPackage() { exists(DataFlow::MethodCallNode freeze | freeze = DataFlow::globalVarRef("Object") - .getAMethodCall(["fromEntries", "freeze", "entries", "values"]) + .getAMethodCall(["fromEntries", "freeze", "seal", "entries", "values"]) | freeze = getAValueExportedByPackage() and result = freeze.getArgument(0) From a28a36ab298f5c4847d12b9da82e7646edfd0d4b Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 19 Mar 2021 10:10:56 +0100 Subject: [PATCH 189/725] add change-note --- javascript/change-notes/2021-03-19-async-execute.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 javascript/change-notes/2021-03-19-async-execute.md diff --git a/javascript/change-notes/2021-03-19-async-execute.md b/javascript/change-notes/2021-03-19-async-execute.md new file mode 100644 index 00000000000..4f7e9240bc3 --- /dev/null +++ b/javascript/change-notes/2021-03-19-async-execute.md @@ -0,0 +1,4 @@ +lgtm,codescanning +* The command injection security queries now recognize additional sinks. + Affected packages are + [async-execute](https://npmjs.com/package/async-execute) From 36b0ab1de55b2862194df0c63672ff880e72cba6 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 19 Mar 2021 10:29:38 +0100 Subject: [PATCH 190/725] Apply suggestions from code review Co-authored-by: Esben Sparre Andreasen --- javascript/ql/src/semmle/javascript/PackageExports.qll | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/PackageExports.qll b/javascript/ql/src/semmle/javascript/PackageExports.qll index c8807043487..ffa96b051e1 100644 --- a/javascript/ql/src/semmle/javascript/PackageExports.qll +++ b/javascript/ql/src/semmle/javascript/PackageExports.qll @@ -42,7 +42,7 @@ PackageJSON getTopmostPackageJSON() { * Gets a value exported by the main module from one of the topmost `package.json` files (see `getTopmostPackageJSON`). * The value is either directly the `module.exports` value, a nested property of `module.exports`, or a method on an exported class. */ -DataFlow::Node getAValueExportedByPackage() { +private DataFlow::Node getAValueExportedByPackage() { result = getAnExportFromModule(getTopmostPackageJSON().getMainModule()) or result = getAValueExportedByPackage().(DataFlow::PropWrite).getRhs() @@ -72,7 +72,7 @@ DataFlow::Node getAValueExportedByPackage() { ) or // ***** - // Various standard library methods for transforming exported objects. + // Common styles of transforming exported objects. // ***** // // Object.defineProperties @@ -96,7 +96,7 @@ DataFlow::Node getAValueExportedByPackage() { .getAReturn() ) or - // Object.assign + // Object.assign and friends exists(ExtendCall assign | getAValueExportedByPackage() = [assign, assign.getDestinationOperand()] and result = assign.getASourceOperand() @@ -113,7 +113,7 @@ DataFlow::Node getAValueExportedByPackage() { result = map.getReceiver() ) or - // Object.{fromEntries, freeze, entries, values} + // Object.{fromEntries, freeze, seal, entries, values} exists(DataFlow::MethodCallNode freeze | freeze = DataFlow::globalVarRef("Object") From 783a63a8a8a20a72394b56676512638138a3ee56 Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Fri, 19 Mar 2021 10:54:41 +0100 Subject: [PATCH 191/725] Update cpp/ql/src/Summary/LinesOfCode.ql Co-authored-by: Shati Patel <42641846+shati-patel@users.noreply.github.com> --- cpp/ql/src/Summary/LinesOfCode.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/Summary/LinesOfCode.ql b/cpp/ql/src/Summary/LinesOfCode.ql index 79e4e7b16f2..3b2aa2ac4c9 100644 --- a/cpp/ql/src/Summary/LinesOfCode.ql +++ b/cpp/ql/src/Summary/LinesOfCode.ql @@ -1,7 +1,7 @@ /** * @id cpp/summary/lines-of-code * @name Total lines of C/C++ code in the database - * @description The total number of lines of C/C++ code across all files, including system headers, libraries, and auto-generated files. This is a useful metric of the size of a database. Lines of code are all lines in a file that was seen during the build that contain code, i.e. are not whitespace or comments. + * @description The total number of lines of C/C++ code across all files, including system headers, libraries, and auto-generated files. This is a useful metric of the size of a database. For all files that were seen during the build, this query counts the lines of code, excluding whitespace or comments. * @kind metric * @tags summary */ From 79d6731ed8e1725c1064214b7a201c4ad0794009 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Fri, 19 Mar 2021 11:01:28 +0100 Subject: [PATCH 192/725] C#: Adjust make_stubs.py to use codeql instead of odasa --- csharp/ql/src/Stubs/make_stubs.py | 50 ++++++++++++++----------------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/csharp/ql/src/Stubs/make_stubs.py b/csharp/ql/src/Stubs/make_stubs.py index e94cf0c7261..19a917cd8ab 100644 --- a/csharp/ql/src/Stubs/make_stubs.py +++ b/csharp/ql/src/Stubs/make_stubs.py @@ -43,12 +43,6 @@ if not foundCS: print("Test directory does not contain .cs files. Please specify a working qltest directory.") exit(1) -cmd = ['odasa', 'selfTest'] -print('Running ' + ' '.join(cmd)) -if subprocess.check_call(cmd): - print("odasa selfTest failed. Ensure odasa is on your current path.") - exit(1) - csharpQueries = os.path.abspath(os.path.dirname(sys.argv[0])) outputFile = os.path.join(testDir, 'stubs.cs') @@ -58,35 +52,36 @@ if os.path.isfile(outputFile): os.remove(outputFile) # It would interfere with the test. print("Removed previous", outputFile) -cmd = ['odasa', 'qltest', '--optimize', '--leave-temp-files', testDir] +cmd = ['codeql', 'test', 'run', '--keep-databases', testDir] print('Running ' + ' '.join(cmd)) if subprocess.check_call(cmd): - print("qltest failed. Please fix up the test before proceeding.") + print("codeql test failed. Please fix up the test before proceeding.") exit(1) -dbDir = os.path.join(testDir, os.path.basename(testDir) + ".testproj", "db-csharp") +dbDir = os.path.join(testDir, os.path.basename(testDir) + ".testproj") if not os.path.isdir(dbDir): - print("Expected database directory " + dbDir + " not found. Please contact Semmle.") + print("Expected database directory " + dbDir + " not found.") exit(1) -cmd = ['odasa', 'runQuery', '--query', os.path.join(csharpQueries, 'MinimalStubsFromSource.ql'), '--db', dbDir, '--output-file', outputFile] +cmd = ['codeql', 'query', 'run', os.path.join( + csharpQueries, 'MinimalStubsFromSource.ql'), '--database', dbDir, '--output', outputFile] print('Running ' + ' '.join(cmd)) if subprocess.check_call(cmd): - print('Failed to run the query to generate output file. Please contact Semmle.') + print('Failed to run the query to generate output file.') exit(1) # Remove the leading " and trailing " bytes from the file len = os.stat(outputFile).st_size f = open(outputFile, "rb") try: - quote = f.read(1) - if quote != b'"': - print("Unexpected character in file. Please contact Semmle.") - contents = f.read(len-3) - quote = f.read(1) - if quote != b'"': - print("Unexpected end character. Please contact Semmle.", quote) + quote = f.read(6) + if quote != b"\x02\x01\x86'\x85'": + print("Unexpected start characters in file.", quote) + contents = f.read(len-21) + quote = f.read(15) + if quote != b'\x0e\x01\x08#select\x01\x01\x00s\x00': + print("Unexpected end character in file.", quote) finally: f.close() @@ -94,16 +89,17 @@ f = open(outputFile, "wb") f.write(contents) f.close() -cmd = ['odasa', 'qltest', '--optimize', testDir] +cmd = ['codeql', 'test', 'run', testDir] print('Running ' + ' '.join(cmd)) if subprocess.check_call(cmd): - print('\nTest failed. You may need to fix up', outputFile) - print('It may help to view', outputFile, ' in Visual Studio') - print("Next steps:") - print('1. Look at the compilation errors, and fix up', outputFile, 'so that the test compiles') - print('2. Re-run odasa qltest --optimize "' + testDir + '"') - print('3. git add "' + outputFile + '"') - exit(1) + print('\nTest failed. You may need to fix up', outputFile) + print('It may help to view', outputFile, ' in Visual Studio') + print("Next steps:") + print('1. Look at the compilation errors, and fix up', + outputFile, 'so that the test compiles') + print('2. Re-run codeql test run "' + testDir + '"') + print('3. git add "' + outputFile + '"') + exit(1) print("\nStub generation successful! Next steps:") print('1. Edit "semmle-extractor-options" in the .cs files to remove unused references') From 39a7d3decc4ba2fd0552d50835d676ecd8d7de7b Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Wed, 17 Mar 2021 12:28:03 +0100 Subject: [PATCH 193/725] C++: Address review comments. --- cpp/ql/src/Diagnostics/FailedExtractions.qll | 5 +---- .../{AbortedExtractions.ql => FailedInvocations.ql} | 4 ++-- 2 files changed, 3 insertions(+), 6 deletions(-) rename cpp/ql/src/Diagnostics/{AbortedExtractions.ql => FailedInvocations.ql} (87%) diff --git a/cpp/ql/src/Diagnostics/FailedExtractions.qll b/cpp/ql/src/Diagnostics/FailedExtractions.qll index 36bf264aa90..ac3088adf19 100644 --- a/cpp/ql/src/Diagnostics/FailedExtractions.qll +++ b/cpp/ql/src/Diagnostics/FailedExtractions.qll @@ -84,10 +84,7 @@ class ExtractionUnrecoverableError extends ExtractionError, TCompilationFailed { result = "Unrecoverable extraction error while compiling " + f.toString() } - override string getErrorMessage() { - result = - "Unrecoverable compilation failure; check logs/build-tracer.log in the database directory for more information." - } + override string getErrorMessage() { result = "unrecoverable compilation failure." } override File getFile() { result = f } diff --git a/cpp/ql/src/Diagnostics/AbortedExtractions.ql b/cpp/ql/src/Diagnostics/FailedInvocations.ql similarity index 87% rename from cpp/ql/src/Diagnostics/AbortedExtractions.ql rename to cpp/ql/src/Diagnostics/FailedInvocations.ql index 5bab529b23e..ec1a243f245 100644 --- a/cpp/ql/src/Diagnostics/AbortedExtractions.ql +++ b/cpp/ql/src/Diagnostics/FailedInvocations.ql @@ -1,8 +1,8 @@ /** - * @name Aborted extractor invocations + * @name Failed extractor invocations * @description Gives the command line of compilations for which extraction did not run to completion. * @kind diagnostic - * @id cpp/diagnostics/aborted-extractions + * @id cpp/diagnostics/failed-extractor-invocations */ import cpp From 63e560e3b4fdba76e434a27ed86b8a36e7242590 Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Fri, 19 Mar 2021 11:27:51 +0100 Subject: [PATCH 194/725] Fix QL doc. --- cpp/ql/src/Diagnostics/FailedExtractions.qll | 1 + 1 file changed, 1 insertion(+) diff --git a/cpp/ql/src/Diagnostics/FailedExtractions.qll b/cpp/ql/src/Diagnostics/FailedExtractions.qll index ac3088adf19..d692be10dac 100644 --- a/cpp/ql/src/Diagnostics/FailedExtractions.qll +++ b/cpp/ql/src/Diagnostics/FailedExtractions.qll @@ -47,6 +47,7 @@ private newtype TExtractionError = * Superclass for the extraction error hierarchy. */ class ExtractionError extends TExtractionError { + /** Gets the string representation of the error. */ string toString() { none() } /** Gets the error message for this error. */ From e482d21949a917fe2585c425acc958710d30bc08 Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Fri, 19 Mar 2021 11:40:20 +0100 Subject: [PATCH 195/725] C++: Make QLdoc check happy. --- cpp/ql/src/Diagnostics/FailedExtractions.qll | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cpp/ql/src/Diagnostics/FailedExtractions.qll b/cpp/ql/src/Diagnostics/FailedExtractions.qll index d692be10dac..62a89f7cdc1 100644 --- a/cpp/ql/src/Diagnostics/FailedExtractions.qll +++ b/cpp/ql/src/Diagnostics/FailedExtractions.qll @@ -1,3 +1,7 @@ +/** + * Provides a common hierarchy of all types of errors that can occur during extraction. + */ + import cpp /* From 4f46908224bd6840ad90ec463a6688d942d003a1 Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 20 Nov 2019 16:30:00 +0000 Subject: [PATCH 196/725] JS: Add test with ES getters/setters --- .../TaintTracking/getters-and-setters.js | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 javascript/ql/test/library-tests/TaintTracking/getters-and-setters.js diff --git a/javascript/ql/test/library-tests/TaintTracking/getters-and-setters.js b/javascript/ql/test/library-tests/TaintTracking/getters-and-setters.js new file mode 100644 index 00000000000..1918fd23e95 --- /dev/null +++ b/javascript/ql/test/library-tests/TaintTracking/getters-and-setters.js @@ -0,0 +1,55 @@ +import * as dummy from 'dummy'; + +function testGetterSource() { + class C { + get x() { + return source(); + } + }; + sink(new C().x); // NOT OK + + function indirection(c) { + if (c) { + sink(c.x); // NOT OK + } + } + indirection(new C()); + indirection(null); +} + +function testSetterSink() { + class C { + set x(v) { + sink(v); // NOT OK + } + }; + function indirection(c) { + c.x = source(); + } + indirection(new C()); + indirection(null); +} + +function testFlowThroughGetter() { + class C { + constructor(x) { + this._x = x; + } + + get x() { + return this._x; + } + }; + + function indirection(c) { + sink(c.x); // NOT OK + } + indirection(new C(source())); + indirection(null); + + function getX(c) { + return c.x; + } + sink(getX(new C(source()))); // NOT OK + sink(getX(new C(source()))); // NOT OK +} From 2f3d51641335525759dd538ef8ef7e068a84aae6 Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 20 Nov 2019 17:19:44 +0000 Subject: [PATCH 197/725] JS: Track flow into ES accessors --- .../semmle/javascript/dataflow/DataFlow.qll | 7 +++++++ .../dataflow/internal/CallGraphs.qll | 14 +++++++++++++ .../dataflow/internal/FlowSteps.qll | 21 ++++++++++++++----- .../TaintTracking/BasicTaintTracking.expected | 4 ++++ .../TaintTracking/DataFlowTracking.expected | 4 ++++ .../TaintTracking/getters-and-setters.js | 4 ++-- 6 files changed, 47 insertions(+), 7 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll index 6f861f1556c..3db26d0af33 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll @@ -531,6 +531,13 @@ module DataFlow { predicate isPrivateField() { getPropertyName().charAt(0) = "#" and getPropertyNameExpr() instanceof Label } + + /** + * Gets an accessor (`get` or `set` method) that may be invoked by this property reference. + */ + final DataFlow::FunctionNode getAnAccessorCallee() { + result = CallGraph::getAnAccessorCallee(this) + } } /** diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/CallGraphs.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/CallGraphs.qll index 433cbc2004b..651c97feb6c 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/CallGraphs.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/CallGraphs.qll @@ -162,4 +162,18 @@ module CallGraph { ) ) } + + /** + * Gets a getter or setter invoked as a result of the given property access. + */ + cached + DataFlow::FunctionNode getAnAccessorCallee(DataFlow::PropRef ref) { + exists(DataFlow::ClassNode cls, string name | + ref = cls.getAnInstanceReference().getAPropertyRead(name) and + result = cls.getInstanceMember(name, DataFlow::MemberKind::getter()) + or + ref = cls.getAnInstanceReference().getAPropertyWrite(name) and + result = cls.getInstanceMember(name, DataFlow::MemberKind::setter()) + ) + } } diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll index 4b9158d3575..0325d41bcc3 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll @@ -25,7 +25,8 @@ predicate shouldTrackProperties(AbstractValue obj) { */ pragma[noinline] predicate returnExpr(Function f, DataFlow::Node source, DataFlow::Node sink) { - sink.asExpr() = f.getAReturnedExpr() and source = sink + sink.asExpr() = f.getAReturnedExpr() and source = sink and + not f = any(SetterMethodDeclaration decl).getBody() } /** @@ -120,7 +121,11 @@ private module CachedSteps { * Holds if `invk` may invoke `f`. */ cached - predicate calls(DataFlow::InvokeNode invk, Function f) { f = invk.getACallee(0) } + predicate calls(DataFlow::SourceNode invk, Function f) { + f = invk.(DataFlow::InvokeNode).getACallee(0) + or + f = invk.(DataFlow::PropRef).getAnAccessorCallee().getFunction() + } private predicate callsBoundInternal( DataFlow::InvokeNode invk, Function f, int boundArgs, boolean contextDependent @@ -177,11 +182,11 @@ private module CachedSteps { */ cached predicate argumentPassing( - DataFlow::InvokeNode invk, DataFlow::ValueNode arg, Function f, DataFlow::SourceNode parm + DataFlow::SourceNode invk, DataFlow::ValueNode arg, Function f, DataFlow::SourceNode parm ) { calls(invk, f) and ( - exists(int i | arg = invk.getArgument(i) | + exists(int i | arg = invk.(DataFlow::InvokeNode).getArgument(i) | exists(Parameter p | f.getParameter(i) = p and not p.isRestParameter() and @@ -193,6 +198,12 @@ private module CachedSteps { or arg = invk.(DataFlow::CallNode).getReceiver() and parm = DataFlow::thisNode(f) + or + arg = invk.(DataFlow::PropRef).getBase() and + parm = DataFlow::thisNode(f) + or + arg = invk.(DataFlow::PropWrite).getRhs() and + parm = DataFlow::parameterNode(f.getParameter(0)) ) or exists(DataFlow::Node callback, int i, Parameter p | @@ -213,7 +224,7 @@ private module CachedSteps { callsBound(invk, f, boundArgs) and f.getParameter(boundArgs + i) = p and not p.isRestParameter() and - arg = invk.getArgument(i) and + arg = invk.(DataFlow::InvokeNode).getArgument(i) and parm = DataFlow::parameterNode(p) ) } diff --git a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected index c98e9ad7e79..b35dff0c16f 100644 --- a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected @@ -66,6 +66,10 @@ typeInferenceMismatch | exceptions.js:144:9:144:16 | source() | exceptions.js:132:8:132:27 | returnThrownSource() | | exceptions.js:150:13:150:20 | source() | exceptions.js:153:10:153:10 | e | | exceptions.js:158:13:158:20 | source() | exceptions.js:161:10:161:10 | e | +| getters-and-setters.js:6:20:6:27 | source() | getters-and-setters.js:9:10:9:18 | new C().x | +| getters-and-setters.js:6:20:6:27 | source() | getters-and-setters.js:13:18:13:20 | c.x | +| getters-and-setters.js:27:15:27:22 | source() | getters-and-setters.js:23:18:23:18 | v | +| getters-and-setters.js:47:23:47:30 | source() | getters-and-setters.js:45:14:45:16 | c.x | | importedReactComponent.jsx:4:40:4:47 | source() | exportedReactComponent.jsx:2:10:2:19 | props.text | | indexOf.js:4:11:4:18 | source() | indexOf.js:9:10:9:10 | x | | json-stringify.js:2:16:2:23 | source() | json-stringify.js:5:8:5:29 | JSON.st ... source) | diff --git a/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected b/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected index 34a6b30bdce..fd9e0fe2b46 100644 --- a/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected @@ -41,6 +41,10 @@ | exceptions.js:144:9:144:16 | source() | exceptions.js:132:8:132:27 | returnThrownSource() | | exceptions.js:150:13:150:20 | source() | exceptions.js:153:10:153:10 | e | | exceptions.js:158:13:158:20 | source() | exceptions.js:161:10:161:10 | e | +| getters-and-setters.js:6:20:6:27 | source() | getters-and-setters.js:9:10:9:18 | new C().x | +| getters-and-setters.js:6:20:6:27 | source() | getters-and-setters.js:13:18:13:20 | c.x | +| getters-and-setters.js:27:15:27:22 | source() | getters-and-setters.js:23:18:23:18 | v | +| getters-and-setters.js:47:23:47:30 | source() | getters-and-setters.js:45:14:45:16 | c.x | | indexOf.js:4:11:4:18 | source() | indexOf.js:9:10:9:10 | x | | indexOf.js:4:11:4:18 | source() | indexOf.js:13:10:13:10 | x | | nested-props.js:4:13:4:20 | source() | nested-props.js:5:10:5:14 | obj.x | diff --git a/javascript/ql/test/library-tests/TaintTracking/getters-and-setters.js b/javascript/ql/test/library-tests/TaintTracking/getters-and-setters.js index 1918fd23e95..00691e4987d 100644 --- a/javascript/ql/test/library-tests/TaintTracking/getters-and-setters.js +++ b/javascript/ql/test/library-tests/TaintTracking/getters-and-setters.js @@ -50,6 +50,6 @@ function testFlowThroughGetter() { function getX(c) { return c.x; } - sink(getX(new C(source()))); // NOT OK - sink(getX(new C(source()))); // NOT OK + sink(getX(new C(source()))); // NOT OK - but not flagged + getX(null); } From 01fd00de564b0e61f6cedf7dadea2563d628b57d Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 19 Mar 2021 11:49:06 +0000 Subject: [PATCH 198/725] JS: Fix join order in argumentPassing --- .../ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll index 0325d41bcc3..79ffecad221 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll @@ -206,10 +206,11 @@ private module CachedSteps { parm = DataFlow::parameterNode(f.getParameter(0)) ) or - exists(DataFlow::Node callback, int i, Parameter p | + exists(DataFlow::Node callback, int i, Parameter p, Function target | invk.(DataFlow::PartialInvokeNode).isPartialArgument(callback, arg, i) and partiallyCalls(invk, callback, f) and - f.getParameter(i) = p and + f = pragma[only_bind_into](target) and + target.getParameter(i) = p and not p.isRestParameter() and parm = DataFlow::parameterNode(p) ) From 42c4b22ea130a3ed50b13563f249f8465256904c Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 19 Mar 2021 12:41:34 +0000 Subject: [PATCH 199/725] JS: Fix query ID for UntrustedCheckout --- .../ql/src/experimental/Security/CWE-094/UntrustedCheckout.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-094/UntrustedCheckout.ql b/javascript/ql/src/experimental/Security/CWE-094/UntrustedCheckout.ql index 62a0d743152..5227d433088 100644 --- a/javascript/ql/src/experimental/Security/CWE-094/UntrustedCheckout.ql +++ b/javascript/ql/src/experimental/Security/CWE-094/UntrustedCheckout.ql @@ -6,7 +6,7 @@ * @kind problem * @problem.severity warning * @precision low - * @id js/actions/pull_request_target + * @id js/actions/pull-request-target * @tags actions * security * external/cwe/cwe-094 From 18ac2596d0214490a7c88063dbd716389e1a5127 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 19 Mar 2021 13:54:03 +0100 Subject: [PATCH 200/725] Data flow: Add section on lambda flow to `dataflow.md` --- docs/ql-libraries/dataflow/dataflow.md | 39 ++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/docs/ql-libraries/dataflow/dataflow.md b/docs/ql-libraries/dataflow/dataflow.md index 46ba27acccf..77e75a36241 100644 --- a/docs/ql-libraries/dataflow/dataflow.md +++ b/docs/ql-libraries/dataflow/dataflow.md @@ -186,6 +186,45 @@ values, for example through `out` parameters in C#, the `ReturnKind` class can be defined and used to match up different kinds of `ReturnNode`s with the corresponding `OutNode`s. +#### Lambda flow + +For lambda-like calls, the library supports built-in call resolution based on data flow between a lambda creation expression and a lambda call. The interface that needs to be implemented is + +```ql +class LambdaCallKind + +/** Holds if `creation` is an expression that creates a lambda of kind `kind` for `c`. */ +predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) + +/** Holds if `call` is a lambda call of kind `kind` where `receiver` is the lambda expression. */ +predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) + +/** Extra data-flow steps needed for lamba flow analysis. */ +predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) +``` + +with the semantics that `call` will resolve to `c` if there is a data-flow path from `creation` to `receiver`, with matching `kind`s. + +The implementation keeps track of a one-level call context, which means that we are able to handle situations like this: +```csharp +Apply(f, x) { f(x); } + +Apply(x => NonSink(x), "tainted"); // GOOD + +Apply(x => Sink(x), "not tainted"); // GOOD +``` + +However, since we only track one level the following example will have false-positive flow: +```csharp +Apply(f, x) { f(x); } + +ApplyWrapper(f, x) { Apply(f, x) } + +ApplyWrapper(x => NonSink(x), "tainted"); // GOOD (FALSE POSITIVE) + +ApplyWrapper(x => Sink(x), "not tainted"); // GOOD (FALSE POSITIVE) +``` + ## Flow through global variables Flow through global variables are called jump-steps, since such flow steps From d9079e34e3ae78c51cec8a28b33ae2cac8a3e69c Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 19 Mar 2021 15:51:54 +0100 Subject: [PATCH 201/725] Python: Move framework tests out of experimental Since they are not experimental anymore :smile: --- .../library-tests/frameworks/crypto/ConceptsTest.expected | 0 .../library-tests/frameworks/crypto/ConceptsTest.ql | 0 .../library-tests/frameworks/crypto/test_dsa.py | 0 .../{experimental => }/library-tests/frameworks/crypto/test_ec.py | 0 .../library-tests/frameworks/crypto/test_rsa.py | 0 .../library-tests/frameworks/cryptodome/ConceptsTest.expected | 0 .../library-tests/frameworks/cryptodome/ConceptsTest.ql | 0 .../library-tests/frameworks/cryptodome/test_dsa.py | 0 .../library-tests/frameworks/cryptodome/test_ec.py | 0 .../library-tests/frameworks/cryptodome/test_rsa.py | 0 .../library-tests/frameworks/cryptography/ConceptsTest.expected | 0 .../library-tests/frameworks/cryptography/ConceptsTest.ql | 0 .../library-tests/frameworks/cryptography/test_dsa.py | 0 .../library-tests/frameworks/cryptography/test_ec.py | 0 .../library-tests/frameworks/cryptography/test_rsa.py | 0 .../library-tests/frameworks/dill/ConceptsTest.expected | 0 .../library-tests/frameworks/dill/ConceptsTest.ql | 0 .../{experimental => }/library-tests/frameworks/dill/Decoding.py | 0 .../library-tests/frameworks/django-v1/ConceptsTest.expected | 0 .../library-tests/frameworks/django-v1/ConceptsTest.ql | 0 .../library-tests/frameworks/django-v1/routing_test.py | 0 .../library-tests/frameworks/django-v2-v3/ConceptsTest.expected | 0 .../library-tests/frameworks/django-v2-v3/ConceptsTest.ql | 0 .../library-tests/frameworks/django-v2-v3/README.md | 0 .../library-tests/frameworks/django-v2-v3/TestTaint.expected | 0 .../library-tests/frameworks/django-v2-v3/TestTaint.ql | 0 .../library-tests/frameworks/django-v2-v3/dummy_import.py | 0 .../library-tests/frameworks/django-v2-v3/manage.py | 0 .../library-tests/frameworks/django-v2-v3/options | 0 .../library-tests/frameworks/django-v2-v3/response_test.py | 0 .../library-tests/frameworks/django-v2-v3/routing_test.py | 0 .../library-tests/frameworks/django-v2-v3/taint_test.py | 0 .../library-tests/frameworks/django-v2-v3/testapp/__init__.py | 0 .../library-tests/frameworks/django-v2-v3/testapp/admin.py | 0 .../library-tests/frameworks/django-v2-v3/testapp/apps.py | 0 .../frameworks/django-v2-v3/testapp/migrations/__init__.py | 0 .../library-tests/frameworks/django-v2-v3/testapp/models.py | 0 .../library-tests/frameworks/django-v2-v3/testapp/tests.py | 0 .../library-tests/frameworks/django-v2-v3/testapp/urls.py | 0 .../library-tests/frameworks/django-v2-v3/testapp/views.py | 0 .../library-tests/frameworks/django-v2-v3/testproj/__init__.py | 0 .../library-tests/frameworks/django-v2-v3/testproj/asgi.py | 0 .../library-tests/frameworks/django-v2-v3/testproj/settings.py | 0 .../library-tests/frameworks/django-v2-v3/testproj/urls.py | 0 .../library-tests/frameworks/django-v2-v3/testproj/wsgi.py | 0 .../library-tests/frameworks/django/ConceptsTest.expected | 0 .../library-tests/frameworks/django/ConceptsTest.ql | 0 .../library-tests/frameworks/django/SqlExecution.py | 0 .../library-tests/frameworks/fabric/ConceptsTest.expected | 0 .../library-tests/frameworks/fabric/ConceptsTest.ql | 0 .../library-tests/frameworks/fabric/TestTaint.expected | 0 .../library-tests/frameworks/fabric/TestTaint.ql | 0 .../library-tests/frameworks/fabric/fabric_v1_execute.py | 0 .../library-tests/frameworks/fabric/fabric_v1_test.py | 0 .../library-tests/frameworks/fabric/fabric_v2_test.py | 0 .../library-tests/frameworks/flask/ConceptsTest.expected | 0 .../library-tests/frameworks/flask/ConceptsTest.ql | 0 .../library-tests/frameworks/flask/TestTaint.expected | 0 .../library-tests/frameworks/flask/TestTaint.ql | 0 .../library-tests/frameworks/flask/external_blueprint.py | 0 .../{experimental => }/library-tests/frameworks/flask/old_test.py | 0 .../library-tests/frameworks/flask/response_test.py | 0 .../library-tests/frameworks/flask/routing_test.py | 0 .../library-tests/frameworks/flask/taint_test.py | 0 .../library-tests/frameworks/invoke/ConceptsTest.expected | 0 .../library-tests/frameworks/invoke/ConceptsTest.ql | 0 .../library-tests/frameworks/invoke/invoke_test.py | 0 .../library-tests/frameworks/modeling-example/NaiveModel.expected | 0 .../library-tests/frameworks/modeling-example/NaiveModel.ql | 0 .../frameworks/modeling-example/ProperModel.expected | 0 .../library-tests/frameworks/modeling-example/ProperModel.ql | 0 .../library-tests/frameworks/modeling-example/README.md | 0 .../library-tests/frameworks/modeling-example/SharedCode.qll | 0 .../library-tests/frameworks/modeling-example/test.py | 0 .../frameworks/mysql-connector-python/ConceptsTest.expected | 0 .../frameworks/mysql-connector-python/ConceptsTest.ql | 0 .../library-tests/frameworks/mysql-connector-python/pep249.py | 0 .../library-tests/frameworks/mysqldb/ConceptsTest.expected | 0 .../library-tests/frameworks/mysqldb/ConceptsTest.ql | 0 .../{experimental => }/library-tests/frameworks/mysqldb/pep249.py | 0 .../library-tests/frameworks/pymysql/ConceptsTest.expected | 0 .../library-tests/frameworks/pymysql/ConceptsTest.ql | 0 .../{experimental => }/library-tests/frameworks/pymysql/pep249.py | 0 .../library-tests/frameworks/stdlib-py2/CodeExecution.py | 0 .../library-tests/frameworks/stdlib-py2/ConceptsTest.expected | 0 .../library-tests/frameworks/stdlib-py2/ConceptsTest.ql | 0 .../library-tests/frameworks/stdlib-py2/SystemCommandExecution.py | 0 .../library-tests/frameworks/stdlib-py2/options | 0 .../library-tests/frameworks/stdlib-py3/CodeExecution.py | 0 .../library-tests/frameworks/stdlib-py3/ConceptsTest.expected | 0 .../library-tests/frameworks/stdlib-py3/ConceptsTest.ql | 0 .../library-tests/frameworks/stdlib-py3/Decoding.py | 0 .../library-tests/frameworks/stdlib-py3/Encoding.py | 0 .../library-tests/frameworks/stdlib-py3/options | 0 .../library-tests/frameworks/stdlib/CodeExecution.py | 0 .../library-tests/frameworks/stdlib/CodeExecutionPossibleFP1.py | 0 .../library-tests/frameworks/stdlib/CodeExecutionPossibleFP2.py | 0 .../library-tests/frameworks/stdlib/CodeExecutionPossibleFP3.py | 0 .../library-tests/frameworks/stdlib/ConceptsTest.expected | 0 .../library-tests/frameworks/stdlib/ConceptsTest.ql | 0 .../library-tests/frameworks/stdlib/Decoding.py | 0 .../library-tests/frameworks/stdlib/Encoding.py | 0 .../library-tests/frameworks/stdlib/FileSystemAccess.py | 0 .../library-tests/frameworks/stdlib/PathNormalization.py | 0 .../library-tests/frameworks/stdlib/SafeAccessCheck.py | 0 .../library-tests/frameworks/stdlib/SystemCommandExecution.py | 0 .../library-tests/frameworks/stdlib/TestTaint.expected | 0 .../library-tests/frameworks/stdlib/TestTaint.ql | 0 .../library-tests/frameworks/stdlib/http_server.py | 0 .../{experimental => }/library-tests/frameworks/stdlib/pep249.py | 0 .../library-tests/frameworks/tornado/ConceptsTest.expected | 0 .../library-tests/frameworks/tornado/ConceptsTest.ql | 0 .../{experimental => }/library-tests/frameworks/tornado/README.md | 0 .../library-tests/frameworks/tornado/TestTaint.expected | 0 .../library-tests/frameworks/tornado/TestTaint.ql | 0 .../{experimental => }/library-tests/frameworks/tornado/basic.py | 0 .../{experimental => }/library-tests/frameworks/tornado/options | 0 .../library-tests/frameworks/tornado/response_test.py | 0 .../library-tests/frameworks/tornado/routing_test.py | 0 .../library-tests/frameworks/tornado/taint_test.py | 0 .../library-tests/frameworks/yaml/ConceptsTest.expected | 0 .../library-tests/frameworks/yaml/ConceptsTest.ql | 0 .../{experimental => }/library-tests/frameworks/yaml/Decoding.py | 0 123 files changed, 0 insertions(+), 0 deletions(-) rename python/ql/test/{experimental => }/library-tests/frameworks/crypto/ConceptsTest.expected (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/crypto/ConceptsTest.ql (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/crypto/test_dsa.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/crypto/test_ec.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/crypto/test_rsa.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/cryptodome/ConceptsTest.expected (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/cryptodome/ConceptsTest.ql (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/cryptodome/test_dsa.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/cryptodome/test_ec.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/cryptodome/test_rsa.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/cryptography/ConceptsTest.expected (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/cryptography/ConceptsTest.ql (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/cryptography/test_dsa.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/cryptography/test_ec.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/cryptography/test_rsa.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/dill/ConceptsTest.expected (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/dill/ConceptsTest.ql (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/dill/Decoding.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/django-v1/ConceptsTest.expected (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/django-v1/ConceptsTest.ql (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/django-v1/routing_test.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/django-v2-v3/ConceptsTest.expected (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/django-v2-v3/ConceptsTest.ql (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/django-v2-v3/README.md (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/django-v2-v3/TestTaint.expected (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/django-v2-v3/TestTaint.ql (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/django-v2-v3/dummy_import.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/django-v2-v3/manage.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/django-v2-v3/options (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/django-v2-v3/response_test.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/django-v2-v3/routing_test.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/django-v2-v3/taint_test.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/django-v2-v3/testapp/__init__.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/django-v2-v3/testapp/admin.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/django-v2-v3/testapp/apps.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/django-v2-v3/testapp/migrations/__init__.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/django-v2-v3/testapp/models.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/django-v2-v3/testapp/tests.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/django-v2-v3/testapp/urls.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/django-v2-v3/testapp/views.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/django-v2-v3/testproj/__init__.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/django-v2-v3/testproj/asgi.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/django-v2-v3/testproj/settings.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/django-v2-v3/testproj/urls.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/django-v2-v3/testproj/wsgi.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/django/ConceptsTest.expected (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/django/ConceptsTest.ql (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/django/SqlExecution.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/fabric/ConceptsTest.expected (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/fabric/ConceptsTest.ql (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/fabric/TestTaint.expected (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/fabric/TestTaint.ql (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/fabric/fabric_v1_execute.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/fabric/fabric_v1_test.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/fabric/fabric_v2_test.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/flask/ConceptsTest.expected (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/flask/ConceptsTest.ql (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/flask/TestTaint.expected (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/flask/TestTaint.ql (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/flask/external_blueprint.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/flask/old_test.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/flask/response_test.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/flask/routing_test.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/flask/taint_test.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/invoke/ConceptsTest.expected (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/invoke/ConceptsTest.ql (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/invoke/invoke_test.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/modeling-example/NaiveModel.expected (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/modeling-example/NaiveModel.ql (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/modeling-example/ProperModel.expected (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/modeling-example/ProperModel.ql (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/modeling-example/README.md (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/modeling-example/SharedCode.qll (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/modeling-example/test.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/mysql-connector-python/ConceptsTest.expected (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/mysql-connector-python/ConceptsTest.ql (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/mysql-connector-python/pep249.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/mysqldb/ConceptsTest.expected (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/mysqldb/ConceptsTest.ql (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/mysqldb/pep249.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/pymysql/ConceptsTest.expected (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/pymysql/ConceptsTest.ql (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/pymysql/pep249.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/stdlib-py2/CodeExecution.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/stdlib-py2/ConceptsTest.expected (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/stdlib-py2/ConceptsTest.ql (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/stdlib-py2/SystemCommandExecution.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/stdlib-py2/options (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/stdlib-py3/CodeExecution.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/stdlib-py3/ConceptsTest.expected (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/stdlib-py3/ConceptsTest.ql (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/stdlib-py3/Decoding.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/stdlib-py3/Encoding.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/stdlib-py3/options (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/stdlib/CodeExecution.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/stdlib/CodeExecutionPossibleFP1.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/stdlib/CodeExecutionPossibleFP2.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/stdlib/CodeExecutionPossibleFP3.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/stdlib/ConceptsTest.expected (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/stdlib/ConceptsTest.ql (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/stdlib/Decoding.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/stdlib/Encoding.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/stdlib/FileSystemAccess.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/stdlib/PathNormalization.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/stdlib/SafeAccessCheck.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/stdlib/SystemCommandExecution.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/stdlib/TestTaint.expected (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/stdlib/TestTaint.ql (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/stdlib/http_server.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/stdlib/pep249.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/tornado/ConceptsTest.expected (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/tornado/ConceptsTest.ql (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/tornado/README.md (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/tornado/TestTaint.expected (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/tornado/TestTaint.ql (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/tornado/basic.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/tornado/options (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/tornado/response_test.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/tornado/routing_test.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/tornado/taint_test.py (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/yaml/ConceptsTest.expected (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/yaml/ConceptsTest.ql (100%) rename python/ql/test/{experimental => }/library-tests/frameworks/yaml/Decoding.py (100%) diff --git a/python/ql/test/experimental/library-tests/frameworks/crypto/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/crypto/ConceptsTest.expected similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/crypto/ConceptsTest.expected rename to python/ql/test/library-tests/frameworks/crypto/ConceptsTest.expected diff --git a/python/ql/test/experimental/library-tests/frameworks/crypto/ConceptsTest.ql b/python/ql/test/library-tests/frameworks/crypto/ConceptsTest.ql similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/crypto/ConceptsTest.ql rename to python/ql/test/library-tests/frameworks/crypto/ConceptsTest.ql diff --git a/python/ql/test/experimental/library-tests/frameworks/crypto/test_dsa.py b/python/ql/test/library-tests/frameworks/crypto/test_dsa.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/crypto/test_dsa.py rename to python/ql/test/library-tests/frameworks/crypto/test_dsa.py diff --git a/python/ql/test/experimental/library-tests/frameworks/crypto/test_ec.py b/python/ql/test/library-tests/frameworks/crypto/test_ec.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/crypto/test_ec.py rename to python/ql/test/library-tests/frameworks/crypto/test_ec.py diff --git a/python/ql/test/experimental/library-tests/frameworks/crypto/test_rsa.py b/python/ql/test/library-tests/frameworks/crypto/test_rsa.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/crypto/test_rsa.py rename to python/ql/test/library-tests/frameworks/crypto/test_rsa.py diff --git a/python/ql/test/experimental/library-tests/frameworks/cryptodome/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/cryptodome/ConceptsTest.expected similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/cryptodome/ConceptsTest.expected rename to python/ql/test/library-tests/frameworks/cryptodome/ConceptsTest.expected diff --git a/python/ql/test/experimental/library-tests/frameworks/cryptodome/ConceptsTest.ql b/python/ql/test/library-tests/frameworks/cryptodome/ConceptsTest.ql similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/cryptodome/ConceptsTest.ql rename to python/ql/test/library-tests/frameworks/cryptodome/ConceptsTest.ql diff --git a/python/ql/test/experimental/library-tests/frameworks/cryptodome/test_dsa.py b/python/ql/test/library-tests/frameworks/cryptodome/test_dsa.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/cryptodome/test_dsa.py rename to python/ql/test/library-tests/frameworks/cryptodome/test_dsa.py diff --git a/python/ql/test/experimental/library-tests/frameworks/cryptodome/test_ec.py b/python/ql/test/library-tests/frameworks/cryptodome/test_ec.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/cryptodome/test_ec.py rename to python/ql/test/library-tests/frameworks/cryptodome/test_ec.py diff --git a/python/ql/test/experimental/library-tests/frameworks/cryptodome/test_rsa.py b/python/ql/test/library-tests/frameworks/cryptodome/test_rsa.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/cryptodome/test_rsa.py rename to python/ql/test/library-tests/frameworks/cryptodome/test_rsa.py diff --git a/python/ql/test/experimental/library-tests/frameworks/cryptography/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/cryptography/ConceptsTest.expected similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/cryptography/ConceptsTest.expected rename to python/ql/test/library-tests/frameworks/cryptography/ConceptsTest.expected diff --git a/python/ql/test/experimental/library-tests/frameworks/cryptography/ConceptsTest.ql b/python/ql/test/library-tests/frameworks/cryptography/ConceptsTest.ql similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/cryptography/ConceptsTest.ql rename to python/ql/test/library-tests/frameworks/cryptography/ConceptsTest.ql diff --git a/python/ql/test/experimental/library-tests/frameworks/cryptography/test_dsa.py b/python/ql/test/library-tests/frameworks/cryptography/test_dsa.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/cryptography/test_dsa.py rename to python/ql/test/library-tests/frameworks/cryptography/test_dsa.py diff --git a/python/ql/test/experimental/library-tests/frameworks/cryptography/test_ec.py b/python/ql/test/library-tests/frameworks/cryptography/test_ec.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/cryptography/test_ec.py rename to python/ql/test/library-tests/frameworks/cryptography/test_ec.py diff --git a/python/ql/test/experimental/library-tests/frameworks/cryptography/test_rsa.py b/python/ql/test/library-tests/frameworks/cryptography/test_rsa.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/cryptography/test_rsa.py rename to python/ql/test/library-tests/frameworks/cryptography/test_rsa.py diff --git a/python/ql/test/experimental/library-tests/frameworks/dill/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/dill/ConceptsTest.expected similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/dill/ConceptsTest.expected rename to python/ql/test/library-tests/frameworks/dill/ConceptsTest.expected diff --git a/python/ql/test/experimental/library-tests/frameworks/dill/ConceptsTest.ql b/python/ql/test/library-tests/frameworks/dill/ConceptsTest.ql similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/dill/ConceptsTest.ql rename to python/ql/test/library-tests/frameworks/dill/ConceptsTest.ql diff --git a/python/ql/test/experimental/library-tests/frameworks/dill/Decoding.py b/python/ql/test/library-tests/frameworks/dill/Decoding.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/dill/Decoding.py rename to python/ql/test/library-tests/frameworks/dill/Decoding.py diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v1/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/django-v1/ConceptsTest.expected similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/django-v1/ConceptsTest.expected rename to python/ql/test/library-tests/frameworks/django-v1/ConceptsTest.expected diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v1/ConceptsTest.ql b/python/ql/test/library-tests/frameworks/django-v1/ConceptsTest.ql similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/django-v1/ConceptsTest.ql rename to python/ql/test/library-tests/frameworks/django-v1/ConceptsTest.ql diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v1/routing_test.py b/python/ql/test/library-tests/frameworks/django-v1/routing_test.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/django-v1/routing_test.py rename to python/ql/test/library-tests/frameworks/django-v1/routing_test.py diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/django-v2-v3/ConceptsTest.expected similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/django-v2-v3/ConceptsTest.expected rename to python/ql/test/library-tests/frameworks/django-v2-v3/ConceptsTest.expected diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/ConceptsTest.ql b/python/ql/test/library-tests/frameworks/django-v2-v3/ConceptsTest.ql similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/django-v2-v3/ConceptsTest.ql rename to python/ql/test/library-tests/frameworks/django-v2-v3/ConceptsTest.ql diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/README.md b/python/ql/test/library-tests/frameworks/django-v2-v3/README.md similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/django-v2-v3/README.md rename to python/ql/test/library-tests/frameworks/django-v2-v3/README.md diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/TestTaint.expected b/python/ql/test/library-tests/frameworks/django-v2-v3/TestTaint.expected similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/django-v2-v3/TestTaint.expected rename to python/ql/test/library-tests/frameworks/django-v2-v3/TestTaint.expected diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/TestTaint.ql b/python/ql/test/library-tests/frameworks/django-v2-v3/TestTaint.ql similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/django-v2-v3/TestTaint.ql rename to python/ql/test/library-tests/frameworks/django-v2-v3/TestTaint.ql diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/dummy_import.py b/python/ql/test/library-tests/frameworks/django-v2-v3/dummy_import.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/django-v2-v3/dummy_import.py rename to python/ql/test/library-tests/frameworks/django-v2-v3/dummy_import.py diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/manage.py b/python/ql/test/library-tests/frameworks/django-v2-v3/manage.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/django-v2-v3/manage.py rename to python/ql/test/library-tests/frameworks/django-v2-v3/manage.py diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/options b/python/ql/test/library-tests/frameworks/django-v2-v3/options similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/django-v2-v3/options rename to python/ql/test/library-tests/frameworks/django-v2-v3/options diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/response_test.py b/python/ql/test/library-tests/frameworks/django-v2-v3/response_test.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/django-v2-v3/response_test.py rename to python/ql/test/library-tests/frameworks/django-v2-v3/response_test.py diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/routing_test.py b/python/ql/test/library-tests/frameworks/django-v2-v3/routing_test.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/django-v2-v3/routing_test.py rename to python/ql/test/library-tests/frameworks/django-v2-v3/routing_test.py diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/taint_test.py b/python/ql/test/library-tests/frameworks/django-v2-v3/taint_test.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/django-v2-v3/taint_test.py rename to python/ql/test/library-tests/frameworks/django-v2-v3/taint_test.py diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/__init__.py b/python/ql/test/library-tests/frameworks/django-v2-v3/testapp/__init__.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/__init__.py rename to python/ql/test/library-tests/frameworks/django-v2-v3/testapp/__init__.py diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/admin.py b/python/ql/test/library-tests/frameworks/django-v2-v3/testapp/admin.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/admin.py rename to python/ql/test/library-tests/frameworks/django-v2-v3/testapp/admin.py diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/apps.py b/python/ql/test/library-tests/frameworks/django-v2-v3/testapp/apps.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/apps.py rename to python/ql/test/library-tests/frameworks/django-v2-v3/testapp/apps.py diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/migrations/__init__.py b/python/ql/test/library-tests/frameworks/django-v2-v3/testapp/migrations/__init__.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/migrations/__init__.py rename to python/ql/test/library-tests/frameworks/django-v2-v3/testapp/migrations/__init__.py diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/models.py b/python/ql/test/library-tests/frameworks/django-v2-v3/testapp/models.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/models.py rename to python/ql/test/library-tests/frameworks/django-v2-v3/testapp/models.py diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/tests.py b/python/ql/test/library-tests/frameworks/django-v2-v3/testapp/tests.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/tests.py rename to python/ql/test/library-tests/frameworks/django-v2-v3/testapp/tests.py diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/urls.py b/python/ql/test/library-tests/frameworks/django-v2-v3/testapp/urls.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/urls.py rename to python/ql/test/library-tests/frameworks/django-v2-v3/testapp/urls.py diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/views.py b/python/ql/test/library-tests/frameworks/django-v2-v3/testapp/views.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/views.py rename to python/ql/test/library-tests/frameworks/django-v2-v3/testapp/views.py diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testproj/__init__.py b/python/ql/test/library-tests/frameworks/django-v2-v3/testproj/__init__.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testproj/__init__.py rename to python/ql/test/library-tests/frameworks/django-v2-v3/testproj/__init__.py diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testproj/asgi.py b/python/ql/test/library-tests/frameworks/django-v2-v3/testproj/asgi.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testproj/asgi.py rename to python/ql/test/library-tests/frameworks/django-v2-v3/testproj/asgi.py diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testproj/settings.py b/python/ql/test/library-tests/frameworks/django-v2-v3/testproj/settings.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testproj/settings.py rename to python/ql/test/library-tests/frameworks/django-v2-v3/testproj/settings.py diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testproj/urls.py b/python/ql/test/library-tests/frameworks/django-v2-v3/testproj/urls.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testproj/urls.py rename to python/ql/test/library-tests/frameworks/django-v2-v3/testproj/urls.py diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testproj/wsgi.py b/python/ql/test/library-tests/frameworks/django-v2-v3/testproj/wsgi.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testproj/wsgi.py rename to python/ql/test/library-tests/frameworks/django-v2-v3/testproj/wsgi.py diff --git a/python/ql/test/experimental/library-tests/frameworks/django/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/django/ConceptsTest.expected similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/django/ConceptsTest.expected rename to python/ql/test/library-tests/frameworks/django/ConceptsTest.expected diff --git a/python/ql/test/experimental/library-tests/frameworks/django/ConceptsTest.ql b/python/ql/test/library-tests/frameworks/django/ConceptsTest.ql similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/django/ConceptsTest.ql rename to python/ql/test/library-tests/frameworks/django/ConceptsTest.ql diff --git a/python/ql/test/experimental/library-tests/frameworks/django/SqlExecution.py b/python/ql/test/library-tests/frameworks/django/SqlExecution.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/django/SqlExecution.py rename to python/ql/test/library-tests/frameworks/django/SqlExecution.py diff --git a/python/ql/test/experimental/library-tests/frameworks/fabric/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/fabric/ConceptsTest.expected similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/fabric/ConceptsTest.expected rename to python/ql/test/library-tests/frameworks/fabric/ConceptsTest.expected diff --git a/python/ql/test/experimental/library-tests/frameworks/fabric/ConceptsTest.ql b/python/ql/test/library-tests/frameworks/fabric/ConceptsTest.ql similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/fabric/ConceptsTest.ql rename to python/ql/test/library-tests/frameworks/fabric/ConceptsTest.ql diff --git a/python/ql/test/experimental/library-tests/frameworks/fabric/TestTaint.expected b/python/ql/test/library-tests/frameworks/fabric/TestTaint.expected similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/fabric/TestTaint.expected rename to python/ql/test/library-tests/frameworks/fabric/TestTaint.expected diff --git a/python/ql/test/experimental/library-tests/frameworks/fabric/TestTaint.ql b/python/ql/test/library-tests/frameworks/fabric/TestTaint.ql similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/fabric/TestTaint.ql rename to python/ql/test/library-tests/frameworks/fabric/TestTaint.ql diff --git a/python/ql/test/experimental/library-tests/frameworks/fabric/fabric_v1_execute.py b/python/ql/test/library-tests/frameworks/fabric/fabric_v1_execute.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/fabric/fabric_v1_execute.py rename to python/ql/test/library-tests/frameworks/fabric/fabric_v1_execute.py diff --git a/python/ql/test/experimental/library-tests/frameworks/fabric/fabric_v1_test.py b/python/ql/test/library-tests/frameworks/fabric/fabric_v1_test.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/fabric/fabric_v1_test.py rename to python/ql/test/library-tests/frameworks/fabric/fabric_v1_test.py diff --git a/python/ql/test/experimental/library-tests/frameworks/fabric/fabric_v2_test.py b/python/ql/test/library-tests/frameworks/fabric/fabric_v2_test.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/fabric/fabric_v2_test.py rename to python/ql/test/library-tests/frameworks/fabric/fabric_v2_test.py diff --git a/python/ql/test/experimental/library-tests/frameworks/flask/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/flask/ConceptsTest.expected similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/flask/ConceptsTest.expected rename to python/ql/test/library-tests/frameworks/flask/ConceptsTest.expected diff --git a/python/ql/test/experimental/library-tests/frameworks/flask/ConceptsTest.ql b/python/ql/test/library-tests/frameworks/flask/ConceptsTest.ql similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/flask/ConceptsTest.ql rename to python/ql/test/library-tests/frameworks/flask/ConceptsTest.ql diff --git a/python/ql/test/experimental/library-tests/frameworks/flask/TestTaint.expected b/python/ql/test/library-tests/frameworks/flask/TestTaint.expected similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/flask/TestTaint.expected rename to python/ql/test/library-tests/frameworks/flask/TestTaint.expected diff --git a/python/ql/test/experimental/library-tests/frameworks/flask/TestTaint.ql b/python/ql/test/library-tests/frameworks/flask/TestTaint.ql similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/flask/TestTaint.ql rename to python/ql/test/library-tests/frameworks/flask/TestTaint.ql diff --git a/python/ql/test/experimental/library-tests/frameworks/flask/external_blueprint.py b/python/ql/test/library-tests/frameworks/flask/external_blueprint.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/flask/external_blueprint.py rename to python/ql/test/library-tests/frameworks/flask/external_blueprint.py diff --git a/python/ql/test/experimental/library-tests/frameworks/flask/old_test.py b/python/ql/test/library-tests/frameworks/flask/old_test.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/flask/old_test.py rename to python/ql/test/library-tests/frameworks/flask/old_test.py diff --git a/python/ql/test/experimental/library-tests/frameworks/flask/response_test.py b/python/ql/test/library-tests/frameworks/flask/response_test.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/flask/response_test.py rename to python/ql/test/library-tests/frameworks/flask/response_test.py diff --git a/python/ql/test/experimental/library-tests/frameworks/flask/routing_test.py b/python/ql/test/library-tests/frameworks/flask/routing_test.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/flask/routing_test.py rename to python/ql/test/library-tests/frameworks/flask/routing_test.py diff --git a/python/ql/test/experimental/library-tests/frameworks/flask/taint_test.py b/python/ql/test/library-tests/frameworks/flask/taint_test.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/flask/taint_test.py rename to python/ql/test/library-tests/frameworks/flask/taint_test.py diff --git a/python/ql/test/experimental/library-tests/frameworks/invoke/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/invoke/ConceptsTest.expected similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/invoke/ConceptsTest.expected rename to python/ql/test/library-tests/frameworks/invoke/ConceptsTest.expected diff --git a/python/ql/test/experimental/library-tests/frameworks/invoke/ConceptsTest.ql b/python/ql/test/library-tests/frameworks/invoke/ConceptsTest.ql similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/invoke/ConceptsTest.ql rename to python/ql/test/library-tests/frameworks/invoke/ConceptsTest.ql diff --git a/python/ql/test/experimental/library-tests/frameworks/invoke/invoke_test.py b/python/ql/test/library-tests/frameworks/invoke/invoke_test.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/invoke/invoke_test.py rename to python/ql/test/library-tests/frameworks/invoke/invoke_test.py diff --git a/python/ql/test/experimental/library-tests/frameworks/modeling-example/NaiveModel.expected b/python/ql/test/library-tests/frameworks/modeling-example/NaiveModel.expected similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/modeling-example/NaiveModel.expected rename to python/ql/test/library-tests/frameworks/modeling-example/NaiveModel.expected diff --git a/python/ql/test/experimental/library-tests/frameworks/modeling-example/NaiveModel.ql b/python/ql/test/library-tests/frameworks/modeling-example/NaiveModel.ql similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/modeling-example/NaiveModel.ql rename to python/ql/test/library-tests/frameworks/modeling-example/NaiveModel.ql diff --git a/python/ql/test/experimental/library-tests/frameworks/modeling-example/ProperModel.expected b/python/ql/test/library-tests/frameworks/modeling-example/ProperModel.expected similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/modeling-example/ProperModel.expected rename to python/ql/test/library-tests/frameworks/modeling-example/ProperModel.expected diff --git a/python/ql/test/experimental/library-tests/frameworks/modeling-example/ProperModel.ql b/python/ql/test/library-tests/frameworks/modeling-example/ProperModel.ql similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/modeling-example/ProperModel.ql rename to python/ql/test/library-tests/frameworks/modeling-example/ProperModel.ql diff --git a/python/ql/test/experimental/library-tests/frameworks/modeling-example/README.md b/python/ql/test/library-tests/frameworks/modeling-example/README.md similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/modeling-example/README.md rename to python/ql/test/library-tests/frameworks/modeling-example/README.md diff --git a/python/ql/test/experimental/library-tests/frameworks/modeling-example/SharedCode.qll b/python/ql/test/library-tests/frameworks/modeling-example/SharedCode.qll similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/modeling-example/SharedCode.qll rename to python/ql/test/library-tests/frameworks/modeling-example/SharedCode.qll diff --git a/python/ql/test/experimental/library-tests/frameworks/modeling-example/test.py b/python/ql/test/library-tests/frameworks/modeling-example/test.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/modeling-example/test.py rename to python/ql/test/library-tests/frameworks/modeling-example/test.py diff --git a/python/ql/test/experimental/library-tests/frameworks/mysql-connector-python/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/mysql-connector-python/ConceptsTest.expected similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/mysql-connector-python/ConceptsTest.expected rename to python/ql/test/library-tests/frameworks/mysql-connector-python/ConceptsTest.expected diff --git a/python/ql/test/experimental/library-tests/frameworks/mysql-connector-python/ConceptsTest.ql b/python/ql/test/library-tests/frameworks/mysql-connector-python/ConceptsTest.ql similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/mysql-connector-python/ConceptsTest.ql rename to python/ql/test/library-tests/frameworks/mysql-connector-python/ConceptsTest.ql diff --git a/python/ql/test/experimental/library-tests/frameworks/mysql-connector-python/pep249.py b/python/ql/test/library-tests/frameworks/mysql-connector-python/pep249.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/mysql-connector-python/pep249.py rename to python/ql/test/library-tests/frameworks/mysql-connector-python/pep249.py diff --git a/python/ql/test/experimental/library-tests/frameworks/mysqldb/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/mysqldb/ConceptsTest.expected similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/mysqldb/ConceptsTest.expected rename to python/ql/test/library-tests/frameworks/mysqldb/ConceptsTest.expected diff --git a/python/ql/test/experimental/library-tests/frameworks/mysqldb/ConceptsTest.ql b/python/ql/test/library-tests/frameworks/mysqldb/ConceptsTest.ql similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/mysqldb/ConceptsTest.ql rename to python/ql/test/library-tests/frameworks/mysqldb/ConceptsTest.ql diff --git a/python/ql/test/experimental/library-tests/frameworks/mysqldb/pep249.py b/python/ql/test/library-tests/frameworks/mysqldb/pep249.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/mysqldb/pep249.py rename to python/ql/test/library-tests/frameworks/mysqldb/pep249.py diff --git a/python/ql/test/experimental/library-tests/frameworks/pymysql/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/pymysql/ConceptsTest.expected similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/pymysql/ConceptsTest.expected rename to python/ql/test/library-tests/frameworks/pymysql/ConceptsTest.expected diff --git a/python/ql/test/experimental/library-tests/frameworks/pymysql/ConceptsTest.ql b/python/ql/test/library-tests/frameworks/pymysql/ConceptsTest.ql similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/pymysql/ConceptsTest.ql rename to python/ql/test/library-tests/frameworks/pymysql/ConceptsTest.ql diff --git a/python/ql/test/experimental/library-tests/frameworks/pymysql/pep249.py b/python/ql/test/library-tests/frameworks/pymysql/pep249.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/pymysql/pep249.py rename to python/ql/test/library-tests/frameworks/pymysql/pep249.py diff --git a/python/ql/test/experimental/library-tests/frameworks/stdlib-py2/CodeExecution.py b/python/ql/test/library-tests/frameworks/stdlib-py2/CodeExecution.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/stdlib-py2/CodeExecution.py rename to python/ql/test/library-tests/frameworks/stdlib-py2/CodeExecution.py diff --git a/python/ql/test/experimental/library-tests/frameworks/stdlib-py2/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/stdlib-py2/ConceptsTest.expected similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/stdlib-py2/ConceptsTest.expected rename to python/ql/test/library-tests/frameworks/stdlib-py2/ConceptsTest.expected diff --git a/python/ql/test/experimental/library-tests/frameworks/stdlib-py2/ConceptsTest.ql b/python/ql/test/library-tests/frameworks/stdlib-py2/ConceptsTest.ql similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/stdlib-py2/ConceptsTest.ql rename to python/ql/test/library-tests/frameworks/stdlib-py2/ConceptsTest.ql diff --git a/python/ql/test/experimental/library-tests/frameworks/stdlib-py2/SystemCommandExecution.py b/python/ql/test/library-tests/frameworks/stdlib-py2/SystemCommandExecution.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/stdlib-py2/SystemCommandExecution.py rename to python/ql/test/library-tests/frameworks/stdlib-py2/SystemCommandExecution.py diff --git a/python/ql/test/experimental/library-tests/frameworks/stdlib-py2/options b/python/ql/test/library-tests/frameworks/stdlib-py2/options similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/stdlib-py2/options rename to python/ql/test/library-tests/frameworks/stdlib-py2/options diff --git a/python/ql/test/experimental/library-tests/frameworks/stdlib-py3/CodeExecution.py b/python/ql/test/library-tests/frameworks/stdlib-py3/CodeExecution.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/stdlib-py3/CodeExecution.py rename to python/ql/test/library-tests/frameworks/stdlib-py3/CodeExecution.py diff --git a/python/ql/test/experimental/library-tests/frameworks/stdlib-py3/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/stdlib-py3/ConceptsTest.expected similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/stdlib-py3/ConceptsTest.expected rename to python/ql/test/library-tests/frameworks/stdlib-py3/ConceptsTest.expected diff --git a/python/ql/test/experimental/library-tests/frameworks/stdlib-py3/ConceptsTest.ql b/python/ql/test/library-tests/frameworks/stdlib-py3/ConceptsTest.ql similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/stdlib-py3/ConceptsTest.ql rename to python/ql/test/library-tests/frameworks/stdlib-py3/ConceptsTest.ql diff --git a/python/ql/test/experimental/library-tests/frameworks/stdlib-py3/Decoding.py b/python/ql/test/library-tests/frameworks/stdlib-py3/Decoding.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/stdlib-py3/Decoding.py rename to python/ql/test/library-tests/frameworks/stdlib-py3/Decoding.py diff --git a/python/ql/test/experimental/library-tests/frameworks/stdlib-py3/Encoding.py b/python/ql/test/library-tests/frameworks/stdlib-py3/Encoding.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/stdlib-py3/Encoding.py rename to python/ql/test/library-tests/frameworks/stdlib-py3/Encoding.py diff --git a/python/ql/test/experimental/library-tests/frameworks/stdlib-py3/options b/python/ql/test/library-tests/frameworks/stdlib-py3/options similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/stdlib-py3/options rename to python/ql/test/library-tests/frameworks/stdlib-py3/options diff --git a/python/ql/test/experimental/library-tests/frameworks/stdlib/CodeExecution.py b/python/ql/test/library-tests/frameworks/stdlib/CodeExecution.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/stdlib/CodeExecution.py rename to python/ql/test/library-tests/frameworks/stdlib/CodeExecution.py diff --git a/python/ql/test/experimental/library-tests/frameworks/stdlib/CodeExecutionPossibleFP1.py b/python/ql/test/library-tests/frameworks/stdlib/CodeExecutionPossibleFP1.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/stdlib/CodeExecutionPossibleFP1.py rename to python/ql/test/library-tests/frameworks/stdlib/CodeExecutionPossibleFP1.py diff --git a/python/ql/test/experimental/library-tests/frameworks/stdlib/CodeExecutionPossibleFP2.py b/python/ql/test/library-tests/frameworks/stdlib/CodeExecutionPossibleFP2.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/stdlib/CodeExecutionPossibleFP2.py rename to python/ql/test/library-tests/frameworks/stdlib/CodeExecutionPossibleFP2.py diff --git a/python/ql/test/experimental/library-tests/frameworks/stdlib/CodeExecutionPossibleFP3.py b/python/ql/test/library-tests/frameworks/stdlib/CodeExecutionPossibleFP3.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/stdlib/CodeExecutionPossibleFP3.py rename to python/ql/test/library-tests/frameworks/stdlib/CodeExecutionPossibleFP3.py diff --git a/python/ql/test/experimental/library-tests/frameworks/stdlib/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/stdlib/ConceptsTest.expected similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/stdlib/ConceptsTest.expected rename to python/ql/test/library-tests/frameworks/stdlib/ConceptsTest.expected diff --git a/python/ql/test/experimental/library-tests/frameworks/stdlib/ConceptsTest.ql b/python/ql/test/library-tests/frameworks/stdlib/ConceptsTest.ql similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/stdlib/ConceptsTest.ql rename to python/ql/test/library-tests/frameworks/stdlib/ConceptsTest.ql diff --git a/python/ql/test/experimental/library-tests/frameworks/stdlib/Decoding.py b/python/ql/test/library-tests/frameworks/stdlib/Decoding.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/stdlib/Decoding.py rename to python/ql/test/library-tests/frameworks/stdlib/Decoding.py diff --git a/python/ql/test/experimental/library-tests/frameworks/stdlib/Encoding.py b/python/ql/test/library-tests/frameworks/stdlib/Encoding.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/stdlib/Encoding.py rename to python/ql/test/library-tests/frameworks/stdlib/Encoding.py diff --git a/python/ql/test/experimental/library-tests/frameworks/stdlib/FileSystemAccess.py b/python/ql/test/library-tests/frameworks/stdlib/FileSystemAccess.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/stdlib/FileSystemAccess.py rename to python/ql/test/library-tests/frameworks/stdlib/FileSystemAccess.py diff --git a/python/ql/test/experimental/library-tests/frameworks/stdlib/PathNormalization.py b/python/ql/test/library-tests/frameworks/stdlib/PathNormalization.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/stdlib/PathNormalization.py rename to python/ql/test/library-tests/frameworks/stdlib/PathNormalization.py diff --git a/python/ql/test/experimental/library-tests/frameworks/stdlib/SafeAccessCheck.py b/python/ql/test/library-tests/frameworks/stdlib/SafeAccessCheck.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/stdlib/SafeAccessCheck.py rename to python/ql/test/library-tests/frameworks/stdlib/SafeAccessCheck.py diff --git a/python/ql/test/experimental/library-tests/frameworks/stdlib/SystemCommandExecution.py b/python/ql/test/library-tests/frameworks/stdlib/SystemCommandExecution.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/stdlib/SystemCommandExecution.py rename to python/ql/test/library-tests/frameworks/stdlib/SystemCommandExecution.py diff --git a/python/ql/test/experimental/library-tests/frameworks/stdlib/TestTaint.expected b/python/ql/test/library-tests/frameworks/stdlib/TestTaint.expected similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/stdlib/TestTaint.expected rename to python/ql/test/library-tests/frameworks/stdlib/TestTaint.expected diff --git a/python/ql/test/experimental/library-tests/frameworks/stdlib/TestTaint.ql b/python/ql/test/library-tests/frameworks/stdlib/TestTaint.ql similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/stdlib/TestTaint.ql rename to python/ql/test/library-tests/frameworks/stdlib/TestTaint.ql diff --git a/python/ql/test/experimental/library-tests/frameworks/stdlib/http_server.py b/python/ql/test/library-tests/frameworks/stdlib/http_server.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/stdlib/http_server.py rename to python/ql/test/library-tests/frameworks/stdlib/http_server.py diff --git a/python/ql/test/experimental/library-tests/frameworks/stdlib/pep249.py b/python/ql/test/library-tests/frameworks/stdlib/pep249.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/stdlib/pep249.py rename to python/ql/test/library-tests/frameworks/stdlib/pep249.py diff --git a/python/ql/test/experimental/library-tests/frameworks/tornado/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/tornado/ConceptsTest.expected similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/tornado/ConceptsTest.expected rename to python/ql/test/library-tests/frameworks/tornado/ConceptsTest.expected diff --git a/python/ql/test/experimental/library-tests/frameworks/tornado/ConceptsTest.ql b/python/ql/test/library-tests/frameworks/tornado/ConceptsTest.ql similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/tornado/ConceptsTest.ql rename to python/ql/test/library-tests/frameworks/tornado/ConceptsTest.ql diff --git a/python/ql/test/experimental/library-tests/frameworks/tornado/README.md b/python/ql/test/library-tests/frameworks/tornado/README.md similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/tornado/README.md rename to python/ql/test/library-tests/frameworks/tornado/README.md diff --git a/python/ql/test/experimental/library-tests/frameworks/tornado/TestTaint.expected b/python/ql/test/library-tests/frameworks/tornado/TestTaint.expected similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/tornado/TestTaint.expected rename to python/ql/test/library-tests/frameworks/tornado/TestTaint.expected diff --git a/python/ql/test/experimental/library-tests/frameworks/tornado/TestTaint.ql b/python/ql/test/library-tests/frameworks/tornado/TestTaint.ql similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/tornado/TestTaint.ql rename to python/ql/test/library-tests/frameworks/tornado/TestTaint.ql diff --git a/python/ql/test/experimental/library-tests/frameworks/tornado/basic.py b/python/ql/test/library-tests/frameworks/tornado/basic.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/tornado/basic.py rename to python/ql/test/library-tests/frameworks/tornado/basic.py diff --git a/python/ql/test/experimental/library-tests/frameworks/tornado/options b/python/ql/test/library-tests/frameworks/tornado/options similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/tornado/options rename to python/ql/test/library-tests/frameworks/tornado/options diff --git a/python/ql/test/experimental/library-tests/frameworks/tornado/response_test.py b/python/ql/test/library-tests/frameworks/tornado/response_test.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/tornado/response_test.py rename to python/ql/test/library-tests/frameworks/tornado/response_test.py diff --git a/python/ql/test/experimental/library-tests/frameworks/tornado/routing_test.py b/python/ql/test/library-tests/frameworks/tornado/routing_test.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/tornado/routing_test.py rename to python/ql/test/library-tests/frameworks/tornado/routing_test.py diff --git a/python/ql/test/experimental/library-tests/frameworks/tornado/taint_test.py b/python/ql/test/library-tests/frameworks/tornado/taint_test.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/tornado/taint_test.py rename to python/ql/test/library-tests/frameworks/tornado/taint_test.py diff --git a/python/ql/test/experimental/library-tests/frameworks/yaml/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/yaml/ConceptsTest.expected similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/yaml/ConceptsTest.expected rename to python/ql/test/library-tests/frameworks/yaml/ConceptsTest.expected diff --git a/python/ql/test/experimental/library-tests/frameworks/yaml/ConceptsTest.ql b/python/ql/test/library-tests/frameworks/yaml/ConceptsTest.ql similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/yaml/ConceptsTest.ql rename to python/ql/test/library-tests/frameworks/yaml/ConceptsTest.ql diff --git a/python/ql/test/experimental/library-tests/frameworks/yaml/Decoding.py b/python/ql/test/library-tests/frameworks/yaml/Decoding.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/yaml/Decoding.py rename to python/ql/test/library-tests/frameworks/yaml/Decoding.py From 8949b9eb0a659765640c13ada6755bc86c21388d Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 19 Mar 2021 15:59:06 +0100 Subject: [PATCH 202/725] add shell interpreted arrays as sinks for js/shell-command-constructed-from-input --- ...ShellCommandConstructionCustomizations.qll | 47 +++++++++++++ .../UnsafeShellCommandConstruction.expected | 69 +++++++++++++++++++ .../Security/CWE-078/UselessUseOfCat.expected | 9 +++ .../query-tests/Security/CWE-078/lib/lib.js | 28 ++++++++ 4 files changed, 153 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/UnsafeShellCommandConstructionCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/UnsafeShellCommandConstructionCustomizations.qll index 32eda1db8de..ac5f8e2c56b 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/UnsafeShellCommandConstructionCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/UnsafeShellCommandConstructionCustomizations.qll @@ -143,6 +143,53 @@ module UnsafeShellCommandConstruction { override DataFlow::Node getAlertLocation() { result = this } } + /** + * Gets a node that ends up in an array that is ultimately executed as a shell script by `sys`. + */ + private DataFlow::SourceNode endsInShellExecutedArray( + DataFlow::TypeBackTracker t, SystemCommandExecution sys + ) { + t.start() and + result = sys.getArgumentList().getALocalSource() and + // the array gets joined to a string when `shell` is set to true. + sys.getOptionsArg() + .getALocalSource() + .getAPropertyWrite("shell") + .getRhs() + .asExpr() + .(BooleanLiteral) + .getValue() = "true" + or + exists(DataFlow::TypeBackTracker t2 | + result = endsInShellExecutedArray(t2, sys).backtrack(t2, t) + ) + } + + /** + * An argument to a command invocation where the `shell` option is set to true. + */ + class ShellTrueCommandExecutionSink extends Sink { + SystemCommandExecution sys; + + ShellTrueCommandExecutionSink() { + // `shell` is set to true. That means string-concatenation happens behind the scenes. + // We just assume that a `shell` option in any library means the same thing as it does in NodeJS. + exists(DataFlow::SourceNode arr | + arr = endsInShellExecutedArray(DataFlow::TypeBackTracker::end(), sys) + | + this = arr.(DataFlow::ArrayCreationNode).getAnElement() + or + this = arr.getAMethodCall(["push", "unshift"]).getAnArgument() + ) + } + + override string getSinkType() { result = "Shell argument" } + + override SystemCommandExecution getCommandExecution() { result = sys } + + override DataFlow::Node getAlertLocation() { result = this } + } + /** * A sanitizer like: "'"+name.replace(/'/g,"'\\''")+"'" * Which sanitizes on Unix. diff --git a/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction.expected b/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction.expected index 2d707e1a693..de59b2e9cde 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction.expected @@ -205,6 +205,30 @@ nodes | lib/lib.js:405:39:405:42 | name | | lib/lib.js:406:22:406:25 | name | | lib/lib.js:406:22:406:25 | name | +| lib/lib.js:414:40:414:43 | name | +| lib/lib.js:414:40:414:43 | name | +| lib/lib.js:415:22:415:25 | name | +| lib/lib.js:415:22:415:25 | name | +| lib/lib.js:417:28:417:31 | name | +| lib/lib.js:417:28:417:31 | name | +| lib/lib.js:418:25:418:28 | name | +| lib/lib.js:418:25:418:28 | name | +| lib/lib.js:419:32:419:35 | name | +| lib/lib.js:419:32:419:35 | name | +| lib/lib.js:420:29:420:32 | name | +| lib/lib.js:420:29:420:32 | name | +| lib/lib.js:424:24:424:27 | name | +| lib/lib.js:424:24:424:27 | name | +| lib/lib.js:426:11:426:14 | name | +| lib/lib.js:426:11:426:14 | name | +| lib/lib.js:428:28:428:51 | (name ? ... ' : '') | +| lib/lib.js:428:28:428:57 | (name ? ... ) + '-' | +| lib/lib.js:428:29:428:50 | name ? ... :' : '' | +| lib/lib.js:428:36:428:39 | name | +| lib/lib.js:428:36:428:45 | name + ':' | +| lib/lib.js:431:23:431:26 | last | +| lib/lib.js:436:19:436:22 | last | +| lib/lib.js:436:19:436:22 | last | edges | lib/lib2.js:3:28:3:31 | name | lib/lib2.js:4:22:4:25 | name | | lib/lib2.js:3:28:3:31 | name | lib/lib2.js:4:22:4:25 | name | @@ -444,6 +468,43 @@ edges | lib/lib.js:405:39:405:42 | name | lib/lib.js:406:22:406:25 | name | | lib/lib.js:405:39:405:42 | name | lib/lib.js:406:22:406:25 | name | | lib/lib.js:405:39:405:42 | name | lib/lib.js:406:22:406:25 | name | +| lib/lib.js:414:40:414:43 | name | lib/lib.js:415:22:415:25 | name | +| lib/lib.js:414:40:414:43 | name | lib/lib.js:415:22:415:25 | name | +| lib/lib.js:414:40:414:43 | name | lib/lib.js:415:22:415:25 | name | +| lib/lib.js:414:40:414:43 | name | lib/lib.js:415:22:415:25 | name | +| lib/lib.js:414:40:414:43 | name | lib/lib.js:417:28:417:31 | name | +| lib/lib.js:414:40:414:43 | name | lib/lib.js:417:28:417:31 | name | +| lib/lib.js:414:40:414:43 | name | lib/lib.js:417:28:417:31 | name | +| lib/lib.js:414:40:414:43 | name | lib/lib.js:417:28:417:31 | name | +| lib/lib.js:414:40:414:43 | name | lib/lib.js:418:25:418:28 | name | +| lib/lib.js:414:40:414:43 | name | lib/lib.js:418:25:418:28 | name | +| lib/lib.js:414:40:414:43 | name | lib/lib.js:418:25:418:28 | name | +| lib/lib.js:414:40:414:43 | name | lib/lib.js:418:25:418:28 | name | +| lib/lib.js:414:40:414:43 | name | lib/lib.js:419:32:419:35 | name | +| lib/lib.js:414:40:414:43 | name | lib/lib.js:419:32:419:35 | name | +| lib/lib.js:414:40:414:43 | name | lib/lib.js:419:32:419:35 | name | +| lib/lib.js:414:40:414:43 | name | lib/lib.js:419:32:419:35 | name | +| lib/lib.js:414:40:414:43 | name | lib/lib.js:420:29:420:32 | name | +| lib/lib.js:414:40:414:43 | name | lib/lib.js:420:29:420:32 | name | +| lib/lib.js:414:40:414:43 | name | lib/lib.js:420:29:420:32 | name | +| lib/lib.js:414:40:414:43 | name | lib/lib.js:420:29:420:32 | name | +| lib/lib.js:414:40:414:43 | name | lib/lib.js:424:24:424:27 | name | +| lib/lib.js:414:40:414:43 | name | lib/lib.js:424:24:424:27 | name | +| lib/lib.js:414:40:414:43 | name | lib/lib.js:424:24:424:27 | name | +| lib/lib.js:414:40:414:43 | name | lib/lib.js:424:24:424:27 | name | +| lib/lib.js:414:40:414:43 | name | lib/lib.js:426:11:426:14 | name | +| lib/lib.js:414:40:414:43 | name | lib/lib.js:426:11:426:14 | name | +| lib/lib.js:414:40:414:43 | name | lib/lib.js:426:11:426:14 | name | +| lib/lib.js:414:40:414:43 | name | lib/lib.js:426:11:426:14 | name | +| lib/lib.js:414:40:414:43 | name | lib/lib.js:428:36:428:39 | name | +| lib/lib.js:414:40:414:43 | name | lib/lib.js:428:36:428:39 | name | +| lib/lib.js:428:28:428:51 | (name ? ... ' : '') | lib/lib.js:428:28:428:57 | (name ? ... ) + '-' | +| lib/lib.js:428:28:428:57 | (name ? ... ) + '-' | lib/lib.js:431:23:431:26 | last | +| lib/lib.js:428:29:428:50 | name ? ... :' : '' | lib/lib.js:428:28:428:51 | (name ? ... ' : '') | +| lib/lib.js:428:36:428:39 | name | lib/lib.js:428:36:428:45 | name + ':' | +| lib/lib.js:428:36:428:45 | name + ':' | lib/lib.js:428:29:428:50 | name ? ... :' : '' | +| lib/lib.js:431:23:431:26 | last | lib/lib.js:436:19:436:22 | last | +| lib/lib.js:431:23:431:26 | last | lib/lib.js:436:19:436:22 | last | #select | lib/lib2.js:4:10:4:25 | "rm -rf " + name | lib/lib2.js:3:28:3:31 | name | lib/lib2.js:4:22:4:25 | name | $@ based on library input is later used in $@. | lib/lib2.js:4:10:4:25 | "rm -rf " + name | String concatenation | lib/lib2.js:4:2:4:26 | cp.exec ... + name) | shell command | | lib/lib2.js:8:10:8:25 | "rm -rf " + name | lib/lib2.js:7:32:7:35 | name | lib/lib2.js:8:22:8:25 | name | $@ based on library input is later used in $@. | lib/lib2.js:8:10:8:25 | "rm -rf " + name | String concatenation | lib/lib2.js:8:2:8:26 | cp.exec ... + name) | shell command | @@ -502,3 +563,11 @@ edges | lib/lib.js:351:10:351:27 | "rm -rf " + unsafe | lib/lib.js:349:29:349:34 | unsafe | lib/lib.js:351:22:351:27 | unsafe | $@ based on library input is later used in $@. | lib/lib.js:351:10:351:27 | "rm -rf " + unsafe | String concatenation | lib/lib.js:351:2:351:28 | cp.exec ... unsafe) | shell command | | lib/lib.js:366:17:366:56 | "learn ... + model | lib/lib.js:360:20:360:23 | opts | lib/lib.js:366:28:366:42 | this.learn_args | $@ based on library input is later used in $@. | lib/lib.js:366:17:366:56 | "learn ... + model | String concatenation | lib/lib.js:367:3:367:18 | cp.exec(command) | shell command | | lib/lib.js:406:10:406:25 | "rm -rf " + name | lib/lib.js:405:39:405:42 | name | lib/lib.js:406:22:406:25 | name | $@ based on library input is later used in $@. | lib/lib.js:406:10:406:25 | "rm -rf " + name | String concatenation | lib/lib.js:406:2:406:26 | cp.exec ... + name) | shell command | +| lib/lib.js:415:10:415:25 | "rm -rf " + name | lib/lib.js:414:40:414:43 | name | lib/lib.js:415:22:415:25 | name | $@ based on library input is later used in $@. | lib/lib.js:415:10:415:25 | "rm -rf " + name | String concatenation | lib/lib.js:415:2:415:26 | cp.exec ... + name) | shell command | +| lib/lib.js:417:28:417:31 | name | lib/lib.js:414:40:414:43 | name | lib/lib.js:417:28:417:31 | name | $@ based on library input is later used in $@. | lib/lib.js:417:28:417:31 | name | Shell argument | lib/lib.js:417:2:417:66 | cp.exec ... => {}) | shell command | +| lib/lib.js:418:25:418:28 | name | lib/lib.js:414:40:414:43 | name | lib/lib.js:418:25:418:28 | name | $@ based on library input is later used in $@. | lib/lib.js:418:25:418:28 | name | Shell argument | lib/lib.js:418:2:418:45 | cp.spaw ... true}) | shell command | +| lib/lib.js:419:32:419:35 | name | lib/lib.js:414:40:414:43 | name | lib/lib.js:419:32:419:35 | name | $@ based on library input is later used in $@. | lib/lib.js:419:32:419:35 | name | Shell argument | lib/lib.js:419:2:419:52 | cp.exec ... true}) | shell command | +| lib/lib.js:420:29:420:32 | name | lib/lib.js:414:40:414:43 | name | lib/lib.js:420:29:420:32 | name | $@ based on library input is later used in $@. | lib/lib.js:420:29:420:32 | name | Shell argument | lib/lib.js:420:2:420:49 | cp.spaw ... true}) | shell command | +| lib/lib.js:424:24:424:27 | name | lib/lib.js:414:40:414:43 | name | lib/lib.js:424:24:424:27 | name | $@ based on library input is later used in $@. | lib/lib.js:424:24:424:27 | name | Shell argument | lib/lib.js:424:2:424:40 | spawn(" ... WN_OPT) | shell command | +| lib/lib.js:426:11:426:14 | name | lib/lib.js:414:40:414:43 | name | lib/lib.js:426:11:426:14 | name | $@ based on library input is later used in $@. | lib/lib.js:426:11:426:14 | name | Shell argument | lib/lib.js:427:2:427:28 | spawn(" ... WN_OPT) | shell command | +| lib/lib.js:436:19:436:22 | last | lib/lib.js:414:40:414:43 | name | lib/lib.js:436:19:436:22 | last | $@ based on library input is later used in $@. | lib/lib.js:436:19:436:22 | last | Shell argument | lib/lib.js:428:2:428:70 | spawn(" ... WN_OPT) | shell command | diff --git a/javascript/ql/test/query-tests/Security/CWE-078/UselessUseOfCat.expected b/javascript/ql/test/query-tests/Security/CWE-078/UselessUseOfCat.expected index 7a7e22fb332..4c7e10b658e 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/UselessUseOfCat.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/UselessUseOfCat.expected @@ -53,6 +53,8 @@ syncCommand | command-line-parameter-command-injection.js:20:2:20:30 | cp.exec ... + arg0) | | command-line-parameter-command-injection.js:26:2:26:51 | cp.exec ... tion"`) | | command-line-parameter-command-injection.js:27:2:27:58 | cp.exec ... tion"`) | +| lib/lib.js:419:2:419:52 | cp.exec ... true}) | +| lib/lib.js:420:2:420:49 | cp.spaw ... true}) | | other.js:7:5:7:36 | require ... nc(cmd) | | other.js:9:5:9:35 | require ... nc(cmd) | | other.js:12:5:12:30 | require ... nc(cmd) | @@ -100,6 +102,13 @@ options | lib/lib.js:152:2:152:23 | cp.spaw ... gs, cb) | lib/lib.js:152:21:152:22 | cb | | lib/lib.js:159:2:159:23 | cp.spaw ... gs, cb) | lib/lib.js:159:21:159:22 | cb | | lib/lib.js:163:2:167:2 | cp.spaw ... t' }\\n\\t) | lib/lib.js:166:3:166:22 | { stdio: 'inherit' } | +| lib/lib.js:417:2:417:66 | cp.exec ... => {}) | lib/lib.js:417:35:417:47 | {shell: true} | +| lib/lib.js:418:2:418:45 | cp.spaw ... true}) | lib/lib.js:418:32:418:44 | {shell: true} | +| lib/lib.js:419:2:419:52 | cp.exec ... true}) | lib/lib.js:419:39:419:51 | {shell: true} | +| lib/lib.js:420:2:420:49 | cp.spaw ... true}) | lib/lib.js:420:36:420:48 | {shell: true} | +| lib/lib.js:424:2:424:40 | spawn(" ... WN_OPT) | lib/lib.js:424:31:424:39 | SPAWN_OPT | +| lib/lib.js:427:2:427:28 | spawn(" ... WN_OPT) | lib/lib.js:427:19:427:27 | SPAWN_OPT | +| lib/lib.js:428:2:428:70 | spawn(" ... WN_OPT) | lib/lib.js:428:61:428:69 | SPAWN_OPT | | uselesscat.js:28:1:28:39 | execSyn ... 1000}) | uselesscat.js:28:28:28:38 | {uid: 1000} | | uselesscat.js:30:1:30:64 | exec('c ... t) { }) | uselesscat.js:30:26:30:38 | { cwd: './' } | | uselesscat.js:34:1:34:54 | execSyn ... utf8'}) | uselesscat.js:34:36:34:53 | {encoding: 'utf8'} | diff --git a/javascript/ql/test/query-tests/Security/CWE-078/lib/lib.js b/javascript/ql/test/query-tests/Security/CWE-078/lib/lib.js index d1a885438ff..ea10bf14fa0 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/lib/lib.js +++ b/javascript/ql/test/query-tests/Security/CWE-078/lib/lib.js @@ -408,3 +408,31 @@ module.exports.sanitizer3 = function (name) { var sanitized = yetAnohterSanitizer(name); cp.exec("rm -rf " + sanitized); // OK } + +const cp = require("child_process"); +const spawn = cp.spawn; +module.exports.shellOption = function (name) { + cp.exec("rm -rf " + name); // NOT OK + + cp.execFile("rm", ["-rf", name], {shell: true}, (err, out) => {}); // NOT OK + cp.spawn("rm", ["-rf", name], {shell: true}); // NOT OK + cp.execFileSync("rm", ["-rf", name], {shell: true}); // NOT OK + cp.spawnSync("rm", ["-rf", name], {shell: true}); // NOT OK + + const SPAWN_OPT = {shell: true}; + + spawn("rm", ["first", name], SPAWN_OPT); // NOT OK + var arr = []; + arr.push(name); // NOT OK + spawn("rm", arr, SPAWN_OPT); + spawn("rm", build("node", (name ? name + ':' : '') + '-'), SPAWN_OPT); // This is bad, but the alert location is down in `build`. +} + +function build(first, last) { + var arr = []; + if (something() === 'gm') + arr.push('convert'); + first && arr.push(first); + last && arr.push(last); // NOT OK + return arr; +}; \ No newline at end of file From 6c1ec6d96b1bfd7ab98b2d47c6fb059339956c16 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 19 Mar 2021 16:09:05 +0100 Subject: [PATCH 203/725] C++: Accept test changes. --- .../UncontrolledFormatString.expected | 115 ++++++++++++++++ ...olledFormatStringThroughGlobalVar.expected | 125 ++++++++++++++++++ 2 files changed, 240 insertions(+) diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatString.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatString.expected index 58e3dda0964..01ef5030e5f 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatString.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatString.expected @@ -1,3 +1,118 @@ edges +| globalVars.c:8:7:8:10 | copy | globalVars.c:27:9:27:12 | copy | +| globalVars.c:8:7:8:10 | copy | globalVars.c:27:9:27:12 | copy | +| globalVars.c:8:7:8:10 | copy | globalVars.c:30:15:30:18 | copy | +| globalVars.c:8:7:8:10 | copy | globalVars.c:30:15:30:18 | copy | +| globalVars.c:8:7:8:10 | copy | globalVars.c:33:15:33:18 | copy | +| globalVars.c:8:7:8:10 | copy | globalVars.c:33:15:33:18 | copy | +| globalVars.c:8:7:8:10 | copy | globalVars.c:35:11:35:14 | copy | +| globalVars.c:8:7:8:10 | copy | globalVars.c:35:11:35:14 | copy | +| globalVars.c:9:7:9:11 | copy2 | globalVars.c:38:9:38:13 | copy2 | +| globalVars.c:9:7:9:11 | copy2 | globalVars.c:38:9:38:13 | copy2 | +| globalVars.c:9:7:9:11 | copy2 | globalVars.c:41:15:41:19 | copy2 | +| globalVars.c:9:7:9:11 | copy2 | globalVars.c:41:15:41:19 | copy2 | +| globalVars.c:9:7:9:11 | copy2 | globalVars.c:44:15:44:19 | copy2 | +| globalVars.c:9:7:9:11 | copy2 | globalVars.c:44:15:44:19 | copy2 | +| globalVars.c:9:7:9:11 | copy2 | globalVars.c:50:9:50:13 | copy2 | +| globalVars.c:9:7:9:11 | copy2 | globalVars.c:50:9:50:13 | copy2 | +| globalVars.c:15:21:15:23 | val | globalVars.c:16:10:16:12 | val | +| globalVars.c:19:25:19:27 | *str | globalVars.c:20:9:20:11 | (const char *)... | +| globalVars.c:19:25:19:27 | *str | globalVars.c:20:9:20:11 | str indirection | +| globalVars.c:19:25:19:27 | str | globalVars.c:20:9:20:11 | (const char *)... | +| globalVars.c:19:25:19:27 | str | globalVars.c:20:9:20:11 | str | +| globalVars.c:19:25:19:27 | str | globalVars.c:20:9:20:11 | str | +| globalVars.c:19:25:19:27 | str | globalVars.c:20:9:20:11 | str indirection | +| globalVars.c:20:9:20:11 | str | globalVars.c:20:9:20:11 | (const char *)... | +| globalVars.c:20:9:20:11 | str | globalVars.c:20:9:20:11 | str indirection | +| globalVars.c:27:9:27:12 | copy | globalVars.c:27:9:27:12 | (const char *)... | +| globalVars.c:27:9:27:12 | copy | globalVars.c:27:9:27:12 | copy indirection | +| globalVars.c:30:2:30:13 | copy | globalVars.c:19:25:19:27 | str | +| globalVars.c:30:2:30:13 | copy | globalVars.c:19:25:19:27 | str | +| globalVars.c:30:15:30:18 | copy | globalVars.c:30:2:30:13 | copy | +| globalVars.c:30:15:30:18 | copy | globalVars.c:30:15:30:18 | copy | +| globalVars.c:30:15:30:18 | copy | globalVars.c:30:15:30:18 | copy | +| globalVars.c:30:15:30:18 | copy | globalVars.c:30:15:30:18 | copy indirection | +| globalVars.c:30:15:30:18 | copy | globalVars.c:30:15:30:18 | copy indirection | +| globalVars.c:30:15:30:18 | copy indirection | globalVars.c:19:25:19:27 | *str | +| globalVars.c:33:15:33:18 | copy | globalVars.c:33:15:33:18 | copy | +| globalVars.c:33:15:33:18 | copy | globalVars.c:33:15:33:18 | copy | +| globalVars.c:33:15:33:18 | copy | globalVars.c:33:15:33:18 | copy indirection | +| globalVars.c:35:2:35:9 | copy | globalVars.c:15:21:15:23 | val | +| globalVars.c:35:2:35:9 | copy | globalVars.c:15:21:15:23 | val | +| globalVars.c:35:11:35:14 | copy | globalVars.c:35:2:35:9 | copy | +| globalVars.c:35:11:35:14 | copy | globalVars.c:35:11:35:14 | copy | +| globalVars.c:35:11:35:14 | copy | globalVars.c:35:11:35:14 | copy | +| globalVars.c:35:11:35:14 | copy | globalVars.c:35:11:35:14 | copy indirection | +| globalVars.c:38:9:38:13 | copy2 | globalVars.c:38:9:38:13 | (const char *)... | +| globalVars.c:38:9:38:13 | copy2 | globalVars.c:38:9:38:13 | copy2 indirection | +| globalVars.c:41:2:41:13 | copy2 | globalVars.c:19:25:19:27 | str | +| globalVars.c:41:2:41:13 | copy2 | globalVars.c:19:25:19:27 | str | +| globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:2:41:13 | copy2 | +| globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:15:41:19 | copy2 | +| globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:15:41:19 | copy2 | +| globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:15:41:19 | copy2 indirection | +| globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:15:41:19 | copy2 indirection | +| globalVars.c:41:15:41:19 | copy2 indirection | globalVars.c:19:25:19:27 | *str | +| globalVars.c:44:15:44:19 | copy2 | globalVars.c:44:15:44:19 | copy2 | +| globalVars.c:44:15:44:19 | copy2 | globalVars.c:44:15:44:19 | copy2 | +| globalVars.c:44:15:44:19 | copy2 | globalVars.c:44:15:44:19 | copy2 indirection | +| globalVars.c:50:9:50:13 | copy2 | globalVars.c:50:9:50:13 | (const char *)... | +| globalVars.c:50:9:50:13 | copy2 | globalVars.c:50:9:50:13 | copy2 indirection | nodes +| globalVars.c:8:7:8:10 | copy | semmle.label | copy | +| globalVars.c:9:7:9:11 | copy2 | semmle.label | copy2 | +| globalVars.c:15:21:15:23 | val | semmle.label | val | +| globalVars.c:15:21:15:23 | val | semmle.label | val | +| globalVars.c:16:10:16:12 | val | semmle.label | val | +| globalVars.c:16:10:16:12 | val | semmle.label | val | +| globalVars.c:19:25:19:27 | *str | semmle.label | *str | +| globalVars.c:19:25:19:27 | str | semmle.label | str | +| globalVars.c:19:25:19:27 | str | semmle.label | str | +| globalVars.c:20:9:20:11 | (const char *)... | semmle.label | (const char *)... | +| globalVars.c:20:9:20:11 | (const char *)... | semmle.label | (const char *)... | +| globalVars.c:20:9:20:11 | str | semmle.label | str | +| globalVars.c:20:9:20:11 | str | semmle.label | str | +| globalVars.c:20:9:20:11 | str indirection | semmle.label | str indirection | +| globalVars.c:20:9:20:11 | str indirection | semmle.label | str indirection | +| globalVars.c:27:9:27:12 | (const char *)... | semmle.label | (const char *)... | +| globalVars.c:27:9:27:12 | (const char *)... | semmle.label | (const char *)... | +| globalVars.c:27:9:27:12 | copy | semmle.label | copy | +| globalVars.c:27:9:27:12 | copy | semmle.label | copy | +| globalVars.c:27:9:27:12 | copy indirection | semmle.label | copy indirection | +| globalVars.c:27:9:27:12 | copy indirection | semmle.label | copy indirection | +| globalVars.c:30:2:30:13 | copy | semmle.label | copy | +| globalVars.c:30:15:30:18 | copy | semmle.label | copy | +| globalVars.c:30:15:30:18 | copy | semmle.label | copy | +| globalVars.c:30:15:30:18 | copy indirection | semmle.label | copy indirection | +| globalVars.c:30:15:30:18 | copy indirection | semmle.label | copy indirection | +| globalVars.c:33:15:33:18 | copy | semmle.label | copy | +| globalVars.c:33:15:33:18 | copy | semmle.label | copy | +| globalVars.c:33:15:33:18 | copy indirection | semmle.label | copy indirection | +| globalVars.c:33:15:33:18 | copy indirection | semmle.label | copy indirection | +| globalVars.c:35:2:35:9 | copy | semmle.label | copy | +| globalVars.c:35:11:35:14 | copy | semmle.label | copy | +| globalVars.c:35:11:35:14 | copy | semmle.label | copy | +| globalVars.c:35:11:35:14 | copy indirection | semmle.label | copy indirection | +| globalVars.c:35:11:35:14 | copy indirection | semmle.label | copy indirection | +| globalVars.c:38:9:38:13 | (const char *)... | semmle.label | (const char *)... | +| globalVars.c:38:9:38:13 | (const char *)... | semmle.label | (const char *)... | +| globalVars.c:38:9:38:13 | copy2 | semmle.label | copy2 | +| globalVars.c:38:9:38:13 | copy2 | semmle.label | copy2 | +| globalVars.c:38:9:38:13 | copy2 indirection | semmle.label | copy2 indirection | +| globalVars.c:38:9:38:13 | copy2 indirection | semmle.label | copy2 indirection | +| globalVars.c:41:2:41:13 | copy2 | semmle.label | copy2 | +| globalVars.c:41:15:41:19 | copy2 | semmle.label | copy2 | +| globalVars.c:41:15:41:19 | copy2 | semmle.label | copy2 | +| globalVars.c:41:15:41:19 | copy2 indirection | semmle.label | copy2 indirection | +| globalVars.c:41:15:41:19 | copy2 indirection | semmle.label | copy2 indirection | +| globalVars.c:44:15:44:19 | copy2 | semmle.label | copy2 | +| globalVars.c:44:15:44:19 | copy2 | semmle.label | copy2 | +| globalVars.c:44:15:44:19 | copy2 indirection | semmle.label | copy2 indirection | +| globalVars.c:44:15:44:19 | copy2 indirection | semmle.label | copy2 indirection | +| globalVars.c:50:9:50:13 | (const char *)... | semmle.label | (const char *)... | +| globalVars.c:50:9:50:13 | (const char *)... | semmle.label | (const char *)... | +| globalVars.c:50:9:50:13 | copy2 | semmle.label | copy2 | +| globalVars.c:50:9:50:13 | copy2 | semmle.label | copy2 | +| globalVars.c:50:9:50:13 | copy2 indirection | semmle.label | copy2 indirection | +| globalVars.c:50:9:50:13 | copy2 indirection | semmle.label | copy2 indirection | #select diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatStringThroughGlobalVar.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatStringThroughGlobalVar.expected index f095153f39c..5ac81e70545 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatStringThroughGlobalVar.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatStringThroughGlobalVar.expected @@ -2,16 +2,37 @@ edges | globalVars.c:8:7:8:10 | copy | globalVars.c:27:9:27:12 | copy | | globalVars.c:8:7:8:10 | copy | globalVars.c:27:9:27:12 | copy | | globalVars.c:8:7:8:10 | copy | globalVars.c:27:9:27:12 | copy | +| globalVars.c:8:7:8:10 | copy | globalVars.c:27:9:27:12 | copy | +| globalVars.c:8:7:8:10 | copy | globalVars.c:27:9:27:12 | copy | +| globalVars.c:8:7:8:10 | copy | globalVars.c:27:9:27:12 | copy | | globalVars.c:8:7:8:10 | copy | globalVars.c:30:15:30:18 | copy | | globalVars.c:8:7:8:10 | copy | globalVars.c:30:15:30:18 | copy | | globalVars.c:8:7:8:10 | copy | globalVars.c:30:15:30:18 | copy | +| globalVars.c:8:7:8:10 | copy | globalVars.c:30:15:30:18 | copy | +| globalVars.c:8:7:8:10 | copy | globalVars.c:30:15:30:18 | copy | +| globalVars.c:8:7:8:10 | copy | globalVars.c:30:15:30:18 | copy | +| globalVars.c:8:7:8:10 | copy | globalVars.c:33:15:33:18 | copy | +| globalVars.c:8:7:8:10 | copy | globalVars.c:33:15:33:18 | copy | +| globalVars.c:8:7:8:10 | copy | globalVars.c:35:11:35:14 | copy | +| globalVars.c:8:7:8:10 | copy | globalVars.c:35:11:35:14 | copy | | globalVars.c:8:7:8:10 | copy | globalVars.c:35:11:35:14 | copy | | globalVars.c:9:7:9:11 | copy2 | globalVars.c:38:9:38:13 | copy2 | | globalVars.c:9:7:9:11 | copy2 | globalVars.c:38:9:38:13 | copy2 | | globalVars.c:9:7:9:11 | copy2 | globalVars.c:38:9:38:13 | copy2 | +| globalVars.c:9:7:9:11 | copy2 | globalVars.c:38:9:38:13 | copy2 | +| globalVars.c:9:7:9:11 | copy2 | globalVars.c:38:9:38:13 | copy2 | +| globalVars.c:9:7:9:11 | copy2 | globalVars.c:38:9:38:13 | copy2 | | globalVars.c:9:7:9:11 | copy2 | globalVars.c:41:15:41:19 | copy2 | | globalVars.c:9:7:9:11 | copy2 | globalVars.c:41:15:41:19 | copy2 | | globalVars.c:9:7:9:11 | copy2 | globalVars.c:41:15:41:19 | copy2 | +| globalVars.c:9:7:9:11 | copy2 | globalVars.c:41:15:41:19 | copy2 | +| globalVars.c:9:7:9:11 | copy2 | globalVars.c:41:15:41:19 | copy2 | +| globalVars.c:9:7:9:11 | copy2 | globalVars.c:41:15:41:19 | copy2 | +| globalVars.c:9:7:9:11 | copy2 | globalVars.c:44:15:44:19 | copy2 | +| globalVars.c:9:7:9:11 | copy2 | globalVars.c:44:15:44:19 | copy2 | +| globalVars.c:9:7:9:11 | copy2 | globalVars.c:50:9:50:13 | copy2 | +| globalVars.c:9:7:9:11 | copy2 | globalVars.c:50:9:50:13 | copy2 | +| globalVars.c:9:7:9:11 | copy2 | globalVars.c:50:9:50:13 | copy2 | | globalVars.c:9:7:9:11 | copy2 | globalVars.c:50:9:50:13 | copy2 | | globalVars.c:9:7:9:11 | copy2 | globalVars.c:50:9:50:13 | copy2 | | globalVars.c:9:7:9:11 | copy2 | globalVars.c:50:9:50:13 | copy2 | @@ -20,7 +41,16 @@ edges | globalVars.c:11:22:11:25 | argv | globalVars.c:12:2:12:15 | Store | | globalVars.c:12:2:12:15 | Store | globalVars.c:8:7:8:10 | copy | | globalVars.c:15:21:15:23 | val | globalVars.c:16:2:16:12 | Store | +| globalVars.c:15:21:15:23 | val | globalVars.c:16:10:16:12 | val | | globalVars.c:16:2:16:12 | Store | globalVars.c:9:7:9:11 | copy2 | +| globalVars.c:19:25:19:27 | *str | globalVars.c:20:9:20:11 | (const char *)... | +| globalVars.c:19:25:19:27 | *str | globalVars.c:20:9:20:11 | str indirection | +| globalVars.c:19:25:19:27 | str | globalVars.c:20:9:20:11 | (const char *)... | +| globalVars.c:19:25:19:27 | str | globalVars.c:20:9:20:11 | str | +| globalVars.c:19:25:19:27 | str | globalVars.c:20:9:20:11 | str | +| globalVars.c:19:25:19:27 | str | globalVars.c:20:9:20:11 | str indirection | +| globalVars.c:20:9:20:11 | str | globalVars.c:20:9:20:11 | (const char *)... | +| globalVars.c:20:9:20:11 | str | globalVars.c:20:9:20:11 | str indirection | | globalVars.c:24:2:24:9 | argv | globalVars.c:11:22:11:25 | argv | | globalVars.c:24:11:24:14 | argv | globalVars.c:24:2:24:9 | argv | | globalVars.c:24:11:24:14 | argv | globalVars.c:24:2:24:9 | argv | @@ -28,67 +58,162 @@ edges | globalVars.c:24:11:24:14 | argv | globalVars.c:24:11:24:14 | argv indirection | | globalVars.c:24:11:24:14 | argv indirection | globalVars.c:11:22:11:25 | *argv | | globalVars.c:27:9:27:12 | copy | globalVars.c:27:9:27:12 | (const char *)... | +| globalVars.c:27:9:27:12 | copy | globalVars.c:27:9:27:12 | (const char *)... | +| globalVars.c:27:9:27:12 | copy | globalVars.c:27:9:27:12 | copy | | globalVars.c:27:9:27:12 | copy | globalVars.c:27:9:27:12 | copy | | globalVars.c:27:9:27:12 | copy | globalVars.c:27:9:27:12 | copy indirection | +| globalVars.c:27:9:27:12 | copy | globalVars.c:27:9:27:12 | copy indirection | +| globalVars.c:30:2:30:13 | copy | globalVars.c:19:25:19:27 | str | +| globalVars.c:30:2:30:13 | copy | globalVars.c:19:25:19:27 | str | +| globalVars.c:30:15:30:18 | copy | globalVars.c:30:2:30:13 | copy | +| globalVars.c:30:15:30:18 | copy | globalVars.c:30:15:30:18 | copy | +| globalVars.c:30:15:30:18 | copy | globalVars.c:30:15:30:18 | copy | +| globalVars.c:30:15:30:18 | copy | globalVars.c:30:15:30:18 | copy | | globalVars.c:30:15:30:18 | copy | globalVars.c:30:15:30:18 | copy | | globalVars.c:30:15:30:18 | copy | globalVars.c:30:15:30:18 | copy | | globalVars.c:30:15:30:18 | copy | globalVars.c:30:15:30:18 | copy | | globalVars.c:30:15:30:18 | copy | globalVars.c:30:15:30:18 | copy indirection | +| globalVars.c:30:15:30:18 | copy | globalVars.c:30:15:30:18 | copy indirection | +| globalVars.c:30:15:30:18 | copy | globalVars.c:30:15:30:18 | copy indirection | +| globalVars.c:30:15:30:18 | copy indirection | globalVars.c:19:25:19:27 | *str | +| globalVars.c:33:15:33:18 | copy | globalVars.c:33:15:33:18 | copy | +| globalVars.c:33:15:33:18 | copy | globalVars.c:33:15:33:18 | copy | +| globalVars.c:33:15:33:18 | copy | globalVars.c:33:15:33:18 | copy indirection | +| globalVars.c:35:2:35:9 | copy | globalVars.c:15:21:15:23 | val | +| globalVars.c:35:2:35:9 | copy | globalVars.c:15:21:15:23 | val | | globalVars.c:35:2:35:9 | copy | globalVars.c:15:21:15:23 | val | | globalVars.c:35:11:35:14 | copy | globalVars.c:35:2:35:9 | copy | +| globalVars.c:35:11:35:14 | copy | globalVars.c:35:2:35:9 | copy | +| globalVars.c:35:11:35:14 | copy | globalVars.c:35:11:35:14 | copy | +| globalVars.c:35:11:35:14 | copy | globalVars.c:35:11:35:14 | copy | +| globalVars.c:35:11:35:14 | copy | globalVars.c:35:11:35:14 | copy indirection | +| globalVars.c:38:9:38:13 | copy2 | globalVars.c:38:9:38:13 | (const char *)... | | globalVars.c:38:9:38:13 | copy2 | globalVars.c:38:9:38:13 | (const char *)... | | globalVars.c:38:9:38:13 | copy2 | globalVars.c:38:9:38:13 | copy2 | +| globalVars.c:38:9:38:13 | copy2 | globalVars.c:38:9:38:13 | copy2 | | globalVars.c:38:9:38:13 | copy2 | globalVars.c:38:9:38:13 | copy2 indirection | +| globalVars.c:38:9:38:13 | copy2 | globalVars.c:38:9:38:13 | copy2 indirection | +| globalVars.c:41:2:41:13 | copy2 | globalVars.c:19:25:19:27 | str | +| globalVars.c:41:2:41:13 | copy2 | globalVars.c:19:25:19:27 | str | +| globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:2:41:13 | copy2 | +| globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:15:41:19 | copy2 | +| globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:15:41:19 | copy2 | +| globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:15:41:19 | copy2 | | globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:15:41:19 | copy2 | | globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:15:41:19 | copy2 | | globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:15:41:19 | copy2 | | globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:15:41:19 | copy2 indirection | +| globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:15:41:19 | copy2 indirection | +| globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:15:41:19 | copy2 indirection | +| globalVars.c:41:15:41:19 | copy2 indirection | globalVars.c:19:25:19:27 | *str | +| globalVars.c:44:15:44:19 | copy2 | globalVars.c:44:15:44:19 | copy2 | +| globalVars.c:44:15:44:19 | copy2 | globalVars.c:44:15:44:19 | copy2 | +| globalVars.c:44:15:44:19 | copy2 | globalVars.c:44:15:44:19 | copy2 indirection | +| globalVars.c:50:9:50:13 | copy2 | globalVars.c:50:9:50:13 | (const char *)... | | globalVars.c:50:9:50:13 | copy2 | globalVars.c:50:9:50:13 | (const char *)... | | globalVars.c:50:9:50:13 | copy2 | globalVars.c:50:9:50:13 | copy2 | +| globalVars.c:50:9:50:13 | copy2 | globalVars.c:50:9:50:13 | copy2 | +| globalVars.c:50:9:50:13 | copy2 | globalVars.c:50:9:50:13 | copy2 indirection | | globalVars.c:50:9:50:13 | copy2 | globalVars.c:50:9:50:13 | copy2 indirection | nodes | globalVars.c:8:7:8:10 | copy | semmle.label | copy | +| globalVars.c:8:7:8:10 | copy | semmle.label | copy | +| globalVars.c:9:7:9:11 | copy2 | semmle.label | copy2 | | globalVars.c:9:7:9:11 | copy2 | semmle.label | copy2 | | globalVars.c:11:22:11:25 | *argv | semmle.label | *argv | | globalVars.c:11:22:11:25 | argv | semmle.label | argv | | globalVars.c:12:2:12:15 | Store | semmle.label | Store | | globalVars.c:15:21:15:23 | val | semmle.label | val | +| globalVars.c:15:21:15:23 | val | semmle.label | val | +| globalVars.c:15:21:15:23 | val | semmle.label | val | | globalVars.c:16:2:16:12 | Store | semmle.label | Store | +| globalVars.c:16:10:16:12 | val | semmle.label | val | +| globalVars.c:16:10:16:12 | val | semmle.label | val | +| globalVars.c:19:25:19:27 | *str | semmle.label | *str | +| globalVars.c:19:25:19:27 | str | semmle.label | str | +| globalVars.c:19:25:19:27 | str | semmle.label | str | +| globalVars.c:20:9:20:11 | (const char *)... | semmle.label | (const char *)... | +| globalVars.c:20:9:20:11 | (const char *)... | semmle.label | (const char *)... | +| globalVars.c:20:9:20:11 | str | semmle.label | str | +| globalVars.c:20:9:20:11 | str | semmle.label | str | +| globalVars.c:20:9:20:11 | str indirection | semmle.label | str indirection | +| globalVars.c:20:9:20:11 | str indirection | semmle.label | str indirection | | globalVars.c:24:2:24:9 | argv | semmle.label | argv | | globalVars.c:24:11:24:14 | argv | semmle.label | argv | | globalVars.c:24:11:24:14 | argv | semmle.label | argv | | globalVars.c:24:11:24:14 | argv indirection | semmle.label | argv indirection | | globalVars.c:27:9:27:12 | (const char *)... | semmle.label | (const char *)... | | globalVars.c:27:9:27:12 | (const char *)... | semmle.label | (const char *)... | +| globalVars.c:27:9:27:12 | (const char *)... | semmle.label | (const char *)... | +| globalVars.c:27:9:27:12 | (const char *)... | semmle.label | (const char *)... | +| globalVars.c:27:9:27:12 | copy | semmle.label | copy | +| globalVars.c:27:9:27:12 | copy | semmle.label | copy | | globalVars.c:27:9:27:12 | copy | semmle.label | copy | | globalVars.c:27:9:27:12 | copy | semmle.label | copy | | globalVars.c:27:9:27:12 | copy | semmle.label | copy | | globalVars.c:27:9:27:12 | copy indirection | semmle.label | copy indirection | | globalVars.c:27:9:27:12 | copy indirection | semmle.label | copy indirection | +| globalVars.c:27:9:27:12 | copy indirection | semmle.label | copy indirection | +| globalVars.c:27:9:27:12 | copy indirection | semmle.label | copy indirection | +| globalVars.c:30:2:30:13 | copy | semmle.label | copy | +| globalVars.c:30:15:30:18 | copy | semmle.label | copy | +| globalVars.c:30:15:30:18 | copy | semmle.label | copy | | globalVars.c:30:15:30:18 | copy | semmle.label | copy | | globalVars.c:30:15:30:18 | copy | semmle.label | copy | | globalVars.c:30:15:30:18 | copy | semmle.label | copy | | globalVars.c:30:15:30:18 | copy indirection | semmle.label | copy indirection | | globalVars.c:30:15:30:18 | copy indirection | semmle.label | copy indirection | +| globalVars.c:30:15:30:18 | copy indirection | semmle.label | copy indirection | +| globalVars.c:30:15:30:18 | copy indirection | semmle.label | copy indirection | +| globalVars.c:33:15:33:18 | copy | semmle.label | copy | +| globalVars.c:33:15:33:18 | copy | semmle.label | copy | +| globalVars.c:33:15:33:18 | copy indirection | semmle.label | copy indirection | +| globalVars.c:33:15:33:18 | copy indirection | semmle.label | copy indirection | +| globalVars.c:35:2:35:9 | copy | semmle.label | copy | | globalVars.c:35:2:35:9 | copy | semmle.label | copy | | globalVars.c:35:11:35:14 | copy | semmle.label | copy | +| globalVars.c:35:11:35:14 | copy | semmle.label | copy | +| globalVars.c:35:11:35:14 | copy | semmle.label | copy | +| globalVars.c:35:11:35:14 | copy indirection | semmle.label | copy indirection | +| globalVars.c:35:11:35:14 | copy indirection | semmle.label | copy indirection | +| globalVars.c:38:9:38:13 | (const char *)... | semmle.label | (const char *)... | +| globalVars.c:38:9:38:13 | (const char *)... | semmle.label | (const char *)... | | globalVars.c:38:9:38:13 | (const char *)... | semmle.label | (const char *)... | | globalVars.c:38:9:38:13 | (const char *)... | semmle.label | (const char *)... | | globalVars.c:38:9:38:13 | copy2 | semmle.label | copy2 | | globalVars.c:38:9:38:13 | copy2 | semmle.label | copy2 | | globalVars.c:38:9:38:13 | copy2 | semmle.label | copy2 | +| globalVars.c:38:9:38:13 | copy2 | semmle.label | copy2 | +| globalVars.c:38:9:38:13 | copy2 | semmle.label | copy2 | | globalVars.c:38:9:38:13 | copy2 indirection | semmle.label | copy2 indirection | | globalVars.c:38:9:38:13 | copy2 indirection | semmle.label | copy2 indirection | +| globalVars.c:38:9:38:13 | copy2 indirection | semmle.label | copy2 indirection | +| globalVars.c:38:9:38:13 | copy2 indirection | semmle.label | copy2 indirection | +| globalVars.c:41:2:41:13 | copy2 | semmle.label | copy2 | +| globalVars.c:41:15:41:19 | copy2 | semmle.label | copy2 | +| globalVars.c:41:15:41:19 | copy2 | semmle.label | copy2 | | globalVars.c:41:15:41:19 | copy2 | semmle.label | copy2 | | globalVars.c:41:15:41:19 | copy2 | semmle.label | copy2 | | globalVars.c:41:15:41:19 | copy2 | semmle.label | copy2 | | globalVars.c:41:15:41:19 | copy2 indirection | semmle.label | copy2 indirection | | globalVars.c:41:15:41:19 | copy2 indirection | semmle.label | copy2 indirection | +| globalVars.c:41:15:41:19 | copy2 indirection | semmle.label | copy2 indirection | +| globalVars.c:41:15:41:19 | copy2 indirection | semmle.label | copy2 indirection | +| globalVars.c:44:15:44:19 | copy2 | semmle.label | copy2 | +| globalVars.c:44:15:44:19 | copy2 | semmle.label | copy2 | +| globalVars.c:44:15:44:19 | copy2 indirection | semmle.label | copy2 indirection | +| globalVars.c:44:15:44:19 | copy2 indirection | semmle.label | copy2 indirection | +| globalVars.c:50:9:50:13 | (const char *)... | semmle.label | (const char *)... | +| globalVars.c:50:9:50:13 | (const char *)... | semmle.label | (const char *)... | | globalVars.c:50:9:50:13 | (const char *)... | semmle.label | (const char *)... | | globalVars.c:50:9:50:13 | (const char *)... | semmle.label | (const char *)... | | globalVars.c:50:9:50:13 | copy2 | semmle.label | copy2 | | globalVars.c:50:9:50:13 | copy2 | semmle.label | copy2 | | globalVars.c:50:9:50:13 | copy2 | semmle.label | copy2 | +| globalVars.c:50:9:50:13 | copy2 | semmle.label | copy2 | +| globalVars.c:50:9:50:13 | copy2 | semmle.label | copy2 | +| globalVars.c:50:9:50:13 | copy2 indirection | semmle.label | copy2 indirection | +| globalVars.c:50:9:50:13 | copy2 indirection | semmle.label | copy2 indirection | | globalVars.c:50:9:50:13 | copy2 indirection | semmle.label | copy2 indirection | | globalVars.c:50:9:50:13 | copy2 indirection | semmle.label | copy2 indirection | #select From 6e1ee07e908b1beb91169b4abd891c53018a5c23 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 19 Mar 2021 16:25:48 +0100 Subject: [PATCH 204/725] Address review comment --- docs/ql-libraries/dataflow/dataflow.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/ql-libraries/dataflow/dataflow.md b/docs/ql-libraries/dataflow/dataflow.md index 77e75a36241..c4c09a4c949 100644 --- a/docs/ql-libraries/dataflow/dataflow.md +++ b/docs/ql-libraries/dataflow/dataflow.md @@ -186,9 +186,9 @@ values, for example through `out` parameters in C#, the `ReturnKind` class can be defined and used to match up different kinds of `ReturnNode`s with the corresponding `OutNode`s. -#### Lambda flow +#### First-class functions -For lambda-like calls, the library supports built-in call resolution based on data flow between a lambda creation expression and a lambda call. The interface that needs to be implemented is +For calls to first-class functions, the library supports built-in call resolution based on data flow between a function creation expression and a call. The interface that needs to be implemented is ```ql class LambdaCallKind From ea8c8df65338cd08347652388343335972d8d83b Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 19 Mar 2021 15:30:49 +0000 Subject: [PATCH 205/725] JS: Fix bad join orders in summarizedHigherOrderCall --- .../javascript/dataflow/Configuration.qll | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll index 9c4587d1414..f45ed826b8c 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll @@ -1356,19 +1356,20 @@ private predicate summarizedHigherOrderCall( DataFlow::Node arg, DataFlow::Node cb, int i, DataFlow::Configuration cfg, PathSummary summary ) { exists( - Function f, DataFlow::InvokeNode outer, DataFlow::InvokeNode inner, int j, - DataFlow::Node innerArg, DataFlow::SourceNode cbParm, PathSummary oldSummary + Function f, DataFlow::InvokeNode inner, int j, DataFlow::Node innerArg, + DataFlow::SourceNode cbParm, PathSummary oldSummary | // Captured flow does not need to be summarized - it is handled by the local case in `higherOrderCall`. - not arg = DataFlow::capturedVariableNode(_) and - summarizedHigherOrderCallAux(f, outer, arg, innerArg, cfg, oldSummary, cbParm, inner, j, cb) + not arg = DataFlow::capturedVariableNode(_) | // direct higher-order call + summarizedHigherOrderCallAux(f, arg, innerArg, cfg, oldSummary, cbParm, inner, j, cb) and cbParm.flowsTo(inner.getCalleeNode()) and i = j and summary = oldSummary or // indirect higher-order call + summarizedHigherOrderCallAux(f, arg, innerArg, cfg, oldSummary, cbParm, inner, j, cb) and exists(DataFlow::Node cbArg, PathSummary newSummary | cbParm.flowsTo(cbArg) and summarizedHigherOrderCall(innerArg, cbArg, i, cfg, newSummary) and @@ -1382,14 +1383,17 @@ private predicate summarizedHigherOrderCall( */ pragma[noinline] private predicate summarizedHigherOrderCallAux( - Function f, DataFlow::InvokeNode outer, DataFlow::Node arg, DataFlow::Node innerArg, - DataFlow::Configuration cfg, PathSummary oldSummary, DataFlow::SourceNode cbParm, - DataFlow::InvokeNode inner, int j, DataFlow::Node cb + Function f, DataFlow::Node arg, DataFlow::Node innerArg, DataFlow::Configuration cfg, + PathSummary oldSummary, DataFlow::SourceNode cbParm, DataFlow::InvokeNode inner, int j, + DataFlow::Node cb ) { - reachableFromInput(f, outer, arg, innerArg, cfg, oldSummary) and - // Only track actual parameter flow. - argumentPassing(outer, cb, f, cbParm) and - innerArg = inner.getArgument(j) + exists(DataFlow::Node outer1, DataFlow::Node outer2 | + reachableFromInput(f, outer1, arg, innerArg, cfg, oldSummary) and + outer1 = pragma[only_bind_into](outer2) and + // Only track actual parameter flow. + argumentPassing(outer2, cb, f, cbParm) and + innerArg = inner.getArgument(j) + ) } /** From eae7bccaad7999b0c1cc3d825718e36de486d617 Mon Sep 17 00:00:00 2001 From: yoff Date: Fri, 19 Mar 2021 16:50:48 +0100 Subject: [PATCH 206/725] Apply suggestions from code review Co-authored-by: Shati Patel <42641846+shati-patel@users.noreply.github.com> --- .../analyzing-data-flow-in-python.rst | 2 +- .../codeql-library-for-python.rst | 4 +- .../using-api-graphs-in-python.rst | 42 +++++++++---------- 3 files changed, 25 insertions(+), 23 deletions(-) diff --git a/docs/codeql/codeql-language-guides/analyzing-data-flow-in-python.rst b/docs/codeql/codeql-language-guides/analyzing-data-flow-in-python.rst index 6e35c78a5a4..f5128e5eafd 100644 --- a/docs/codeql/codeql-language-guides/analyzing-data-flow-in-python.rst +++ b/docs/codeql/codeql-language-guides/analyzing-data-flow-in-python.rst @@ -99,7 +99,7 @@ Python has builtin functionality for reading and writing files, such as the func ➤ `See this in the query console on LGTM.com `__. Two of the demo projects make use of this low-level API. -Notice the use of the ``API`` module for referring to library functions. It is further described in ":doc:`Using API graphs in Python `." +Notice the use of the ``API`` module for referring to library functions. For more information, see ":doc:`Using API graphs in Python `." Unfortunately this will only give the expression in the argument, not the values which could be passed to it. So we use local data flow to find all expressions that flow into the argument: diff --git a/docs/codeql/codeql-language-guides/codeql-library-for-python.rst b/docs/codeql/codeql-language-guides/codeql-library-for-python.rst index ed5cf8b1deb..204a6d22c3b 100644 --- a/docs/codeql/codeql-language-guides/codeql-library-for-python.rst +++ b/docs/codeql/codeql-language-guides/codeql-library-for-python.rst @@ -23,7 +23,9 @@ The CodeQL library for Python incorporates a large number of classes. Each class - **Data flow** - classes that represent entities from the data flow graphs. - **API graphs** - classes that represent entities from the API graphs. -The first two categories are described below. See ":doc:`Analyzing data flow in Python `" for a description of data flow and associated classes and ":doc:`Using API graphs in Python `" for a description of API graphs and their use. +The first two categories are described below. +For a description of data flow and associated classes, see ":doc:`Analyzing data flow in Python `". +For a description of API graphs and their use, see ":doc:`Using API graphs in Python `." Syntactic classes ----------------- diff --git a/docs/codeql/codeql-language-guides/using-api-graphs-in-python.rst b/docs/codeql/codeql-language-guides/using-api-graphs-in-python.rst index ebfd70fe1fc..219519d6d92 100644 --- a/docs/codeql/codeql-language-guides/using-api-graphs-in-python.rst +++ b/docs/codeql/codeql-language-guides/using-api-graphs-in-python.rst @@ -10,7 +10,7 @@ About this article ------------------ This article describes how to use API graphs to reference classes and functions defined in library -code. This can be used to conveniently refer to external library functions when defining things like +code. You can use API graphs to conveniently refer to external library functions when defining things like remote flow sources. @@ -18,8 +18,8 @@ Module imports -------------- The most common entry point into the API graph will be the point where an external module or package is -imported. The API graph node corresponding to the ``re`` library, for instance, can be accessed -using the ``API::moduleImport`` method defined in the ``semmle.python.ApiGraphs`` module, as the +imported. For example, you can access the API graph node corresponding to the ``re`` library +by using the ``API::moduleImport`` method defined in the ``semmle.python.ApiGraphs`` module, as the following snippet demonstrates. .. code-block:: ql @@ -31,8 +31,8 @@ following snippet demonstrates. ➤ `See this in the query console on LGTM.com `__. -On its own, this only selects the API graph node corresponding to the ``re`` module. To find -where this module is referenced, we use the ``getAUse`` method. Thus, the following query selects +This query only selects the API graph node corresponding to the ``re`` module. To find +where this module is referenced, you can use the ``getAUse`` method. The following query selects all references to the ``re`` module in the current database. .. code-block:: ql @@ -56,8 +56,8 @@ correctly recognized as a reference to the ``re.compile`` function. r = my_re_compile(".*") -If only immediate uses are required, without taking local flow into account, then the method -``getAnImmediateUse`` may be used instead. +If you only require immediate uses, without taking local flow into account, then you can use +the ``getAnImmediateUse`` method instead. Note that the given module name *must not* contain any dots. Thus, something like ``API::moduleImport("flask.views")`` will not do what you expect. Instead, this should be decomposed @@ -67,8 +67,8 @@ section. Accessing attributes -------------------- -Given a node in the API graph, we may access its attributes by using the ``getMember`` method. Using -the above ``re.compile`` example, we may now find references to ``re.compile`` by doing +Given a node in the API graph, you can access its attributes by using the ``getMember`` method. Using +the above ``re.compile`` example, you can now find references to ``re.compile``. .. code-block:: ql @@ -79,15 +79,15 @@ the above ``re.compile`` example, we may now find references to ``re.compile`` b ➤ `See this in the query console on LGTM.com `__. -In addition to ``getMember``, the method ``getUnknownMember`` can be used to find references to API -components where the name is not known statically, and the ``getAMember`` method can be used to +In addition to ``getMember``, you can use the ``getUnknownMember`` method to find references to API +components where the name is not known statically. You can use the ``getAMember`` method to access all members, both known and unknown. Calls and class instantiations ------------------------------ To track instances of classes defined in external libraries, or the results of calling externally -defined functions, we may use the ``getReturn`` method. Thus, the following snippet finds all places +defined functions, you can use the ``getReturn`` method. The following snippet finds all places where the return value of ``re.compile`` is used: .. code-block:: ql @@ -100,8 +100,8 @@ where the return value of ``re.compile`` is used: ➤ `See this in the query console on LGTM.com `__. Note that this includes all uses of the result of ``re.compile``, including those reachable via -local flow. To get just the *calls* to ``re.compile``, we can use ``getAnImmediateUse`` instead of -``getAUse``. As this is a common occurrence, the method ``getACall`` can be used instead of +local flow. To get just the *calls* to ``re.compile``, you can use ``getAnImmediateUse`` instead of +``getAUse``. As this is a common occurrence, you can use ``getACall`` instead of ``getReturn`` followed by ``getAnImmediateUse``. ➤ `See this in the query console on LGTM.com `__. @@ -113,14 +113,14 @@ Subclasses ---------- For many libraries, the main mode of usage is to extend one or more library classes. To track this -in the API graph, we can use the ``getASubclass`` method to get the API graph node corresponding to +in the API graph, you can use the ``getASubclass`` method to get the API graph node corresponding to all the immediate subclasses of this node. To find *all* subclasses, use ``*`` or ``+`` to apply the -method repeatedly, as in `getASubclass*`. +method repeatedly, as in ``getASubclass*``. Note that ``getASubclass`` does not account for any subclassing that takes place in library code that has not been extracted. Thus, it may be necessary to account for this in the models you write. -For example, the ``flask.views.View`` class has a predefined subclass ``MethodView``, and so to find -all subclasses of ``View``, we must explicitly include the subclasses of ``MethodView`` as well. +For example, the ``flask.views.View`` class has a predefined subclass ``MethodView``. To find +all subclasses of ``View``, you must explicitly include the subclasses of ``MethodView`` as well. .. code-block:: ql @@ -132,7 +132,7 @@ all subclasses of ``View``, we must explicitly include the subclasses of ``Metho API::moduleImport("flask").getMember("views").getMember(["View", "MethodView"]).getASubclass*() } - select viewClass() + select viewClass().getAUse() ➤ `See this in the query console on LGTM.com `__. @@ -141,10 +141,10 @@ Note the use of the set literal ``["View", "MethodView"]`` to match both classes Built-in functions and classes ------------------------------ -Built-in functions and classes can be accessed using the ``API::builtin`` method, giving the name of +You can access built-in functions and classes using the ``API::builtin`` method, giving the name of the built-in as an argument. -To find all calls to the built-in ``open`` function, for instance, can be done using the following snippet +For example, to find all calls to the built-in ``open`` function, you can use the following snippet. .. code-block:: ql From 6ca425f03384bdce531fcd2f972080839593b11a Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 1 Mar 2021 15:19:08 +0000 Subject: [PATCH 207/725] JS: Implement new metric queries for line counting --- javascript/ql/src/Diagnostics/Files.ql | 10 ++++++++++ javascript/ql/src/Diagnostics/Lines.ql | 10 ++++++++++ javascript/ql/src/Diagnostics/LinesOfCode.ql | 10 ++++++++++ javascript/ql/src/Diagnostics/LinesOfCodePerFile.ql | 12 ++++++++++++ javascript/ql/src/Diagnostics/LinesPerFile.ql | 12 ++++++++++++ .../ql/test/query-tests/Diagnostics/Lines.expected | 1 + .../ql/test/query-tests/Diagnostics/Lines.qlref | 1 + .../query-tests/Diagnostics/LinesOfCode.expected | 1 + .../test/query-tests/Diagnostics/LinesOfCode.qlref | 1 + .../Diagnostics/LinesOfCodePerFile.expected | 4 ++++ .../query-tests/Diagnostics/LinesOfCodePerFile.qlref | 1 + .../query-tests/Diagnostics/LinesPerFile.expected | 4 ++++ .../test/query-tests/Diagnostics/LinesPerFile.qlref | 1 + .../test/query-tests/Diagnostics/src/.eslintrc.yml | 2 ++ .../ql/test/query-tests/Diagnostics/src/externs.js | 8 ++++++++ .../query-tests/Diagnostics/src/javascript_file.js | 7 +++++++ .../ql/test/query-tests/Diagnostics/src/package.json | 6 ++++++ .../query-tests/Diagnostics/src/typescript_file.ts | 7 +++++++ 18 files changed, 98 insertions(+) create mode 100644 javascript/ql/src/Diagnostics/Files.ql create mode 100644 javascript/ql/src/Diagnostics/Lines.ql create mode 100644 javascript/ql/src/Diagnostics/LinesOfCode.ql create mode 100644 javascript/ql/src/Diagnostics/LinesOfCodePerFile.ql create mode 100644 javascript/ql/src/Diagnostics/LinesPerFile.ql create mode 100644 javascript/ql/test/query-tests/Diagnostics/Lines.expected create mode 100644 javascript/ql/test/query-tests/Diagnostics/Lines.qlref create mode 100644 javascript/ql/test/query-tests/Diagnostics/LinesOfCode.expected create mode 100644 javascript/ql/test/query-tests/Diagnostics/LinesOfCode.qlref create mode 100644 javascript/ql/test/query-tests/Diagnostics/LinesOfCodePerFile.expected create mode 100644 javascript/ql/test/query-tests/Diagnostics/LinesOfCodePerFile.qlref create mode 100644 javascript/ql/test/query-tests/Diagnostics/LinesPerFile.expected create mode 100644 javascript/ql/test/query-tests/Diagnostics/LinesPerFile.qlref create mode 100644 javascript/ql/test/query-tests/Diagnostics/src/.eslintrc.yml create mode 100644 javascript/ql/test/query-tests/Diagnostics/src/externs.js create mode 100644 javascript/ql/test/query-tests/Diagnostics/src/javascript_file.js create mode 100644 javascript/ql/test/query-tests/Diagnostics/src/package.json create mode 100644 javascript/ql/test/query-tests/Diagnostics/src/typescript_file.ts diff --git a/javascript/ql/src/Diagnostics/Files.ql b/javascript/ql/src/Diagnostics/Files.ql new file mode 100644 index 00000000000..61e5bf53fd5 --- /dev/null +++ b/javascript/ql/src/Diagnostics/Files.ql @@ -0,0 +1,10 @@ +/** + * @name Total source files + * @description The total number of source files. + * @kind metric + * @id js/metrics/files + */ + +import javascript + +select count(File f | not f.getATopLevel().isExterns()) diff --git a/javascript/ql/src/Diagnostics/Lines.ql b/javascript/ql/src/Diagnostics/Lines.ql new file mode 100644 index 00000000000..6b49b93cfc4 --- /dev/null +++ b/javascript/ql/src/Diagnostics/Lines.ql @@ -0,0 +1,10 @@ +/** + * @name Total lines of text + * @description The total number of lines of text across all source files. + * @kind metric + * @id js/metrics/lines + */ + +import javascript + +select sum(File f | not f.getATopLevel().isExterns() | f.getNumberOfLines()) diff --git a/javascript/ql/src/Diagnostics/LinesOfCode.ql b/javascript/ql/src/Diagnostics/LinesOfCode.ql new file mode 100644 index 00000000000..039f78798d7 --- /dev/null +++ b/javascript/ql/src/Diagnostics/LinesOfCode.ql @@ -0,0 +1,10 @@ +/** + * @name Total lines of code + * @description The total number of lines of code across all source files. + * @kind metric + * @id js/metrics/lines-of-code + */ + +import javascript + +select sum(File f | not f.getATopLevel().isExterns() | f.getNumberOfLinesOfCode()) diff --git a/javascript/ql/src/Diagnostics/LinesOfCodePerFile.ql b/javascript/ql/src/Diagnostics/LinesOfCodePerFile.ql new file mode 100644 index 00000000000..1b6fdbb4346 --- /dev/null +++ b/javascript/ql/src/Diagnostics/LinesOfCodePerFile.ql @@ -0,0 +1,12 @@ +/** + * @name Lines of code per source file + * @description The number of lines of code for each source file. + * @kind metric + * @id js/metrics/lines-of-code-per-file + */ + +import javascript + +from File f +where not f.getATopLevel().isExterns() +select f, f.getNumberOfLinesOfCode() diff --git a/javascript/ql/src/Diagnostics/LinesPerFile.ql b/javascript/ql/src/Diagnostics/LinesPerFile.ql new file mode 100644 index 00000000000..639c77e2c4b --- /dev/null +++ b/javascript/ql/src/Diagnostics/LinesPerFile.ql @@ -0,0 +1,12 @@ +/** + * @name Lines of text per source file + * @description The number of lines of text for each source file. + * @kind metric + * @id js/metrics/lines-per-file + */ + +import javascript + +from File f +where not f.getATopLevel().isExterns() +select f, f.getNumberOfLines() diff --git a/javascript/ql/test/query-tests/Diagnostics/Lines.expected b/javascript/ql/test/query-tests/Diagnostics/Lines.expected new file mode 100644 index 00000000000..2e7d809d9b6 --- /dev/null +++ b/javascript/ql/test/query-tests/Diagnostics/Lines.expected @@ -0,0 +1 @@ +| 22 | diff --git a/javascript/ql/test/query-tests/Diagnostics/Lines.qlref b/javascript/ql/test/query-tests/Diagnostics/Lines.qlref new file mode 100644 index 00000000000..ecdef1053f4 --- /dev/null +++ b/javascript/ql/test/query-tests/Diagnostics/Lines.qlref @@ -0,0 +1 @@ +Diagnostics/Lines.ql \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Diagnostics/LinesOfCode.expected b/javascript/ql/test/query-tests/Diagnostics/LinesOfCode.expected new file mode 100644 index 00000000000..0c89049708a --- /dev/null +++ b/javascript/ql/test/query-tests/Diagnostics/LinesOfCode.expected @@ -0,0 +1 @@ +| 12 | diff --git a/javascript/ql/test/query-tests/Diagnostics/LinesOfCode.qlref b/javascript/ql/test/query-tests/Diagnostics/LinesOfCode.qlref new file mode 100644 index 00000000000..b07f3413688 --- /dev/null +++ b/javascript/ql/test/query-tests/Diagnostics/LinesOfCode.qlref @@ -0,0 +1 @@ +Diagnostics/LinesOfCode.ql \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Diagnostics/LinesOfCodePerFile.expected b/javascript/ql/test/query-tests/Diagnostics/LinesOfCodePerFile.expected new file mode 100644 index 00000000000..2b4e70ee13b --- /dev/null +++ b/javascript/ql/test/query-tests/Diagnostics/LinesOfCodePerFile.expected @@ -0,0 +1,4 @@ +| src/.eslintrc.yml:0:0:0:0 | src/.eslintrc.yml | 0 | +| src/javascript_file.js:0:0:0:0 | src/javascript_file.js | 6 | +| src/package.json:0:0:0:0 | src/package.json | 0 | +| src/typescript_file.ts:0:0:0:0 | src/typescript_file.ts | 6 | diff --git a/javascript/ql/test/query-tests/Diagnostics/LinesOfCodePerFile.qlref b/javascript/ql/test/query-tests/Diagnostics/LinesOfCodePerFile.qlref new file mode 100644 index 00000000000..ea50143078c --- /dev/null +++ b/javascript/ql/test/query-tests/Diagnostics/LinesOfCodePerFile.qlref @@ -0,0 +1 @@ +Diagnostics/LinesOfCodePerFile.ql \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Diagnostics/LinesPerFile.expected b/javascript/ql/test/query-tests/Diagnostics/LinesPerFile.expected new file mode 100644 index 00000000000..cb0dc13db43 --- /dev/null +++ b/javascript/ql/test/query-tests/Diagnostics/LinesPerFile.expected @@ -0,0 +1,4 @@ +| src/.eslintrc.yml:0:0:0:0 | src/.eslintrc.yml | 2 | +| src/javascript_file.js:0:0:0:0 | src/javascript_file.js | 7 | +| src/package.json:0:0:0:0 | src/package.json | 6 | +| src/typescript_file.ts:0:0:0:0 | src/typescript_file.ts | 7 | diff --git a/javascript/ql/test/query-tests/Diagnostics/LinesPerFile.qlref b/javascript/ql/test/query-tests/Diagnostics/LinesPerFile.qlref new file mode 100644 index 00000000000..768a83875e6 --- /dev/null +++ b/javascript/ql/test/query-tests/Diagnostics/LinesPerFile.qlref @@ -0,0 +1 @@ +Diagnostics/LinesPerFile.ql \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Diagnostics/src/.eslintrc.yml b/javascript/ql/test/query-tests/Diagnostics/src/.eslintrc.yml new file mode 100644 index 00000000000..2b4028c44b8 --- /dev/null +++ b/javascript/ql/test/query-tests/Diagnostics/src/.eslintrc.yml @@ -0,0 +1,2 @@ +rules: + semi: error diff --git a/javascript/ql/test/query-tests/Diagnostics/src/externs.js b/javascript/ql/test/query-tests/Diagnostics/src/externs.js new file mode 100644 index 00000000000..c8e9cec9bc4 --- /dev/null +++ b/javascript/ql/test/query-tests/Diagnostics/src/externs.js @@ -0,0 +1,8 @@ +/** + * @externs + */ + +// Should not be counted + +function Object() {} +function String() {} \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Diagnostics/src/javascript_file.js b/javascript/ql/test/query-tests/Diagnostics/src/javascript_file.js new file mode 100644 index 00000000000..e80d023d0d8 --- /dev/null +++ b/javascript/ql/test/query-tests/Diagnostics/src/javascript_file.js @@ -0,0 +1,7 @@ +function foo(x) { + return x; +} + +function bar(y) { + return y; +} diff --git a/javascript/ql/test/query-tests/Diagnostics/src/package.json b/javascript/ql/test/query-tests/Diagnostics/src/package.json new file mode 100644 index 00000000000..9ab61fa5ee4 --- /dev/null +++ b/javascript/ql/test/query-tests/Diagnostics/src/package.json @@ -0,0 +1,6 @@ +{ + "private": true, + "devDependencies": { + "typescript": "*" + } +} diff --git a/javascript/ql/test/query-tests/Diagnostics/src/typescript_file.ts b/javascript/ql/test/query-tests/Diagnostics/src/typescript_file.ts new file mode 100644 index 00000000000..e922c80dfdb --- /dev/null +++ b/javascript/ql/test/query-tests/Diagnostics/src/typescript_file.ts @@ -0,0 +1,7 @@ +export interface Foo { + x: number; +} + +export function getX(f: Foo) { + return f.x; +} From 0c0556bb38273722586f09b34f204a2719e4b97e Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 19 Mar 2021 16:42:05 +0000 Subject: [PATCH 208/725] JS: Update LinesOfCode.ql to match the style from C++ --- javascript/ql/src/Diagnostics/LinesOfCode.ql | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/Diagnostics/LinesOfCode.ql b/javascript/ql/src/Diagnostics/LinesOfCode.ql index 039f78798d7..9f89e0e2163 100644 --- a/javascript/ql/src/Diagnostics/LinesOfCode.ql +++ b/javascript/ql/src/Diagnostics/LinesOfCode.ql @@ -1,8 +1,9 @@ /** - * @name Total lines of code - * @description The total number of lines of code across all source files. + * @id js/summary/lines-of-code + * @name Total lines of JavaScript and TypeScript code in the database + * @description The total number of lines of JavaScript or TypeScript code across all files checked into the repository, except in `node_modules`. This is a useful metric of the size of a database. For all files that were seen during extraction, this query counts the lines of code, excluding whitespace or comments. * @kind metric - * @id js/metrics/lines-of-code + * @tags summary */ import javascript From 347cbe422daf851c31334541a055932e1f063055 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 19 Mar 2021 16:42:43 +0000 Subject: [PATCH 209/725] JS: Remove the other summary queries --- javascript/ql/src/Diagnostics/Files.ql | 10 ---------- javascript/ql/src/Diagnostics/Lines.ql | 10 ---------- javascript/ql/src/Diagnostics/LinesOfCodePerFile.ql | 12 ------------ javascript/ql/src/Diagnostics/LinesPerFile.ql | 12 ------------ 4 files changed, 44 deletions(-) delete mode 100644 javascript/ql/src/Diagnostics/Files.ql delete mode 100644 javascript/ql/src/Diagnostics/Lines.ql delete mode 100644 javascript/ql/src/Diagnostics/LinesOfCodePerFile.ql delete mode 100644 javascript/ql/src/Diagnostics/LinesPerFile.ql diff --git a/javascript/ql/src/Diagnostics/Files.ql b/javascript/ql/src/Diagnostics/Files.ql deleted file mode 100644 index 61e5bf53fd5..00000000000 --- a/javascript/ql/src/Diagnostics/Files.ql +++ /dev/null @@ -1,10 +0,0 @@ -/** - * @name Total source files - * @description The total number of source files. - * @kind metric - * @id js/metrics/files - */ - -import javascript - -select count(File f | not f.getATopLevel().isExterns()) diff --git a/javascript/ql/src/Diagnostics/Lines.ql b/javascript/ql/src/Diagnostics/Lines.ql deleted file mode 100644 index 6b49b93cfc4..00000000000 --- a/javascript/ql/src/Diagnostics/Lines.ql +++ /dev/null @@ -1,10 +0,0 @@ -/** - * @name Total lines of text - * @description The total number of lines of text across all source files. - * @kind metric - * @id js/metrics/lines - */ - -import javascript - -select sum(File f | not f.getATopLevel().isExterns() | f.getNumberOfLines()) diff --git a/javascript/ql/src/Diagnostics/LinesOfCodePerFile.ql b/javascript/ql/src/Diagnostics/LinesOfCodePerFile.ql deleted file mode 100644 index 1b6fdbb4346..00000000000 --- a/javascript/ql/src/Diagnostics/LinesOfCodePerFile.ql +++ /dev/null @@ -1,12 +0,0 @@ -/** - * @name Lines of code per source file - * @description The number of lines of code for each source file. - * @kind metric - * @id js/metrics/lines-of-code-per-file - */ - -import javascript - -from File f -where not f.getATopLevel().isExterns() -select f, f.getNumberOfLinesOfCode() diff --git a/javascript/ql/src/Diagnostics/LinesPerFile.ql b/javascript/ql/src/Diagnostics/LinesPerFile.ql deleted file mode 100644 index 639c77e2c4b..00000000000 --- a/javascript/ql/src/Diagnostics/LinesPerFile.ql +++ /dev/null @@ -1,12 +0,0 @@ -/** - * @name Lines of text per source file - * @description The number of lines of text for each source file. - * @kind metric - * @id js/metrics/lines-per-file - */ - -import javascript - -from File f -where not f.getATopLevel().isExterns() -select f, f.getNumberOfLines() From fa2ae1420a8eaf30dcf3671f4528dd7eec2db0a5 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 19 Mar 2021 16:43:23 +0000 Subject: [PATCH 210/725] JS: Rename Diagnostics folder to Summary --- javascript/ql/src/{Diagnostics => Summary}/LinesOfCode.ql | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename javascript/ql/src/{Diagnostics => Summary}/LinesOfCode.ql (100%) diff --git a/javascript/ql/src/Diagnostics/LinesOfCode.ql b/javascript/ql/src/Summary/LinesOfCode.ql similarity index 100% rename from javascript/ql/src/Diagnostics/LinesOfCode.ql rename to javascript/ql/src/Summary/LinesOfCode.ql From 405c1f3fc7c731137672bdb0ce1d52672e08db14 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 19 Mar 2021 16:45:31 +0000 Subject: [PATCH 211/725] JS: Update test suite --- javascript/ql/test/query-tests/Diagnostics/Lines.expected | 1 - javascript/ql/test/query-tests/Diagnostics/Lines.qlref | 1 - javascript/ql/test/query-tests/Diagnostics/LinesOfCode.qlref | 1 - .../test/query-tests/Diagnostics/LinesOfCodePerFile.expected | 4 ---- .../ql/test/query-tests/Diagnostics/LinesOfCodePerFile.qlref | 1 - .../ql/test/query-tests/Diagnostics/LinesPerFile.expected | 4 ---- javascript/ql/test/query-tests/Diagnostics/LinesPerFile.qlref | 1 - .../query-tests/{Diagnostics => Summary}/LinesOfCode.expected | 0 javascript/ql/test/query-tests/Summary/LinesOfCode.qlref | 1 + .../query-tests/{Diagnostics => Summary}/src/.eslintrc.yml | 0 .../test/query-tests/{Diagnostics => Summary}/src/externs.js | 0 .../{Diagnostics => Summary}/src/javascript_file.js | 0 .../query-tests/{Diagnostics => Summary}/src/package.json | 0 .../{Diagnostics => Summary}/src/typescript_file.ts | 0 14 files changed, 1 insertion(+), 13 deletions(-) delete mode 100644 javascript/ql/test/query-tests/Diagnostics/Lines.expected delete mode 100644 javascript/ql/test/query-tests/Diagnostics/Lines.qlref delete mode 100644 javascript/ql/test/query-tests/Diagnostics/LinesOfCode.qlref delete mode 100644 javascript/ql/test/query-tests/Diagnostics/LinesOfCodePerFile.expected delete mode 100644 javascript/ql/test/query-tests/Diagnostics/LinesOfCodePerFile.qlref delete mode 100644 javascript/ql/test/query-tests/Diagnostics/LinesPerFile.expected delete mode 100644 javascript/ql/test/query-tests/Diagnostics/LinesPerFile.qlref rename javascript/ql/test/query-tests/{Diagnostics => Summary}/LinesOfCode.expected (100%) create mode 100644 javascript/ql/test/query-tests/Summary/LinesOfCode.qlref rename javascript/ql/test/query-tests/{Diagnostics => Summary}/src/.eslintrc.yml (100%) rename javascript/ql/test/query-tests/{Diagnostics => Summary}/src/externs.js (100%) rename javascript/ql/test/query-tests/{Diagnostics => Summary}/src/javascript_file.js (100%) rename javascript/ql/test/query-tests/{Diagnostics => Summary}/src/package.json (100%) rename javascript/ql/test/query-tests/{Diagnostics => Summary}/src/typescript_file.ts (100%) diff --git a/javascript/ql/test/query-tests/Diagnostics/Lines.expected b/javascript/ql/test/query-tests/Diagnostics/Lines.expected deleted file mode 100644 index 2e7d809d9b6..00000000000 --- a/javascript/ql/test/query-tests/Diagnostics/Lines.expected +++ /dev/null @@ -1 +0,0 @@ -| 22 | diff --git a/javascript/ql/test/query-tests/Diagnostics/Lines.qlref b/javascript/ql/test/query-tests/Diagnostics/Lines.qlref deleted file mode 100644 index ecdef1053f4..00000000000 --- a/javascript/ql/test/query-tests/Diagnostics/Lines.qlref +++ /dev/null @@ -1 +0,0 @@ -Diagnostics/Lines.ql \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Diagnostics/LinesOfCode.qlref b/javascript/ql/test/query-tests/Diagnostics/LinesOfCode.qlref deleted file mode 100644 index b07f3413688..00000000000 --- a/javascript/ql/test/query-tests/Diagnostics/LinesOfCode.qlref +++ /dev/null @@ -1 +0,0 @@ -Diagnostics/LinesOfCode.ql \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Diagnostics/LinesOfCodePerFile.expected b/javascript/ql/test/query-tests/Diagnostics/LinesOfCodePerFile.expected deleted file mode 100644 index 2b4e70ee13b..00000000000 --- a/javascript/ql/test/query-tests/Diagnostics/LinesOfCodePerFile.expected +++ /dev/null @@ -1,4 +0,0 @@ -| src/.eslintrc.yml:0:0:0:0 | src/.eslintrc.yml | 0 | -| src/javascript_file.js:0:0:0:0 | src/javascript_file.js | 6 | -| src/package.json:0:0:0:0 | src/package.json | 0 | -| src/typescript_file.ts:0:0:0:0 | src/typescript_file.ts | 6 | diff --git a/javascript/ql/test/query-tests/Diagnostics/LinesOfCodePerFile.qlref b/javascript/ql/test/query-tests/Diagnostics/LinesOfCodePerFile.qlref deleted file mode 100644 index ea50143078c..00000000000 --- a/javascript/ql/test/query-tests/Diagnostics/LinesOfCodePerFile.qlref +++ /dev/null @@ -1 +0,0 @@ -Diagnostics/LinesOfCodePerFile.ql \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Diagnostics/LinesPerFile.expected b/javascript/ql/test/query-tests/Diagnostics/LinesPerFile.expected deleted file mode 100644 index cb0dc13db43..00000000000 --- a/javascript/ql/test/query-tests/Diagnostics/LinesPerFile.expected +++ /dev/null @@ -1,4 +0,0 @@ -| src/.eslintrc.yml:0:0:0:0 | src/.eslintrc.yml | 2 | -| src/javascript_file.js:0:0:0:0 | src/javascript_file.js | 7 | -| src/package.json:0:0:0:0 | src/package.json | 6 | -| src/typescript_file.ts:0:0:0:0 | src/typescript_file.ts | 7 | diff --git a/javascript/ql/test/query-tests/Diagnostics/LinesPerFile.qlref b/javascript/ql/test/query-tests/Diagnostics/LinesPerFile.qlref deleted file mode 100644 index 768a83875e6..00000000000 --- a/javascript/ql/test/query-tests/Diagnostics/LinesPerFile.qlref +++ /dev/null @@ -1 +0,0 @@ -Diagnostics/LinesPerFile.ql \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Diagnostics/LinesOfCode.expected b/javascript/ql/test/query-tests/Summary/LinesOfCode.expected similarity index 100% rename from javascript/ql/test/query-tests/Diagnostics/LinesOfCode.expected rename to javascript/ql/test/query-tests/Summary/LinesOfCode.expected diff --git a/javascript/ql/test/query-tests/Summary/LinesOfCode.qlref b/javascript/ql/test/query-tests/Summary/LinesOfCode.qlref new file mode 100644 index 00000000000..ac8650d6dcc --- /dev/null +++ b/javascript/ql/test/query-tests/Summary/LinesOfCode.qlref @@ -0,0 +1 @@ +Summary/LinesOfCode.ql \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Diagnostics/src/.eslintrc.yml b/javascript/ql/test/query-tests/Summary/src/.eslintrc.yml similarity index 100% rename from javascript/ql/test/query-tests/Diagnostics/src/.eslintrc.yml rename to javascript/ql/test/query-tests/Summary/src/.eslintrc.yml diff --git a/javascript/ql/test/query-tests/Diagnostics/src/externs.js b/javascript/ql/test/query-tests/Summary/src/externs.js similarity index 100% rename from javascript/ql/test/query-tests/Diagnostics/src/externs.js rename to javascript/ql/test/query-tests/Summary/src/externs.js diff --git a/javascript/ql/test/query-tests/Diagnostics/src/javascript_file.js b/javascript/ql/test/query-tests/Summary/src/javascript_file.js similarity index 100% rename from javascript/ql/test/query-tests/Diagnostics/src/javascript_file.js rename to javascript/ql/test/query-tests/Summary/src/javascript_file.js diff --git a/javascript/ql/test/query-tests/Diagnostics/src/package.json b/javascript/ql/test/query-tests/Summary/src/package.json similarity index 100% rename from javascript/ql/test/query-tests/Diagnostics/src/package.json rename to javascript/ql/test/query-tests/Summary/src/package.json diff --git a/javascript/ql/test/query-tests/Diagnostics/src/typescript_file.ts b/javascript/ql/test/query-tests/Summary/src/typescript_file.ts similarity index 100% rename from javascript/ql/test/query-tests/Diagnostics/src/typescript_file.ts rename to javascript/ql/test/query-tests/Summary/src/typescript_file.ts From b565e3de91b2b6abe9f527b76c71ad00000f2041 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 19 Mar 2021 21:07:22 +0100 Subject: [PATCH 212/725] expand outDir support in tsconfig files --- .../com/semmle/js/extractor/AutoBuild.java | 2 +- .../src/com/semmle/js/extractor/Main.java | 2 +- javascript/ql/src/semmle/javascript/Paths.qll | 115 +++++++++++------- .../ImportOutDir/slashAndExtension/index.js | 2 + .../slashAndExtension/package.json | 4 + .../slashAndExtension/src/index.ts | 1 + .../slashAndExtension/tsconfig.json | 8 ++ .../TypeScript/ImportOutDir/tests.expected | 5 + .../TypeScript/ImportOutDir/tests.ql | 2 + 9 files changed, 98 insertions(+), 43 deletions(-) create mode 100644 javascript/ql/test/library-tests/TypeScript/ImportOutDir/slashAndExtension/index.js create mode 100644 javascript/ql/test/library-tests/TypeScript/ImportOutDir/slashAndExtension/package.json create mode 100644 javascript/ql/test/library-tests/TypeScript/ImportOutDir/slashAndExtension/src/index.ts create mode 100644 javascript/ql/test/library-tests/TypeScript/ImportOutDir/slashAndExtension/tsconfig.json diff --git a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java index 505c45832e2..94319e4998c 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java +++ b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java @@ -407,7 +407,7 @@ public class AutoBuild { // codeql-javascript-*.json files patterns.add("**/.eslintrc*"); patterns.add("**/package.json"); - patterns.add("**/tsconfig.json"); + patterns.add("**/tsconfig*.json"); patterns.add("**/codeql-javascript-*.json"); // include any explicitly specified extensions diff --git a/javascript/extractor/src/com/semmle/js/extractor/Main.java b/javascript/extractor/src/com/semmle/js/extractor/Main.java index 7b5df6946d4..7c5a8a25984 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/Main.java +++ b/javascript/extractor/src/com/semmle/js/extractor/Main.java @@ -43,7 +43,7 @@ public class Main { * A version identifier that should be updated every time the extractor changes in such a way that * it may produce different tuples for the same file under the same {@link ExtractorConfig}. */ - public static final String EXTRACTOR_VERSION = "2021-03-08"; + public static final String EXTRACTOR_VERSION = "2021-03-19"; public static final Pattern NEWLINE = Pattern.compile("\n"); diff --git a/javascript/ql/src/semmle/javascript/Paths.qll b/javascript/ql/src/semmle/javascript/Paths.qll index 6c25f8795d9..37098fc130f 100644 --- a/javascript/ql/src/semmle/javascript/Paths.qll +++ b/javascript/ql/src/semmle/javascript/Paths.qll @@ -141,29 +141,7 @@ abstract class PathString extends string { * components of this path refers to when resolved relative to the * given `root` folder. */ - Path resolveUpTo(int n, Folder root) { - n = 0 and result.getContainer() = root and root = getARootFolder() - or - exists(Path base, string next | next = getComponent(this, n - 1, base, root) | - // handle empty components and the special "." folder - (next = "" or next = ".") and - result = base - or - // handle the special ".." folder - next = ".." and result = base.(ConsPath).getParent() - or - // special handling for Windows drive letters when resolving absolute path: - // the extractor populates "C:/" as a folder that has path "C:/" but name "" - n = 1 and - next.regexpMatch("[A-Za-z]:") and - root.getBaseName() = "" and - root.toString() = next.toUpperCase() + "/" and - result = base - or - // default case - result = TConsPath(base, next) - ) - } + Path resolveUpTo(int n, Folder root) { result = resolveUpTo(this, n, root, _) } /** * Gets the absolute path that this path refers to when resolved relative to @@ -172,16 +150,57 @@ abstract class PathString extends string { Path resolve(Folder root) { result = resolveUpTo(getNumComponent(), root) } } +/** + * Gets the absolute path that the sub-path consisting of the first `n` + * components of this path refers to when resolved relative to the + * given `root` folder. + */ +private Path resolveUpTo(PathString p, int n, Folder root, boolean inTS) { + n = 0 and result.getContainer() = root and root = p.getARootFolder() and inTS = false + or + exists(Path base, string next | next = getComponent(p, n - 1, base, root, inTS) | + // handle empty components and the special "." folder + (next = "" or next = ".") and + result = base + or + // handle the special ".." folder + next = ".." and result = base.(ConsPath).getParent() + or + // special handling for Windows drive letters when resolving absolute path: + // the extractor populates "C:/" as a folder that has path "C:/" but name "" + n = 1 and + next.regexpMatch("[A-Za-z]:") and + root.getBaseName() = "" and + root.toString() = next.toUpperCase() + "/" and + result = base + or + // default case + result = TConsPath(base, next) + ) +} + /** * Gets the `i`th component of the path `str`, where `base` is the resolved path one level up. * Supports that the root directory might be compiled output from TypeScript. + * `inTS` is true if the result is TypeScript that is compiled into the path specified by `str`. */ -private string getComponent(PathString str, int n, Path base, Folder root) { - base = str.resolveUpTo(n, root) and - ( - result = str.getComponent(n) - or - result = TypeScriptOutDir::getOriginalTypeScriptFolder(str.getComponent(n), base.getContainer()) +private string getComponent(PathString str, int n, Path base, Folder root, boolean inTS) { + exists(boolean prevTS | + base = resolveUpTo(str, n, root, prevTS) and + ( + result = str.getComponent(n) and prevTS = inTS + or + // If we are in a TypeScript source folder, try to replace file endings with ".ts" or ".tsx" + n = str.getNumComponent() - 1 and + prevTS = true and + inTS = prevTS and + result = str.getComponent(n).regexpCapture("^(.*)\\.js$", 1) + "." + ["ts", "tsx"] + or + prevTS = false and + inTS = true and + result = + TypeScriptOutDir::getOriginalTypeScriptFolder(str.getComponent(n), base.getContainer()) + ) ) } @@ -194,21 +213,35 @@ private module TypeScriptOutDir { */ string getOriginalTypeScriptFolder(string outdir, Folder parent) { exists(JSONObject tsconfig | - tsconfig.getFile().getBaseName() = "tsconfig.json" and - tsconfig.isTopLevel() and - tsconfig.getFile().getParentContainer() = parent - | - outdir = - tsconfig - .getPropValue("compilerOptions") - .(JSONObject) - .getPropValue("outDir") - .(JSONString) - .getValue() and - result = getEffectiveRootDirFromTSConfig(tsconfig) + outdir = removeLeadingSlash(getOutDir(tsconfig, parent)) and + result = removeLeadingSlash(getEffectiveRootDirFromTSConfig(tsconfig)) ) } + /** + * Removes a leading dot and/or slash from `raw`. + */ + bindingset[raw] + private string removeLeadingSlash(string raw) { + result = raw.regexpCapture("^\\.?/?([\\w.\\-]+)$", 1) + } + + /** + * Gets the `outDir` option from a tsconfig file from the folder `parent`. + */ + private string getOutDir(JSONObject tsconfig, Folder parent) { + tsconfig.getFile().getBaseName().regexpMatch("tsconfig.*\\.json") and + tsconfig.isTopLevel() and + tsconfig.getFile().getParentContainer() = parent and + result = + tsconfig + .getPropValue("compilerOptions") + .(JSONObject) + .getPropValue("outDir") + .(JSONString) + .getValue() + } + /** * Gets the directory that contains the TypeScript source files. * Based on the tsconfig.json file `tsconfig`. diff --git a/javascript/ql/test/library-tests/TypeScript/ImportOutDir/slashAndExtension/index.js b/javascript/ql/test/library-tests/TypeScript/ImportOutDir/slashAndExtension/index.js new file mode 100644 index 00000000000..905a92e15a4 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/ImportOutDir/slashAndExtension/index.js @@ -0,0 +1,2 @@ +var foo1 = require('./lib/index.js'); +var foo2 = require('./src/index.ts'); \ No newline at end of file diff --git a/javascript/ql/test/library-tests/TypeScript/ImportOutDir/slashAndExtension/package.json b/javascript/ql/test/library-tests/TypeScript/ImportOutDir/slashAndExtension/package.json new file mode 100644 index 00000000000..4c8d1a457cb --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/ImportOutDir/slashAndExtension/package.json @@ -0,0 +1,4 @@ +{ + "name": "foo", + "main": "./lib/index.js" +} \ No newline at end of file diff --git a/javascript/ql/test/library-tests/TypeScript/ImportOutDir/slashAndExtension/src/index.ts b/javascript/ql/test/library-tests/TypeScript/ImportOutDir/slashAndExtension/src/index.ts new file mode 100644 index 00000000000..06f1c250ccd --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/ImportOutDir/slashAndExtension/src/index.ts @@ -0,0 +1 @@ +export default class Foo {} \ No newline at end of file diff --git a/javascript/ql/test/library-tests/TypeScript/ImportOutDir/slashAndExtension/tsconfig.json b/javascript/ql/test/library-tests/TypeScript/ImportOutDir/slashAndExtension/tsconfig.json new file mode 100644 index 00000000000..0ae78b4a7cb --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/ImportOutDir/slashAndExtension/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig", + "compilerOptions": { + "module": "commonjs", + "rootDir": "./src", + "outDir": "./lib" + } +} \ No newline at end of file diff --git a/javascript/ql/test/library-tests/TypeScript/ImportOutDir/tests.expected b/javascript/ql/test/library-tests/TypeScript/ImportOutDir/tests.expected index 4050e660521..af67932f33d 100644 --- a/javascript/ql/test/library-tests/TypeScript/ImportOutDir/tests.expected +++ b/javascript/ql/test/library-tests/TypeScript/ImportOutDir/tests.expected @@ -1,3 +1,4 @@ +resolveableImport | nonUniqueInclude/index.js:1:12:1:38 | require ... oo.js') | nonUniqueInclude/src/foo.ts:1:1:1:27 | | | nonUniqueInclude/index.js:2:12:2:39 | require ... oo.js') | nonUniqueInclude/src2/foo.ts:1:1:1:27 | | | nonUniqueInclude/index.js:3:12:3:34 | require ... oo.ts') | nonUniqueInclude/src/foo.ts:1:1:1:27 | | @@ -10,3 +11,7 @@ | simpleOutDir/index.js:2:12:2:36 | require ... ex.ts') | simpleOutDir/src/index.ts:1:1:1:27 | | | simpleOutDir/index.js:4:12:4:33 | require ... index') | simpleOutDir/src/index.ts:1:1:1:27 | | | simpleOutDir/index.js:5:12:5:33 | require ... index') | simpleOutDir/src/index.ts:1:1:1:27 | | +| slashAndExtension/index.js:1:12:1:36 | require ... ex.js') | slashAndExtension/src/index.ts:1:1:1:27 | | +| slashAndExtension/index.js:2:12:2:36 | require ... ex.ts') | slashAndExtension/src/index.ts:1:1:1:27 | | +getMain +| slashAndExtension/package.json:1:1:4:1 | {\\n " ... x.js"\\n} | slashAndExtension/src/index.ts:1:1:1:27 | | diff --git a/javascript/ql/test/library-tests/TypeScript/ImportOutDir/tests.ql b/javascript/ql/test/library-tests/TypeScript/ImportOutDir/tests.ql index 35d4a969236..450989f717b 100644 --- a/javascript/ql/test/library-tests/TypeScript/ImportOutDir/tests.ql +++ b/javascript/ql/test/library-tests/TypeScript/ImportOutDir/tests.ql @@ -5,3 +5,5 @@ query predicate resolveableImport(Import imp, Module mod) { not imp.getTopLevel().isExterns() and not mod.getTopLevel().isExterns() } + +query Module getMain(PackageJSON json) { result = json.getMainModule() } From 1385b2264234bc6fa3deaaeb7537ee47d89c47fe Mon Sep 17 00:00:00 2001 From: Dilan Date: Fri, 19 Mar 2021 16:43:29 -0700 Subject: [PATCH 213/725] pr fixes, typo in qhelp file and helper method for queries --- .../Classes/NamingConventionsClasses.qhelp | 2 +- .../Classes/NamingConventionsClasses.ql | 17 +++++++----- .../NamingConventionsFunctions.qhelp | 2 +- .../Functions/NamingConventionsFunctions.ql | 27 +++++++++++-------- 4 files changed, 29 insertions(+), 19 deletions(-) diff --git a/python/ql/src/experimental/Classes/NamingConventionsClasses.qhelp b/python/ql/src/experimental/Classes/NamingConventionsClasses.qhelp index 1a7f4bc45a4..a928668dc6f 100644 --- a/python/ql/src/experimental/Classes/NamingConventionsClasses.qhelp +++ b/python/ql/src/experimental/Classes/NamingConventionsClasses.qhelp @@ -21,7 +21,7 @@ Write the class name beginning with an uppercase letter. For example, clas
  • - Guido van Rossum, Barry Warsaw, Nick Coghlan PEP 8 -- Style Guide for Python Code + Guido van Rossum, Barry Warsaw, Nick Coghlan PEP 8 -- Style Guide for Python Code Python Class Names
  • diff --git a/python/ql/src/experimental/Classes/NamingConventionsClasses.ql b/python/ql/src/experimental/Classes/NamingConventionsClasses.ql index d4919c3ece8..f16d242eadf 100644 --- a/python/ql/src/experimental/Classes/NamingConventionsClasses.ql +++ b/python/ql/src/experimental/Classes/NamingConventionsClasses.ql @@ -9,15 +9,20 @@ import python -from Class c, string first_char +predicate lower_case_class(Class c) { + exists(string first_char | + first_char = c.getName().prefix(1) and + not first_char = first_char.toUpperCase() + ) +} + +from Class c where c.inSource() and - first_char = c.getName().prefix(1) and - not first_char = first_char.toUpperCase() and - not exists(Class c1, string first_char1 | + lower_case_class(c) and + not exists(Class c1 | c1 != c and c1.getLocation().getFile() = c.getLocation().getFile() and - first_char1 = c1.getName().prefix(1) and - not first_char1 = first_char1.toUpperCase() + lower_case_class(c1) ) select c, "Class names should start in uppercase." diff --git a/python/ql/src/experimental/Functions/NamingConventionsFunctions.qhelp b/python/ql/src/experimental/Functions/NamingConventionsFunctions.qhelp index 46d948592ff..b4ff738782c 100644 --- a/python/ql/src/experimental/Functions/NamingConventionsFunctions.qhelp +++ b/python/ql/src/experimental/Functions/NamingConventionsFunctions.qhelp @@ -21,7 +21,7 @@ Write the function name beginning with an lowercase letter. For example, j
  • - Guido van Rossum, Barry Warsaw, Nick Coghlan PEP 8 -- Style Guide for Python Code + Guido van Rossum, Barry Warsaw, Nick Coghlan PEP 8 -- Style Guide for Python Code Python Function and Variable Names
  • diff --git a/python/ql/src/experimental/Functions/NamingConventionsFunctions.ql b/python/ql/src/experimental/Functions/NamingConventionsFunctions.ql index 80dc0e99cd8..d2868af22c9 100644 --- a/python/ql/src/experimental/Functions/NamingConventionsFunctions.ql +++ b/python/ql/src/experimental/Functions/NamingConventionsFunctions.ql @@ -9,15 +9,20 @@ import python -from Function f, string first_char -where - f.inSource() and - first_char = f.getName().prefix(1) and - not first_char = first_char.toLowerCase() and - not exists(Function f1, string first_char1 | - f1 != f and - f1.getLocation().getFile() = f.getLocation().getFile() and - first_char1 = f1.getName().prefix(1) and - not first_char1 = first_char1.toLowerCase() +predicate upper_case_function(Function func) { + exists(string first_char | + first_char = func.getName().prefix(1) and + not first_char = first_char.toLowerCase() ) -select f, "Function names should start in lowercase." +} + +from Function func +where + func.inSource() and + upper_case_function(func) and + not exists(Function func1 | + func1 != func and + func1.getLocation().getFile() = func.getLocation().getFile() and + upper_case_function(func1) + ) +select func, "Function names should start in lowercase." From f4a476ea4e8e27d100b35ac8758c9b36dac7f3aa Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Sat, 20 Mar 2021 09:05:04 +0000 Subject: [PATCH 214/725] JS: Change type ValueNode -> Node --- .../ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll index 79ffecad221..2d9f05ce592 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll @@ -182,7 +182,7 @@ private module CachedSteps { */ cached predicate argumentPassing( - DataFlow::SourceNode invk, DataFlow::ValueNode arg, Function f, DataFlow::SourceNode parm + DataFlow::SourceNode invk, DataFlow::Node arg, Function f, DataFlow::SourceNode parm ) { calls(invk, f) and ( From a54e810804256e0abafd8c13a32fef818a330bec Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Sat, 20 Mar 2021 11:37:15 +0000 Subject: [PATCH 215/725] JS: Include accessor-calls in CallGraph.ql --- javascript/ql/src/meta/alerts/CallGraph.ql | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/meta/alerts/CallGraph.ql b/javascript/ql/src/meta/alerts/CallGraph.ql index ea86e7b474a..13cb8a94ecd 100644 --- a/javascript/ql/src/meta/alerts/CallGraph.ql +++ b/javascript/ql/src/meta/alerts/CallGraph.ql @@ -10,6 +10,7 @@ import javascript -from DataFlow::InvokeNode invoke, Function f -where invoke.getACallee() = f -select invoke, "Call to $@", f, f.describe() +from DataFlow::Node invoke, Function f, string kind +where invoke.(DataFlow::InvokeNode).getACallee() = f and kind = "Call" or + invoke.(DataFlow::PropRef).getAnAccessorCallee().getFunction() = f and kind = "Accessor call" +select invoke, kind + " to $@", f, f.describe() From 26bac9f425c2ecab54759797da19bcc1586ed95d Mon Sep 17 00:00:00 2001 From: ihsinme Date: Sun, 21 Mar 2021 15:25:29 +0300 Subject: [PATCH 216/725] Apply suggestions from code review Co-authored-by: Robert Marsh --- .../CWE-783/OperatorPrecedenceLogicErrorWhenUseBoolType.ql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-783/OperatorPrecedenceLogicErrorWhenUseBoolType.ql b/cpp/ql/src/experimental/Security/CWE/CWE-783/OperatorPrecedenceLogicErrorWhenUseBoolType.ql index 1a116a83dbf..034df703bc3 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-783/OperatorPrecedenceLogicErrorWhenUseBoolType.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-783/OperatorPrecedenceLogicErrorWhenUseBoolType.ql @@ -15,12 +15,12 @@ import cpp import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis -/** Holds, if it is an expression, a boolean increment. */ +/** Holds if `exp` increments a boolean value. */ predicate incrementBoolType(Expr exp) { exp.(IncrementOperation).getOperand().getType() instanceof BoolType } -/** Holds, if this is an expression, applies a minus to a boolean type. */ +/** Holds if `exp` applies the unary minus operator to a boolean type. */ predicate revertSignBoolType(Expr exp) { exp.(AssignExpr).getRValue().(UnaryMinusExpr).getAnOperand().getType() instanceof BoolType and exp.(AssignExpr).getLValue().getType() instanceof BoolType From 0200aedc2efc939b96170951d848d440fcbb8e4a Mon Sep 17 00:00:00 2001 From: yo-h <55373593+yo-h@users.noreply.github.com> Date: Sun, 21 Mar 2021 12:55:25 -0400 Subject: [PATCH 217/725] Java 16: adjust test `options` --- java/ql/test/library-tests/dataflow/records/options | 2 +- java/ql/test/library-tests/dataflow/taint-format/options | 1 - java/ql/test/library-tests/printAst/options | 2 +- java/ql/test/library-tests/ssa/options | 2 +- java/ql/test/query-tests/StringFormat/options | 1 - 5 files changed, 3 insertions(+), 5 deletions(-) delete mode 100644 java/ql/test/library-tests/dataflow/taint-format/options delete mode 100644 java/ql/test/query-tests/StringFormat/options diff --git a/java/ql/test/library-tests/dataflow/records/options b/java/ql/test/library-tests/dataflow/records/options index 81817b37785..fc57fe025b9 100644 --- a/java/ql/test/library-tests/dataflow/records/options +++ b/java/ql/test/library-tests/dataflow/records/options @@ -1 +1 @@ -//semmle-extractor-options: --javac-args --enable-preview -source 15 -target 15 +//semmle-extractor-options: --javac-args -source 16 -target 16 diff --git a/java/ql/test/library-tests/dataflow/taint-format/options b/java/ql/test/library-tests/dataflow/taint-format/options deleted file mode 100644 index 81817b37785..00000000000 --- a/java/ql/test/library-tests/dataflow/taint-format/options +++ /dev/null @@ -1 +0,0 @@ -//semmle-extractor-options: --javac-args --enable-preview -source 15 -target 15 diff --git a/java/ql/test/library-tests/printAst/options b/java/ql/test/library-tests/printAst/options index 81817b37785..e41003a6e3c 100644 --- a/java/ql/test/library-tests/printAst/options +++ b/java/ql/test/library-tests/printAst/options @@ -1 +1 @@ -//semmle-extractor-options: --javac-args --enable-preview -source 15 -target 15 +//semmle-extractor-options: --javac-args --enable-preview -source 16 -target 16 diff --git a/java/ql/test/library-tests/ssa/options b/java/ql/test/library-tests/ssa/options index 81817b37785..e41003a6e3c 100644 --- a/java/ql/test/library-tests/ssa/options +++ b/java/ql/test/library-tests/ssa/options @@ -1 +1 @@ -//semmle-extractor-options: --javac-args --enable-preview -source 15 -target 15 +//semmle-extractor-options: --javac-args --enable-preview -source 16 -target 16 diff --git a/java/ql/test/query-tests/StringFormat/options b/java/ql/test/query-tests/StringFormat/options deleted file mode 100644 index 81817b37785..00000000000 --- a/java/ql/test/query-tests/StringFormat/options +++ /dev/null @@ -1 +0,0 @@ -//semmle-extractor-options: --javac-args --enable-preview -source 15 -target 15 From fa98443bb7e3fe3ca1c594d27ecb0c6661930c2b Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Wed, 17 Mar 2021 01:41:36 +0100 Subject: [PATCH 218/725] Java: Add value predicates for float and double literals; improve tests --- java/ql/src/semmle/code/java/Expr.qll | 12 ++ .../literals/literalBoolean.expected | 4 +- .../library-tests/literals/literalBoolean.ql | 2 +- .../literals/literalChar.expected | 11 +- .../library-tests/literals/literalChar.ql | 2 +- .../literals/literalDouble.expected | 17 ++- .../library-tests/literals/literalDouble.ql | 2 +- .../literals/literalFloat.expected | 17 ++- .../library-tests/literals/literalFloat.ql | 2 +- .../literals/literalInteger.expected | 28 +++- .../library-tests/literals/literalInteger.ql | 2 +- .../literals/literalLong.expected | 24 ++- .../library-tests/literals/literalLong.ql | 2 +- .../literals/literalString.expected | 26 +++- .../library-tests/literals/literalString.ql | 2 +- .../literals/literals/Literals.java | 137 ++++++++++++++++-- 16 files changed, 248 insertions(+), 42 deletions(-) diff --git a/java/ql/src/semmle/code/java/Expr.qll b/java/ql/src/semmle/code/java/Expr.qll index 43ad6634fc1..054e41958be 100755 --- a/java/ql/src/semmle/code/java/Expr.qll +++ b/java/ql/src/semmle/code/java/Expr.qll @@ -653,11 +653,23 @@ class LongLiteral extends Literal, @longliteral { /** A floating point literal. For example, `4.2f`. */ class FloatingPointLiteral extends Literal, @floatingpointliteral { + /** + * Gets the value of this literal as CodeQL 64-bit `float`. The value will + * be parsed as Java 32-bit `float` and then converted to a CodeQL `float`. + */ + float getFloatValue() { result = getValue().toFloat() } + override string getAPrimaryQlClass() { result = "FloatingPointLiteral" } } /** A double literal. For example, `4.2`. */ class DoubleLiteral extends Literal, @doubleliteral { + /** + * Gets the value of this literal as CodeQL 64-bit `float`. The result will + * have the same effective value as the Java `double` literal. + */ + float getDoubleValue() { result = getValue().toFloat() } + override string getAPrimaryQlClass() { result = "DoubleLiteral" } } diff --git a/java/ql/test/library-tests/literals/literalBoolean.expected b/java/ql/test/library-tests/literals/literalBoolean.expected index 73460f4206b..bfc9f1a043f 100644 --- a/java/ql/test/library-tests/literals/literalBoolean.expected +++ b/java/ql/test/library-tests/literals/literalBoolean.expected @@ -1 +1,3 @@ -| literals/Literals.java:11:22:11:25 | true | \ No newline at end of file +| literals/Literals.java:11:22:11:25 | true | true | true | +| literals/Literals.java:16:3:16:6 | true | true | true | +| literals/Literals.java:17:3:17:7 | false | false | false | diff --git a/java/ql/test/library-tests/literals/literalBoolean.ql b/java/ql/test/library-tests/literals/literalBoolean.ql index bddc59b40a2..811d0a9aae8 100644 --- a/java/ql/test/library-tests/literals/literalBoolean.ql +++ b/java/ql/test/library-tests/literals/literalBoolean.ql @@ -2,4 +2,4 @@ import semmle.code.java.Expr from BooleanLiteral lit where lit.getCompilationUnit().fromSource() -select lit +select lit, lit.getValue(), lit.getBooleanValue() diff --git a/java/ql/test/library-tests/literals/literalChar.expected b/java/ql/test/library-tests/literals/literalChar.expected index c6ab2b79a5e..00eb45eff57 100644 --- a/java/ql/test/library-tests/literals/literalChar.expected +++ b/java/ql/test/library-tests/literals/literalChar.expected @@ -1 +1,10 @@ -| literals/Literals.java:12:22:12:24 | 'x' | +| literals/Literals.java:12:22:12:24 | 'x' | x | +| literals/Literals.java:21:3:21:5 | 'a' | a | +| literals/Literals.java:22:3:22:10 | '\\u0061' | a | +| literals/Literals.java:23:3:23:10 | '\\u0000' | \u0000 | +| literals/Literals.java:24:3:24:6 | '\\0' | \u0000 | +| literals/Literals.java:25:3:25:6 | '\\n' | \n | +| literals/Literals.java:26:3:26:6 | '\\0' | \u0000 | +| literals/Literals.java:27:3:27:6 | '\\\\' | \\ | +| literals/Literals.java:28:3:28:6 | '\\'' | ' | +| literals/Literals.java:29:3:29:8 | '\\123' | S | diff --git a/java/ql/test/library-tests/literals/literalChar.ql b/java/ql/test/library-tests/literals/literalChar.ql index 2253c5bb21e..104e2c03dc4 100644 --- a/java/ql/test/library-tests/literals/literalChar.ql +++ b/java/ql/test/library-tests/literals/literalChar.ql @@ -1,4 +1,4 @@ import semmle.code.java.Expr from CharacterLiteral lit -select lit +select lit, lit.getValue() diff --git a/java/ql/test/library-tests/literals/literalDouble.expected b/java/ql/test/library-tests/literals/literalDouble.expected index 8a6d6e3e483..ba64bdd8446 100644 --- a/java/ql/test/library-tests/literals/literalDouble.expected +++ b/java/ql/test/library-tests/literals/literalDouble.expected @@ -1 +1,16 @@ -| literals/Literals.java:10:22:10:27 | 456.0D | +| literals/Literals.java:10:22:10:27 | 456.0D | 456.0 | 456.0 | +| literals/Literals.java:33:3:33:5 | 0.0 | 0.0 | 0.0 | +| literals/Literals.java:34:3:34:4 | 0d | 0.0 | 0.0 | +| literals/Literals.java:35:3:35:5 | .0d | 0.0 | 0.0 | +| literals/Literals.java:36:3:36:4 | .0 | 0.0 | 0.0 | +| literals/Literals.java:37:4:37:6 | 0.d | 0.0 | 0.0 | +| literals/Literals.java:38:4:38:6 | 0.d | 0.0 | 0.0 | +| literals/Literals.java:39:3:39:22 | 1.234567890123456789 | 1.2345678901234567 | 1.2345678901234567 | +| literals/Literals.java:40:3:40:24 | 1.55555555555555555555 | 1.5555555555555556 | 1.5555555555555556 | +| literals/Literals.java:42:3:42:5 | 1e1 | 10.0 | 10.0 | +| literals/Literals.java:43:3:43:24 | 1.7976931348623157E308 | 1.7976931348623157E308 | 1.7976931348623157E308 | +| literals/Literals.java:44:4:44:25 | 1.7976931348623157E308 | 1.7976931348623157E308 | 1.7976931348623157E308 | +| literals/Literals.java:45:3:45:28 | 0x1.f_ffff_ffff_ffffP+1023 | 1.7976931348623157E308 | 1.7976931348623157E308 | +| literals/Literals.java:46:3:46:10 | 4.9e-324 | 4.9E-324 | 4.9E-324 | +| literals/Literals.java:47:3:47:28 | 0x0.0_0000_0000_0001P-1022 | 4.9E-324 | 4.9E-324 | +| literals/Literals.java:48:3:48:13 | 0x1.0P-1074 | 4.9E-324 | 4.9E-324 | diff --git a/java/ql/test/library-tests/literals/literalDouble.ql b/java/ql/test/library-tests/literals/literalDouble.ql index 28c30eb439b..a3766e9676c 100644 --- a/java/ql/test/library-tests/literals/literalDouble.ql +++ b/java/ql/test/library-tests/literals/literalDouble.ql @@ -1,4 +1,4 @@ import semmle.code.java.Expr from DoubleLiteral lit -select lit +select lit, lit.getValue(), lit.getDoubleValue() diff --git a/java/ql/test/library-tests/literals/literalFloat.expected b/java/ql/test/library-tests/literals/literalFloat.expected index d421532944b..f6221533fdb 100644 --- a/java/ql/test/library-tests/literals/literalFloat.expected +++ b/java/ql/test/library-tests/literals/literalFloat.expected @@ -1 +1,16 @@ -| literals/Literals.java:9:22:9:27 | 123.0F | +| literals/Literals.java:9:22:9:27 | 123.0F | 123.0 | 123.0 | +| literals/Literals.java:52:3:52:6 | 0.0f | 0.0 | 0.0 | +| literals/Literals.java:53:3:53:4 | 0f | 0.0 | 0.0 | +| literals/Literals.java:54:3:54:5 | .0f | 0.0 | 0.0 | +| literals/Literals.java:55:4:55:6 | 0.f | 0.0 | 0.0 | +| literals/Literals.java:56:4:56:6 | 0.f | 0.0 | 0.0 | +| literals/Literals.java:57:3:57:10 | 1_0_0.0f | 100.0 | 100.0 | +| literals/Literals.java:58:3:58:23 | 1.234567890123456789f | 1.2345679 | 1.2345679 | +| literals/Literals.java:59:3:59:25 | 1.55555555555555555555f | 1.5555556 | 1.5555556 | +| literals/Literals.java:61:3:61:6 | 1e1f | 10.0 | 10.0 | +| literals/Literals.java:62:3:62:15 | 3.4028235e38f | 3.4028235E38 | 3.4028235E38 | +| literals/Literals.java:63:4:63:16 | 3.4028235e38f | 3.4028235E38 | 3.4028235E38 | +| literals/Literals.java:64:3:64:18 | 0x1.fffffeP+127f | 3.4028235E38 | 3.4028235E38 | +| literals/Literals.java:65:3:65:10 | 1.4e-45f | 1.4E-45 | 1.4E-45 | +| literals/Literals.java:66:3:66:18 | 0x0.000002P-126f | 1.4E-45 | 1.4E-45 | +| literals/Literals.java:67:3:67:13 | 0x1.0P-149f | 1.4E-45 | 1.4E-45 | diff --git a/java/ql/test/library-tests/literals/literalFloat.ql b/java/ql/test/library-tests/literals/literalFloat.ql index e9d18be607a..6a4a9093225 100644 --- a/java/ql/test/library-tests/literals/literalFloat.ql +++ b/java/ql/test/library-tests/literals/literalFloat.ql @@ -1,4 +1,4 @@ import semmle.code.java.Expr from FloatingPointLiteral lit -select lit +select lit, lit.getValue(), lit.getFloatValue() diff --git a/java/ql/test/library-tests/literals/literalInteger.expected b/java/ql/test/library-tests/literals/literalInteger.expected index 1f31642509a..40c6a89cd98 100644 --- a/java/ql/test/library-tests/literals/literalInteger.expected +++ b/java/ql/test/library-tests/literals/literalInteger.expected @@ -1,8 +1,20 @@ -| literals/Literals.java:7:22:7:24 | 123 | -| literals/Literals.java:14:16:14:26 | -2147483648 | -| literals/Literals.java:16:21:16:30 | 2147483647 | -| literals/Literals.java:18:20:18:29 | 0x80000000 | -| literals/Literals.java:20:10:20:11 | 23 | -| literals/Literals.java:20:15:20:16 | 19 | -| literals/Literals.java:21:10:21:11 | 23 | -| literals/Literals.java:21:15:21:16 | 19 | +| literals/Literals.java:7:22:7:24 | 123 | 123 | 123 | +| literals/Literals.java:71:3:71:3 | 0 | 0 | 0 | +| literals/Literals.java:72:3:72:5 | 0_0 | 0 | 0 | +| literals/Literals.java:73:3:73:7 | 0___0 | 0 | 0 | +| literals/Literals.java:74:3:74:6 | 0_12 | 10 | 10 | +| literals/Literals.java:75:3:75:7 | 0X012 | 18 | 18 | +| literals/Literals.java:76:3:76:10 | 0xaBcDeF | 11259375 | 11259375 | +| literals/Literals.java:77:3:77:6 | 0B11 | 3 | 3 | +| literals/Literals.java:78:3:78:12 | 0x80000000 | -2147483648 | -2147483648 | +| literals/Literals.java:79:3:79:12 | 2147483647 | 2147483647 | 2147483647 | +| literals/Literals.java:80:3:80:13 | -2147483648 | -2147483648 | -2147483648 | +| literals/Literals.java:82:3:82:13 | 0x7fff_ffff | 2147483647 | 2147483647 | +| literals/Literals.java:83:3:83:16 | 0177_7777_7777 | 2147483647 | 2147483647 | +| literals/Literals.java:84:3:84:43 | 0b0111_1111_1111_1111_1111_1111_1111_1111 | 2147483647 | 2147483647 | +| literals/Literals.java:85:3:85:13 | 0x8000_0000 | -2147483648 | -2147483648 | +| literals/Literals.java:86:3:86:16 | 0200_0000_0000 | -2147483648 | -2147483648 | +| literals/Literals.java:87:3:87:43 | 0b1000_0000_0000_0000_0000_0000_0000_0000 | -2147483648 | -2147483648 | +| literals/Literals.java:88:3:88:13 | 0xffff_ffff | -1 | -1 | +| literals/Literals.java:89:3:89:16 | 0377_7777_7777 | -1 | -1 | +| literals/Literals.java:90:3:90:43 | 0b1111_1111_1111_1111_1111_1111_1111_1111 | -1 | -1 | diff --git a/java/ql/test/library-tests/literals/literalInteger.ql b/java/ql/test/library-tests/literals/literalInteger.ql index b654370a192..264f5b77b99 100644 --- a/java/ql/test/library-tests/literals/literalInteger.ql +++ b/java/ql/test/library-tests/literals/literalInteger.ql @@ -1,4 +1,4 @@ import semmle.code.java.Expr from IntegerLiteral lit -select lit +select lit, lit.getValue(), lit.getIntValue() diff --git a/java/ql/test/library-tests/literals/literalLong.expected b/java/ql/test/library-tests/literals/literalLong.expected index 4caf96df7cb..f46c55f9f37 100644 --- a/java/ql/test/library-tests/literals/literalLong.expected +++ b/java/ql/test/library-tests/literals/literalLong.expected @@ -1,4 +1,20 @@ -| literals/Literals.java:8:22:8:25 | 456L | -| literals/Literals.java:15:18:15:38 | -9223372036854775808l | -| literals/Literals.java:17:23:17:42 | 9223372036854775807l | -| literals/Literals.java:19:22:19:40 | 0x8000000000000000L | +| literals/Literals.java:8:22:8:25 | 456L | 456 | +| literals/Literals.java:94:3:94:4 | 0l | 0 | +| literals/Literals.java:95:3:95:4 | 0L | 0 | +| literals/Literals.java:96:3:96:6 | 0_0L | 0 | +| literals/Literals.java:97:3:97:8 | 0___0L | 0 | +| literals/Literals.java:98:3:98:7 | 0_12L | 10 | +| literals/Literals.java:99:3:99:8 | 0X012L | 18 | +| literals/Literals.java:100:3:100:11 | 0xaBcDeFL | 11259375 | +| literals/Literals.java:101:3:101:7 | 0B11L | 3 | +| literals/Literals.java:102:3:102:22 | 9223372036854775807L | 9223372036854775807 | +| literals/Literals.java:103:3:103:23 | -9223372036854775808L | -9223372036854775808 | +| literals/Literals.java:105:3:105:24 | 0x7fff_ffff_ffff_ffffL | 9223372036854775807 | +| literals/Literals.java:106:3:106:30 | 07_7777_7777_7777_7777_7777L | 9223372036854775807 | +| literals/Literals.java:107:3:107:84 | 0b0111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111L | 9223372036854775807 | +| literals/Literals.java:108:3:108:24 | 0x8000_0000_0000_0000L | -9223372036854775808 | +| literals/Literals.java:109:3:109:31 | 010_0000_0000_0000_0000_0000L | -9223372036854775808 | +| literals/Literals.java:110:3:110:84 | 0b1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000L | -9223372036854775808 | +| literals/Literals.java:111:3:111:24 | 0xffff_ffff_ffff_ffffL | -1 | +| literals/Literals.java:112:3:112:31 | 017_7777_7777_7777_7777_7777L | -1 | +| literals/Literals.java:113:3:113:84 | 0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111L | -1 | diff --git a/java/ql/test/library-tests/literals/literalLong.ql b/java/ql/test/library-tests/literals/literalLong.ql index 9f0c5a789c9..54109369b3a 100644 --- a/java/ql/test/library-tests/literals/literalLong.ql +++ b/java/ql/test/library-tests/literals/literalLong.ql @@ -1,4 +1,4 @@ import semmle.code.java.Expr from LongLiteral lit -select lit +select lit, lit.getValue() diff --git a/java/ql/test/library-tests/literals/literalString.expected b/java/ql/test/library-tests/literals/literalString.expected index addd494a5b1..bf980e80bf6 100644 --- a/java/ql/test/library-tests/literals/literalString.expected +++ b/java/ql/test/library-tests/literals/literalString.expected @@ -1,6 +1,20 @@ -| literals/Literals.java:6:22:6:37 | "literal string" | -| literals/Literals.java:22:22:22:38 | "hello" + "world" | -| literals/Literals.java:23:24:23:47 | "hello" + ", " + "world" | -| literals/Literals.java:24:23:24:52 | "hello" + ", " + "world" + "!" | -| literals/Literals.java:25:22:25:36 | "hello,\\tworld" | -| literals/Literals.java:26:30:26:48 | "hello,\\u0009world" | +| literals/Literals.java:6:22:6:37 | "literal string" | literal string | literal string | +| literals/Literals.java:117:3:117:19 | "hello" + "world" | helloworld | helloworld | +| literals/Literals.java:118:3:118:17 | "hello,\\tworld" | hello,\tworld | hello,\tworld | +| literals/Literals.java:119:3:119:21 | "hello,\\u0009world" | hello,\tworld | hello,\tworld | +| literals/Literals.java:120:3:120:10 | "\\u0061" | a | a | +| literals/Literals.java:121:3:121:6 | "\\0" | \u0000 | \u0000 | +| literals/Literals.java:122:3:122:9 | "\\0000" | \u00000 | \u00000 | +| literals/Literals.java:123:3:123:6 | "\\"" | " | " | +| literals/Literals.java:124:3:124:6 | "\\'" | ' | ' | +| literals/Literals.java:125:3:125:6 | "\\n" | \n | \n | +| literals/Literals.java:126:3:126:6 | "\\\\" | \\ | \\ | +| literals/Literals.java:127:3:127:13 | "test \\123" | test S | test S | +| literals/Literals.java:128:3:128:9 | "\\1234" | S4 | S4 | +| literals/Literals.java:129:3:129:13 | "\\u0061567" | a567 | a567 | +| literals/Literals.java:130:3:130:13 | "\\u1234567" | \u1234567 | \u1234567 | +| literals/Literals.java:131:3:131:18 | "\\uaBcDeF\\u0aB1" | \uabcdeF\u0ab1 | \uabcdeF\u0ab1 | +| literals/Literals.java:132:3:132:16 | "\\uD800\\uDC00" | \ud800\udc00 | \ud800\udc00 | +| literals/Literals.java:134:3:134:10 | "\\uD800" | ? | ? | +| literals/Literals.java:135:3:135:10 | "\\uDC00" | ? | ? | +| literals/Literals.java:136:3:136:31 | "hello\\uD800hello\\uDC00world" | hello?hello?world | hello?hello?world | diff --git a/java/ql/test/library-tests/literals/literalString.ql b/java/ql/test/library-tests/literals/literalString.ql index e69d4f89b6b..e2128e54e0e 100644 --- a/java/ql/test/library-tests/literals/literalString.ql +++ b/java/ql/test/library-tests/literals/literalString.ql @@ -2,4 +2,4 @@ import semmle.code.java.Expr from StringLiteral lit where lit.getFile().(CompilationUnit).fromSource() -select lit +select lit, lit.getValue(), lit.getRepresentedString() diff --git a/java/ql/test/library-tests/literals/literals/Literals.java b/java/ql/test/library-tests/literals/literals/Literals.java index 82b21ae2763..082310acb80 100644 --- a/java/ql/test/library-tests/literals/literals/Literals.java +++ b/java/ql/test/library-tests/literals/literals/Literals.java @@ -11,17 +11,128 @@ public class Literals { System.out.println(true); System.out.println('x'); } - int min_int = -2147483648; - long min_long = -9223372036854775808l; - int neg_max_int = -2147483647; - long neg_max_long = -9223372036854775807l; - int alt_min_int = 0x80000000; - long alt_min_long = 0x8000000000000000L; - int i = 23 + 19; - int j = 23 +19; - String twostrings = "hello" + "world"; - String threestrings = "hello" + ", " + "world"; - String fourstrings = "hello" + ", " + "world" + "!"; - String escape_seq = "hello,\tworld"; - String unicode_escape_seq = "hello,\u0009world"; + + boolean[] booleans = { + true, + false + }; + + char[] chars = { + 'a', + '\u0061', // 'a' + '\u0000', + '\0', + '\n', + '\0', + '\\', + '\'', + '\123' // octal escape sequence for 'S' + }; + + double[] doubles = { + 0.0, + 0d, + .0d, + .0, + -0.d, + +0.d, + 1.234567890123456789, + 1.55555555555555555555, + // From the JLS + 1e1, + 1.7976931348623157E308, + -1.7976931348623157E308, + 0x1.f_ffff_ffff_ffffP+1023, + 4.9e-324, + 0x0.0_0000_0000_0001P-1022, + 0x1.0P-1074 + }; + + float[] floats = { + 0.0f, + 0f, + .0f, + -0.f, + +0.f, + 1_0_0.0f, + 1.234567890123456789f, + 1.55555555555555555555f, + // From the JLS + 1e1f, + 3.4028235e38f, + -3.4028235e38f, + 0x1.fffffeP+127f, + 1.4e-45f, + 0x0.000002P-126f, + 0x1.0P-149f + }; + + int[] ints = { + 0, + 0_0, + 0___0, + 0_12, // octal + 0X012, // hex + 0xaBcDeF, // hex + 0B11, // binary + 0x80000000, + 2147483647, + -2147483648, + // From the JLS + 0x7fff_ffff, + 0177_7777_7777, // octal + 0b0111_1111_1111_1111_1111_1111_1111_1111, // binary + 0x8000_0000, + 0200_0000_0000, + 0b1000_0000_0000_0000_0000_0000_0000_0000, + 0xffff_ffff, + 0377_7777_7777, + 0b1111_1111_1111_1111_1111_1111_1111_1111 + }; + + long[] longs = { + 0l, + 0L, + 0_0L, + 0___0L, + 0_12L, // octal + 0X012L, // hex + 0xaBcDeFL, // hex + 0B11L, // binary + 9223372036854775807L, + -9223372036854775808L, + // From the JLS + 0x7fff_ffff_ffff_ffffL, + 07_7777_7777_7777_7777_7777L, // octal + 0b0111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111L, // binary + 0x8000_0000_0000_0000L, + 010_0000_0000_0000_0000_0000L, + 0b1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000L, + 0xffff_ffff_ffff_ffffL, + 017_7777_7777_7777_7777_7777L, + 0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111L + }; + + String[] strings = { + "hello" + "world", // two separate literals + "hello,\tworld", + "hello,\u0009world", + "\u0061", // 'a' + "\0", + "\0000", + "\"", + "\'", + "\n", + "\\", + "test \123", // octal escape sequence for 'S' + "\1234", // octal escape followed by '4' + "\u0061567", // escape sequence for 'a' followed by "567" + "\u1234567", // '\u1234' followed by "567" + "\uaBcDeF\u0aB1", // '\uABCD' followed by "eF" followed by '\u0AB1' + "\uD800\uDC00", // surrogate pair + // Unpaired surrogates + "\uD800", + "\uDC00", + "hello\uD800hello\uDC00world" + }; } From 73e940de74bb326664db451b97fa58e67e683400 Mon Sep 17 00:00:00 2001 From: Artem Smotrakov Date: Tue, 2 Feb 2021 17:37:14 +0100 Subject: [PATCH 219/725] Added query for Jakarta EL injections - Added JakartaExpressionInjection.ql - Added a qhelp file with examples --- .../Security/CWE/CWE-094/InjectionLib.qll | 14 +++ .../CWE-094/JakartaExpressionInjection.qhelp | 65 ++++++++++++ .../CWE/CWE-094/JakartaExpressionInjection.ql | 20 ++++ .../CWE-094/JakartaExpressionInjectionLib.qll | 98 +++++++++++++++++++ .../Security/CWE/CWE-094/JexlInjectionLib.qll | 13 +-- .../SaferExpressionEvaluationWithJuel.java | 10 ++ .../UnsafeExpressionEvaluationWithJuel.java | 5 + 7 files changed, 213 insertions(+), 12 deletions(-) create mode 100644 java/ql/src/experimental/Security/CWE/CWE-094/InjectionLib.qll create mode 100644 java/ql/src/experimental/Security/CWE/CWE-094/JakartaExpressionInjection.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-094/JakartaExpressionInjection.ql create mode 100644 java/ql/src/experimental/Security/CWE/CWE-094/JakartaExpressionInjectionLib.qll create mode 100644 java/ql/src/experimental/Security/CWE/CWE-094/SaferExpressionEvaluationWithJuel.java create mode 100644 java/ql/src/experimental/Security/CWE/CWE-094/UnsafeExpressionEvaluationWithJuel.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/InjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-094/InjectionLib.qll new file mode 100644 index 00000000000..adab79d6f5c --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/InjectionLib.qll @@ -0,0 +1,14 @@ +import java +import semmle.code.java.dataflow.FlowSources + +/** + * Holds if `fromNode` to `toNode` is a dataflow step that returns data from + * a bean by calling one of its getters. + */ +predicate returnsDataFromBean(DataFlow::Node fromNode, DataFlow::Node toNode) { + exists(MethodAccess ma, Method m | ma.getMethod() = m | + m instanceof GetterMethod and + ma.getQualifier() = fromNode.asExpr() and + ma = toNode.asExpr() + ) +} diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/JakartaExpressionInjection.qhelp b/java/ql/src/experimental/Security/CWE/CWE-094/JakartaExpressionInjection.qhelp new file mode 100644 index 00000000000..6e6b5f63394 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/JakartaExpressionInjection.qhelp @@ -0,0 +1,65 @@ + + + + +

    +Jakarta Expression Language (EL) is an expression language for Java applications. +There are a single language specification and multiple implementations +such as Glassfish, Juel, Apache Commons EL, etc. +The language allows invocation of methods available in the JVM. +If an expression is built using attacker-controlled data, +and then evaluated, then it may allow the attacker to run arbitrary code. +

    +
    + + +

    +It is generally recommended to avoid using untrusted data in an EL expression. +Before using untrusted data to build an EL expressoin, the data should be validated +to ensure it is not evaluated as expression language. If the EL implementaion offers +configuring a sandbox for EL expression, they should be run in a restircitive sandbox +that allows accessing only explicitly allowed classes. If the EL implementation +does not allow sandboxing, consider using other expressiong language implementations +with sandboxing capabilities such as Apache Commons JEXL or the Spring Expression Language. +

    +
    + + +

    +The following example shows how untrusted data is used to build and run an expression +using the JUEL interpreter: +

    + + +

    +JUEL does not allow to run expression in a sandbox. To prevent running arbitrary code, +incoming data has to be checked before including to an expression. The next example +uses a Regex pattern to check whether a user tries to run an allowed exression or not: +

    + + +
    + + +
  • + Eclipse Foundation: + Jakarta Expression Language. +
  • +
  • + Jakarta EE documentation: + Jakarta Expression Language API +
  • +
  • + OWASP: + Expression Language Injection. +
  • +
  • + JUEL: + Home page +
  • +
  • + Apache Foundation: + Apache Commons EL +
  • +
    +
    diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/JakartaExpressionInjection.ql b/java/ql/src/experimental/Security/CWE/CWE-094/JakartaExpressionInjection.ql new file mode 100644 index 00000000000..b94c98201de --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/JakartaExpressionInjection.ql @@ -0,0 +1,20 @@ +/** + * @name Java EE Expression Language injection + * @description Evaluation of a user-controlled Jave EE expression + * may lead to arbitrary code execution. + * @kind path-problem + * @problem.severity error + * @precision high + * @id java/javaee-expression-injection + * @tags security + * external/cwe/cwe-094 + */ + +import java +import JavaEEExpressionInjectionLib +import DataFlow::PathGraph + +from DataFlow::PathNode source, DataFlow::PathNode sink, JavaEEExpressionInjectionConfig conf +where conf.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "Java EE Expression Language injection from $@.", + source.getNode(), "this user input" diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/JakartaExpressionInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-094/JakartaExpressionInjectionLib.qll new file mode 100644 index 00000000000..d43b31c9888 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/JakartaExpressionInjectionLib.qll @@ -0,0 +1,98 @@ +import java +import InjectionLib +import semmle.code.java.dataflow.FlowSources +import semmle.code.java.dataflow.TaintTracking + +/** + * A taint-tracking configuration for unsafe user input + * that is used to construct and evaluate a Java EE expression. + */ +class JavaEEExpressionInjectionConfig extends TaintTracking::Configuration { + JavaEEExpressionInjectionConfig() { this = "JavaEEExpressionInjectionConfig" } + + override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } + + override predicate isSink(DataFlow::Node sink) { sink instanceof ExpressionEvaluationSink } + + override predicate isAdditionalTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) { + any(TaintPropagatingCall c).taintFlow(fromNode, toNode) or + returnsDataFromBean(fromNode, toNode) + } +} + +/** + * A sink for Expresssion Language injection vulnerabilities, + * i.e. method calls that run evaluation of a Java EE expression. + */ +private class ExpressionEvaluationSink extends DataFlow::ExprNode { + ExpressionEvaluationSink() { + exists(MethodAccess ma, Method m, Expr taintFrom | + ma.getMethod() = m and taintFrom = this.asExpr() + | + m.getDeclaringType() instanceof ValueExpression and + m.hasName(["getValue", "setValue"]) and + ma.getQualifier() = taintFrom + or + m.getDeclaringType() instanceof MethodExpression and + m.hasName("invoke") and + ma.getQualifier() = taintFrom + or + m.getDeclaringType() instanceof LambdaExpression and + m.hasName("invoke") and + ma.getQualifier() = taintFrom + or + m.getDeclaringType() instanceof ELProcessor and + m.hasName(["eval", "getValue", "setValue"]) and + ma.getArgument(0) = taintFrom + ) + } +} + +/** + * Defines method calls that propagate tainted expressions. + */ +private class TaintPropagatingCall extends Call { + Expr taintFromExpr; + + TaintPropagatingCall() { + taintFromExpr = this.getArgument(1) and + exists(Method m | this.(MethodAccess).getMethod() = m | + m.getDeclaringType() instanceof ExpressionFactory and + m.hasName(["createValueExpression", "createMethodExpression"]) and + taintFromExpr.getType() instanceof TypeString + ) + or + exists(Constructor c | this.(ConstructorCall).getConstructor() = c | + c.getDeclaringType() instanceof LambdaExpression and + taintFromExpr.getType() instanceof ValueExpression + ) + } + + /** + * Holds if `fromNode` to `toNode` is a dataflow step that propagates + * tainted data. + */ + predicate taintFlow(DataFlow::Node fromNode, DataFlow::Node toNode) { + fromNode.asExpr() = taintFromExpr and toNode.asExpr() = this + } +} + +private class ELProcessor extends RefType { + ELProcessor() { hasQualifiedName("javax.el", "ELProcessor") } +} + +private class ExpressionFactory extends RefType { + ExpressionFactory() { hasQualifiedName("javax.el", "ExpressionFactory") } +} + +private class ValueExpression extends RefType { + ValueExpression() { hasQualifiedName("javax.el", "ValueExpression") } +} + +private class MethodExpression extends RefType { + MethodExpression() { hasQualifiedName("javax.el", "MethodExpression") } +} + +private class LambdaExpression extends RefType { + LambdaExpression() { hasQualifiedName("javax.el", "LambdaExpression") } +} diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/JexlInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-094/JexlInjectionLib.qll index 561d7e46ae9..51084a9862c 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-094/JexlInjectionLib.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-094/JexlInjectionLib.qll @@ -1,4 +1,5 @@ import java +import InjectionLib import semmle.code.java.dataflow.FlowSources import semmle.code.java.dataflow.TaintTracking @@ -152,18 +153,6 @@ private predicate createsJexlEngine(DataFlow::Node fromNode, DataFlow::Node toNo ) } -/** - * Holds if `fromNode` to `toNode` is a dataflow step that returns data from - * a bean by calling one of its getters. - */ -private predicate returnsDataFromBean(DataFlow::Node fromNode, DataFlow::Node toNode) { - exists(MethodAccess ma, Method m | ma.getMethod() = m | - m instanceof GetterMethod and - ma.getQualifier() = fromNode.asExpr() and - ma = toNode.asExpr() - ) -} - /** * A methods in the `JexlEngine` class that gets or sets a property with a JEXL expression. */ diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/SaferExpressionEvaluationWithJuel.java b/java/ql/src/experimental/Security/CWE/CWE-094/SaferExpressionEvaluationWithJuel.java new file mode 100644 index 00000000000..54fb9a0ed36 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/SaferExpressionEvaluationWithJuel.java @@ -0,0 +1,10 @@ +String input = getRemoteUserInput(); +String pattern = "(inside|outside)\\.(temperature|humidity)"; +if (!input.matches(pattern)) { + throw new IllegalArgumentException("Unexpected exression"); +} +String expression = "${" + input + "}"; +ExpressionFactory factory = new de.odysseus.el.ExpressionFactoryImpl(); +ValueExpression e = factory.createValueExpression(context, expression, Object.class); +SimpleContext context = getContext(); +Object result = e.getValue(context); \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/UnsafeExpressionEvaluationWithJuel.java b/java/ql/src/experimental/Security/CWE/CWE-094/UnsafeExpressionEvaluationWithJuel.java new file mode 100644 index 00000000000..27afa0fcb49 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/UnsafeExpressionEvaluationWithJuel.java @@ -0,0 +1,5 @@ +String expression = "${" + getRemoteUserInput() + "}"; +ExpressionFactory factory = new de.odysseus.el.ExpressionFactoryImpl(); +ValueExpression e = factory.createValueExpression(context, expression, Object.class); +SimpleContext context = getContext(); +Object result = e.getValue(context); \ No newline at end of file From adb1ed380ac4736860eac8ea6cfadb8f38497db5 Mon Sep 17 00:00:00 2001 From: Artem Smotrakov Date: Sun, 21 Mar 2021 20:36:47 +0300 Subject: [PATCH 220/725] Added tests for Jakarta expression injection --- .../CWE/CWE-094/JakartaExpressionInjection.ql | 10 +-- .../CWE-094/JakartaExpressionInjectionLib.qll | 8 +- .../JakartaExpressionInjection.expected | 59 +++++++++++++ .../CWE-094/JakartaExpressionInjection.java | 87 +++++++++++++++++++ .../CWE-094/JakartaExpressionInjection.qlref | 1 + .../query-tests/security/CWE-094/options | 3 +- .../stubs/java-ee-el/javax/el/ELContext.java | 3 + .../stubs/java-ee-el/javax/el/ELManager.java | 5 ++ .../java-ee-el/javax/el/ELProcessor.java | 7 ++ .../javax/el/ExpressionFactory.java | 17 ++++ .../java-ee-el/javax/el/LambdaExpression.java | 8 ++ .../java-ee-el/javax/el/MethodExpression.java | 5 ++ .../javax/el/StandardELContext.java | 5 ++ .../java-ee-el/javax/el/ValueExpression.java | 6 ++ .../de/odysseus/el/ExpressionFactoryImpl.java | 5 ++ .../de/odysseus/el/util/SimpleContext.java | 5 ++ 16 files changed, 223 insertions(+), 11 deletions(-) create mode 100644 java/ql/test/experimental/query-tests/security/CWE-094/JakartaExpressionInjection.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-094/JakartaExpressionInjection.java create mode 100644 java/ql/test/experimental/query-tests/security/CWE-094/JakartaExpressionInjection.qlref create mode 100644 java/ql/test/stubs/java-ee-el/javax/el/ELContext.java create mode 100644 java/ql/test/stubs/java-ee-el/javax/el/ELManager.java create mode 100644 java/ql/test/stubs/java-ee-el/javax/el/ELProcessor.java create mode 100644 java/ql/test/stubs/java-ee-el/javax/el/ExpressionFactory.java create mode 100644 java/ql/test/stubs/java-ee-el/javax/el/LambdaExpression.java create mode 100644 java/ql/test/stubs/java-ee-el/javax/el/MethodExpression.java create mode 100644 java/ql/test/stubs/java-ee-el/javax/el/StandardELContext.java create mode 100644 java/ql/test/stubs/java-ee-el/javax/el/ValueExpression.java create mode 100644 java/ql/test/stubs/juel-2.2/de/odysseus/el/ExpressionFactoryImpl.java create mode 100644 java/ql/test/stubs/juel-2.2/de/odysseus/el/util/SimpleContext.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/JakartaExpressionInjection.ql b/java/ql/src/experimental/Security/CWE/CWE-094/JakartaExpressionInjection.ql index b94c98201de..8190ec3d61f 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-094/JakartaExpressionInjection.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-094/JakartaExpressionInjection.ql @@ -1,6 +1,6 @@ /** - * @name Java EE Expression Language injection - * @description Evaluation of a user-controlled Jave EE expression + * @name Jakarta Expression Language injection + * @description Evaluation of a user-controlled expression * may lead to arbitrary code execution. * @kind path-problem * @problem.severity error @@ -11,10 +11,10 @@ */ import java -import JavaEEExpressionInjectionLib +import JakartaExpressionInjectionLib import DataFlow::PathGraph -from DataFlow::PathNode source, DataFlow::PathNode sink, JavaEEExpressionInjectionConfig conf +from DataFlow::PathNode source, DataFlow::PathNode sink, JakartaExpressionInjectionConfig conf where conf.hasFlowPath(source, sink) -select sink.getNode(), source, sink, "Java EE Expression Language injection from $@.", +select sink.getNode(), source, sink, "Jakarta Expression Language injection from $@.", source.getNode(), "this user input" diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/JakartaExpressionInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-094/JakartaExpressionInjectionLib.qll index d43b31c9888..bc22f7c3257 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-094/JakartaExpressionInjectionLib.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-094/JakartaExpressionInjectionLib.qll @@ -5,10 +5,10 @@ import semmle.code.java.dataflow.TaintTracking /** * A taint-tracking configuration for unsafe user input - * that is used to construct and evaluate a Java EE expression. + * that is used to construct and evaluate an expression. */ -class JavaEEExpressionInjectionConfig extends TaintTracking::Configuration { - JavaEEExpressionInjectionConfig() { this = "JavaEEExpressionInjectionConfig" } +class JakartaExpressionInjectionConfig extends TaintTracking::Configuration { + JakartaExpressionInjectionConfig() { this = "JakartaExpressionInjectionConfig" } override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } @@ -22,7 +22,7 @@ class JavaEEExpressionInjectionConfig extends TaintTracking::Configuration { /** * A sink for Expresssion Language injection vulnerabilities, - * i.e. method calls that run evaluation of a Java EE expression. + * i.e. method calls that run evaluation of an expression. */ private class ExpressionEvaluationSink extends DataFlow::ExprNode { ExpressionEvaluationSink() { diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/JakartaExpressionInjection.expected b/java/ql/test/experimental/query-tests/security/CWE-094/JakartaExpressionInjection.expected new file mode 100644 index 00000000000..111cc81541c --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-094/JakartaExpressionInjection.expected @@ -0,0 +1,59 @@ +edges +| JakartaExpressionInjection.java:22:25:22:47 | getInputStream(...) : InputStream | JakartaExpressionInjection.java:24:31:24:40 | expression : String | +| JakartaExpressionInjection.java:24:31:24:40 | expression : String | JakartaExpressionInjection.java:30:24:30:33 | expression : String | +| JakartaExpressionInjection.java:24:31:24:40 | expression : String | JakartaExpressionInjection.java:37:24:37:33 | expression : String | +| JakartaExpressionInjection.java:24:31:24:40 | expression : String | JakartaExpressionInjection.java:44:24:44:33 | expression : String | +| JakartaExpressionInjection.java:24:31:24:40 | expression : String | JakartaExpressionInjection.java:54:24:54:33 | expression : String | +| JakartaExpressionInjection.java:24:31:24:40 | expression : String | JakartaExpressionInjection.java:61:24:61:33 | expression : String | +| JakartaExpressionInjection.java:24:31:24:40 | expression : String | JakartaExpressionInjection.java:70:24:70:33 | expression : String | +| JakartaExpressionInjection.java:24:31:24:40 | expression : String | JakartaExpressionInjection.java:79:24:79:33 | expression : String | +| JakartaExpressionInjection.java:30:24:30:33 | expression : String | JakartaExpressionInjection.java:32:28:32:37 | expression | +| JakartaExpressionInjection.java:37:24:37:33 | expression : String | JakartaExpressionInjection.java:39:32:39:41 | expression | +| JakartaExpressionInjection.java:44:24:44:33 | expression : String | JakartaExpressionInjection.java:49:13:49:28 | lambdaExpression | +| JakartaExpressionInjection.java:48:49:48:104 | new LambdaExpression(...) : LambdaExpression | JakartaExpressionInjection.java:49:13:49:28 | lambdaExpression | +| JakartaExpressionInjection.java:54:24:54:33 | expression : String | JakartaExpressionInjection.java:56:32:56:41 | expression | +| JakartaExpressionInjection.java:61:24:61:33 | expression : String | JakartaExpressionInjection.java:64:33:64:96 | createValueExpression(...) : ValueExpression | +| JakartaExpressionInjection.java:61:24:61:33 | expression : String | JakartaExpressionInjection.java:65:13:65:13 | e | +| JakartaExpressionInjection.java:61:24:61:33 | expression : String | JakartaExpressionInjection.java:65:13:65:13 | e : ValueExpression | +| JakartaExpressionInjection.java:64:33:64:96 | createValueExpression(...) : ValueExpression | JakartaExpressionInjection.java:48:49:48:104 | new LambdaExpression(...) : LambdaExpression | +| JakartaExpressionInjection.java:64:33:64:96 | createValueExpression(...) : ValueExpression | JakartaExpressionInjection.java:65:13:65:13 | e | +| JakartaExpressionInjection.java:64:33:64:96 | createValueExpression(...) : ValueExpression | JakartaExpressionInjection.java:65:13:65:13 | e : ValueExpression | +| JakartaExpressionInjection.java:65:13:65:13 | e : ValueExpression | JakartaExpressionInjection.java:48:49:48:104 | new LambdaExpression(...) : LambdaExpression | +| JakartaExpressionInjection.java:70:24:70:33 | expression : String | JakartaExpressionInjection.java:73:33:73:96 | createValueExpression(...) : ValueExpression | +| JakartaExpressionInjection.java:70:24:70:33 | expression : String | JakartaExpressionInjection.java:74:13:74:13 | e | +| JakartaExpressionInjection.java:70:24:70:33 | expression : String | JakartaExpressionInjection.java:74:13:74:13 | e : ValueExpression | +| JakartaExpressionInjection.java:73:33:73:96 | createValueExpression(...) : ValueExpression | JakartaExpressionInjection.java:48:49:48:104 | new LambdaExpression(...) : LambdaExpression | +| JakartaExpressionInjection.java:73:33:73:96 | createValueExpression(...) : ValueExpression | JakartaExpressionInjection.java:74:13:74:13 | e | +| JakartaExpressionInjection.java:73:33:73:96 | createValueExpression(...) : ValueExpression | JakartaExpressionInjection.java:74:13:74:13 | e : ValueExpression | +| JakartaExpressionInjection.java:74:13:74:13 | e : ValueExpression | JakartaExpressionInjection.java:48:49:48:104 | new LambdaExpression(...) : LambdaExpression | +| JakartaExpressionInjection.java:79:24:79:33 | expression : String | JakartaExpressionInjection.java:83:13:83:13 | e | +nodes +| JakartaExpressionInjection.java:22:25:22:47 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| JakartaExpressionInjection.java:24:31:24:40 | expression : String | semmle.label | expression : String | +| JakartaExpressionInjection.java:30:24:30:33 | expression : String | semmle.label | expression : String | +| JakartaExpressionInjection.java:32:28:32:37 | expression | semmle.label | expression | +| JakartaExpressionInjection.java:37:24:37:33 | expression : String | semmle.label | expression : String | +| JakartaExpressionInjection.java:39:32:39:41 | expression | semmle.label | expression | +| JakartaExpressionInjection.java:44:24:44:33 | expression : String | semmle.label | expression : String | +| JakartaExpressionInjection.java:48:49:48:104 | new LambdaExpression(...) : LambdaExpression | semmle.label | new LambdaExpression(...) : LambdaExpression | +| JakartaExpressionInjection.java:49:13:49:28 | lambdaExpression | semmle.label | lambdaExpression | +| JakartaExpressionInjection.java:54:24:54:33 | expression : String | semmle.label | expression : String | +| JakartaExpressionInjection.java:56:32:56:41 | expression | semmle.label | expression | +| JakartaExpressionInjection.java:61:24:61:33 | expression : String | semmle.label | expression : String | +| JakartaExpressionInjection.java:64:33:64:96 | createValueExpression(...) : ValueExpression | semmle.label | createValueExpression(...) : ValueExpression | +| JakartaExpressionInjection.java:65:13:65:13 | e | semmle.label | e | +| JakartaExpressionInjection.java:65:13:65:13 | e : ValueExpression | semmle.label | e : ValueExpression | +| JakartaExpressionInjection.java:70:24:70:33 | expression : String | semmle.label | expression : String | +| JakartaExpressionInjection.java:73:33:73:96 | createValueExpression(...) : ValueExpression | semmle.label | createValueExpression(...) : ValueExpression | +| JakartaExpressionInjection.java:74:13:74:13 | e | semmle.label | e | +| JakartaExpressionInjection.java:74:13:74:13 | e : ValueExpression | semmle.label | e : ValueExpression | +| JakartaExpressionInjection.java:79:24:79:33 | expression : String | semmle.label | expression : String | +| JakartaExpressionInjection.java:83:13:83:13 | e | semmle.label | e | +#select +| JakartaExpressionInjection.java:32:28:32:37 | expression | JakartaExpressionInjection.java:22:25:22:47 | getInputStream(...) : InputStream | JakartaExpressionInjection.java:32:28:32:37 | expression | Jakarta Expression Language injection from $@. | JakartaExpressionInjection.java:22:25:22:47 | getInputStream(...) | this user input | +| JakartaExpressionInjection.java:39:32:39:41 | expression | JakartaExpressionInjection.java:22:25:22:47 | getInputStream(...) : InputStream | JakartaExpressionInjection.java:39:32:39:41 | expression | Jakarta Expression Language injection from $@. | JakartaExpressionInjection.java:22:25:22:47 | getInputStream(...) | this user input | +| JakartaExpressionInjection.java:49:13:49:28 | lambdaExpression | JakartaExpressionInjection.java:22:25:22:47 | getInputStream(...) : InputStream | JakartaExpressionInjection.java:49:13:49:28 | lambdaExpression | Jakarta Expression Language injection from $@. | JakartaExpressionInjection.java:22:25:22:47 | getInputStream(...) | this user input | +| JakartaExpressionInjection.java:56:32:56:41 | expression | JakartaExpressionInjection.java:22:25:22:47 | getInputStream(...) : InputStream | JakartaExpressionInjection.java:56:32:56:41 | expression | Jakarta Expression Language injection from $@. | JakartaExpressionInjection.java:22:25:22:47 | getInputStream(...) | this user input | +| JakartaExpressionInjection.java:65:13:65:13 | e | JakartaExpressionInjection.java:22:25:22:47 | getInputStream(...) : InputStream | JakartaExpressionInjection.java:65:13:65:13 | e | Jakarta Expression Language injection from $@. | JakartaExpressionInjection.java:22:25:22:47 | getInputStream(...) | this user input | +| JakartaExpressionInjection.java:74:13:74:13 | e | JakartaExpressionInjection.java:22:25:22:47 | getInputStream(...) : InputStream | JakartaExpressionInjection.java:74:13:74:13 | e | Jakarta Expression Language injection from $@. | JakartaExpressionInjection.java:22:25:22:47 | getInputStream(...) | this user input | +| JakartaExpressionInjection.java:83:13:83:13 | e | JakartaExpressionInjection.java:22:25:22:47 | getInputStream(...) : InputStream | JakartaExpressionInjection.java:83:13:83:13 | e | Jakarta Expression Language injection from $@. | JakartaExpressionInjection.java:22:25:22:47 | getInputStream(...) | this user input | diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/JakartaExpressionInjection.java b/java/ql/test/experimental/query-tests/security/CWE-094/JakartaExpressionInjection.java new file mode 100644 index 00000000000..a9fb2d45d6f --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-094/JakartaExpressionInjection.java @@ -0,0 +1,87 @@ +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.ArrayList; +import java.util.function.Consumer; + +import javax.el.ELContext; +import javax.el.ELManager; +import javax.el.ELProcessor; +import javax.el.ExpressionFactory; +import javax.el.LambdaExpression; +import javax.el.MethodExpression; +import javax.el.StandardELContext; +import javax.el.ValueExpression; + +public class JakartaExpressionInjection { + + private static void testWithSocket(Consumer action) throws IOException { + try (ServerSocket serverSocket = new ServerSocket(0)) { + try (Socket socket = serverSocket.accept()) { + byte[] bytes = new byte[1024]; + int n = socket.getInputStream().read(bytes); + String expression = new String(bytes, 0, n); + action.accept(expression); + } + } + } + + private static void testWithELProcessorEval() throws IOException { + testWithSocket(expression -> { + ELProcessor processor = new ELProcessor(); + processor.eval(expression); + }); + } + + private static void testWithELProcessorGetValue() throws IOException { + testWithSocket(expression -> { + ELProcessor processor = new ELProcessor(); + processor.getValue(expression, Object.class); + }); + } + + private static void testWithLambdaExpressionInvoke() throws IOException { + testWithSocket(expression -> { + ExpressionFactory factory = ELManager.getExpressionFactory(); + StandardELContext context = new StandardELContext(factory); + ValueExpression valueExpression = factory.createValueExpression(context, expression, Object.class); + LambdaExpression lambdaExpression = new LambdaExpression(new ArrayList<>(), valueExpression); + lambdaExpression.invoke(context, new Object[0]); + }); + } + + private static void testWithELProcessorSetValue() throws IOException { + testWithSocket(expression -> { + ELProcessor processor = new ELProcessor(); + processor.setValue(expression, new Object()); + }); + } + + private static void testWithJuelValueExpressionGetValue() throws IOException { + testWithSocket(expression -> { + ExpressionFactory factory = new de.odysseus.el.ExpressionFactoryImpl(); + ELContext context = new de.odysseus.el.util.SimpleContext(); + ValueExpression e = factory.createValueExpression(context, expression, Object.class); + e.getValue(context); + }); + } + + private static void testWithJuelValueExpressionSetValue() throws IOException { + testWithSocket(expression -> { + ExpressionFactory factory = new de.odysseus.el.ExpressionFactoryImpl(); + ELContext context = new de.odysseus.el.util.SimpleContext(); + ValueExpression e = factory.createValueExpression(context, expression, Object.class); + e.setValue(context, new Object()); + }); + } + + private static void testWithJuelMethodExpressionInvoke() throws IOException { + testWithSocket(expression -> { + ExpressionFactory factory = new de.odysseus.el.ExpressionFactoryImpl(); + ELContext context = new de.odysseus.el.util.SimpleContext(); + MethodExpression e = factory.createMethodExpression(context, expression, Object.class, new Class[0]); + e.invoke(context, new Object[0]); + }); + } + +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/JakartaExpressionInjection.qlref b/java/ql/test/experimental/query-tests/security/CWE-094/JakartaExpressionInjection.qlref new file mode 100644 index 00000000000..3154ee5ccad --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-094/JakartaExpressionInjection.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-094/JakartaExpressionInjection.ql \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/options b/java/ql/test/experimental/query-tests/security/CWE-094/options index a8e30ce30b4..ec3354ea41c 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-094/options +++ b/java/ql/test/experimental/query-tests/security/CWE-094/options @@ -1,2 +1 @@ -//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3:${testdir}/../../../../stubs/mvel2-2.4.7:${testdir}/../../../../stubs/jsr223-api:${testdir}/../../../../stubs/apache-commons-jexl-2.1.1:${testdir}/../../../../stubs/apache-commons-jexl-3.1:${testdir}/../../../../stubs/scriptengine - +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3:${testdir}/../../../../stubs/mvel2-2.4.7:${testdir}/../../../../stubs/jsr223-api:${testdir}/../../../../stubs/apache-commons-jexl-2.1.1:${testdir}/../../../../stubs/apache-commons-jexl-3.1:${testdir}/../../../../stubs/scriptengine:${testdir}/../../../../stubs/java-ee-el:${testdir}/../../../../stubs/juel-2.2 \ No newline at end of file diff --git a/java/ql/test/stubs/java-ee-el/javax/el/ELContext.java b/java/ql/test/stubs/java-ee-el/javax/el/ELContext.java new file mode 100644 index 00000000000..ce3840c69c8 --- /dev/null +++ b/java/ql/test/stubs/java-ee-el/javax/el/ELContext.java @@ -0,0 +1,3 @@ +package javax.el; + +public class ELContext {} diff --git a/java/ql/test/stubs/java-ee-el/javax/el/ELManager.java b/java/ql/test/stubs/java-ee-el/javax/el/ELManager.java new file mode 100644 index 00000000000..7d24f739a3f --- /dev/null +++ b/java/ql/test/stubs/java-ee-el/javax/el/ELManager.java @@ -0,0 +1,5 @@ +package javax.el; + +public class ELManager { + public static ExpressionFactory getExpressionFactory() { return null; } +} \ No newline at end of file diff --git a/java/ql/test/stubs/java-ee-el/javax/el/ELProcessor.java b/java/ql/test/stubs/java-ee-el/javax/el/ELProcessor.java new file mode 100644 index 00000000000..3c523e685c5 --- /dev/null +++ b/java/ql/test/stubs/java-ee-el/javax/el/ELProcessor.java @@ -0,0 +1,7 @@ +package javax.el; + +public class ELProcessor { + public Object eval(String expression) { return null; } + public Object getValue(String expression, Class expectedType) { return null; } + public void setValue(String expression, Object value) {} +} diff --git a/java/ql/test/stubs/java-ee-el/javax/el/ExpressionFactory.java b/java/ql/test/stubs/java-ee-el/javax/el/ExpressionFactory.java new file mode 100644 index 00000000000..31ff79169ac --- /dev/null +++ b/java/ql/test/stubs/java-ee-el/javax/el/ExpressionFactory.java @@ -0,0 +1,17 @@ +package javax.el; + +public class ExpressionFactory { + public MethodExpression createMethodExpression(ELContext context, String expression, Class expectedReturnType, + Class[] expectedParamTypes) { + + return null; + } + + public ValueExpression createValueExpression(ELContext context, String expression, Class expectedType) { + return null; + } + + public ValueExpression createValueExpression(Object instance, Class expectedType) { + return null; + } +} diff --git a/java/ql/test/stubs/java-ee-el/javax/el/LambdaExpression.java b/java/ql/test/stubs/java-ee-el/javax/el/LambdaExpression.java new file mode 100644 index 00000000000..4be01e9d2e4 --- /dev/null +++ b/java/ql/test/stubs/java-ee-el/javax/el/LambdaExpression.java @@ -0,0 +1,8 @@ +package javax.el; + +import java.util.List; + +public class LambdaExpression { + public LambdaExpression(List formalParameters, ValueExpression expression) {} + public Object invoke(Object... args) { return null; } +} diff --git a/java/ql/test/stubs/java-ee-el/javax/el/MethodExpression.java b/java/ql/test/stubs/java-ee-el/javax/el/MethodExpression.java new file mode 100644 index 00000000000..ac50ece80e3 --- /dev/null +++ b/java/ql/test/stubs/java-ee-el/javax/el/MethodExpression.java @@ -0,0 +1,5 @@ +package javax.el; + +public class MethodExpression { + public Object invoke(ELContext context, Object[] params) { return null; } +} diff --git a/java/ql/test/stubs/java-ee-el/javax/el/StandardELContext.java b/java/ql/test/stubs/java-ee-el/javax/el/StandardELContext.java new file mode 100644 index 00000000000..22e3f2a9fc1 --- /dev/null +++ b/java/ql/test/stubs/java-ee-el/javax/el/StandardELContext.java @@ -0,0 +1,5 @@ +package javax.el; + +public class StandardELContext extends ELContext { + public StandardELContext(ExpressionFactory factory) {} +} diff --git a/java/ql/test/stubs/java-ee-el/javax/el/ValueExpression.java b/java/ql/test/stubs/java-ee-el/javax/el/ValueExpression.java new file mode 100644 index 00000000000..9a231215640 --- /dev/null +++ b/java/ql/test/stubs/java-ee-el/javax/el/ValueExpression.java @@ -0,0 +1,6 @@ +package javax.el; + +public class ValueExpression { + public Object getValue(ELContext context) { return null; } + public void setValue(ELContext context, Object value) {} +} diff --git a/java/ql/test/stubs/juel-2.2/de/odysseus/el/ExpressionFactoryImpl.java b/java/ql/test/stubs/juel-2.2/de/odysseus/el/ExpressionFactoryImpl.java new file mode 100644 index 00000000000..a555cf88dee --- /dev/null +++ b/java/ql/test/stubs/juel-2.2/de/odysseus/el/ExpressionFactoryImpl.java @@ -0,0 +1,5 @@ +package de.odysseus.el; + +import javax.el.ExpressionFactory; + +public class ExpressionFactoryImpl extends ExpressionFactory {} diff --git a/java/ql/test/stubs/juel-2.2/de/odysseus/el/util/SimpleContext.java b/java/ql/test/stubs/juel-2.2/de/odysseus/el/util/SimpleContext.java new file mode 100644 index 00000000000..aa4f449e5fa --- /dev/null +++ b/java/ql/test/stubs/juel-2.2/de/odysseus/el/util/SimpleContext.java @@ -0,0 +1,5 @@ +package de.odysseus.el.util; + +import javax.el.ELContext; + +public class SimpleContext extends ELContext {} From 6c246994035a35925d870f97abc58c04162d53f9 Mon Sep 17 00:00:00 2001 From: Artem Smotrakov Date: Sun, 21 Mar 2021 21:16:00 +0300 Subject: [PATCH 221/725] Cover both javax.el and jakarta.el packages --- .../CWE-094/JakartaExpressionInjectionLib.qll | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/JakartaExpressionInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-094/JakartaExpressionInjectionLib.qll index bc22f7c3257..22f421b8bf8 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-094/JakartaExpressionInjectionLib.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-094/JakartaExpressionInjectionLib.qll @@ -77,22 +77,26 @@ private class TaintPropagatingCall extends Call { } } -private class ELProcessor extends RefType { - ELProcessor() { hasQualifiedName("javax.el", "ELProcessor") } +private class JakartaType extends RefType { + JakartaType() { getPackage().hasName(["javax.el", "jakarta.el"]) } } -private class ExpressionFactory extends RefType { - ExpressionFactory() { hasQualifiedName("javax.el", "ExpressionFactory") } +private class ELProcessor extends JakartaType { + ELProcessor() { hasName("ELProcessor") } } -private class ValueExpression extends RefType { - ValueExpression() { hasQualifiedName("javax.el", "ValueExpression") } +private class ExpressionFactory extends JakartaType { + ExpressionFactory() { hasName("ExpressionFactory") } } -private class MethodExpression extends RefType { - MethodExpression() { hasQualifiedName("javax.el", "MethodExpression") } +private class ValueExpression extends JakartaType { + ValueExpression() { hasName("ValueExpression") } +} + +private class MethodExpression extends JakartaType { + MethodExpression() { hasName("MethodExpression") } } private class LambdaExpression extends RefType { - LambdaExpression() { hasQualifiedName("javax.el", "LambdaExpression") } + LambdaExpression() { hasName("LambdaExpression") } } From cd059eb965238127ca5ce196afc9f01322c36ff0 Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Mon, 22 Mar 2021 00:19:23 +0100 Subject: [PATCH 222/725] Java: Add StringBuildingType --- .../src/Likely Bugs/Likely Typos/StringBufferCharInit.ql | 7 +------ .../src/Security/CWE/CWE-327/MaybeBrokenCryptoAlgorithm.ql | 3 +-- java/ql/src/semmle/code/java/JDK.qll | 5 +++++ java/ql/src/semmle/code/java/StringFormat.qll | 5 +---- java/ql/src/semmle/code/java/dataflow/FlowSteps.qll | 3 +-- .../code/java/dataflow/internal/TaintTrackingUtil.qll | 5 +---- 6 files changed, 10 insertions(+), 18 deletions(-) diff --git a/java/ql/src/Likely Bugs/Likely Typos/StringBufferCharInit.ql b/java/ql/src/Likely Bugs/Likely Typos/StringBufferCharInit.ql index c410c7745ee..d565c5bb7ad 100644 --- a/java/ql/src/Likely Bugs/Likely Typos/StringBufferCharInit.ql +++ b/java/ql/src/Likely Bugs/Likely Typos/StringBufferCharInit.ql @@ -13,12 +13,7 @@ import java class NewStringBufferOrBuilder extends ClassInstanceExpr { - NewStringBufferOrBuilder() { - exists(Class c | c = this.getConstructedType() | - c.hasQualifiedName("java.lang", "StringBuilder") or - c.hasQualifiedName("java.lang", "StringBuffer") - ) - } + NewStringBufferOrBuilder() { getConstructedType() instanceof StringBuildingType } string getName() { result = this.getConstructedType().getName() } } diff --git a/java/ql/src/Security/CWE/CWE-327/MaybeBrokenCryptoAlgorithm.ql b/java/ql/src/Security/CWE/CWE-327/MaybeBrokenCryptoAlgorithm.ql index efcd01548d8..c84abe1ff75 100644 --- a/java/ql/src/Security/CWE/CWE-327/MaybeBrokenCryptoAlgorithm.ql +++ b/java/ql/src/Security/CWE/CWE-327/MaybeBrokenCryptoAlgorithm.ql @@ -44,8 +44,7 @@ predicate objectToString(MethodAccess ma) { class StringContainer extends RefType { StringContainer() { this instanceof TypeString or - this.hasQualifiedName("java.lang", "StringBuilder") or - this.hasQualifiedName("java.lang", "StringBuffer") or + this instanceof StringBuildingType or this.hasQualifiedName("java.util", "StringTokenizer") or this.(Array).getComponentType() instanceof StringContainer } diff --git a/java/ql/src/semmle/code/java/JDK.qll b/java/ql/src/semmle/code/java/JDK.qll index 3b71396c920..cf2ae1ab207 100644 --- a/java/ql/src/semmle/code/java/JDK.qll +++ b/java/ql/src/semmle/code/java/JDK.qll @@ -46,6 +46,11 @@ class TypeStringBuilder extends Class { TypeStringBuilder() { this.hasQualifiedName("java.lang", "StringBuilder") } } +/** Class `java.lang.StringBuffer` or `java.lang.StringBuilder`. */ +class StringBuildingType extends Class { + StringBuildingType() { this instanceof TypeStringBuffer or this instanceof TypeStringBuilder } +} + /** The class `java.lang.System`. */ class TypeSystem extends Class { TypeSystem() { this.hasQualifiedName("java.lang", "System") } diff --git a/java/ql/src/semmle/code/java/StringFormat.qll b/java/ql/src/semmle/code/java/StringFormat.qll index 000a074f31d..aa77feafeb9 100644 --- a/java/ql/src/semmle/code/java/StringFormat.qll +++ b/java/ql/src/semmle/code/java/StringFormat.qll @@ -210,10 +210,7 @@ private predicate printMethod(Method m, int i) { (t.hasQualifiedName("java.io", "PrintWriter") or t.hasQualifiedName("java.io", "PrintStream")) and (m.hasName("print") or m.hasName("println")) or - ( - t.hasQualifiedName("java.lang", "StringBuilder") or - t.hasQualifiedName("java.lang", "StringBuffer") - ) and + t instanceof StringBuildingType and (m.hasName("append") or m.hasName("insert")) or t instanceof TypeString and m.hasName("valueOf") diff --git a/java/ql/src/semmle/code/java/dataflow/FlowSteps.qll b/java/ql/src/semmle/code/java/dataflow/FlowSteps.qll index 60308f44f65..d30cca6afe6 100644 --- a/java/ql/src/semmle/code/java/dataflow/FlowSteps.qll +++ b/java/ql/src/semmle/code/java/dataflow/FlowSteps.qll @@ -152,8 +152,7 @@ private class NumberTaintPreservingCallable extends TaintPreservingCallable { /** Holds for the types `StringBuilder`, `StringBuffer`, and `StringWriter`. */ private predicate stringBuilderType(RefType t) { - t.hasQualifiedName("java.lang", "StringBuilder") or - t.hasQualifiedName("java.lang", "StringBuffer") or + t instanceof StringBuildingType or t.hasQualifiedName("java.io", "StringWriter") } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll b/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll index f8e11e8c770..2e27a390bdc 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll @@ -552,10 +552,7 @@ module StringBuilderVarModule { * build up a query using string concatenation. */ class StringBuilderVar extends LocalVariableDecl { - StringBuilderVar() { - this.getType() instanceof TypeStringBuilder or - this.getType() instanceof TypeStringBuffer - } + StringBuilderVar() { getType() instanceof StringBuildingType } /** * Gets a call that adds something to this string builder, from the argument at the given index. From 1534b387bb64cdcd6d88cf36f8516d2b830fd4d5 Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Mon, 22 Mar 2021 00:54:14 +0100 Subject: [PATCH 223/725] Java: Improve documentation regarding minus in front of numeric literals --- java/ql/src/semmle/code/java/Expr.qll | 45 ++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/java/ql/src/semmle/code/java/Expr.qll b/java/ql/src/semmle/code/java/Expr.qll index 43ad6634fc1..2e90075c1eb 100755 --- a/java/ql/src/semmle/code/java/Expr.qll +++ b/java/ql/src/semmle/code/java/Expr.qll @@ -638,7 +638,20 @@ class BooleanLiteral extends Literal, @booleanliteral { override string getAPrimaryQlClass() { result = "BooleanLiteral" } } -/** An integer literal. For example, `23`. */ +/** + * An integer literal. For example, `23`. + * + * An integer literal can never be negative except when: + * - It is written in binary, octal or hexadecimal notation + * - It is written in decimal notation, has the value `2147483648` and is preceded + * by a minus; in this case the value of the IntegerLiteral is -2147483648 and + * the preceding minus will *not* be modeled as `MinusExpr`.
    + * In all other cases the preceding minus, if any, will be modeled as separate + * `MinusExpr`. + * + * The last exception is necessary because `2147483648` on its own would not be + * a valid integer literal (and could also not be parsed as CodeQL `int`). + */ class IntegerLiteral extends Literal, @integerliteral { /** Gets the int representation of this literal. */ int getIntValue() { result = getValue().toInt() } @@ -646,17 +659,41 @@ class IntegerLiteral extends Literal, @integerliteral { override string getAPrimaryQlClass() { result = "IntegerLiteral" } } -/** A long literal. For example, `23l`. */ +/** + * A long literal. For example, `23L`. + * + * A long literal can never be negative except when: + * - It is written in binary, octal or hexadecimal notation + * - It is written in decimal notation, has the value `9223372036854775808` and + * is preceded by a minus; in this case the value of the LongLiteral is + * -9223372036854775808 and the preceding minus will *not* be modeled as + * `MinusExpr`.
    + * In all other cases the preceding minus, if any, will be modeled as separate + * `MinusExpr`. + * + * The last exception is necessary because `9223372036854775808` on its own + * would not be a valid long literal. + */ class LongLiteral extends Literal, @longliteral { override string getAPrimaryQlClass() { result = "LongLiteral" } } -/** A floating point literal. For example, `4.2f`. */ +/** + * A float literal. For example, `4.2f`. + * + * A float literal is never negative; a preceding minus, if any, will always + * be modeled as separate `MinusExpr`. + */ class FloatingPointLiteral extends Literal, @floatingpointliteral { override string getAPrimaryQlClass() { result = "FloatingPointLiteral" } } -/** A double literal. For example, `4.2`. */ +/** + * A double literal. For example, `4.2`. + * + * A double literal is never negative; a preceding minus, if any, will always + * be modeled as separate `MinusExpr`. + */ class DoubleLiteral extends Literal, @doubleliteral { override string getAPrimaryQlClass() { result = "DoubleLiteral" } } From 701b935564521d64cc35dc51753493f4dc2782f6 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 22 Mar 2021 00:57:43 +0100 Subject: [PATCH 224/725] Python: Add example of QuerySet chain (django) --- python/ql/test/library-tests/frameworks/django/SqlExecution.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/python/ql/test/library-tests/frameworks/django/SqlExecution.py b/python/ql/test/library-tests/frameworks/django/SqlExecution.py index 67a6ee81a5d..fba2ccdc73e 100644 --- a/python/ql/test/library-tests/frameworks/django/SqlExecution.py +++ b/python/ql/test/library-tests/frameworks/django/SqlExecution.py @@ -27,3 +27,6 @@ def test_model(): raw = RawSQL("so raw") User.objects.annotate(val=raw) # $getSql="so raw" + + # chaining QuerySet calls + User.objects.using("db-name").exclude(username="admin").extra("some sql") # $ MISSING: getSql="some sql" From f800bf243fdbc573fbe97e4ecfe8c5ed997e1bb8 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 22 Mar 2021 01:39:19 +0100 Subject: [PATCH 225/725] Python: Better text for getSourceType in Django --- python/ql/src/semmle/python/frameworks/Django.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/src/semmle/python/frameworks/Django.qll b/python/ql/src/semmle/python/frameworks/Django.qll index 9f56bd5a299..10cd7d5c197 100644 --- a/python/ql/src/semmle/python/frameworks/Django.qll +++ b/python/ql/src/semmle/python/frameworks/Django.qll @@ -2393,7 +2393,7 @@ private module Django { } override string getSourceType() { - result = "django.http.request.HttpRequest (attribute on self in View class)" + result = "django HttpRequest from self.request in View class" } } @@ -2413,7 +2413,7 @@ private module Django { } override string getSourceType() { - result = "django routed param from attribute on self in View class" + result = "django routed param from self.args/kwargs in View class" } } From 98558c7c59bdb36a18b20f4756a32611a0389de6 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 22 Mar 2021 09:42:27 +0100 Subject: [PATCH 226/725] Update docs/ql-libraries/dataflow/dataflow.md Co-authored-by: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com> --- docs/ql-libraries/dataflow/dataflow.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ql-libraries/dataflow/dataflow.md b/docs/ql-libraries/dataflow/dataflow.md index c4c09a4c949..3c46436a87a 100644 --- a/docs/ql-libraries/dataflow/dataflow.md +++ b/docs/ql-libraries/dataflow/dataflow.md @@ -199,7 +199,7 @@ predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) /** Holds if `call` is a lambda call of kind `kind` where `receiver` is the lambda expression. */ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) -/** Extra data-flow steps needed for lamba flow analysis. */ +/** Extra data-flow steps needed for lambda flow analysis. */ predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) ``` From 3a83ecf067a5391bf4f54252fc0d2a2454b5fefb Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 22 Mar 2021 01:38:38 +0100 Subject: [PATCH 227/725] Python: Add test for taint in django forms/fields --- .../django-v2-v3/TestTaint.expected | 11 +++++ .../frameworks/django-v2-v3/taint_forms.py | 46 +++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 python/ql/test/library-tests/frameworks/django-v2-v3/taint_forms.py diff --git a/python/ql/test/library-tests/frameworks/django-v2-v3/TestTaint.expected b/python/ql/test/library-tests/frameworks/django-v2-v3/TestTaint.expected index 0602985a392..95d0a58df3b 100644 --- a/python/ql/test/library-tests/frameworks/django-v2-v3/TestTaint.expected +++ b/python/ql/test/library-tests/frameworks/django-v2-v3/TestTaint.expected @@ -1,4 +1,15 @@ | response_test.py:61 | ok | get_redirect_url | foo | +| taint_forms.py:6 | fail | to_python | value | +| taint_forms.py:9 | fail | validate | value | +| taint_forms.py:12 | fail | run_validators | value | +| taint_forms.py:15 | fail | clean | value | +| taint_forms.py:33 | fail | clean | cleaned_data | +| taint_forms.py:34 | fail | clean | cleaned_data["key"] | +| taint_forms.py:35 | fail | clean | cleaned_data.get(..) | +| taint_forms.py:39 | fail | clean | self.cleaned_data | +| taint_forms.py:40 | fail | clean | self.cleaned_data["key"] | +| taint_forms.py:41 | fail | clean | self.cleaned_data.get(..) | +| taint_forms.py:46 | fail | clean_foo | self.cleaned_data | | taint_test.py:8 | ok | test_taint | bar | | taint_test.py:8 | ok | test_taint | foo | | taint_test.py:9 | ok | test_taint | baz | diff --git a/python/ql/test/library-tests/frameworks/django-v2-v3/taint_forms.py b/python/ql/test/library-tests/frameworks/django-v2-v3/taint_forms.py new file mode 100644 index 00000000000..a702f89ee26 --- /dev/null +++ b/python/ql/test/library-tests/frameworks/django-v2-v3/taint_forms.py @@ -0,0 +1,46 @@ +import django.forms + + +class MyField(django.forms.Field): + def to_python(self, value): + ensure_tainted(value) + + def validate(self, value): + ensure_tainted(value) + + def run_validators(self, value): + ensure_tainted(value) + + def clean(self, value): + ensure_tainted(value) + + # # Base definition of `clean` looks like the following, so there is actually + # # _data flow_ from the methods, but we will ignore for simplicity. + # value = self.to_python(value) + # self.validate(value) + # self.run_validators(value) + # return value + + +class MyForm(django.forms.Form): + + foo = MyField() + + def clean(self): + cleaned_data = super().clean() + + ensure_tainted( + cleaned_data, + cleaned_data["key"], + cleaned_data.get("key"), + ) + + ensure_tainted( + self.cleaned_data, + self.cleaned_data["key"], + self.cleaned_data.get("key"), + ) + + def clean_foo(self): + # This method is supposed to clean a the `foo` field in context of this form. + ensure_tainted(self.cleaned_data) From b422a972bffebd75ff23c8544cb1687638c4ad23 Mon Sep 17 00:00:00 2001 From: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Mon, 22 Mar 2021 10:00:18 +0000 Subject: [PATCH 228/725] Update conf.py --- docs/codeql/support/conf.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/codeql/support/conf.py b/docs/codeql/support/conf.py index 45a8456ce9a..3d2f5d6cf81 100644 --- a/docs/codeql/support/conf.py +++ b/docs/codeql/support/conf.py @@ -16,7 +16,7 @@ ############################################################################## # -# Modified 22052019. +# Modified 22032021. # The configuration values below are specific to the supported languages and frameworks project # To amend html_theme_options, update version/release number, or add more sphinx extensions, @@ -41,9 +41,9 @@ project = u'Supported languages and frameworks for LGTM Enterprise' # The version info for this project, if different from version and release in main conf.py file. # The short X.Y version. -version = u'1.26' +version = u'1.27' # The full version, including alpha/beta/rc tags. -release = u'1.26' +release = u'1.27' # -- Project-specifc options for HTML output ---------------------------------------------- @@ -95,4 +95,4 @@ html_favicon = '../images/site/favicon.ico' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns = ['read-me-project.rst', 'reusables/*'] \ No newline at end of file +exclude_patterns = ['read-me-project.rst', 'reusables/*'] From 668841cefa83f984a53a31d6146cee238ea30ebf Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Mon, 22 Mar 2021 11:13:49 +0100 Subject: [PATCH 229/725] C++: Rename diagnostic queries. --- cpp/ql/src/Diagnostics/ExtractionErrors.ql | 16 ++++++++++++++++ ...ailedExtractions.qll => ExtractionErrors.qll} | 4 ++-- cpp/ql/src/Diagnostics/FailedExtractions.ql | 16 ---------------- ...ocations.ql => FailedExtractorInvocations.ql} | 0 ...ractions.ql => SuccessfullyExtractedFiles.ql} | 4 ++-- 5 files changed, 20 insertions(+), 20 deletions(-) create mode 100644 cpp/ql/src/Diagnostics/ExtractionErrors.ql rename cpp/ql/src/Diagnostics/{FailedExtractions.qll => ExtractionErrors.qll} (96%) delete mode 100644 cpp/ql/src/Diagnostics/FailedExtractions.ql rename cpp/ql/src/Diagnostics/{FailedInvocations.ql => FailedExtractorInvocations.ql} (100%) rename cpp/ql/src/Diagnostics/{SuccessfulExtractions.ql => SuccessfullyExtractedFiles.ql} (78%) diff --git a/cpp/ql/src/Diagnostics/ExtractionErrors.ql b/cpp/ql/src/Diagnostics/ExtractionErrors.ql new file mode 100644 index 00000000000..a445c3bc0c4 --- /dev/null +++ b/cpp/ql/src/Diagnostics/ExtractionErrors.ql @@ -0,0 +1,16 @@ +/** + * @name Extraction errors + * @description List all extraction errors for files in the source code directory. + * @kind diagnostic + * @id cpp/diagnostics/extraction-errors + */ + +import cpp +import ExtractionErrors + +from ExtractionError error +where + error instanceof ExtractionUnknownError or + exists(error.getFile().getRelativePath()) +select error, "Extraction failed in " + error.getFile() + " with error " + error.getErrorMessage(), + error.getSeverity() diff --git a/cpp/ql/src/Diagnostics/FailedExtractions.qll b/cpp/ql/src/Diagnostics/ExtractionErrors.qll similarity index 96% rename from cpp/ql/src/Diagnostics/FailedExtractions.qll rename to cpp/ql/src/Diagnostics/ExtractionErrors.qll index 62a89f7cdc1..4cf6f8145f8 100644 --- a/cpp/ql/src/Diagnostics/FailedExtractions.qll +++ b/cpp/ql/src/Diagnostics/ExtractionErrors.qll @@ -12,12 +12,12 @@ import cpp * Thus, if the extractor emitted at least one diagnostic of severity discretionary * error (or higher), it *also* emits a simple "There was an error during this compilation" * error diagnostic, without location information. - * In the common case, this means that a file with one (or more) errors also gets + * In the common case, this means that a compilation during which one or more errors happened also gets * the catch-all diagnostic. * This diagnostic has the empty string as file path. * We filter out these useless diagnostics if there is at least one error-level diagnostic * for the affected compilation in the database. - * Otherwise, we show it to, to indicate that something went wrong, and we + * Otherwise, we show it to indicate that something went wrong and that we * don't know what exactly happened. */ diff --git a/cpp/ql/src/Diagnostics/FailedExtractions.ql b/cpp/ql/src/Diagnostics/FailedExtractions.ql deleted file mode 100644 index 52b07ca2559..00000000000 --- a/cpp/ql/src/Diagnostics/FailedExtractions.ql +++ /dev/null @@ -1,16 +0,0 @@ -/** - * @name Failed extractions - * @description List all files in the source code directory with extraction errors. - * @kind diagnostic - * @id cpp/diagnostics/failed-extractions - */ - -import cpp -import FailedExtractions - -from ExtractionError error -where - error instanceof ExtractionUnknownError or - exists(error.getFile().getRelativePath()) -select error, "Extracting failed in " + error.getFile() + " with error " + error.getErrorMessage(), - error.getSeverity() diff --git a/cpp/ql/src/Diagnostics/FailedInvocations.ql b/cpp/ql/src/Diagnostics/FailedExtractorInvocations.ql similarity index 100% rename from cpp/ql/src/Diagnostics/FailedInvocations.ql rename to cpp/ql/src/Diagnostics/FailedExtractorInvocations.ql diff --git a/cpp/ql/src/Diagnostics/SuccessfulExtractions.ql b/cpp/ql/src/Diagnostics/SuccessfullyExtractedFiles.ql similarity index 78% rename from cpp/ql/src/Diagnostics/SuccessfulExtractions.ql rename to cpp/ql/src/Diagnostics/SuccessfullyExtractedFiles.ql index 380f1ce8bbe..a920af8e767 100644 --- a/cpp/ql/src/Diagnostics/SuccessfulExtractions.ql +++ b/cpp/ql/src/Diagnostics/SuccessfullyExtractedFiles.ql @@ -1,12 +1,12 @@ /** * @name Successfully extracted files - * @description Lists all files in the source code directory that were extracted without encountering an error. + * @description Lists all files in the source code directory that were extracted without encountering an error in the file. * @kind diagnostic * @id cpp/diagnostics/successfully-extracted-files */ import cpp -import FailedExtractions +import ExtractionErrors from File f where From 7ec86b5e7f1314f0649888651daff8df75fd6948 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Mon, 22 Mar 2021 11:35:29 +0100 Subject: [PATCH 230/725] C++: AdjustedConfiguration should not extend the same dataflow configuration as FromGlobalVarTaintTrackingCfg as this causes multiple configurations to be in scope for dataflow. --- .../cpp/ir/dataflow/DefaultTaintTracking.qll | 21 ++-- .../code/cpp/ir/dataflow/TaintTracking3.qll | 15 +++ .../tainttracking3/TaintTrackingImpl.qll | 115 ++++++++++++++++++ .../tainttracking3/TaintTrackingParameter.qll | 5 + 4 files changed, 146 insertions(+), 10 deletions(-) create mode 100644 cpp/ql/src/semmle/code/cpp/ir/dataflow/TaintTracking3.qll create mode 100644 cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingImpl.qll create mode 100644 cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingParameter.qll 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 7b97bc738f4..3092031cbc7 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll @@ -2,7 +2,7 @@ import cpp import semmle.code.cpp.security.Security private import semmle.code.cpp.ir.dataflow.DataFlow private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil -private import semmle.code.cpp.ir.dataflow.DataFlow2 +private import semmle.code.cpp.ir.dataflow.DataFlow3 private import semmle.code.cpp.ir.IR private import semmle.code.cpp.ir.dataflow.internal.DataFlowDispatch as Dispatch private import semmle.code.cpp.controlflow.IRGuards @@ -10,6 +10,7 @@ private import semmle.code.cpp.models.interfaces.Taint private import semmle.code.cpp.models.interfaces.DataFlow private import semmle.code.cpp.ir.dataflow.TaintTracking private import semmle.code.cpp.ir.dataflow.TaintTracking2 +private import semmle.code.cpp.ir.dataflow.TaintTracking3 private import semmle.code.cpp.ir.dataflow.internal.ModelUtil /** @@ -380,7 +381,7 @@ module TaintedWithPath { string toString() { result = "TaintTrackingConfiguration" } } - private class AdjustedConfiguration extends TaintTracking2::Configuration { + private class AdjustedConfiguration extends TaintTracking3::Configuration { AdjustedConfiguration() { this = "AdjustedConfiguration" } override predicate isSource(DataFlow::Node source) { @@ -438,11 +439,11 @@ module TaintedWithPath { */ private newtype TPathNode = - TWrapPathNode(DataFlow2::PathNode n) or + TWrapPathNode(DataFlow3::PathNode n) or // There's a single newtype constructor for both sources and sinks since // that makes it easiest to deal with the case where source = sink. TEndpointPathNode(Element e) { - exists(AdjustedConfiguration cfg, DataFlow2::Node sourceNode, DataFlow2::Node sinkNode | + exists(AdjustedConfiguration cfg, DataFlow3::Node sourceNode, DataFlow3::Node sinkNode | cfg.hasFlow(sourceNode, sinkNode) | sourceNode = getNodeForExpr(e) and @@ -473,7 +474,7 @@ module TaintedWithPath { } private class WrapPathNode extends PathNode, TWrapPathNode { - DataFlow2::PathNode inner() { this = TWrapPathNode(result) } + DataFlow3::PathNode inner() { this = TWrapPathNode(result) } override string toString() { result = this.inner().toString() } @@ -510,25 +511,25 @@ module TaintedWithPath { /** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */ query predicate edges(PathNode a, PathNode b) { - DataFlow2::PathGraph::edges(a.(WrapPathNode).inner(), b.(WrapPathNode).inner()) + DataFlow3::PathGraph::edges(a.(WrapPathNode).inner(), b.(WrapPathNode).inner()) or // To avoid showing trivial-looking steps, we _replace_ the last node instead // of adding an edge out of it. exists(WrapPathNode sinkNode | - DataFlow2::PathGraph::edges(a.(WrapPathNode).inner(), sinkNode.inner()) and + DataFlow3::PathGraph::edges(a.(WrapPathNode).inner(), sinkNode.inner()) and b.(FinalPathNode).inner() = adjustedSink(sinkNode.inner().getNode()) ) or // Same for the first node exists(WrapPathNode sourceNode | - DataFlow2::PathGraph::edges(sourceNode.inner(), b.(WrapPathNode).inner()) and + DataFlow3::PathGraph::edges(sourceNode.inner(), b.(WrapPathNode).inner()) and sourceNode.inner().getNode() = getNodeForExpr(a.(InitialPathNode).inner()) ) or // Finally, handle the case where the path goes directly from a source to a // sink, meaning that they both need to be translated. exists(WrapPathNode sinkNode, WrapPathNode sourceNode | - DataFlow2::PathGraph::edges(sourceNode.inner(), sinkNode.inner()) and + DataFlow3::PathGraph::edges(sourceNode.inner(), sinkNode.inner()) and sourceNode.inner().getNode() = getNodeForExpr(a.(InitialPathNode).inner()) and b.(FinalPathNode).inner() = adjustedSink(sinkNode.inner().getNode()) ) @@ -550,7 +551,7 @@ module TaintedWithPath { * the computation. */ predicate taintedWithPath(Expr source, Element tainted, PathNode sourceNode, PathNode sinkNode) { - exists(AdjustedConfiguration cfg, DataFlow2::Node flowSource, DataFlow2::Node flowSink | + exists(AdjustedConfiguration cfg, DataFlow3::Node flowSource, DataFlow3::Node flowSink | source = sourceNode.(InitialPathNode).inner() and flowSource = getNodeForExpr(source) and cfg.hasFlow(flowSource, flowSink) and diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/TaintTracking3.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/TaintTracking3.qll new file mode 100644 index 00000000000..98e1caebf38 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/TaintTracking3.qll @@ -0,0 +1,15 @@ +/** + * Provides a `TaintTracking3` module, which is a copy of the `TaintTracking` + * module. Use this class when data-flow configurations or taint-tracking + * configurations must depend on each other. Two classes extending + * `DataFlow::Configuration` should never depend on each other, but one of them + * should instead depend on a `DataFlow2::Configuration`, a + * `DataFlow3::Configuration`, or a `DataFlow4::Configuration`. The + * `TaintTracking::Configuration` class extends `DataFlow::Configuration`, and + * `TaintTracking2::Configuration` extends `DataFlow2::Configuration`. + * + * See `semmle.code.cpp.ir.dataflow.TaintTracking` for the full documentation. + */ +module TaintTracking3 { + import semmle.code.cpp.ir.dataflow.internal.tainttracking3.TaintTrackingImpl +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingImpl.qll new file mode 100644 index 00000000000..b509fad9cd2 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingImpl.qll @@ -0,0 +1,115 @@ +/** + * Provides an implementation of global (interprocedural) taint tracking. + * This file re-exports the local (intraprocedural) taint-tracking analysis + * from `TaintTrackingParameter::Public` and adds a global analysis, mainly + * exposed through the `Configuration` class. For some languages, this file + * exists in several identical copies, allowing queries to use multiple + * `Configuration` classes that depend on each other without introducing + * mutual recursion among those configurations. + */ + +import TaintTrackingParameter::Public +private import TaintTrackingParameter::Private + +/** + * A configuration of interprocedural taint tracking analysis. This defines + * sources, sinks, and any other configurable aspect of the analysis. Each + * use of the taint tracking library must define its own unique extension of + * this abstract class. + * + * A taint-tracking configuration is a special data flow configuration + * (`DataFlow::Configuration`) that allows for flow through nodes that do not + * necessarily preserve values but are still relevant from a taint tracking + * perspective. (For example, string concatenation, where one of the operands + * is tainted.) + * + * To create a configuration, extend this class with a subclass whose + * characteristic predicate is a unique singleton string. For example, write + * + * ```ql + * class MyAnalysisConfiguration extends TaintTracking::Configuration { + * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } + * // Override `isSource` and `isSink`. + * // Optionally override `isSanitizer`. + * // Optionally override `isSanitizerIn`. + * // Optionally override `isSanitizerOut`. + * // Optionally override `isSanitizerGuard`. + * // Optionally override `isAdditionalTaintStep`. + * } + * ``` + * + * Then, to query whether there is flow between some `source` and `sink`, + * write + * + * ```ql + * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) + * ``` + * + * Multiple configurations can coexist, but it is unsupported to depend on + * another `TaintTracking::Configuration` or a `DataFlow::Configuration` in the + * overridden predicates that define sources, sinks, or additional steps. + * Instead, the dependency should go to a `TaintTracking2::Configuration` or a + * `DataFlow2::Configuration`, `DataFlow3::Configuration`, etc. + */ +abstract class Configuration extends DataFlow::Configuration { + bindingset[this] + Configuration() { any() } + + /** + * Holds if `source` is a relevant taint source. + * + * The smaller this predicate is, the faster `hasFlow()` will converge. + */ + // overridden to provide taint-tracking specific qldoc + abstract override predicate isSource(DataFlow::Node source); + + /** + * Holds if `sink` is a relevant taint sink. + * + * The smaller this predicate is, the faster `hasFlow()` will converge. + */ + // overridden to provide taint-tracking specific qldoc + abstract override predicate isSink(DataFlow::Node sink); + + /** Holds if the node `node` is a taint sanitizer. */ + predicate isSanitizer(DataFlow::Node node) { none() } + + final override predicate isBarrier(DataFlow::Node node) { + isSanitizer(node) or + defaultTaintSanitizer(node) + } + + /** Holds if taint propagation into `node` is prohibited. */ + predicate isSanitizerIn(DataFlow::Node node) { none() } + + final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) } + + /** Holds if taint propagation out of `node` is prohibited. */ + predicate isSanitizerOut(DataFlow::Node node) { none() } + + final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) } + + /** Holds if taint propagation through nodes guarded by `guard` is prohibited. */ + predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() } + + final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) } + + /** + * Holds if the additional taint propagation step from `node1` to `node2` + * must be taken into account in the analysis. + */ + predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() } + + final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { + isAdditionalTaintStep(node1, node2) or + defaultAdditionalTaintStep(node1, node2) + } + + /** + * Holds if taint may flow from `source` to `sink` for this configuration. + */ + // overridden to provide taint-tracking specific qldoc + override predicate hasFlow(DataFlow::Node source, DataFlow::Node sink) { + super.hasFlow(source, sink) + } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingParameter.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingParameter.qll new file mode 100644 index 00000000000..2a3b69f55cd --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingParameter.qll @@ -0,0 +1,5 @@ +import semmle.code.cpp.ir.dataflow.internal.TaintTrackingUtil as Public + +module Private { + import semmle.code.cpp.ir.dataflow.DataFlow3::DataFlow3 as DataFlow +} From d09458a4868a86af333394bc45ee7d43d9c3c8fc Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Mon, 22 Mar 2021 11:35:59 +0100 Subject: [PATCH 231/725] C++: Add another taint tracking copy to identical-files.json --- config/identical-files.json | 1 + 1 file changed, 1 insertion(+) diff --git a/config/identical-files.json b/config/identical-files.json index b63690c5f1e..de7075b7fc8 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -36,6 +36,7 @@ "cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll", "cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll", "cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll", + "cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingImpl.qll", "csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll", "csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll", "csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll", From 9e84b756f783439a84da4e10ccf1dac171ce3363 Mon Sep 17 00:00:00 2001 From: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Mon, 22 Mar 2021 10:40:17 +0000 Subject: [PATCH 232/725] Update supported frameworks --- docs/codeql/support/framework-support.rst | 2 -- docs/codeql/support/reusables/frameworks.rst | 24 +++++++++++++++++++- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/docs/codeql/support/framework-support.rst b/docs/codeql/support/framework-support.rst index 37d54829475..d04293adfe5 100644 --- a/docs/codeql/support/framework-support.rst +++ b/docs/codeql/support/framework-support.rst @@ -10,6 +10,4 @@ The libraries and queries in version |version| have been explicitly checked agai If you're interested in other libraries or frameworks, you can extend the analysis to cover them. For example, by extending the data flow libraries to include data sources and sinks for additional libraries or frameworks. -.. There is currently no built-in support for libraries or frameworks for C/C++. - .. include:: reusables/frameworks.rst diff --git a/docs/codeql/support/reusables/frameworks.rst b/docs/codeql/support/reusables/frameworks.rst index 4dd155e2302..6e3cf5e7664 100644 --- a/docs/codeql/support/reusables/frameworks.rst +++ b/docs/codeql/support/reusables/frameworks.rst @@ -1,4 +1,15 @@ -.. There is currently no built-in support for libraries or frameworks for C/C++. +C and C++ built-in support +================================ + +.. csv-table:: + :header-rows: 1 + :class: fullWidthTable + :widths: auto + + Name, Category + `Bloomberg Standard Library `__, xxx + `Berkeley socket API library `__, API library + string.h, xxx C# built-in support ================================ @@ -78,6 +89,8 @@ Java built-in support :widths: auto Name, Category + Apache Commons, Language library (?) + Guava, xxx Hibernate, Database iBatis / MyBatis, Database Java Persistence API (JPA), Database @@ -102,21 +115,28 @@ JavaScript and TypeScript built-in support Name, Category angular (modern version), HTML framework angular.js (legacy version), HTML framework + apollo-link-http, xxx axios, Network communicator browser, Runtime environment electron, Runtime environment express, Server + Formik hapi, Server + Immutable.js, xxx jquery, Utility library koa, Server lodash, Utility library + marked, xxx mongodb, Database mssql, Database + Multer, xxx mysql, Database node, Runtime environment postgres, Database + pug, xxx ramda, Utility library react, HTML framework + react-helmet, xxx request, Network communicator sequelize, Database socket.io, Network communicator @@ -124,6 +144,8 @@ JavaScript and TypeScript built-in support superagent, Network communicator underscore, Utility library vue, HTML framework + vue-router, xxx + xml2js, xxx From 343f4e442f88211e4a76971ecb4ff3d6d3f58028 Mon Sep 17 00:00:00 2001 From: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Mon, 22 Mar 2021 10:46:29 +0000 Subject: [PATCH 233/725] Add "TODO"s --- docs/codeql/support/reusables/frameworks.rst | 24 ++++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/codeql/support/reusables/frameworks.rst b/docs/codeql/support/reusables/frameworks.rst index 6e3cf5e7664..ee948496334 100644 --- a/docs/codeql/support/reusables/frameworks.rst +++ b/docs/codeql/support/reusables/frameworks.rst @@ -7,9 +7,9 @@ C and C++ built-in support :widths: auto Name, Category - `Bloomberg Standard Library `__, xxx + `Bloomberg Standard Library `__, TODO `Berkeley socket API library `__, API library - string.h, xxx + string.h, TODO C# built-in support ================================ @@ -90,7 +90,7 @@ Java built-in support Name, Category Apache Commons, Language library (?) - Guava, xxx + Guava, TODO Hibernate, Database iBatis / MyBatis, Database Java Persistence API (JPA), Database @@ -115,28 +115,28 @@ JavaScript and TypeScript built-in support Name, Category angular (modern version), HTML framework angular.js (legacy version), HTML framework - apollo-link-http, xxx + apollo-link-http, TODO axios, Network communicator browser, Runtime environment electron, Runtime environment express, Server - Formik + Formik, TODO hapi, Server - Immutable.js, xxx + Immutable.js, TODO jquery, Utility library koa, Server lodash, Utility library - marked, xxx + marked, TODO mongodb, Database mssql, Database - Multer, xxx + Multer, TODO mysql, Database node, Runtime environment postgres, Database - pug, xxx + pug, TODO ramda, Utility library react, HTML framework - react-helmet, xxx + react-helmet, TODO request, Network communicator sequelize, Database socket.io, Network communicator @@ -144,8 +144,8 @@ JavaScript and TypeScript built-in support superagent, Network communicator underscore, Utility library vue, HTML framework - vue-router, xxx - xml2js, xxx + vue-router, TODO + xml2js, TODO From 54a91c73b09c28cea7e655b63c61666fd37a55c3 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 22 Mar 2021 10:56:03 +0000 Subject: [PATCH 234/725] JS: Tweak summarizedHigherOrderCall --- javascript/ql/src/semmle/javascript/dataflow/Configuration.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll index f45ed826b8c..33d49542466 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll @@ -1364,7 +1364,7 @@ private predicate summarizedHigherOrderCall( | // direct higher-order call summarizedHigherOrderCallAux(f, arg, innerArg, cfg, oldSummary, cbParm, inner, j, cb) and - cbParm.flowsTo(inner.getCalleeNode()) and + inner = cbParm.getAnInvocation() and i = j and summary = oldSummary or From 7a0bfd1a69c9a0eb7e13d665ad1f4ce67d05d6fd Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Mon, 22 Mar 2021 12:20:35 +0100 Subject: [PATCH 235/725] Skip through any stub preamble --- csharp/ql/src/Stubs/make_stubs.py | 43 +++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/csharp/ql/src/Stubs/make_stubs.py b/csharp/ql/src/Stubs/make_stubs.py index 19a917cd8ab..dcdd9e87cfe 100644 --- a/csharp/ql/src/Stubs/make_stubs.py +++ b/csharp/ql/src/Stubs/make_stubs.py @@ -71,19 +71,36 @@ if subprocess.check_call(cmd): print('Failed to run the query to generate output file.') exit(1) -# Remove the leading " and trailing " bytes from the file -len = os.stat(outputFile).st_size -f = open(outputFile, "rb") -try: - quote = f.read(6) - if quote != b"\x02\x01\x86'\x85'": - print("Unexpected start characters in file.", quote) - contents = f.read(len-21) - quote = f.read(15) - if quote != b'\x0e\x01\x08#select\x01\x01\x00s\x00': - print("Unexpected end character in file.", quote) -finally: - f.close() +# Remove the leading and trailing bytes from the file +length = os.stat(outputFile).st_size +if length < 20: + contents = b'' +else: + f = open(outputFile, "rb") + try: + countTillSlash = 0 + foundSlash = False + slash = f.read(1) + while slash != b'': + if slash == b'/': + foundSlash = True + break + countTillSlash += 1 + slash = f.read(1) + + if not foundSlash: + countTillSlash = 0 + + f.seek(0) + quote = f.read(countTillSlash) + print("Start characters in file skipped.", quote) + post = b'\x0e\x01\x08#select\x01\x01\x00s\x00' + contents = f.read(length - len(post) - countTillSlash) + quote = f.read(len(post)) + if quote != post: + print("Unexpected end character in file.", quote) + finally: + f.close() f = open(outputFile, "wb") f.write(contents) From c5ef57c4085e21334ab5cf997f6b14ef968be451 Mon Sep 17 00:00:00 2001 From: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Mon, 22 Mar 2021 11:40:13 +0000 Subject: [PATCH 236/725] Update docs/codeql/support/reusables/frameworks.rst Co-authored-by: Chris Smowton --- docs/codeql/support/reusables/frameworks.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/codeql/support/reusables/frameworks.rst b/docs/codeql/support/reusables/frameworks.rst index ee948496334..6df22e5b01a 100644 --- a/docs/codeql/support/reusables/frameworks.rst +++ b/docs/codeql/support/reusables/frameworks.rst @@ -89,8 +89,8 @@ Java built-in support :widths: auto Name, Category - Apache Commons, Language library (?) - Guava, TODO + Apache Commons Lang, utility library + Guava, utility and collections library Hibernate, Database iBatis / MyBatis, Database Java Persistence API (JPA), Database From 0f8372276799fe4d0edb5df5570f003c69dbc0b8 Mon Sep 17 00:00:00 2001 From: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Mon, 22 Mar 2021 12:01:08 +0000 Subject: [PATCH 237/725] Revert JS changes and add another Java entry --- docs/codeql/support/reusables/frameworks.rst | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/docs/codeql/support/reusables/frameworks.rst b/docs/codeql/support/reusables/frameworks.rst index 6df22e5b01a..4f553daba78 100644 --- a/docs/codeql/support/reusables/frameworks.rst +++ b/docs/codeql/support/reusables/frameworks.rst @@ -89,8 +89,9 @@ Java built-in support :widths: auto Name, Category - Apache Commons Lang, utility library - Guava, utility and collections library + Apache Commons Lang, Utility library + Apache HTTP components, Network communicator + Guava, Utility and collections library Hibernate, Database iBatis / MyBatis, Database Java Persistence API (JPA), Database @@ -115,28 +116,21 @@ JavaScript and TypeScript built-in support Name, Category angular (modern version), HTML framework angular.js (legacy version), HTML framework - apollo-link-http, TODO axios, Network communicator browser, Runtime environment electron, Runtime environment express, Server - Formik, TODO hapi, Server - Immutable.js, TODO jquery, Utility library koa, Server lodash, Utility library - marked, TODO mongodb, Database mssql, Database - Multer, TODO mysql, Database node, Runtime environment postgres, Database - pug, TODO ramda, Utility library react, HTML framework - react-helmet, TODO request, Network communicator sequelize, Database socket.io, Network communicator @@ -144,9 +138,6 @@ JavaScript and TypeScript built-in support superagent, Network communicator underscore, Utility library vue, HTML framework - vue-router, TODO - xml2js, TODO - Python built-in support From 257fc7459d1f924d4b8177ccc337717e22717f54 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Mon, 22 Mar 2021 13:28:48 +0100 Subject: [PATCH 238/725] Update categories for new the C++ libraries. --- docs/codeql/support/reusables/frameworks.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/codeql/support/reusables/frameworks.rst b/docs/codeql/support/reusables/frameworks.rst index 4f553daba78..5a8099b1c85 100644 --- a/docs/codeql/support/reusables/frameworks.rst +++ b/docs/codeql/support/reusables/frameworks.rst @@ -7,9 +7,9 @@ C and C++ built-in support :widths: auto Name, Category - `Bloomberg Standard Library `__, TODO - `Berkeley socket API library `__, API library - string.h, TODO + `Bloomberg Standard Library `__, Utility library + `Berkeley socket API library `__, Network communicator + string.h, String library C# built-in support ================================ From c8a6e837b57513df5c8ccd081e193be3443987d1 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 22 Mar 2021 14:36:29 +0100 Subject: [PATCH 239/725] Python: Model QuerySet chains in django --- .../2021-03-22-django-queryset-chains.md | 2 + .../src/semmle/python/frameworks/Django.qll | 128 +++++++----------- .../frameworks/django/SqlExecution.py | 2 +- 3 files changed, 54 insertions(+), 78 deletions(-) create mode 100644 python/change-notes/2021-03-22-django-queryset-chains.md diff --git a/python/change-notes/2021-03-22-django-queryset-chains.md b/python/change-notes/2021-03-22-django-queryset-chains.md new file mode 100644 index 00000000000..116a7573360 --- /dev/null +++ b/python/change-notes/2021-03-22-django-queryset-chains.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* Improved modeling of `django` to recognize QuerySet chains such as `User.objects.using("db-name").exclude(username="admin").extra("some sql")`. This can lead to new results for `py/sql-injection`. diff --git a/python/ql/src/semmle/python/frameworks/Django.qll b/python/ql/src/semmle/python/frameworks/Django.qll index 9f56bd5a299..384fdf69a15 100644 --- a/python/ql/src/semmle/python/frameworks/Django.qll +++ b/python/ql/src/semmle/python/frameworks/Django.qll @@ -8,6 +8,7 @@ private import semmle.python.dataflow.new.DataFlow private import semmle.python.dataflow.new.RemoteFlowSources private import semmle.python.dataflow.new.TaintTracking private import semmle.python.Concepts +private import semmle.python.ApiGraphs private import semmle.python.frameworks.PEP249 private import semmle.python.regex @@ -104,9 +105,6 @@ private module Django { // ------------------------------------------------------------------------- // django.db.models // ------------------------------------------------------------------------- - // NOTE: The modelling of django models is currently fairly incomplete. - // It does not fully take `Model`s, `Manager`s, `and QuerySet`s into account. - // It simply identifies some common dangerous cases. /** Gets a reference to the `django.db.models` module. */ private DataFlow::Node models(DataFlow::TypeTracker t) { t.start() and @@ -123,72 +121,52 @@ private module Django { /** Provides models for the `django.db.models` module. */ module models { - /** Provides models for the `django.db.models.Model` class. */ + /** + * Provides models for the `django.db.models.Model` class and subclasses. + * + * See https://docs.djangoproject.com/en/3.1/topics/db/models/. + */ module Model { - /** Gets a reference to the `django.db.models.Model` class. */ - private DataFlow::Node classRef(DataFlow::TypeTracker t) { - t.start() and - result = DataFlow::importNode("django.db.models.Model") - or - t.startInAttr("Model") and - result = models() - or - // subclass - result.asExpr().(ClassExpr).getABase() = classRef(t.continue()).asExpr() - or - exists(DataFlow::TypeTracker t2 | result = classRef(t2).track(t2, t)) + /** Gets a reference to the `flask.views.View` class or any subclass. */ + API::Node subclassRef() { + result = + API::moduleImport("django") + .getMember("db") + .getMember("models") + .getMember("Model") + .getASubclass*() } - - /** Gets a reference to the `django.db.models.Model` class. */ - DataFlow::Node classRef() { result = classRef(DataFlow::TypeTracker::end()) } - } - - /** Gets a reference to the `objects` object of a django model. */ - private DataFlow::Node objects(DataFlow::TypeTracker t) { - t.startInAttr("objects") and - result = Model::classRef() - or - exists(DataFlow::TypeTracker t2 | result = objects(t2).track(t2, t)) - } - - /** Gets a reference to the `objects` object of a model. */ - DataFlow::Node objects() { result = objects(DataFlow::TypeTracker::end()) } - - /** - * Gets a reference to the attribute `attr_name` of an `objects` object. - * WARNING: Only holds for a few predefined attributes. - */ - private DataFlow::Node objects_attr(DataFlow::TypeTracker t, string attr_name) { - attr_name in ["annotate", "extra", "raw"] and - t.startInAttr(attr_name) and - result = objects() - or - // Due to bad performance when using normal setup with `objects_attr(t2, attr_name).track(t2, t)` - // we have inlined that code and forced a join - exists(DataFlow::TypeTracker t2 | - exists(DataFlow::StepSummary summary | - objects_attr_first_join(t2, attr_name, result, summary) and - t = t2.append(summary) - ) - ) - } - - pragma[nomagic] - private predicate objects_attr_first_join( - DataFlow::TypeTracker t2, string attr_name, DataFlow::Node res, - DataFlow::StepSummary summary - ) { - DataFlow::StepSummary::step(objects_attr(t2, attr_name), res, summary) } /** - * Gets a reference to the attribute `attr_name` of an `objects` object. - * WARNING: Only holds for a few predefined attributes. + * Gets a reference to the Manager (django.db.models.Manager) for a django Model, + * accessed by `.objects`. */ - DataFlow::Node objects_attr(string attr_name) { - result = objects_attr(DataFlow::TypeTracker::end(), attr_name) + API::Node manager() { result = Model::subclassRef().getMember("objects") } + + /** + * Gets a method with `name` that returns a QuerySet. + * This method can originate on a QuerySet or a Manager. + * + * See https://docs.djangoproject.com/en/3.1/ref/models/querysets/ + */ + API::Node querySetReturningMethod(string name) { + name in [ + "none", "all", "filter", "exclude", "complex_filter", "union", "intersection", + "difference", "select_for_update", "select_related", "prefetch_related", "order_by", + "distinct", "reverse", "defer", "only", "using", "annotate", "extra", "raw", + "datetimes", "dates", "values", "values_list" + ] and + result = [manager(), querySet()].getMember(name) } + /** + * Gets a reference to a QuerySet (django.db.models.query.QuerySet). + * + * See https://docs.djangoproject.com/en/3.1/ref/models/querysets/ + */ + API::Node querySet() { result = querySetReturningMethod(_).getReturn() } + /** Gets a reference to the `django.db.models.expressions` module. */ private DataFlow::Node expressions(DataFlow::TypeTracker t) { t.start() and @@ -253,14 +231,13 @@ private module Django { * * See https://docs.djangoproject.com/en/3.1/ref/models/querysets/#annotate */ - private class ObjectsAnnotate extends SqlExecution::Range, DataFlow::CfgNode { - override CallNode node; + private class ObjectsAnnotate extends SqlExecution::Range, DataFlow::CallCfgNode { ControlFlowNode sql; ObjectsAnnotate() { - node.getFunction() = django::db::models::objects_attr("annotate").asCfgNode() and - django::db::models::expressions::RawSQL::instance(sql).asCfgNode() in [ - node.getArg(_), node.getArgByName(_) + this = django::db::models::querySetReturningMethod("annotate").getACall() and + django::db::models::expressions::RawSQL::instance(sql) in [ + this.getArg(_), this.getArgByName(_) ] } @@ -274,12 +251,10 @@ private module Django { * - https://docs.djangoproject.com/en/3.1/topics/db/sql/#django.db.models.Manager.raw * - https://docs.djangoproject.com/en/3.1/ref/models/querysets/#raw */ - private class ObjectsRaw extends SqlExecution::Range, DataFlow::CfgNode { - override CallNode node; + private class ObjectsRaw extends SqlExecution::Range, DataFlow::CallCfgNode { + ObjectsRaw() { this = django::db::models::querySetReturningMethod("raw").getACall() } - ObjectsRaw() { node.getFunction() = django::db::models::objects_attr("raw").asCfgNode() } - - override DataFlow::Node getSql() { result.asCfgNode() = node.getArg(0) } + override DataFlow::Node getSql() { result = this.getArg(0) } } /** @@ -287,14 +262,13 @@ private module Django { * * See https://docs.djangoproject.com/en/3.1/ref/models/querysets/#extra */ - private class ObjectsExtra extends SqlExecution::Range, DataFlow::CfgNode { - override CallNode node; - - ObjectsExtra() { node.getFunction() = django::db::models::objects_attr("extra").asCfgNode() } + private class ObjectsExtra extends SqlExecution::Range, DataFlow::CallCfgNode { + ObjectsExtra() { this = django::db::models::querySetReturningMethod("extra").getACall() } override DataFlow::Node getSql() { - result.asCfgNode() = - [node.getArg([0, 1, 3, 4]), node.getArgByName(["select", "where", "tables", "order_by"])] + result in [ + this.getArg([0, 1, 3, 4]), this.getArgByName(["select", "where", "tables", "order_by"]) + ] } } diff --git a/python/ql/test/library-tests/frameworks/django/SqlExecution.py b/python/ql/test/library-tests/frameworks/django/SqlExecution.py index fba2ccdc73e..449983fc898 100644 --- a/python/ql/test/library-tests/frameworks/django/SqlExecution.py +++ b/python/ql/test/library-tests/frameworks/django/SqlExecution.py @@ -29,4 +29,4 @@ def test_model(): User.objects.annotate(val=raw) # $getSql="so raw" # chaining QuerySet calls - User.objects.using("db-name").exclude(username="admin").extra("some sql") # $ MISSING: getSql="some sql" + User.objects.using("db-name").exclude(username="admin").extra("some sql") # $ getSql="some sql" From c1e3ccfb6cf3f4183f32cd23b40694844a93b11f Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Mon, 22 Mar 2021 15:07:51 +0100 Subject: [PATCH 240/725] Python, doc: Note ephemeral nature of import nodes --- .../using-api-graphs-in-python.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/codeql/codeql-language-guides/using-api-graphs-in-python.rst b/docs/codeql/codeql-language-guides/using-api-graphs-in-python.rst index 219519d6d92..38386f52887 100644 --- a/docs/codeql/codeql-language-guides/using-api-graphs-in-python.rst +++ b/docs/codeql/codeql-language-guides/using-api-graphs-in-python.rst @@ -31,9 +31,9 @@ following snippet demonstrates. ➤ `See this in the query console on LGTM.com `__. -This query only selects the API graph node corresponding to the ``re`` module. To find -where this module is referenced, you can use the ``getAUse`` method. The following query selects -all references to the ``re`` module in the current database. +This query selects the API graph node corresponding to the ``re`` module. This node represent the fact that the ``re`` module has been imported rather than a specific place in the program where the import happens. There will, therefore, be at most one result per file, and it will not have a useful location, so you have to click `Show 1 non-source result` in order to see it. + +To find places in the program where the ``re`` module is referenced, you can use the ``getAUse`` method. The following query selects all references to the ``re`` module in the current database. .. code-block:: ql @@ -102,7 +102,7 @@ where the return value of ``re.compile`` is used: Note that this includes all uses of the result of ``re.compile``, including those reachable via local flow. To get just the *calls* to ``re.compile``, you can use ``getAnImmediateUse`` instead of ``getAUse``. As this is a common occurrence, you can use ``getACall`` instead of -``getReturn`` followed by ``getAnImmediateUse``. +``getReturn`` followed by ``getAnImmediateUse``. ➤ `See this in the query console on LGTM.com `__. @@ -131,7 +131,7 @@ all subclasses of ``View``, you must explicitly include the subclasses of ``Meth result = API::moduleImport("flask").getMember("views").getMember(["View", "MethodView"]).getASubclass*() } - + select viewClass().getAUse() ➤ `See this in the query console on LGTM.com `__. From 230b9cf5d34d6aeb7fd0cc2569ab257c898931d4 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 20 Nov 2020 14:27:20 +0000 Subject: [PATCH 241/725] JS: Avoid recursion in SourceNode::Range --- 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 5b3e2ed5f09..329a8495e6e 100644 --- a/javascript/ql/src/semmle/javascript/ApiGraphs.qll +++ b/javascript/ql/src/semmle/javascript/ApiGraphs.qll @@ -992,7 +992,7 @@ private class ModuleAsSourceNode extends DataFlow::SourceNode::Range { ModuleAsSourceNode() { this = DataFlow::ssaDefinitionNode(SSA::implicitInit(m.(NodeModule).getModuleVariable())) or - this = DataFlow::parameterNode(m.(AmdModule).getDefine().getModuleParameter()) + DataFlow::parameterNode(this, m.(AmdModule).getDefine().getModuleParameter()) } Module getModule() { result = m } @@ -1007,7 +1007,7 @@ private class ExportsAsSourceNode extends DataFlow::SourceNode::Range { ExportsAsSourceNode() { this = DataFlow::ssaDefinitionNode(SSA::implicitInit(m.(NodeModule).getExportsVariable())) or - this = DataFlow::parameterNode(m.(AmdModule).getDefine().getExportsParameter()) + DataFlow::parameterNode(this, m.(AmdModule).getDefine().getExportsParameter()) } Module getModule() { result = m } From 5bfdca895b4787dc2bd40cc672b261f04e7cca5c Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 20 Nov 2020 16:13:30 +0000 Subject: [PATCH 242/725] JS: Remove recursive def of SourceNode::Range --- .../ql/src/semmle/javascript/ApiGraphs.qll | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/ApiGraphs.qll b/javascript/ql/src/semmle/javascript/ApiGraphs.qll index 329a8495e6e..674f229dfff 100644 --- a/javascript/ql/src/semmle/javascript/ApiGraphs.qll +++ b/javascript/ql/src/semmle/javascript/ApiGraphs.qll @@ -619,11 +619,11 @@ module API { cached predicate use(TApiNode nd, DataFlow::Node ref) { exists(string m, Module mod | nd = MkModuleDef(m) and mod = importableModule(m) | - ref.(ModuleAsSourceNode).getModule() = mod + ref.(ModuleVarNode).getModule() = mod ) or exists(string m, Module mod | nd = MkModuleExport(m) and mod = importableModule(m) | - ref.(ExportsAsSourceNode).getModule() = mod + ref.(ExportsVarNode).getModule() = mod or exists(DataFlow::Node base | use(MkModuleDef(m), base) | ref = trackUseNode(base).getAPropertyRead("exports") @@ -746,9 +746,9 @@ module API { or // additional backwards step from `require('m')` to `exports` or `module.exports` in m exists(Import imp | imp.getImportedModuleNode() = trackDefNode(nd, t.continue()) | - result.(ExportsAsSourceNode).getModule() = imp.getImportedModule() + result.(ExportsVarNode).getModule() = imp.getImportedModule() or - exists(ModuleAsSourceNode mod | + exists(ModuleVarNode mod | mod.getModule() = imp.getImportedModule() and result = mod.(DataFlow::SourceNode).getAPropertyRead("exports") ) @@ -983,13 +983,21 @@ private module Label { string promised() { result = "promised" } } +private class NodeModuleSourcesNodes extends DataFlow::SourceNode::Range { + NodeModuleSourcesNodes() { + exists(NodeModule m | + this = DataFlow::ssaDefinitionNode(SSA::implicitInit([m.getModuleVariable(), m.getExportsVariable()])) + ) + } +} + /** - * A CommonJS/AMD `module` variable, considered as a source node. + * A CommonJS/AMD `module` variable. */ -private class ModuleAsSourceNode extends DataFlow::SourceNode::Range { +private class ModuleVarNode extends DataFlow::Node { Module m; - ModuleAsSourceNode() { + ModuleVarNode() { this = DataFlow::ssaDefinitionNode(SSA::implicitInit(m.(NodeModule).getModuleVariable())) or DataFlow::parameterNode(this, m.(AmdModule).getDefine().getModuleParameter()) @@ -999,12 +1007,12 @@ private class ModuleAsSourceNode extends DataFlow::SourceNode::Range { } /** - * A CommonJS/AMD `exports` variable, considered as a source node. + * A CommonJS/AMD `exports` variable. */ -private class ExportsAsSourceNode extends DataFlow::SourceNode::Range { +private class ExportsVarNode extends DataFlow::Node { Module m; - ExportsAsSourceNode() { + ExportsVarNode() { this = DataFlow::ssaDefinitionNode(SSA::implicitInit(m.(NodeModule).getExportsVariable())) or DataFlow::parameterNode(this, m.(AmdModule).getDefine().getExportsParameter()) From c03e9d6c758cefbfdeb688076a55ad1d407bf800 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 3 Dec 2020 11:10:43 +0000 Subject: [PATCH 243/725] JS: Address review comments --- javascript/ql/src/semmle/javascript/ApiGraphs.qll | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/ApiGraphs.qll b/javascript/ql/src/semmle/javascript/ApiGraphs.qll index 674f229dfff..a363e472e15 100644 --- a/javascript/ql/src/semmle/javascript/ApiGraphs.qll +++ b/javascript/ql/src/semmle/javascript/ApiGraphs.qll @@ -984,11 +984,16 @@ private module Label { } private class NodeModuleSourcesNodes extends DataFlow::SourceNode::Range { + Variable v; + NodeModuleSourcesNodes() { exists(NodeModule m | - this = DataFlow::ssaDefinitionNode(SSA::implicitInit([m.getModuleVariable(), m.getExportsVariable()])) + this = DataFlow::ssaDefinitionNode(SSA::implicitInit(v)) and + v = [m.getModuleVariable(), m.getExportsVariable()] ) } + + Variable getVariable() { result = v } } /** @@ -998,7 +1003,7 @@ private class ModuleVarNode extends DataFlow::Node { Module m; ModuleVarNode() { - this = DataFlow::ssaDefinitionNode(SSA::implicitInit(m.(NodeModule).getModuleVariable())) + this.(NodeModuleSourcesNodes).getVariable() = m.(NodeModule).getModuleVariable() or DataFlow::parameterNode(this, m.(AmdModule).getDefine().getModuleParameter()) } @@ -1013,7 +1018,7 @@ private class ExportsVarNode extends DataFlow::Node { Module m; ExportsVarNode() { - this = DataFlow::ssaDefinitionNode(SSA::implicitInit(m.(NodeModule).getExportsVariable())) + this.(NodeModuleSourcesNodes).getVariable() = m.(NodeModule).getExportsVariable() or DataFlow::parameterNode(this, m.(AmdModule).getDefine().getExportsParameter()) } From 42e6c7eb2e7231a584c5599e8a9760a32d5b955b Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 19 Mar 2021 13:15:11 +0000 Subject: [PATCH 244/725] JS: Remove field from InvokeNode --- .../semmle/javascript/StringConcatenation.qll | 8 ++--- .../src/semmle/javascript/dataflow/Nodes.qll | 30 +++++++++---------- 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/StringConcatenation.qll b/javascript/ql/src/semmle/javascript/StringConcatenation.qll index 941e6f6b908..0ed53929622 100644 --- a/javascript/ql/src/semmle/javascript/StringConcatenation.qll +++ b/javascript/ql/src/semmle/javascript/StringConcatenation.qll @@ -55,12 +55,8 @@ module StringConcatenation { exists(DataFlow::MethodCallNode call | node = call and call.getMethodName() = "concat" and - not ( - exists(DataFlow::ArrayCreationNode array | - array.flowsTo(call.getAnArgument()) or array.flowsTo(call.getReceiver()) - ) - or - DataFlow::reflectiveCallNode(_) = call + not exists(DataFlow::ArrayCreationNode array | + array.flowsTo(call.getAnArgument()) or array.flowsTo(call.getReceiver()) ) and ( n = 0 and diff --git a/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll b/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll index 3111cbe81ae..9b42b3d6534 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll @@ -59,18 +59,16 @@ class ParameterNode extends DataFlow::SourceNode { * ``` */ class InvokeNode extends DataFlow::SourceNode { - DataFlow::Impl::InvokeNodeDef impl; - - InvokeNode() { this = impl } + InvokeNode() { this instanceof DataFlow::Impl::InvokeNodeDef } /** Gets the syntactic invoke expression underlying this function invocation. */ - InvokeExpr getInvokeExpr() { result = impl.getInvokeExpr() } + InvokeExpr getInvokeExpr() { result = this.(DataFlow::Impl::InvokeNodeDef).getInvokeExpr() } /** Gets the name of the function or method being invoked, if it can be determined. */ - string getCalleeName() { result = impl.getCalleeName() } + string getCalleeName() { result = this.(DataFlow::Impl::InvokeNodeDef).getCalleeName() } /** Gets the data flow node specifying the function to be called. */ - DataFlow::Node getCalleeNode() { result = impl.getCalleeNode() } + DataFlow::Node getCalleeNode() { result = this.(DataFlow::Impl::InvokeNodeDef).getCalleeNode() } /** * Gets the data flow node corresponding to the `i`th argument of this invocation. @@ -91,10 +89,10 @@ class InvokeNode extends DataFlow::SourceNode { * but the position of `z` cannot be determined, hence there are no first and second * argument nodes. */ - DataFlow::Node getArgument(int i) { result = impl.getArgument(i) } + DataFlow::Node getArgument(int i) { result = this.(DataFlow::Impl::InvokeNodeDef).getArgument(i) } /** Gets the data flow node corresponding to an argument of this invocation. */ - DataFlow::Node getAnArgument() { result = impl.getAnArgument() } + DataFlow::Node getAnArgument() { result = this.(DataFlow::Impl::InvokeNodeDef).getAnArgument() } /** Gets the data flow node corresponding to the last argument of this invocation. */ DataFlow::Node getLastArgument() { result = getArgument(getNumArgument() - 1) } @@ -111,10 +109,12 @@ class InvokeNode extends DataFlow::SourceNode { * ``` * . */ - DataFlow::Node getASpreadArgument() { result = impl.getASpreadArgument() } + DataFlow::Node getASpreadArgument() { + result = this.(DataFlow::Impl::InvokeNodeDef).getASpreadArgument() + } /** Gets the number of arguments of this invocation, if it can be determined. */ - int getNumArgument() { result = impl.getNumArgument() } + int getNumArgument() { result = this.(DataFlow::Impl::InvokeNodeDef).getNumArgument() } Function getEnclosingFunction() { result = getBasicBlock().getContainer() } @@ -256,14 +256,14 @@ class InvokeNode extends DataFlow::SourceNode { * ``` */ class CallNode extends InvokeNode { - override DataFlow::Impl::CallNodeDef impl; + CallNode() { this instanceof DataFlow::Impl::CallNodeDef } /** * Gets the data flow node corresponding to the receiver expression of this method call. * * For example, the receiver of `x.m()` is `x`. */ - DataFlow::Node getReceiver() { result = impl.getReceiver() } + DataFlow::Node getReceiver() { result = this.(DataFlow::Impl::CallNodeDef).getReceiver() } } /** @@ -277,10 +277,10 @@ class CallNode extends InvokeNode { * ``` */ class MethodCallNode extends CallNode { - override DataFlow::Impl::MethodCallNodeDef impl; + MethodCallNode() { this instanceof DataFlow::Impl::MethodCallNodeDef } /** Gets the name of the invoked method, if it can be determined. */ - string getMethodName() { result = impl.getMethodName() } + string getMethodName() { result = this.(DataFlow::Impl::MethodCallNodeDef).getMethodName() } /** * Holds if this data flow node calls method `methodName` on receiver node `receiver`. @@ -300,7 +300,7 @@ class MethodCallNode extends CallNode { * ``` */ class NewNode extends InvokeNode { - override DataFlow::Impl::NewNodeDef impl; + NewNode() { this instanceof DataFlow::Impl::NewNodeDef } } /** From 4a6589d0ae4d44bc7b519efdd690786a78a65aa1 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Mon, 22 Mar 2021 16:29:57 +0100 Subject: [PATCH 245/725] Python: Make `API::Node::getACall` return a `CallCfgNode` This should eliminate the need for explicit casting to `CallCfgNode` (which does not appear in our code as far as I can see, but was observed in an external contribution). --- python/change-notes/2021-03-22-getacall-callcfgnode.md | 2 ++ python/ql/src/semmle/python/ApiGraphs.qll | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 python/change-notes/2021-03-22-getacall-callcfgnode.md diff --git a/python/change-notes/2021-03-22-getacall-callcfgnode.md b/python/change-notes/2021-03-22-getacall-callcfgnode.md new file mode 100644 index 00000000000..95b32f1903f --- /dev/null +++ b/python/change-notes/2021-03-22-getacall-callcfgnode.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* The `API::Node::getACall` method now has the more specific return type `DataFlow::CallCfgNode`, which improves the ease of use when working with calls to API functions. diff --git a/python/ql/src/semmle/python/ApiGraphs.qll b/python/ql/src/semmle/python/ApiGraphs.qll index b05a8910530..46f195cd721 100644 --- a/python/ql/src/semmle/python/ApiGraphs.qll +++ b/python/ql/src/semmle/python/ApiGraphs.qll @@ -55,7 +55,7 @@ module API { /** * Gets a call to the function represented by this API component. */ - DataFlow::Node getACall() { result = getReturn().getAnImmediateUse() } + DataFlow::CallCfgNode getACall() { result = getReturn().getAnImmediateUse() } /** * Gets a node representing member `m` of this API component. From 1890e63d4c4f0aa529d07cf4fd652a3ec995dea1 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 22 Mar 2021 16:45:44 +0100 Subject: [PATCH 246/725] Python: Make import private for better auto-complete With the non-private imports, auto-completing on `API::` gave ALL results available from `import python`, as well as the ones specified in the `API` module. The non-private import in Attributes.qll did the same for `DataFlow::`. --- python/ql/src/semmle/python/ApiGraphs.qll | 2 +- .../ql/src/semmle/python/dataflow/new/internal/Attributes.qll | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/python/ql/src/semmle/python/ApiGraphs.qll b/python/ql/src/semmle/python/ApiGraphs.qll index b05a8910530..df322785f43 100644 --- a/python/ql/src/semmle/python/ApiGraphs.qll +++ b/python/ql/src/semmle/python/ApiGraphs.qll @@ -6,7 +6,7 @@ * directed and labeled; they specify how the components represented by nodes relate to each other. */ -import python +private import python import semmle.python.dataflow.new.DataFlow /** diff --git a/python/ql/src/semmle/python/dataflow/new/internal/Attributes.qll b/python/ql/src/semmle/python/dataflow/new/internal/Attributes.qll index 1bd5f961a36..6270e35aa9f 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/Attributes.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/Attributes.qll @@ -3,6 +3,7 @@ import DataFlowUtil import DataFlowPublic private import DataFlowPrivate +private import semmle.python.types.Builtins /** * A data flow node that reads or writes an attribute of an object. @@ -84,8 +85,6 @@ private class AttributeAssignmentAsAttrWrite extends AttrWrite, CfgNode { override string getAttributeName() { result = node.getName() } } -import semmle.python.types.Builtins - /** Represents `CallNode`s that may refer to calls to built-in functions or classes. */ private class BuiltInCallNode extends CallNode { string name; From 6b19e69d30cb280f9040e6146f9ba570043c9a5e Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 22 Mar 2021 16:17:19 +0000 Subject: [PATCH 247/725] JS: Fix some join orders --- javascript/ql/src/semmle/javascript/DOM.qll | 7 +- .../src/semmle/javascript/HtmlSanitizers.qll | 83 ++++++++++--------- .../ql/src/semmle/javascript/Promises.qll | 1 + .../semmle/javascript/frameworks/SocketIO.qll | 6 +- .../javascript/security/dataflow/DOM.qll | 12 ++- 5 files changed, 64 insertions(+), 45 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/DOM.qll b/javascript/ql/src/semmle/javascript/DOM.qll index 84ea28d26f0..73e06441b28 100644 --- a/javascript/ql/src/semmle/javascript/DOM.qll +++ b/javascript/ql/src/semmle/javascript/DOM.qll @@ -315,6 +315,11 @@ module DOM { ) } + private InferredType getArgumentTypeFromJQueryMethodGet(JQuery::MethodCall call) { + call.getMethodName() = "get" and + result = call.getArgument(0).analyze().getAType() + } + private class DefaultRange extends Range { DefaultRange() { this.asExpr().(VarAccess).getVariable() instanceof DOMGlobalVariable @@ -344,7 +349,7 @@ module DOM { or exists(JQuery::MethodCall call | this = call and call.getMethodName() = "get" | call.getNumArgument() = 1 and - unique(InferredType t | t = call.getArgument(0).analyze().getAType()) = TTNumber() + unique(InferredType t | t = getArgumentTypeFromJQueryMethodGet(call)) = TTNumber() ) or // A `this` node from a callback given to a `$().each(callback)` call. diff --git a/javascript/ql/src/semmle/javascript/HtmlSanitizers.qll b/javascript/ql/src/semmle/javascript/HtmlSanitizers.qll index 870cde4bbce..2be99a149cc 100644 --- a/javascript/ql/src/semmle/javascript/HtmlSanitizers.qll +++ b/javascript/ql/src/semmle/javascript/HtmlSanitizers.qll @@ -16,51 +16,54 @@ abstract class HtmlSanitizerCall extends DataFlow::CallNode { abstract DataFlow::Node getInput(); } +pragma[noinline] +private DataFlow::SourceNode htmlSanitizerFunction() { + result = DataFlow::moduleMember("ent", "encode") + or + result = DataFlow::moduleMember("entities", "encodeHTML") + or + result = DataFlow::moduleMember("entities", "encodeXML") + or + result = DataFlow::moduleMember("escape-goat", "escape") + or + result = DataFlow::moduleMember("he", "encode") + or + result = DataFlow::moduleMember("he", "escape") + or + result = DataFlow::moduleImport("sanitize-html") + or + result = DataFlow::moduleMember("sanitizer", "escape") + or + result = DataFlow::moduleMember("sanitizer", "sanitize") + or + result = DataFlow::moduleMember("validator", "escape") + or + result = DataFlow::moduleImport("xss") + or + result = DataFlow::moduleMember("xss-filters", _) + or + result = LodashUnderscore::member("escape") + or + exists(DataFlow::PropRead read | read = result | + read.getPropertyName() = "sanitize" and + read.getBase().asExpr().(VarAccess).getName() = "DOMPurify" + ) + or + exists(string name | name = "encode" or name = "encodeNonUTF" | + result = + DataFlow::moduleMember("html-entities", _).getAnInstantiation().getAPropertyRead(name) or + result = DataFlow::moduleMember("html-entities", _).getAPropertyRead(name) + ) + or + result = Closure::moduleImport("goog.string.htmlEscape") +} + /** * Matches HTML sanitizers from known NPM packages as well as home-made sanitizers (matched by name). */ private class DefaultHtmlSanitizerCall extends HtmlSanitizerCall { DefaultHtmlSanitizerCall() { - exists(DataFlow::SourceNode callee | this = callee.getACall() | - callee = DataFlow::moduleMember("ent", "encode") - or - callee = DataFlow::moduleMember("entities", "encodeHTML") - or - callee = DataFlow::moduleMember("entities", "encodeXML") - or - callee = DataFlow::moduleMember("escape-goat", "escape") - or - callee = DataFlow::moduleMember("he", "encode") - or - callee = DataFlow::moduleMember("he", "escape") - or - callee = DataFlow::moduleImport("sanitize-html") - or - callee = DataFlow::moduleMember("sanitizer", "escape") - or - callee = DataFlow::moduleMember("sanitizer", "sanitize") - or - callee = DataFlow::moduleMember("validator", "escape") - or - callee = DataFlow::moduleImport("xss") - or - callee = DataFlow::moduleMember("xss-filters", _) - or - callee = LodashUnderscore::member("escape") - or - exists(DataFlow::PropRead read | read = callee | - read.getPropertyName() = "sanitize" and - read.getBase().asExpr().(VarAccess).getName() = "DOMPurify" - ) - or - exists(string name | name = "encode" or name = "encodeNonUTF" | - callee = - DataFlow::moduleMember("html-entities", _).getAnInstantiation().getAPropertyRead(name) or - callee = DataFlow::moduleMember("html-entities", _).getAPropertyRead(name) - ) - or - callee = Closure::moduleImport("goog.string.htmlEscape") - ) + this = htmlSanitizerFunction().getACall() or // Match home-made sanitizers by name. exists(string calleeName | calleeName = getCalleeName() | diff --git a/javascript/ql/src/semmle/javascript/Promises.qll b/javascript/ql/src/semmle/javascript/Promises.qll index b7fd4897d35..f0fae1ea802 100644 --- a/javascript/ql/src/semmle/javascript/Promises.qll +++ b/javascript/ql/src/semmle/javascript/Promises.qll @@ -596,6 +596,7 @@ private module ClosurePromise { * A promise created by a call `goog.Promise.resolve(value)`. */ private class ResolvedClosurePromiseDefinition extends ResolvedPromiseDefinition { + pragma[noinline] ResolvedClosurePromiseDefinition() { this = Closure::moduleImport("goog.Promise.resolve").getACall() } diff --git a/javascript/ql/src/semmle/javascript/frameworks/SocketIO.qll b/javascript/ql/src/semmle/javascript/frameworks/SocketIO.qll index a7ba74dfcd2..639d76da2dd 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/SocketIO.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/SocketIO.qll @@ -268,9 +268,11 @@ module SocketIO { /** Gets the `i`th parameter through which data is received from a client. */ override DataFlow::SourceNode getReceivedItem(int i) { - exists(DataFlow::FunctionNode cb | cb = getListener() and result = cb.getParameter(i) | + exists(DataFlow::FunctionNode cb | + cb = getListener() and + result = cb.getParameter(i) and // exclude last parameter if it looks like a callback - result != cb.getLastParameter() or not exists(result.getAnInvocation()) + not (result = cb.getLastParameter() and exists(result.getAnInvocation())) ) } diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/DOM.qll b/javascript/ql/src/semmle/javascript/security/dataflow/DOM.qll index d9484d9575b..356830bd6d4 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/DOM.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/DOM.qll @@ -156,6 +156,12 @@ private module PersistentWebStorage { result = DataFlow::globalVarRef(kind) } + pragma[noinline] + WriteAccess getAWriteByName(string name, string kind) { + result.getKey() = name and + result.getKind() = kind + } + /** * A read access. */ @@ -165,8 +171,10 @@ private module PersistentWebStorage { ReadAccess() { this = webStorage(kind).getAMethodCall("getItem") } override PersistentWriteAccess getAWrite() { - getArgument(0).mayHaveStringValue(result.(WriteAccess).getKey()) and - result.(WriteAccess).getKind() = kind + exists(string name | + getArgument(0).mayHaveStringValue(name) and + result = getAWriteByName(name, kind) + ) } } From 993999f64fd519d358b1276d19b81215a7073e6f Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Mon, 22 Mar 2021 17:37:54 +0100 Subject: [PATCH 248/725] Java: Add test for negative numeric literals --- .../literals-numeric/NumericLiterals.java | 16 ++++++++++++++++ .../negativeNumericLiteral.expected | 12 ++++++++++++ .../literals-numeric/negativeNumericLiteral.ql | 9 +++++++++ 3 files changed, 37 insertions(+) create mode 100644 java/ql/test/library-tests/literals-numeric/NumericLiterals.java create mode 100644 java/ql/test/library-tests/literals-numeric/negativeNumericLiteral.expected create mode 100644 java/ql/test/library-tests/literals-numeric/negativeNumericLiteral.ql diff --git a/java/ql/test/library-tests/literals-numeric/NumericLiterals.java b/java/ql/test/library-tests/literals-numeric/NumericLiterals.java new file mode 100644 index 00000000000..02f2fbfcc6b --- /dev/null +++ b/java/ql/test/library-tests/literals-numeric/NumericLiterals.java @@ -0,0 +1,16 @@ +class NumericLiterals { + void negativeLiterals() { + float f = -1f; + double d = -1d; + int i1 = -2147483647; + int i2 = -2147483648; // CodeQL models minus as part of literal + int i3 = -0b10000000000000000000000000000000; // binary + int i4 = -020000000000; // octal + int i5 = -0x80000000; // hex + long l1 = -9223372036854775807L; + long l2 = -9223372036854775808L; // CodeQL models minus as part of literal + long l3 = -0b1000000000000000000000000000000000000000000000000000000000000000L; // binary + long l4 = -01000000000000000000000L; // octal + long l5 = -0x8000000000000000L; // hex + } +} diff --git a/java/ql/test/library-tests/literals-numeric/negativeNumericLiteral.expected b/java/ql/test/library-tests/literals-numeric/negativeNumericLiteral.expected new file mode 100644 index 00000000000..95100f259dd --- /dev/null +++ b/java/ql/test/library-tests/literals-numeric/negativeNumericLiteral.expected @@ -0,0 +1,12 @@ +| NumericLiterals.java:3:14:3:15 | 1f | 1.0 | NumericLiterals.java:3:13:3:15 | -... | +| NumericLiterals.java:4:15:4:16 | 1d | 1.0 | NumericLiterals.java:4:14:4:16 | -... | +| NumericLiterals.java:5:13:5:22 | 2147483647 | 2147483647 | NumericLiterals.java:5:12:5:22 | -... | +| NumericLiterals.java:6:12:6:22 | -2147483648 | -2147483648 | NumericLiterals.java:6:7:6:22 | i2 | +| NumericLiterals.java:7:13:7:46 | 0b10000000000000000000000000000000 | -2147483648 | NumericLiterals.java:7:12:7:46 | -... | +| NumericLiterals.java:8:13:8:24 | 020000000000 | -2147483648 | NumericLiterals.java:8:12:8:24 | -... | +| NumericLiterals.java:9:13:9:22 | 0x80000000 | -2147483648 | NumericLiterals.java:9:12:9:22 | -... | +| NumericLiterals.java:10:14:10:33 | 9223372036854775807L | 9223372036854775807 | NumericLiterals.java:10:13:10:33 | -... | +| NumericLiterals.java:11:13:11:33 | -9223372036854775808L | -9223372036854775808 | NumericLiterals.java:11:8:11:33 | l2 | +| NumericLiterals.java:12:14:12:80 | 0b1000000000000000000000000000000000000000000000000000000000000000L | -9223372036854775808 | NumericLiterals.java:12:13:12:80 | -... | +| NumericLiterals.java:13:14:13:37 | 01000000000000000000000L | -9223372036854775808 | NumericLiterals.java:13:13:13:37 | -... | +| NumericLiterals.java:14:14:14:32 | 0x8000000000000000L | -9223372036854775808 | NumericLiterals.java:14:13:14:32 | -... | diff --git a/java/ql/test/library-tests/literals-numeric/negativeNumericLiteral.ql b/java/ql/test/library-tests/literals-numeric/negativeNumericLiteral.ql new file mode 100644 index 00000000000..0fbb3989c7a --- /dev/null +++ b/java/ql/test/library-tests/literals-numeric/negativeNumericLiteral.ql @@ -0,0 +1,9 @@ +import java + +from Literal l +where + l instanceof IntegerLiteral or + l instanceof LongLiteral or + l instanceof FloatingPointLiteral or + l instanceof DoubleLiteral +select l, l.getValue(), l.getParent() From 198a4ca79b77b6c6fdf4905ab3b894a3b5bc0622 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Mon, 22 Mar 2021 21:42:06 +0100 Subject: [PATCH 249/725] Python: Add files to `experimental` --- .../src/experimental/semmle/python/Concepts.qll | 15 +++++++++++++++ .../src/experimental/semmle/python/Frameworks.qll | 5 +++++ .../semmle/python/frameworks/Stdlib.qll | 11 +++++++++++ 3 files changed, 31 insertions(+) create mode 100644 python/ql/src/experimental/semmle/python/Concepts.qll create mode 100644 python/ql/src/experimental/semmle/python/Frameworks.qll create mode 100644 python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll diff --git a/python/ql/src/experimental/semmle/python/Concepts.qll b/python/ql/src/experimental/semmle/python/Concepts.qll new file mode 100644 index 00000000000..38d7ffb11c2 --- /dev/null +++ b/python/ql/src/experimental/semmle/python/Concepts.qll @@ -0,0 +1,15 @@ +/** + * This version resides in the experimental area and provides a space for + * external contributors to place new concepts, keeping to our preferred + * structure while remaining in the experimental area. + * + * Provides abstract classes representing generic concepts such as file system + * access or system command execution, for which individual framework libraries + * provide concrete subclasses. + */ + +import python +private import semmle.python.dataflow.new.DataFlow +private import semmle.python.dataflow.new.RemoteFlowSources +private import semmle.python.dataflow.new.TaintTracking +private import experimental.semmle.python.Frameworks diff --git a/python/ql/src/experimental/semmle/python/Frameworks.qll b/python/ql/src/experimental/semmle/python/Frameworks.qll new file mode 100644 index 00000000000..ca1dd04e57d --- /dev/null +++ b/python/ql/src/experimental/semmle/python/Frameworks.qll @@ -0,0 +1,5 @@ +/** + * Helper file that imports all framework modeling. + */ + +private import experimental.semmle.python.frameworks.Stdlib diff --git a/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll b/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll new file mode 100644 index 00000000000..420caf0d73b --- /dev/null +++ b/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll @@ -0,0 +1,11 @@ +/** + * Provides classes modeling security-relevant aspects of the standard libraries. + * Note: some modeling is done internally in the dataflow/taint tracking implementation. + */ + +private import python +private import semmle.python.dataflow.new.DataFlow +private import semmle.python.dataflow.new.TaintTracking +private import semmle.python.dataflow.new.RemoteFlowSources +private import experimental.semmle.python.Concepts +private import semmle.python.ApiGraphs From 0ff7cc845caa6535e9400f0acf388aa1054a6aae Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 23 Mar 2021 09:41:54 +0100 Subject: [PATCH 250/725] C++: Add reduced testcase that broke IR construction in #5492. --- .../syntax-zoo/aliased_ssa_consistency.expected | 1 + cpp/ql/test/library-tests/syntax-zoo/modeled-functions.cpp | 7 +++++++ .../test/library-tests/syntax-zoo/raw_consistency.expected | 4 ++++ .../syntax-zoo/unaliased_ssa_consistency.expected | 1 + 4 files changed, 13 insertions(+) create mode 100644 cpp/ql/test/library-tests/syntax-zoo/modeled-functions.cpp diff --git a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_consistency.expected b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_consistency.expected index fcfef712b56..dc7388db56c 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_consistency.expected @@ -13,6 +13,7 @@ instructionWithoutSuccessor | condition_decls.cpp:41:22:41:23 | Chi: call to BoxedInt | Instruction 'Chi: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:40:6:40:20 | void while_decl_bind(int) | void while_decl_bind(int) | | condition_decls.cpp:48:52:48:53 | Chi: call to BoxedInt | Instruction 'Chi: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:47:6:47:18 | void for_decl_bind(int) | void for_decl_bind(int) | | misc.c:171:10:171:13 | Uninitialized: definition of str2 | Instruction 'Uninitialized: definition of str2' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() | +| modeled-functions.cpp:6:10:6:16 | BufferReadSideEffect: socket2 | Instruction 'BufferReadSideEffect: socket2' has no successors in function '$@'. | modeled-functions.cpp:3:6:3:15 | void testAccept(int, int) | void testAccept(int, int) | | ms_try_except.cpp:3:9:3:9 | Uninitialized: definition of x | Instruction 'Uninitialized: definition of x' has no successors in function '$@'. | ms_try_except.cpp:2:6:2:18 | void ms_try_except(int) | void ms_try_except(int) | | ms_try_mix.cpp:11:12:11:15 | Chi: call to C | Instruction 'Chi: call to C' has no successors in function '$@'. | ms_try_mix.cpp:10:6:10:18 | void ms_except_mix(int) | void ms_except_mix(int) | | ms_try_mix.cpp:28:12:28:15 | Chi: call to C | Instruction 'Chi: call to C' has no successors in function '$@'. | ms_try_mix.cpp:27:6:27:19 | void ms_finally_mix(int) | void ms_finally_mix(int) | diff --git a/cpp/ql/test/library-tests/syntax-zoo/modeled-functions.cpp b/cpp/ql/test/library-tests/syntax-zoo/modeled-functions.cpp new file mode 100644 index 00000000000..c6867a9abe3 --- /dev/null +++ b/cpp/ql/test/library-tests/syntax-zoo/modeled-functions.cpp @@ -0,0 +1,7 @@ +void accept(int arg, char *buf, unsigned long* bufSize); + +void testAccept(int socket1, int socket2) +{ + char buffer[1024]; + accept(socket2, 0, 0); +} diff --git a/cpp/ql/test/library-tests/syntax-zoo/raw_consistency.expected b/cpp/ql/test/library-tests/syntax-zoo/raw_consistency.expected index d6612e5bfad..44d3ba37b0b 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/raw_consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/raw_consistency.expected @@ -31,6 +31,7 @@ instructionWithoutSuccessor | misc.c:174:17:174:22 | CallSideEffect: call to getInt | Instruction 'CallSideEffect: call to getInt' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() | | misc.c:174:30:174:35 | CallSideEffect: call to getInt | Instruction 'CallSideEffect: call to getInt' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() | | misc.c:174:55:174:60 | Store: (char ****)... | Instruction 'Store: (char ****)...' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() | +| modeled-functions.cpp:6:10:6:16 | BufferReadSideEffect: socket2 | Instruction 'BufferReadSideEffect: socket2' has no successors in function '$@'. | modeled-functions.cpp:3:6:3:15 | void testAccept(int, int) | void testAccept(int, int) | | ms_try_except.cpp:3:9:3:9 | Uninitialized: definition of x | Instruction 'Uninitialized: definition of x' has no successors in function '$@'. | ms_try_except.cpp:2:6:2:18 | void ms_try_except(int) | void ms_try_except(int) | | ms_try_except.cpp:7:13:7:17 | Store: ... = ... | Instruction 'Store: ... = ...' has no successors in function '$@'. | ms_try_except.cpp:2:6:2:18 | void ms_try_except(int) | void ms_try_except(int) | | ms_try_except.cpp:9:19:9:19 | Load: j | Instruction 'Load: j' has no successors in function '$@'. | ms_try_except.cpp:2:6:2:18 | void ms_try_except(int) | void ms_try_except(int) | @@ -135,6 +136,9 @@ backEdgeCountMismatch useNotDominatedByDefinition | VacuousDestructorCall.cpp:2:29:2:29 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | VacuousDestructorCall.cpp:2:6:2:6 | void CallDestructor(int, int*) | void CallDestructor(int, int*) | | misc.c:219:47:219:48 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | misc.c:219:5:219:26 | int assign_designated_init(someStruct*) | int assign_designated_init(someStruct*) | +| modeled-functions.cpp:6:19:6:19 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | modeled-functions.cpp:3:6:3:15 | void testAccept(int, int) | void testAccept(int, int) | +| modeled-functions.cpp:6:19:6:19 | BufferSize | Operand 'BufferSize' is not dominated by its definition in function '$@'. | modeled-functions.cpp:3:6:3:15 | void testAccept(int, int) | void testAccept(int, int) | +| modeled-functions.cpp:6:22:6:22 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | modeled-functions.cpp:3:6:3:15 | void testAccept(int, int) | void testAccept(int, int) | | static_init_templates.cpp:15:1:15:18 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | static_init_templates.cpp:15:1:15:18 | void MyClass::MyClass() | void MyClass::MyClass() | | try_catch.cpp:21:13:21:24 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | try_catch.cpp:19:6:19:23 | void throw_from_nonstmt(int) | void throw_from_nonstmt(int) | | vla.c:3:27:3:30 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | vla.c:3:5:3:8 | int main(int, char**) | int main(int, char**) | diff --git a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_consistency.expected b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_consistency.expected index 56e9f2e881a..784fd5e06d1 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_consistency.expected @@ -13,6 +13,7 @@ instructionWithoutSuccessor | condition_decls.cpp:41:22:41:23 | IndirectMayWriteSideEffect: call to BoxedInt | Instruction 'IndirectMayWriteSideEffect: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:40:6:40:20 | void while_decl_bind(int) | void while_decl_bind(int) | | condition_decls.cpp:48:52:48:53 | IndirectMayWriteSideEffect: call to BoxedInt | Instruction 'IndirectMayWriteSideEffect: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:47:6:47:18 | void for_decl_bind(int) | void for_decl_bind(int) | | misc.c:171:10:171:13 | Uninitialized: definition of str2 | Instruction 'Uninitialized: definition of str2' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() | +| modeled-functions.cpp:6:10:6:16 | BufferReadSideEffect: socket2 | Instruction 'BufferReadSideEffect: socket2' has no successors in function '$@'. | modeled-functions.cpp:3:6:3:15 | void testAccept(int, int) | void testAccept(int, int) | | ms_try_except.cpp:3:9:3:9 | Uninitialized: definition of x | Instruction 'Uninitialized: definition of x' has no successors in function '$@'. | ms_try_except.cpp:2:6:2:18 | void ms_try_except(int) | void ms_try_except(int) | | ms_try_mix.cpp:11:12:11:15 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect: call to C' has no successors in function '$@'. | ms_try_mix.cpp:10:6:10:18 | void ms_except_mix(int) | void ms_except_mix(int) | | ms_try_mix.cpp:28:12:28:15 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect: call to C' has no successors in function '$@'. | ms_try_mix.cpp:27:6:27:19 | void ms_finally_mix(int) | void ms_finally_mix(int) | From 7d0cfc69f14a0cc996f068f94ff1390ef0b5b07f Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 23 Mar 2021 09:47:39 +0100 Subject: [PATCH 251/725] C++: Don't override getParameterSizeIndex in the model for Accept. This fixes IR construction of calls to accept. --- cpp/ql/src/semmle/code/cpp/models/implementations/Accept.qll | 4 ++-- .../library-tests/syntax-zoo/aliased_ssa_consistency.expected | 1 - cpp/ql/test/library-tests/syntax-zoo/raw_consistency.expected | 4 ---- .../syntax-zoo/unaliased_ssa_consistency.expected | 1 - 4 files changed, 2 insertions(+), 8 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Accept.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Accept.qll index 150f481de28..092c5a3ca5b 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Accept.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Accept.qll @@ -46,8 +46,8 @@ private class Accept extends ArrayFunction, AliasFunction, TaintFunction, SideEf i = 1 and buffer = false } - override ParameterIndex getParameterSizeIndex(ParameterIndex i) { i = 1 and result = 2 } - + // NOTE: The size parameter is a pointer to the size. So we can't implement `getParameterSizeIndex` for + // this model. // NOTE: We implement thse two predicates as none because we can't model the low-level changes made to // the structure pointed to by the file-descriptor argument. override predicate hasOnlySpecificReadSideEffects() { none() } diff --git a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_consistency.expected b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_consistency.expected index dc7388db56c..fcfef712b56 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_consistency.expected @@ -13,7 +13,6 @@ instructionWithoutSuccessor | condition_decls.cpp:41:22:41:23 | Chi: call to BoxedInt | Instruction 'Chi: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:40:6:40:20 | void while_decl_bind(int) | void while_decl_bind(int) | | condition_decls.cpp:48:52:48:53 | Chi: call to BoxedInt | Instruction 'Chi: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:47:6:47:18 | void for_decl_bind(int) | void for_decl_bind(int) | | misc.c:171:10:171:13 | Uninitialized: definition of str2 | Instruction 'Uninitialized: definition of str2' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() | -| modeled-functions.cpp:6:10:6:16 | BufferReadSideEffect: socket2 | Instruction 'BufferReadSideEffect: socket2' has no successors in function '$@'. | modeled-functions.cpp:3:6:3:15 | void testAccept(int, int) | void testAccept(int, int) | | ms_try_except.cpp:3:9:3:9 | Uninitialized: definition of x | Instruction 'Uninitialized: definition of x' has no successors in function '$@'. | ms_try_except.cpp:2:6:2:18 | void ms_try_except(int) | void ms_try_except(int) | | ms_try_mix.cpp:11:12:11:15 | Chi: call to C | Instruction 'Chi: call to C' has no successors in function '$@'. | ms_try_mix.cpp:10:6:10:18 | void ms_except_mix(int) | void ms_except_mix(int) | | ms_try_mix.cpp:28:12:28:15 | Chi: call to C | Instruction 'Chi: call to C' has no successors in function '$@'. | ms_try_mix.cpp:27:6:27:19 | void ms_finally_mix(int) | void ms_finally_mix(int) | diff --git a/cpp/ql/test/library-tests/syntax-zoo/raw_consistency.expected b/cpp/ql/test/library-tests/syntax-zoo/raw_consistency.expected index 44d3ba37b0b..d6612e5bfad 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/raw_consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/raw_consistency.expected @@ -31,7 +31,6 @@ instructionWithoutSuccessor | misc.c:174:17:174:22 | CallSideEffect: call to getInt | Instruction 'CallSideEffect: call to getInt' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() | | misc.c:174:30:174:35 | CallSideEffect: call to getInt | Instruction 'CallSideEffect: call to getInt' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() | | misc.c:174:55:174:60 | Store: (char ****)... | Instruction 'Store: (char ****)...' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() | -| modeled-functions.cpp:6:10:6:16 | BufferReadSideEffect: socket2 | Instruction 'BufferReadSideEffect: socket2' has no successors in function '$@'. | modeled-functions.cpp:3:6:3:15 | void testAccept(int, int) | void testAccept(int, int) | | ms_try_except.cpp:3:9:3:9 | Uninitialized: definition of x | Instruction 'Uninitialized: definition of x' has no successors in function '$@'. | ms_try_except.cpp:2:6:2:18 | void ms_try_except(int) | void ms_try_except(int) | | ms_try_except.cpp:7:13:7:17 | Store: ... = ... | Instruction 'Store: ... = ...' has no successors in function '$@'. | ms_try_except.cpp:2:6:2:18 | void ms_try_except(int) | void ms_try_except(int) | | ms_try_except.cpp:9:19:9:19 | Load: j | Instruction 'Load: j' has no successors in function '$@'. | ms_try_except.cpp:2:6:2:18 | void ms_try_except(int) | void ms_try_except(int) | @@ -136,9 +135,6 @@ backEdgeCountMismatch useNotDominatedByDefinition | VacuousDestructorCall.cpp:2:29:2:29 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | VacuousDestructorCall.cpp:2:6:2:6 | void CallDestructor(int, int*) | void CallDestructor(int, int*) | | misc.c:219:47:219:48 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | misc.c:219:5:219:26 | int assign_designated_init(someStruct*) | int assign_designated_init(someStruct*) | -| modeled-functions.cpp:6:19:6:19 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | modeled-functions.cpp:3:6:3:15 | void testAccept(int, int) | void testAccept(int, int) | -| modeled-functions.cpp:6:19:6:19 | BufferSize | Operand 'BufferSize' is not dominated by its definition in function '$@'. | modeled-functions.cpp:3:6:3:15 | void testAccept(int, int) | void testAccept(int, int) | -| modeled-functions.cpp:6:22:6:22 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | modeled-functions.cpp:3:6:3:15 | void testAccept(int, int) | void testAccept(int, int) | | static_init_templates.cpp:15:1:15:18 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | static_init_templates.cpp:15:1:15:18 | void MyClass::MyClass() | void MyClass::MyClass() | | try_catch.cpp:21:13:21:24 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | try_catch.cpp:19:6:19:23 | void throw_from_nonstmt(int) | void throw_from_nonstmt(int) | | vla.c:3:27:3:30 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | vla.c:3:5:3:8 | int main(int, char**) | int main(int, char**) | diff --git a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_consistency.expected b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_consistency.expected index 784fd5e06d1..56e9f2e881a 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_consistency.expected @@ -13,7 +13,6 @@ instructionWithoutSuccessor | condition_decls.cpp:41:22:41:23 | IndirectMayWriteSideEffect: call to BoxedInt | Instruction 'IndirectMayWriteSideEffect: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:40:6:40:20 | void while_decl_bind(int) | void while_decl_bind(int) | | condition_decls.cpp:48:52:48:53 | IndirectMayWriteSideEffect: call to BoxedInt | Instruction 'IndirectMayWriteSideEffect: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:47:6:47:18 | void for_decl_bind(int) | void for_decl_bind(int) | | misc.c:171:10:171:13 | Uninitialized: definition of str2 | Instruction 'Uninitialized: definition of str2' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() | -| modeled-functions.cpp:6:10:6:16 | BufferReadSideEffect: socket2 | Instruction 'BufferReadSideEffect: socket2' has no successors in function '$@'. | modeled-functions.cpp:3:6:3:15 | void testAccept(int, int) | void testAccept(int, int) | | ms_try_except.cpp:3:9:3:9 | Uninitialized: definition of x | Instruction 'Uninitialized: definition of x' has no successors in function '$@'. | ms_try_except.cpp:2:6:2:18 | void ms_try_except(int) | void ms_try_except(int) | | ms_try_mix.cpp:11:12:11:15 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect: call to C' has no successors in function '$@'. | ms_try_mix.cpp:10:6:10:18 | void ms_except_mix(int) | void ms_except_mix(int) | | ms_try_mix.cpp:28:12:28:15 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect: call to C' has no successors in function '$@'. | ms_try_mix.cpp:27:6:27:19 | void ms_finally_mix(int) | void ms_finally_mix(int) | From 20aa05b0900e7fa1ca14c5bc8e5e8eff03e4d049 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 11 Jan 2021 21:00:02 +0100 Subject: [PATCH 252/725] C#: Add CIL SSA library --- config/identical-files.json | 5 +- csharp/ql/src/semmle/code/cil/BasicBlock.qll | 5 +- csharp/ql/src/semmle/code/cil/CIL.qll | 1 + .../src/semmle/code/cil/CallableReturns.qll | 12 +- csharp/ql/src/semmle/code/cil/ControlFlow.qll | 3 + csharp/ql/src/semmle/code/cil/DataFlow.qll | 78 ++- csharp/ql/src/semmle/code/cil/Method.qll | 2 +- csharp/ql/src/semmle/code/cil/Ssa.qll | 66 ++ .../src/semmle/code/cil/internal/SsaImpl.qll | 45 ++ .../code/cil/internal/SsaImplCommon.qll | 619 ++++++++++++++++++ .../code/cil/internal/SsaImplSpecific.qll | 30 + .../semmle/code/csharp/commons/Disposal.qll | 19 +- 12 files changed, 853 insertions(+), 32 deletions(-) create mode 100644 csharp/ql/src/semmle/code/cil/Ssa.qll create mode 100644 csharp/ql/src/semmle/code/cil/internal/SsaImpl.qll create mode 100644 csharp/ql/src/semmle/code/cil/internal/SsaImplCommon.qll create mode 100644 csharp/ql/src/semmle/code/cil/internal/SsaImplSpecific.qll diff --git a/config/identical-files.json b/config/identical-files.json index b63690c5f1e..890227b90bf 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -429,10 +429,11 @@ "SSA C#": [ "csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll", "csharp/ql/src/semmle/code/csharp/controlflow/internal/pressa/SsaImplCommon.qll", - "csharp/ql/src/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll" + "csharp/ql/src/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll", + "csharp/ql/src/semmle/code/cil/internal/SsaImplCommon.qll" ], "CryptoAlgorithms Python/JS": [ "javascript/ql/src/semmle/javascript/security/CryptoAlgorithms.qll", "python/ql/src/semmle/crypto/Crypto.qll" ] -} +} \ No newline at end of file diff --git a/csharp/ql/src/semmle/code/cil/BasicBlock.qll b/csharp/ql/src/semmle/code/cil/BasicBlock.qll index 459bb667e6f..0c9c0b8ad07 100644 --- a/csharp/ql/src/semmle/code/cil/BasicBlock.qll +++ b/csharp/ql/src/semmle/code/cil/BasicBlock.qll @@ -240,6 +240,9 @@ class BasicBlock extends Cached::TBasicBlockStart { /** Gets a textual representation of this basic block. */ string toString() { result = getFirstNode().toString() } + + /** Gets the location of this basic block. */ + Location getLocation() { result = this.getFirstNode().getLocation() } } /** @@ -305,7 +308,7 @@ class EntryBasicBlock extends BasicBlock { } /** Holds if `bb` is an entry basic block. */ -private predicate entryBB(BasicBlock bb) { bb.getFirstNode() instanceof EntryPoint } +private predicate entryBB(BasicBlock bb) { bb.getFirstNode() instanceof MethodImplementation } /** * An exit basic block, that is, a basic block whose last node is diff --git a/csharp/ql/src/semmle/code/cil/CIL.qll b/csharp/ql/src/semmle/code/cil/CIL.qll index 1e77d98fd29..db0018d8216 100644 --- a/csharp/ql/src/semmle/code/cil/CIL.qll +++ b/csharp/ql/src/semmle/code/cil/CIL.qll @@ -20,3 +20,4 @@ import Attribute import Stubs import CustomModifierReceiver import Parameterizable +import semmle.code.cil.Ssa diff --git a/csharp/ql/src/semmle/code/cil/CallableReturns.qll b/csharp/ql/src/semmle/code/cil/CallableReturns.qll index ee60713b801..8b029d87dd4 100644 --- a/csharp/ql/src/semmle/code/cil/CallableReturns.qll +++ b/csharp/ql/src/semmle/code/cil/CallableReturns.qll @@ -42,7 +42,11 @@ private predicate alwaysNullExpr(Expr expr) { or alwaysNullMethod(expr.(StaticCall).getTarget()) or - forex(VariableUpdate vu | DefUse::variableUpdateUse(_, vu, expr) | alwaysNullVariableUpdate(vu)) + forex(Ssa::Definition def | + expr = any(Ssa::Definition def0 | def = def0.getAnUltimateDefinition()).getARead() + | + alwaysNullVariableUpdate(def.getVariableUpdate()) + ) } pragma[noinline] @@ -58,7 +62,9 @@ private predicate alwaysNotNullExpr(Expr expr) { or alwaysNotNullMethod(expr.(StaticCall).getTarget()) or - forex(VariableUpdate vu | DefUse::variableUpdateUse(_, vu, expr) | - alwaysNotNullVariableUpdate(vu) + forex(Ssa::Definition def | + expr = any(Ssa::Definition def0 | def = def0.getAnUltimateDefinition()).getARead() + | + alwaysNotNullVariableUpdate(def.getVariableUpdate()) ) } diff --git a/csharp/ql/src/semmle/code/cil/ControlFlow.qll b/csharp/ql/src/semmle/code/cil/ControlFlow.qll index 176df2a20dc..52a2ddc3376 100644 --- a/csharp/ql/src/semmle/code/cil/ControlFlow.qll +++ b/csharp/ql/src/semmle/code/cil/ControlFlow.qll @@ -9,6 +9,9 @@ class ControlFlowNode extends @cil_controlflow_node { /** Gets a textual representation of this control flow node. */ string toString() { none() } + /** Gets the location of this control flow node. */ + Location getLocation() { none() } + /** * Gets the number of items this node pushes onto the stack. * This value is either 0 or 1, except for the instruction `dup` diff --git a/csharp/ql/src/semmle/code/cil/DataFlow.qll b/csharp/ql/src/semmle/code/cil/DataFlow.qll index 6991658ea3a..d62ee739369 100644 --- a/csharp/ql/src/semmle/code/cil/DataFlow.qll +++ b/csharp/ql/src/semmle/code/cil/DataFlow.qll @@ -57,12 +57,40 @@ class Untainted extends TaintType, TExactValue { } /** A taint type where the data is tainted. */ class Tainted extends TaintType, TTaintedValue { } +private predicate localFlowPhiInput(DataFlowNode input, Ssa::PhiNode phi) { + exists(Ssa::Definition def, BasicBlock bb, int i | phi.hasLastInputRef(def, bb, i) | + def.definesAt(_, bb, i) and + input = def.getVariableUpdate().getSource() + or + input = + any(ReadAccess ra | + bb.getNode(i) = ra and + ra.getTarget() = def.getSourceVariable() + ) + ) + or + exists(Ssa::PhiNode mid, BasicBlock bb, int i | + localFlowPhiInput(input, mid) and + phi.hasLastInputRef(mid, bb, i) and + mid.definesAt(_, bb, i) + ) +} + private predicate localExactStep(DataFlowNode src, DataFlowNode sink) { src = sink.(Opcodes::Dup).getAnOperand() or - defUse(_, src, sink) + exists(Ssa::Definition def, VariableUpdate vu | + vu = def.getVariableUpdate() and + src = vu.getSource() and + sink = def.getAFirstRead() + ) or - src = sink.(ParameterReadAccess).getTarget() + any(Ssa::Definition def).hasAdjacentReads(src, sink) + or + exists(Ssa::PhiNode phi | + localFlowPhiInput(src, phi) and + sink = phi.getAFirstRead() + ) or src = sink.(Conversion).getExpr() or @@ -73,12 +101,6 @@ private predicate localExactStep(DataFlowNode src, DataFlowNode sink) { src = sink.(Return).getExpr() or src = sink.(ConditionalBranch).getAnOperand() - or - src = sink.(MethodParameter).getAWrite() - or - exists(VariableUpdate update | - update.getVariable().(Parameter) = sink and src = update.getSource() - ) } private predicate localTaintStep(DataFlowNode src, DataFlowNode sink) { @@ -87,8 +109,7 @@ private predicate localTaintStep(DataFlowNode src, DataFlowNode sink) { src = sink.(UnaryBitwiseOperation).getOperand() } -cached -module DefUse { +deprecated module DefUse { /** * A classification of variable references into reads and writes. */ @@ -189,7 +210,7 @@ module DefUse { /** Holds if the variable update `vu` can be used at the read `use`. */ cached - predicate variableUpdateUse(StackVariable target, VariableUpdate vu, ReadAccess use) { + deprecated predicate variableUpdateUse(StackVariable target, VariableUpdate vu, ReadAccess use) { defReachesReadWithinBlock(target, vu, use) or exists(BasicBlock bb, int i | @@ -202,23 +223,40 @@ module DefUse { /** Holds if the update `def` can be used at the read `use`. */ cached - predicate defUse(StackVariable target, Expr def, ReadAccess use) { + deprecated predicate defUse(StackVariable target, Expr def, ReadAccess use) { exists(VariableUpdate vu | def = vu.getSource() | variableUpdateUse(target, vu, use)) } } -private import DefUse - -abstract library class VariableUpdate extends Instruction { - abstract Expr getSource(); +/** A node that updates a variable. */ +abstract class VariableUpdate extends DataFlowNode { + /** Gets the value assigned, if any. */ + abstract DataFlowNode getSource(); + /** Gets the variable that is updated. */ abstract Variable getVariable(); + + /** Holds if this variable update happens at index `i` in basic block `bb`. */ + abstract predicate updatesAt(BasicBlock bb, int i); +} + +private class MethodParameterDef extends VariableUpdate, MethodParameter { + override MethodParameter getSource() { result = this } + + override MethodParameter getVariable() { result = this } + + override predicate updatesAt(BasicBlock bb, int i) { + bb.(EntryBasicBlock).getANode().getImplementation().getMethod() = this.getMethod() and + i = -1 + } } private class VariableWrite extends VariableUpdate, WriteAccess { - override Expr getSource() { result = getExpr() } + override Expr getSource() { result = this.getExpr() } - override Variable getVariable() { result = getTarget() } + override Variable getVariable() { result = this.getTarget() } + + override predicate updatesAt(BasicBlock bb, int i) { this = bb.getNode(i) } } private class MethodOutOrRefTarget extends VariableUpdate, Call { @@ -230,5 +268,7 @@ private class MethodOutOrRefTarget extends VariableUpdate, Call { result = this.getRawArgument(parameterIndex).(ReadAccess).getTarget() } - override Expr getSource() { result = this } + override Expr getSource() { none() } + + override predicate updatesAt(BasicBlock bb, int i) { this = bb.getNode(i) } } diff --git a/csharp/ql/src/semmle/code/cil/Method.qll b/csharp/ql/src/semmle/code/cil/Method.qll index 5ef282e582a..8da707cb423 100644 --- a/csharp/ql/src/semmle/code/cil/Method.qll +++ b/csharp/ql/src/semmle/code/cil/Method.qll @@ -19,7 +19,7 @@ class MethodImplementation extends EntryPoint, @cil_method_implementation { override MethodImplementation getImplementation() { result = this } /** Gets the location of this implementation. */ - Assembly getLocation() { cil_method_implementation(this, _, result) } + override Assembly getLocation() { cil_method_implementation(this, _, result) } /** Gets the instruction at index `index`. */ Instruction getInstruction(int index) { cil_instruction(result, _, index, this) } diff --git a/csharp/ql/src/semmle/code/cil/Ssa.qll b/csharp/ql/src/semmle/code/cil/Ssa.qll new file mode 100644 index 00000000000..229925f6d08 --- /dev/null +++ b/csharp/ql/src/semmle/code/cil/Ssa.qll @@ -0,0 +1,66 @@ +/** + * Provides the module `Ssa` for working with static single assignment (SSA) form. + */ + +private import CIL + +/** + * Provides classes for working with static single assignment (SSA) form. + */ +module Ssa { + private import internal.SsaImplCommon as SsaImpl + private import internal.SsaImpl + + /** An SSA definition. */ + class Definition extends SsaImpl::Definition { + /** Gets a read of this SSA definition. */ + final ReadAccess getARead() { result = getARead(this) } + + /** Gets the underlying variable update, if any. */ + final VariableUpdate getVariableUpdate() { + exists(BasicBlock bb, int i | + result.updatesAt(bb, i) and + this.definesAt(result.getVariable(), bb, i) + ) + } + + /** Gets a first read of this SSA definition. */ + final ReadAccess getAFirstRead() { result = getAFirstRead(this) } + + /** Holds if `first` and `second` are adjacent reads of this SSA definition. */ + final predicate hasAdjacentReads(ReadAccess first, ReadAccess second) { + hasAdjacentReads(this, first, second) + } + + private Definition getAPhiInput() { result = this.(PhiNode).getAnInput() } + + /** + * Gets a definition that ultimately defines this SSA definition and is + * not itself a phi node. + */ + final Definition getAnUltimateDefinition() { + result = this.getAPhiInput*() and + not result instanceof PhiNode + } + + /** Gets the location of this SSA definition. */ + Location getLocation() { result = this.getVariableUpdate().getLocation() } + } + + /** A phi node. */ + class PhiNode extends SsaImpl::PhiNode, Definition { + final override Location getLocation() { result = this.getBasicBlock().getLocation() } + + /** Gets an input to this phi node. */ + final Definition getAnInput() { result = getAPhiInput(this) } + + /** + * Holds if if `def` is an input to this phi node, and a reference to `def` at + * index `i` in basic block `bb` can reach this phi node without going through + * other references. + */ + final predicate hasLastInputRef(Definition def, BasicBlock bb, int i) { + hasLastInputRef(this, def, bb, i) + } + } +} diff --git a/csharp/ql/src/semmle/code/cil/internal/SsaImpl.qll b/csharp/ql/src/semmle/code/cil/internal/SsaImpl.qll new file mode 100644 index 00000000000..593c877b9af --- /dev/null +++ b/csharp/ql/src/semmle/code/cil/internal/SsaImpl.qll @@ -0,0 +1,45 @@ +private import semmle.code.cil.CIL +private import SsaImplCommon + +cached +private module Cached { + cached + predicate forceCachingInSameStage() { any() } + + cached + ReadAccess getARead(Definition def) { + exists(BasicBlock bb, int i | + ssaDefReachesRead(_, def, bb, i) and + result = bb.getNode(i) + ) + } + + cached + ReadAccess getAFirstRead(Definition def) { + exists(BasicBlock bb1, int i1, BasicBlock bb2, int i2 | + def.definesAt(_, bb1, i1) and + adjacentDefRead(def, bb1, i1, bb2, i2) and + result = bb2.getNode(i2) + ) + } + + cached + predicate hasAdjacentReads(Definition def, ReadAccess first, ReadAccess second) { + exists(BasicBlock bb1, int i1, BasicBlock bb2, int i2 | + first = bb1.getNode(i1) and + adjacentDefRead(def, bb1, i1, bb2, i2) and + second = bb2.getNode(i2) + ) + } + + cached + Definition getAPhiInput(PhiNode phi) { phiHasInputFromBlock(phi, result, _) } + + cached + predicate hasLastInputRef(Definition phi, Definition def, BasicBlock bb, int i) { + lastRefRedef(def, bb, i, phi) and + def = getAPhiInput(phi) + } +} + +import Cached diff --git a/csharp/ql/src/semmle/code/cil/internal/SsaImplCommon.qll b/csharp/ql/src/semmle/code/cil/internal/SsaImplCommon.qll new file mode 100644 index 00000000000..be01c05b8fa --- /dev/null +++ b/csharp/ql/src/semmle/code/cil/internal/SsaImplCommon.qll @@ -0,0 +1,619 @@ +/** + * Provides a language-independant implementation of static single assignment + * (SSA) form. + */ + +private import SsaImplSpecific + +private BasicBlock getABasicBlockPredecessor(BasicBlock bb) { getABasicBlockSuccessor(result) = bb } + +/** + * Liveness analysis (based on source variables) to restrict the size of the + * SSA representation. + */ +private module Liveness { + /** + * A classification of variable references into reads (of a given kind) and + * (certain or uncertain) writes. + */ + private newtype TRefKind = + Read(boolean certain) { certain in [false, true] } or + Write(boolean certain) { certain in [false, true] } + + private class RefKind extends TRefKind { + string toString() { + exists(boolean certain | this = Read(certain) and result = "read (" + certain + ")") + 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` of kind `k`. + */ + private predicate ref(BasicBlock bb, int i, SourceVariable v, RefKind k) { + exists(boolean certain | variableRead(bb, i, v, certain) | k = Read(certain)) + or + exists(boolean certain | variableWrite(bb, i, v, certain) | k = Write(certain)) + } + + private newtype OrderedRefIndex = + MkOrderedRefIndex(int i, int tag) { + exists(RefKind rk | ref(_, i, _, rk) | tag = rk.getOrder()) + } + + private OrderedRefIndex refOrd(BasicBlock bb, int i, SourceVariable v, RefKind k, int ord) { + ref(bb, i, v, k) and + result = MkOrderedRefIndex(i, ord) and + ord = k.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. + */ + private int refRank(BasicBlock bb, int i, SourceVariable v, RefKind k) { + refOrd(bb, i, v, k, _) = + rank[result](int j, int ord, OrderedRefIndex res | + res = refOrd(bb, j, v, _, ord) + | + res order by j, ord + ) + } + + private int maxRefRank(BasicBlock bb, SourceVariable v) { + result = refRank(bb, _, v, _) and + not result + 1 = refRank(bb, _, v, _) + } + + /** + * Gets the (1-based) rank of the first reference to `v` inside basic block `bb` + * that is either a read or a certain write. + */ + private int firstReadOrCertainWrite(BasicBlock bb, SourceVariable v) { + result = + min(int r, RefKind k | + r = refRank(bb, _, v, k) and + k != Write(false) + | + r + ) + } + + /** + * Holds if source variable `v` is live at the beginning of basic block `bb`. + */ + predicate liveAtEntry(BasicBlock bb, SourceVariable v) { + // The first read or certain write to `v` inside `bb` is a read + refRank(bb, _, v, Read(_)) = firstReadOrCertainWrite(bb, v) + or + // There is no certain write to `v` inside `bb`, but `v` is live at entry + // to a successor basic block of `bb` + not exists(firstReadOrCertainWrite(bb, v)) and + liveAtExit(bb, v) + } + + /** + * Holds if source variable `v` is live at the end of basic block `bb`. + */ + predicate liveAtExit(BasicBlock bb, SourceVariable v) { + liveAtEntry(getABasicBlockSuccessor(bb), v) + } + + /** + * Holds if variable `v` is live in basic block `bb` at index `i`. + * The rank of `i` is `rnk` as defined by `refRank()`. + */ + private predicate liveAtRank(BasicBlock bb, int i, SourceVariable v, int rnk) { + exists(RefKind kind | rnk = refRank(bb, i, v, kind) | + rnk = maxRefRank(bb, v) and + liveAtExit(bb, v) + or + ref(bb, i, v, kind) and + kind = Read(_) + or + exists(RefKind nextKind | + liveAtRank(bb, _, v, rnk + 1) and + rnk + 1 = refRank(bb, _, v, nextKind) and + nextKind != Write(true) + ) + ) + } + + /** + * Holds if variable `v` is live after the (certain or uncertain) write at + * index `i` inside basic block `bb`. + */ + predicate liveAfterWrite(BasicBlock bb, int i, SourceVariable v) { + exists(int rnk | rnk = refRank(bb, i, v, Write(_)) | liveAtRank(bb, i, v, rnk)) + } +} + +private import Liveness + +/** Holds if `bb1` strictly dominates `bb2`. */ +private predicate strictlyDominates(BasicBlock bb1, BasicBlock bb2) { + bb1 = getImmediateBasicBlockDominator+(bb2) +} + +/** Holds if `bb1` dominates a predecessor of `bb2`. */ +private predicate dominatesPredecessor(BasicBlock bb1, BasicBlock bb2) { + exists(BasicBlock pred | pred = getABasicBlockPredecessor(bb2) | + bb1 = pred + or + strictlyDominates(bb1, pred) + ) +} + +/** Holds if `df` is in the dominance frontier of `bb`. */ +private predicate inDominanceFrontier(BasicBlock bb, BasicBlock df) { + dominatesPredecessor(bb, df) and + not strictlyDominates(bb, df) +} + +/** + * Holds if `bb` is in the dominance frontier of a block containing a + * definition of `v`. + */ +pragma[noinline] +private predicate inDefDominanceFrontier(BasicBlock bb, SourceVariable v) { + exists(BasicBlock defbb, Definition def | + def.definesAt(v, defbb, _) and + inDominanceFrontier(defbb, bb) + ) +} + +cached +newtype TDefinition = + TWriteDef(SourceVariable v, BasicBlock bb, int i) { + variableWrite(bb, i, v, _) and + liveAfterWrite(bb, i, v) + } or + TPhiNode(SourceVariable v, BasicBlock bb) { + inDefDominanceFrontier(bb, v) and + liveAtEntry(bb, v) + } + +private module SsaDefReaches { + newtype TSsaRefKind = + SsaRead() or + SsaDef() + + /** + * A classification of SSA variable references into reads and definitions. + */ + 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 `SsaRead()`) or an SSA definition (when `k` + * is `SsaDef()`). + * + * Unlike `Liveness::ref`, this includes `phi` nodes. + */ + predicate ssaRef(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) { + variableRead(bb, i, v, _) and + k = SsaRead() + or + exists(Definition def | def.definesAt(v, bb, i)) and + k = SsaDef() + } + + private newtype OrderedSsaRefIndex = + MkOrderedSsaRefIndex(int i, SsaRefKind k) { ssaRef(_, i, _, k) } + + private OrderedSsaRefIndex ssaRefOrd(BasicBlock bb, int i, SourceVariable v, SsaRefKind k, int ord) { + ssaRef(bb, i, v, k) and + result = MkOrderedSsaRefIndex(i, k) and + ord = k.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`. + * + * For example, if `bb` is a basic block with a phi node for `v` (considered + * to be at index -1), reads `v` at node 2, and defines it at node 5, we have: + * + * ```ql + * ssaRefRank(bb, -1, v, SsaDef()) = 1 // phi node + * 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. + */ + int ssaRefRank(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) { + ssaRefOrd(bb, i, v, k, _) = + rank[result](int j, int ord, OrderedSsaRefIndex res | + res = ssaRefOrd(bb, j, v, _, ord) + | + res order by j, ord + ) + } + + int maxSsaRefRank(BasicBlock bb, SourceVariable v) { + result = ssaRefRank(bb, _, v, _) and + not result + 1 = ssaRefRank(bb, _, v, _) + } + + /** + * Holds if the SSA definition `def` reaches rank index `rnk` in its own + * basic block `bb`. + */ + predicate ssaDefReachesRank(BasicBlock bb, Definition def, int rnk, SourceVariable v) { + exists(int i | + rnk = ssaRefRank(bb, i, v, SsaDef()) and + def.definesAt(v, bb, i) + ) + or + ssaDefReachesRank(bb, def, rnk - 1, v) and + rnk = ssaRefRank(bb, _, v, SsaRead()) + } + + /** + * Holds if the SSA definition of `v` at `def` reaches index `i` in the same + * basic block `bb`, without crossing another SSA definition of `v`. + */ + predicate ssaDefReachesReadWithinBlock(SourceVariable v, Definition def, BasicBlock bb, int i) { + exists(int rnk | + ssaDefReachesRank(bb, def, rnk, v) and + rnk = ssaRefRank(bb, i, v, SsaRead()) and + variableRead(bb, i, 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`. + */ + predicate ssaDefReachesUncertainDefWithinBlock( + SourceVariable v, Definition def, UncertainWriteDefinition redef + ) { + exists(BasicBlock bb, int rnk, int i | + ssaDefReachesRank(bb, def, rnk, v) and + rnk = ssaRefRank(bb, i, v, SsaDef()) - 1 and + redef.definesAt(v, bb, i) + ) + } + + /** + * Same as `ssaRefRank()`, but restricted to a particular SSA definition `def`. + */ + int ssaDefRank(Definition def, SourceVariable v, BasicBlock bb, int i, SsaRefKind k) { + v = def.getSourceVariable() and + result = ssaRefRank(bb, i, v, k) and + ( + ssaDefReachesRead(_, def, bb, i) + or + def.definesAt(_, bb, i) + ) + } + + predicate defOccursInBlock(Definition def, BasicBlock bb, SourceVariable v) { + exists(ssaDefRank(def, v, bb, _, _)) + } + + pragma[noinline] + private BasicBlock getAMaybeLiveSuccessor(Definition def, BasicBlock bb) { + result = getABasicBlockSuccessor(bb) and + not defOccursInBlock(_, bb, def.getSourceVariable()) and + ssaDefReachesEndOfBlock(bb, def, _) + } + + /** + * Holds if `def` is accessed in basic block `bb1` (either a read or a write), + * `bb2` is a transitive successor of `bb1`, `def` is live at the end of `bb1`, + * and the underlying variable for `def` is neither read nor written in any block + * on the path between `bb1` and `bb2`. + */ + predicate varBlockReaches(Definition def, BasicBlock bb1, BasicBlock bb2) { + defOccursInBlock(def, bb1, _) and + bb2 = getABasicBlockSuccessor(bb1) + or + exists(BasicBlock mid | varBlockReaches(def, bb1, mid) | bb2 = getAMaybeLiveSuccessor(def, mid)) + } + + /** + * Holds if `def` is accessed in basic block `bb1` (either a read or a write), + * `def` is read at index `i2` in basic block `bb2`, `bb2` is in a transitive + * successor block of `bb1`, and `def` is neither read nor written in any block + * on a path between `bb1` and `bb2`. + */ + predicate defAdjacentRead(Definition def, BasicBlock bb1, BasicBlock bb2, int i2) { + varBlockReaches(def, bb1, bb2) and + ssaRefRank(bb2, i2, def.getSourceVariable(), SsaRead()) = 1 and + variableRead(bb2, i2, _, _) + } +} + +private import SsaDefReaches + +pragma[noinline] +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 + // control flow node if it is the _closest_ SSA definition that dominates + // the node. If two definitions dominate a node then one must dominate the + // other, so therefore the definition of _closest_ is given by the dominator + // tree. Thus, reaching definitions can be calculated in terms of dominance. + idom = getImmediateBasicBlockDominator(bb) + ) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Holds if the SSA definition of `v` at `def` reaches the end of basic + * block `bb`, at which point it is still live, without crossing another + * SSA definition of `v`. + */ +pragma[nomagic] +predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SourceVariable v) { + exists(int last | last = maxSsaRefRank(bb, v) | + ssaDefReachesRank(bb, def, last, v) and + liveAtExit(bb, v) + ) + or + ssaDefReachesEndOfBlockRec(bb, def, v) and + liveAtExit(bb, v) and + not ssaRef(bb, _, v, SsaDef()) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Holds if `inp` is an input to the phi node `phi` along the edge originating in `bb`. + */ +pragma[nomagic] +predicate phiHasInputFromBlock(PhiNode phi, Definition inp, BasicBlock bb) { + exists(SourceVariable v, BasicBlock bbDef | + phi.definesAt(v, bbDef, _) and + getABasicBlockPredecessor(bbDef) = bb and + ssaDefReachesEndOfBlock(bb, inp, v) + ) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Holds if the SSA definition of `v` at `def` reaches a read at index `i` in + * basic block `bb`, without crossing another SSA definition of `v`. The read + * is of kind `rk`. + */ +pragma[nomagic] +predicate ssaDefReachesRead(SourceVariable v, Definition def, BasicBlock bb, int i) { + ssaDefReachesReadWithinBlock(v, def, bb, i) + or + variableRead(bb, i, v, _) and + ssaDefReachesEndOfBlock(getABasicBlockPredecessor(bb), def, v) and + not ssaDefReachesReadWithinBlock(v, _, bb, i) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Holds if `def` is accessed at index `i1` in basic block `bb1` (either a read + * or a write), `def` is read at index `i2` in basic block `bb2`, and there is a + * path between them without any read of `def`. + */ +pragma[nomagic] +predicate adjacentDefRead(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) { + exists(int rnk | + rnk = ssaDefRank(def, _, bb1, i1, _) and + rnk + 1 = ssaDefRank(def, _, bb1, i2, SsaRead()) and + variableRead(bb1, i2, _, _) and + bb2 = bb1 + ) + or + exists(SourceVariable v | ssaDefRank(def, v, bb1, i1, _) = maxSsaRefRank(bb1, v)) and + defAdjacentRead(def, bb1, bb2, i2) +} + +private predicate adjacentDefReachesRead( + Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2 +) { + adjacentDefRead(def, bb1, i1, bb2, i2) and + exists(SourceVariable v | v = def.getSourceVariable() | + ssaRef(bb1, i1, v, SsaDef()) + or + variableRead(bb1, i1, v, true) + ) + or + exists(BasicBlock bb3, int i3 | + adjacentDefReachesRead(def, bb1, i1, bb3, i3) and + variableRead(bb3, i3, _, false) and + adjacentDefRead(def, bb3, i3, bb2, i2) + ) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Same as `adjacentDefRead`, but ignores uncertain reads. + */ +pragma[nomagic] +predicate adjacentDefNoUncertainReads(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) { + adjacentDefReachesRead(def, bb1, i1, bb2, i2) and + variableRead(bb2, i2, _, true) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Holds if the node at index `i` in `bb` is a last reference to SSA definition + * `def`. The reference is last because it can reach another write `next`, + * without passing through another read or write. + */ +pragma[nomagic] +predicate lastRefRedef(Definition def, BasicBlock bb, int i, Definition next) { + exists(int rnk, SourceVariable v, int j | rnk = ssaDefRank(def, v, bb, i, _) | + // Next reference to `v` inside `bb` is a write + next.definesAt(v, bb, j) and + rnk + 1 = ssaRefRank(bb, j, v, SsaDef()) + or + // Can reach a write using one or more steps + rnk = maxSsaRefRank(bb, v) and + exists(BasicBlock bb2 | + varBlockReaches(def, bb, bb2) and + next.definesAt(v, bb2, j) and + 1 = ssaRefRank(bb2, j, v, SsaDef()) + ) + ) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Holds if `inp` is an immediately preceding definition of uncertain definition + * `def`. Since `def` is uncertain, the value from the preceding definition might + * still be valid. + */ +pragma[nomagic] +predicate uncertainWriteDefinitionInput(UncertainWriteDefinition def, Definition inp) { + lastRefRedef(inp, _, _, def) +} + +private predicate adjacentDefReachesUncertainRead( + Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2 +) { + adjacentDefReachesRead(def, bb1, i1, bb2, i2) and + variableRead(bb2, i2, _, false) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Same as `lastRefRedef`, but ignores uncertain reads. + */ +pragma[nomagic] +predicate lastRefRedefNoUncertainReads(Definition def, BasicBlock bb, int i, Definition next) { + lastRefRedef(def, bb, i, next) and + not variableRead(bb, i, def.getSourceVariable(), false) + or + exists(BasicBlock bb0, int i0 | + lastRefRedef(def, bb0, i0, next) and + adjacentDefReachesUncertainRead(def, bb, i, bb0, i0) + ) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * 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. + */ +pragma[nomagic] +predicate lastRef(Definition def, BasicBlock bb, int i) { + lastRefRedef(def, bb, i, _) + or + exists(SourceVariable v | ssaDefRank(def, v, bb, i, _) = maxSsaRefRank(bb, v) | + // Can reach exit directly + bb instanceof ExitBasicBlock + or + // Can reach a block using one or more steps, where `def` is no longer live + exists(BasicBlock bb2 | varBlockReaches(def, bb, bb2) | + not defOccursInBlock(def, bb2, _) and + not ssaDefReachesEndOfBlock(bb2, def, _) + ) + ) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Same as `lastRefRedef`, but ignores uncertain reads. + */ +pragma[nomagic] +predicate lastRefNoUncertainReads(Definition def, BasicBlock bb, int i) { + lastRef(def, bb, i) and + not variableRead(bb, i, def.getSourceVariable(), false) + or + exists(BasicBlock bb0, int i0 | + lastRef(def, bb0, i0) and + adjacentDefReachesUncertainRead(def, bb, i, bb0, i0) + ) +} + +/** A static single assignment (SSA) definition. */ +class Definition extends TDefinition { + /** Gets the source variable underlying this SSA definition. */ + SourceVariable getSourceVariable() { this.definesAt(result, _, _) } + + /** + * Holds if this SSA definition defines `v` at index `i` in basic block `bb`. + * Phi nodes are considered to be at index `-1`, while normal variable writes + * are at the index of the control flow node they wrap. + */ + final 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. */ + final BasicBlock getBasicBlock() { this.definesAt(_, result, _) } + + /** Gets a textual representation of this SSA definition. */ + string toString() { none() } +} + +/** An SSA definition that corresponds to a write. */ +class WriteDefinition extends Definition, TWriteDef { + private SourceVariable v; + private BasicBlock bb; + private int i; + + WriteDefinition() { this = TWriteDef(v, bb, i) } + + override string toString() { result = "WriteDef" } +} + +/** A phi node. */ +class PhiNode extends Definition, TPhiNode { + override string toString() { result = "Phi" } +} + +/** + * An SSA definition that represents an uncertain update of the underlying + * source variable. + */ +class UncertainWriteDefinition extends WriteDefinition { + UncertainWriteDefinition() { + exists(SourceVariable v, BasicBlock bb, int i | + this.definesAt(v, bb, i) and + variableWrite(bb, i, v, false) + ) + } +} diff --git a/csharp/ql/src/semmle/code/cil/internal/SsaImplSpecific.qll b/csharp/ql/src/semmle/code/cil/internal/SsaImplSpecific.qll new file mode 100644 index 00000000000..94b4812d996 --- /dev/null +++ b/csharp/ql/src/semmle/code/cil/internal/SsaImplSpecific.qll @@ -0,0 +1,30 @@ +/** Provides the CIL specific parameters for `SsaImplCommon.qll`. */ + +private import cil +private import SsaImpl + +class BasicBlock = CIL::BasicBlock; + +BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result = bb.getImmediateDominator() } + +BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() } + +class ExitBasicBlock = CIL::ExitBasicBlock; + +class SourceVariable = CIL::StackVariable; + +predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) { + forceCachingInSameStage() and + exists(CIL::VariableUpdate vu | + vu.updatesAt(bb, i) and + v = vu.getVariable() and + certain = true + ) +} + +predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) { + exists(CIL::ReadAccess ra | bb.getNode(i) = ra | + ra.getTarget() = v and + certain = true + ) +} diff --git a/csharp/ql/src/semmle/code/csharp/commons/Disposal.qll b/csharp/ql/src/semmle/code/csharp/commons/Disposal.qll index 28c79d749ff..090599a60a7 100644 --- a/csharp/ql/src/semmle/code/csharp/commons/Disposal.qll +++ b/csharp/ql/src/semmle/code/csharp/commons/Disposal.qll @@ -11,14 +11,22 @@ private predicate isDisposeMethod(DotNet::Callable method) { method.getNumberOfParameters() = 0 } +private predicate cilVariableReadFlowsTo(CIL::Variable variable, CIL::DataFlowNode n) { + n = variable.getARead() + or + exists(CIL::DataFlowNode mid | + cilVariableReadFlowsTo(variable, mid) and + mid.getALocalFlowSucc(n, any(CIL::Untainted u)) + ) +} + private predicate disposedCilVariable(CIL::Variable variable) { // `variable` is the `this` parameter on a dispose method. isDisposeMethod(variable.(CIL::ThisParameter).getMethod()) or // `variable` is passed to a method that disposes it. - exists(CIL::Call call, CIL::Parameter param, CIL::ReadAccess read | - read.getTarget() = variable and - read.flowsTo(call.getArgumentForParameter(param)) and + exists(CIL::Call call, CIL::Parameter param | + cilVariableReadFlowsTo(variable, call.getArgumentForParameter(param)) and disposedCilVariable(param) ) or @@ -27,9 +35,8 @@ private predicate disposedCilVariable(CIL::Variable variable) { or // A variable is disposed if it's assigned to another variable // that may be disposed. - exists(CIL::ReadAccess read, CIL::WriteAccess write | - read.flowsTo(write.getExpr()) and - read.getTarget() = variable and + exists(CIL::WriteAccess write | + cilVariableReadFlowsTo(variable, write.getExpr()) and disposedCilVariable(write.getTarget()) ) } From 0b4650a4c94a449c121bb123a907fcbede46f198 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 23 Mar 2021 10:27:19 +0100 Subject: [PATCH 253/725] C++: Accept test changes. --- cpp/ql/test/library-tests/dataflow/taint-tests/bsd.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/bsd.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/bsd.cpp index 4846420a5a5..fe138a8d8fc 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/bsd.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/bsd.cpp @@ -19,6 +19,6 @@ void test_accept() { int size = sizeof(sockaddr); int a = accept(s, &addr, &size); - sink(a); // $ ast=17:11 SPURIOUS: ast=18:12 MISSING: ir - sink(addr); // $ ast MISSING: ir + sink(a); // $ ast=17:11 ir SPURIOUS: ast=18:12 + sink(addr); // $ ast,ir } From 585606a9331ea97141a62e771080fcfdd1e601bf Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 23 Mar 2021 11:14:29 +0100 Subject: [PATCH 254/725] C++: Respond to review comments. --- cpp/ql/src/semmle/code/cpp/models/implementations/Accept.qll | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Accept.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Accept.qll index 092c5a3ca5b..cea4598acf3 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Accept.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Accept.qll @@ -15,9 +15,7 @@ import semmle.code.cpp.models.interfaces.SideEffect private class Accept extends ArrayFunction, AliasFunction, TaintFunction, SideEffectFunction { Accept() { this.hasGlobalName(["accept", "accept4", "WSAAccept"]) } - override predicate hasArrayWithVariableSize(int bufParam, int countParam) { - bufParam = 1 and countParam = 2 - } + override predicate hasArrayWithUnknownSize(int bufParam) { bufParam = 1 } override predicate hasArrayInput(int bufParam) { bufParam = 1 } From 98143b071dcb7a71a650b175e6c54686eb1052d6 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Tue, 23 Mar 2021 11:26:29 +0000 Subject: [PATCH 255/725] JS: Autoformat --- javascript/ql/src/meta/alerts/CallGraph.ql | 6 ++++-- .../src/semmle/javascript/dataflow/internal/FlowSteps.qll | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/meta/alerts/CallGraph.ql b/javascript/ql/src/meta/alerts/CallGraph.ql index 13cb8a94ecd..364d81e32c9 100644 --- a/javascript/ql/src/meta/alerts/CallGraph.ql +++ b/javascript/ql/src/meta/alerts/CallGraph.ql @@ -11,6 +11,8 @@ import javascript from DataFlow::Node invoke, Function f, string kind -where invoke.(DataFlow::InvokeNode).getACallee() = f and kind = "Call" or - invoke.(DataFlow::PropRef).getAnAccessorCallee().getFunction() = f and kind = "Accessor call" +where + invoke.(DataFlow::InvokeNode).getACallee() = f and kind = "Call" + or + invoke.(DataFlow::PropRef).getAnAccessorCallee().getFunction() = f and kind = "Accessor call" select invoke, kind + " to $@", f, f.describe() diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll index 2d9f05ce592..7036e242426 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll @@ -25,7 +25,8 @@ predicate shouldTrackProperties(AbstractValue obj) { */ pragma[noinline] predicate returnExpr(Function f, DataFlow::Node source, DataFlow::Node sink) { - sink.asExpr() = f.getAReturnedExpr() and source = sink and + sink.asExpr() = f.getAReturnedExpr() and + source = sink and not f = any(SetterMethodDeclaration decl).getBody() } From 6c8b4a82c15c72251452349e1c0b38f4c48fb366 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Tue, 23 Mar 2021 11:55:37 +0000 Subject: [PATCH 256/725] JS: Autoformat --- javascript/ql/src/semmle/javascript/HtmlSanitizers.qll | 3 +-- javascript/ql/src/semmle/javascript/security/dataflow/DOM.qll | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/HtmlSanitizers.qll b/javascript/ql/src/semmle/javascript/HtmlSanitizers.qll index 2be99a149cc..25e8b1ad74c 100644 --- a/javascript/ql/src/semmle/javascript/HtmlSanitizers.qll +++ b/javascript/ql/src/semmle/javascript/HtmlSanitizers.qll @@ -50,8 +50,7 @@ private DataFlow::SourceNode htmlSanitizerFunction() { ) or exists(string name | name = "encode" or name = "encodeNonUTF" | - result = - DataFlow::moduleMember("html-entities", _).getAnInstantiation().getAPropertyRead(name) or + result = DataFlow::moduleMember("html-entities", _).getAnInstantiation().getAPropertyRead(name) or result = DataFlow::moduleMember("html-entities", _).getAPropertyRead(name) ) or diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/DOM.qll b/javascript/ql/src/semmle/javascript/security/dataflow/DOM.qll index 356830bd6d4..204f04e9c52 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/DOM.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/DOM.qll @@ -172,7 +172,7 @@ private module PersistentWebStorage { override PersistentWriteAccess getAWrite() { exists(string name | - getArgument(0).mayHaveStringValue(name) and + getArgument(0).mayHaveStringValue(name) and result = getAWriteByName(name, kind) ) } From 30e1b88b7f23803006fe98f9a8d0534201a50f6f Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 22 Mar 2021 15:12:32 +0000 Subject: [PATCH 257/725] C++: Extend test. --- .../UncontrolledProcessOperation.expected | 10 +++++++ .../UncontrolledProcessOperation/test.cpp | 26 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/UncontrolledProcessOperation.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/UncontrolledProcessOperation.expected index e67d10272aa..d3b7ee8faf5 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/UncontrolledProcessOperation.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/UncontrolledProcessOperation.expected @@ -35,6 +35,10 @@ edges | test.cpp:76:12:76:17 | fgets output argument | test.cpp:78:10:78:15 | buffer | | test.cpp:76:12:76:17 | fgets output argument | test.cpp:79:10:79:13 | (const char *)... | | test.cpp:76:12:76:17 | fgets output argument | test.cpp:79:10:79:13 | data | +| test.cpp:98:17:98:22 | buffer | test.cpp:99:15:99:20 | (const char *)... | +| test.cpp:98:17:98:22 | buffer | test.cpp:99:15:99:20 | buffer | +| test.cpp:98:17:98:22 | recv output argument | test.cpp:99:15:99:20 | (const char *)... | +| test.cpp:98:17:98:22 | recv output argument | test.cpp:99:15:99:20 | buffer | nodes | test.cpp:24:30:24:36 | *command | semmle.label | *command | | test.cpp:24:30:24:36 | command | semmle.label | command | @@ -70,6 +74,11 @@ nodes | test.cpp:79:10:79:13 | (const char *)... | semmle.label | (const char *)... | | test.cpp:79:10:79:13 | (const char *)... | semmle.label | (const char *)... | | test.cpp:79:10:79:13 | data | semmle.label | data | +| test.cpp:98:17:98:22 | buffer | semmle.label | buffer | +| test.cpp:98:17:98:22 | recv output argument | semmle.label | recv output argument | +| test.cpp:99:15:99:20 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:99:15:99:20 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:99:15:99:20 | buffer | semmle.label | buffer | #select | test.cpp:26:10:26:16 | command | test.cpp:42:18:42:23 | call to getenv | test.cpp:26:10:26:16 | command | The value of this argument may come from $@ and is being passed to system | test.cpp:42:18:42:23 | call to getenv | call to getenv | | test.cpp:31:10:31:16 | command | test.cpp:43:18:43:23 | call to getenv | test.cpp:31:10:31:16 | command | The value of this argument may come from $@ and is being passed to system | test.cpp:43:18:43:23 | call to getenv | call to getenv | @@ -77,3 +86,4 @@ nodes | test.cpp:63:10:63:13 | data | test.cpp:56:12:56:17 | buffer | test.cpp:63:10:63:13 | data | The value of this argument may come from $@ and is being passed to system | test.cpp:56:12:56:17 | buffer | buffer | | test.cpp:78:10:78:15 | buffer | test.cpp:76:12:76:17 | buffer | test.cpp:78:10:78:15 | buffer | The value of this argument may come from $@ and is being passed to system | test.cpp:76:12:76:17 | buffer | buffer | | test.cpp:79:10:79:13 | data | test.cpp:76:12:76:17 | buffer | test.cpp:79:10:79:13 | data | The value of this argument may come from $@ and is being passed to system | test.cpp:76:12:76:17 | buffer | buffer | +| test.cpp:99:15:99:20 | buffer | test.cpp:98:17:98:22 | buffer | test.cpp:99:15:99:20 | buffer | The value of this argument may come from $@ and is being passed to LoadLibrary | test.cpp:98:17:98:22 | buffer | buffer | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/test.cpp index eb9436bcadb..3a224d430cb 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/test.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/test.cpp @@ -81,3 +81,29 @@ void testReferencePointer2() system(data2); // BAD [NOT DETECTED] } } + +// --- + +typedef unsigned long size_t; + +void accept(int arg, char *buf, size_t bufSize); +void recv(int arg, char *buf, size_t bufSize); +void LoadLibrary(const char *arg); + +void testAcceptRecv(int socket1, int socket2) +{ + { + char buffer[1024]; + + recv(socket1, buffer, 1024); + LoadLibrary(buffer); // BAD: using data from recv + } + + { + char buffer[1024]; + + accept(socket2, 0, 0); + recv(socket2, buffer, 1024); + LoadLibrary(buffer); // BAD: using data from recv [NOT DETECTED] + } +} From 13eb9e0833ba9ddc716d849de912b17162c1a7b4 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 23 Mar 2021 10:05:00 +0000 Subject: [PATCH 258/725] C++: Fix the test. --- .../CWE/CWE-114/semmle/UncontrolledProcessOperation/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/test.cpp index 3a224d430cb..f509d0f0eda 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/test.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/test.cpp @@ -86,7 +86,7 @@ void testReferencePointer2() typedef unsigned long size_t; -void accept(int arg, char *buf, size_t bufSize); +void accept(int arg, char *buf, size_t *bufSize); void recv(int arg, char *buf, size_t bufSize); void LoadLibrary(const char *arg); From b38a9d51e6e7f7429b3388b6eee04bf72eb6d348 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 23 Mar 2021 10:09:06 +0000 Subject: [PATCH 259/725] C++: Effect of 'Don't override getParameterSizeIndex in the model for Accept'... --- .../UncontrolledProcessOperation.expected | 10 ++++++++++ .../semmle/UncontrolledProcessOperation/test.cpp | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/UncontrolledProcessOperation.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/UncontrolledProcessOperation.expected index d3b7ee8faf5..798a2eff20f 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/UncontrolledProcessOperation.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/UncontrolledProcessOperation.expected @@ -39,6 +39,10 @@ edges | test.cpp:98:17:98:22 | buffer | test.cpp:99:15:99:20 | buffer | | test.cpp:98:17:98:22 | recv output argument | test.cpp:99:15:99:20 | (const char *)... | | test.cpp:98:17:98:22 | recv output argument | test.cpp:99:15:99:20 | buffer | +| test.cpp:106:17:106:22 | buffer | test.cpp:107:15:107:20 | (const char *)... | +| test.cpp:106:17:106:22 | buffer | test.cpp:107:15:107:20 | buffer | +| test.cpp:106:17:106:22 | recv output argument | test.cpp:107:15:107:20 | (const char *)... | +| test.cpp:106:17:106:22 | recv output argument | test.cpp:107:15:107:20 | buffer | nodes | test.cpp:24:30:24:36 | *command | semmle.label | *command | | test.cpp:24:30:24:36 | command | semmle.label | command | @@ -79,6 +83,11 @@ nodes | test.cpp:99:15:99:20 | (const char *)... | semmle.label | (const char *)... | | test.cpp:99:15:99:20 | (const char *)... | semmle.label | (const char *)... | | test.cpp:99:15:99:20 | buffer | semmle.label | buffer | +| test.cpp:106:17:106:22 | buffer | semmle.label | buffer | +| test.cpp:106:17:106:22 | recv output argument | semmle.label | recv output argument | +| test.cpp:107:15:107:20 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:107:15:107:20 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:107:15:107:20 | buffer | semmle.label | buffer | #select | test.cpp:26:10:26:16 | command | test.cpp:42:18:42:23 | call to getenv | test.cpp:26:10:26:16 | command | The value of this argument may come from $@ and is being passed to system | test.cpp:42:18:42:23 | call to getenv | call to getenv | | test.cpp:31:10:31:16 | command | test.cpp:43:18:43:23 | call to getenv | test.cpp:31:10:31:16 | command | The value of this argument may come from $@ and is being passed to system | test.cpp:43:18:43:23 | call to getenv | call to getenv | @@ -87,3 +96,4 @@ nodes | test.cpp:78:10:78:15 | buffer | test.cpp:76:12:76:17 | buffer | test.cpp:78:10:78:15 | buffer | The value of this argument may come from $@ and is being passed to system | test.cpp:76:12:76:17 | buffer | buffer | | test.cpp:79:10:79:13 | data | test.cpp:76:12:76:17 | buffer | test.cpp:79:10:79:13 | data | The value of this argument may come from $@ and is being passed to system | test.cpp:76:12:76:17 | buffer | buffer | | test.cpp:99:15:99:20 | buffer | test.cpp:98:17:98:22 | buffer | test.cpp:99:15:99:20 | buffer | The value of this argument may come from $@ and is being passed to LoadLibrary | test.cpp:98:17:98:22 | buffer | buffer | +| test.cpp:107:15:107:20 | buffer | test.cpp:106:17:106:22 | buffer | test.cpp:107:15:107:20 | buffer | The value of this argument may come from $@ and is being passed to LoadLibrary | test.cpp:106:17:106:22 | buffer | buffer | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/test.cpp index f509d0f0eda..26aff44f3d8 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/test.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/test.cpp @@ -104,6 +104,6 @@ void testAcceptRecv(int socket1, int socket2) accept(socket2, 0, 0); recv(socket2, buffer, 1024); - LoadLibrary(buffer); // BAD: using data from recv [NOT DETECTED] + LoadLibrary(buffer); // BAD: using data from recv } } From b5be9d07aaa69b213feb12f07c6813dedbeea4a1 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Tue, 23 Mar 2021 12:51:14 +0000 Subject: [PATCH 260/725] JS: Add change note --- javascript/change-notes/2021-03-23-accessor-calls.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 javascript/change-notes/2021-03-23-accessor-calls.md diff --git a/javascript/change-notes/2021-03-23-accessor-calls.md b/javascript/change-notes/2021-03-23-accessor-calls.md new file mode 100644 index 00000000000..080a73c7abb --- /dev/null +++ b/javascript/change-notes/2021-03-23-accessor-calls.md @@ -0,0 +1,3 @@ +lgtm,codescanning +* Calls to property accessors are now analyzed on par with regular function calls, + leading to more results from queries that rely on data flow. From 8d0f6086afe96a9a98163b0b4d269079eb08f4e3 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 22 Mar 2021 10:13:57 +0100 Subject: [PATCH 261/725] Python: Model django forms/fields I'm not feeling 100% confident about `SelfRefMixin`, but since I needed it for both DjangoViewClass and DjangoFormClass, I wanted to avoid copy-pasting this code around. However, I'm not so opitimistic about it that I want to add it to a sharable utility qll file :D --- .../2021-03-23-django-forms-fields-classes.md | 2 + .../src/semmle/python/frameworks/Django.qll | 161 +++++++++++++++--- .../django-v2-v3/TestTaint.expected | 22 +-- 3 files changed, 150 insertions(+), 35 deletions(-) create mode 100644 python/change-notes/2021-03-23-django-forms-fields-classes.md diff --git a/python/change-notes/2021-03-23-django-forms-fields-classes.md b/python/change-notes/2021-03-23-django-forms-fields-classes.md new file mode 100644 index 00000000000..b45764da8a6 --- /dev/null +++ b/python/change-notes/2021-03-23-django-forms-fields-classes.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* Improved modeling of `django` to recognize sources of remote user input (`RemoteFlowSource`) in Django forms (`django.forms.Form`) and fields (`django.forms.Field`) subclasses. diff --git a/python/ql/src/semmle/python/frameworks/Django.qll b/python/ql/src/semmle/python/frameworks/Django.qll index 9f56bd5a299..be456cb239c 100644 --- a/python/ql/src/semmle/python/frameworks/Django.qll +++ b/python/ql/src/semmle/python/frameworks/Django.qll @@ -8,6 +8,7 @@ private import semmle.python.dataflow.new.DataFlow private import semmle.python.dataflow.new.RemoteFlowSources private import semmle.python.dataflow.new.TaintTracking private import semmle.python.Concepts +private import semmle.python.ApiGraphs private import semmle.python.frameworks.PEP249 private import semmle.python.regex @@ -1975,6 +1976,50 @@ private module Django { } } + /** Provides models for django forms (defined in the `django.forms` module) */ + module Forms { + /** + * Provides models for the `django.forms.Form` class and subclasses. + * + * See https://docs.djangoproject.com/en/3.1/ref/forms/api/ + */ + module Form { + /** Gets a reference to the `django.forms.Form` class or any subclass. */ + API::Node subclassRef() { + result = + API::moduleImport("django") + .getMember("forms") + .getMember([ + "Form" + // TODO: Known subclasses + ]) + .getASubclass*() + } + } + + /** + * Provides models for the `django.forms.Field` class and subclasses. + * + * See https://docs.djangoproject.com/en/3.1/ref/forms/fields/ + */ + module Field { + /** Gets a reference to the `django.forms.Form` class or any subclass. */ + API::Node subclassRef() { + result = + API::moduleImport("django") + .getMember("forms") + .getMember([ + "Field" + // TODO: Known subclasses + ]) + .getASubclass*() + } + } + } + + // --------------------------------------------------------------------------- + // Helpers + // --------------------------------------------------------------------------- /** * Gets the last decorator call for the function `func`, if `func` has decorators. */ @@ -1983,6 +2028,97 @@ private module Django { not exists(Call other_decorator | other_decorator.getArg(0) = result) } + /** Adds the `getASelfRef` member predicate when modeling a class. */ + abstract private class SelfRefMixin extends Class { + /** + * Gets a reference to instances of this class, originating from a self parameter of + * a method defined on this class. + * + * Note: TODO: This doesn't take MRO into account + * Note: TODO: This doesn't take staticmethod/classmethod into account + */ + private DataFlow::Node getASelfRef(DataFlow::TypeTracker t) { + t.start() and + result.(DataFlow::ParameterNode).getParameter() = this.getAMethod().getArg(0) + or + exists(DataFlow::TypeTracker t2 | result = this.getASelfRef(t2).track(t2, t)) + } + + /** + * Gets a reference to instances of this class, originating from a self parameter of + * a method defined on this class. + * + * Note: TODO: This doesn't take MRO into account + * Note: TODO: This doesn't take staticmethod/classmethod into account + */ + DataFlow::Node getASelfRef() { result = this.getASelfRef(DataFlow::TypeTracker::end()) } + } + + // --------------------------------------------------------------------------- + // Form and form field modeling + // --------------------------------------------------------------------------- + /** + * A class that is a subclass of the `django.forms.Form` class, + * thereby handling user input. + */ + class DjangoFormClass extends Class, SelfRefMixin { + DjangoFormClass() { this.getABase() = Django::Forms::Form::subclassRef().getAUse().asExpr() } + } + + /** + * A source of cleaned_data (either the return value from `super().clean()`, or a reference to `self.cleaned_data`) + * + * See https://docs.djangoproject.com/en/3.1/ref/forms/validation/#form-and-field-validation + */ + private class DjangoFormCleanedData extends RemoteFlowSource::Range, DataFlow::Node { + DjangoFormCleanedData() { + exists(DjangoFormClass cls, Function meth | + cls.getAMethod() = meth and + ( + this = API::builtin("super").getReturn().getMember("clean").getACall() and + this.getScope() = meth + or + this.(DataFlow::AttrRead).getAttributeName() = "cleaned_data" and + this.(DataFlow::AttrRead).getObject() = cls.getASelfRef() + ) + ) + } + + override string getSourceType() { + result = "django.forms.Field subclass, value parameter in method" + } + } + + /** + * A class that is a subclass of the `django.forms.Field` class, + * thereby handling user input. + */ + class DjangoFormFieldClass extends Class { + DjangoFormFieldClass() { + this.getABase() = Django::Forms::Field::subclassRef().getAUse().asExpr() + // api_node.getAnImmediateUse().asExpr().(ClassExpr) = this.getParent() + } + } + + /** + * A parameter in a method on a `DjangoFormFieldClass` that receives the user-supplied value for this field. + * + * See https://docs.djangoproject.com/en/3.1/ref/forms/validation/#form-and-field-validation + */ + private class DjangoFormFieldValueParam extends RemoteFlowSource::Range, DataFlow::ParameterNode { + DjangoFormFieldValueParam() { + exists(DjangoFormFieldClass cls, Function meth | + cls.getAMethod() = meth and + meth.getName() in ["to_python", "validate", "run_validators", "clean"] and + this.getParameter() = meth.getArg(1) + ) + } + + override string getSourceType() { + result = "django.forms.Field subclass, value parameter in method" + } + } + // --------------------------------------------------------------------------- // routing modeling // --------------------------------------------------------------------------- @@ -2068,7 +2204,7 @@ private module Django { } /** A class that we consider a django View class. */ - abstract class DjangoViewClass extends DjangoViewClassHelper { + abstract class DjangoViewClass extends DjangoViewClassHelper, SelfRefMixin { /** Gets a function that could handle incoming requests, if any. */ Function getARequestHandler() { // TODO: This doesn't handle attribute assignment. Should be OK, but analysis is not as complete as with @@ -2080,29 +2216,6 @@ private module Django { result.getName() = "get_redirect_url" ) } - - /** - * Gets a reference to instances of this class, originating from a self parameter of - * a method defined on this class. - * - * Note: TODO: This doesn't take MRO into account - * Note: TODO: This doesn't take staticmethod/classmethod into account - */ - private DataFlow::Node getASelfRef(DataFlow::TypeTracker t) { - t.start() and - result.(DataFlow::ParameterNode).getParameter() = this.getAMethod().getArg(0) - or - exists(DataFlow::TypeTracker t2 | result = this.getASelfRef(t2).track(t2, t)) - } - - /** - * Gets a reference to instances of this class, originating from a self parameter of - * a method defined on this class. - * - * Note: TODO: This doesn't take MRO into account - * Note: TODO: This doesn't take staticmethod/classmethod into account - */ - DataFlow::Node getASelfRef() { result = this.getASelfRef(DataFlow::TypeTracker::end()) } } /** diff --git a/python/ql/test/library-tests/frameworks/django-v2-v3/TestTaint.expected b/python/ql/test/library-tests/frameworks/django-v2-v3/TestTaint.expected index 95d0a58df3b..0888473f41c 100644 --- a/python/ql/test/library-tests/frameworks/django-v2-v3/TestTaint.expected +++ b/python/ql/test/library-tests/frameworks/django-v2-v3/TestTaint.expected @@ -1,15 +1,15 @@ | response_test.py:61 | ok | get_redirect_url | foo | -| taint_forms.py:6 | fail | to_python | value | -| taint_forms.py:9 | fail | validate | value | -| taint_forms.py:12 | fail | run_validators | value | -| taint_forms.py:15 | fail | clean | value | -| taint_forms.py:33 | fail | clean | cleaned_data | -| taint_forms.py:34 | fail | clean | cleaned_data["key"] | -| taint_forms.py:35 | fail | clean | cleaned_data.get(..) | -| taint_forms.py:39 | fail | clean | self.cleaned_data | -| taint_forms.py:40 | fail | clean | self.cleaned_data["key"] | -| taint_forms.py:41 | fail | clean | self.cleaned_data.get(..) | -| taint_forms.py:46 | fail | clean_foo | self.cleaned_data | +| taint_forms.py:6 | ok | to_python | value | +| taint_forms.py:9 | ok | validate | value | +| taint_forms.py:12 | ok | run_validators | value | +| taint_forms.py:15 | ok | clean | value | +| taint_forms.py:33 | ok | clean | cleaned_data | +| taint_forms.py:34 | ok | clean | cleaned_data["key"] | +| taint_forms.py:35 | ok | clean | cleaned_data.get(..) | +| taint_forms.py:39 | ok | clean | self.cleaned_data | +| taint_forms.py:40 | ok | clean | self.cleaned_data["key"] | +| taint_forms.py:41 | ok | clean | self.cleaned_data.get(..) | +| taint_forms.py:46 | ok | clean_foo | self.cleaned_data | | taint_test.py:8 | ok | test_taint | bar | | taint_test.py:8 | ok | test_taint | foo | | taint_test.py:9 | ok | test_taint | baz | From a4924856a2d97ed75d32241a08a1c39c23a590f0 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 23 Mar 2021 11:39:22 +0100 Subject: [PATCH 262/725] Python: Model known form/field subclasses in Django I used some ad-hoc QL queries to help me find all these extra instances, but not quite ready to share that code yet :P --- .../src/semmle/python/frameworks/Django.qll | 175 +++++++++++++++++- 1 file changed, 165 insertions(+), 10 deletions(-) diff --git a/python/ql/src/semmle/python/frameworks/Django.qll b/python/ql/src/semmle/python/frameworks/Django.qll index be456cb239c..6cc71922caa 100644 --- a/python/ql/src/semmle/python/frameworks/Django.qll +++ b/python/ql/src/semmle/python/frameworks/Django.qll @@ -1979,39 +1979,194 @@ private module Django { /** Provides models for django forms (defined in the `django.forms` module) */ module Forms { /** - * Provides models for the `django.forms.Form` class and subclasses. + * Provides models for the `django.forms.forms.BaseForm` class and subclasses. This + * is usually used by the `django.forms.forms.Form` class, which is also available + * under the more commonly used alias `django.forms.Form`. * * See https://docs.djangoproject.com/en/3.1/ref/forms/api/ */ module Form { - /** Gets a reference to the `django.forms.Form` class or any subclass. */ + /** Gets a reference to the `django.forms.forms.BaseForm` class or any subclass. */ API::Node subclassRef() { + // canonical definition result = API::moduleImport("django") + .getMember("forms") + .getMember("forms") + .getMember(["BaseForm", "Form"]) + .getASubclass*() + or + result = + API::moduleImport("django") + .getMember("forms") + .getMember("models") + .getMember(["BaseModelForm", "ModelForm"]) + .getASubclass*() + or + // aliases from `django.forms` + result = + API::moduleImport("django") + .getMember("forms") + .getMember(["BaseForm", "Form", "BaseModelForm", "ModelForm"]) + .getASubclass*() + or + // other Form subclasses defined in Django + result = + API::moduleImport("django") + .getMember("contrib") + .getMember("admin") + .getMember("forms") + .getMember(["AdminAuthenticationForm", "AdminPasswordChangeForm"]) + .getASubclass*() + or + result = + API::moduleImport("django") + .getMember("contrib") + .getMember("admin") + .getMember("helpers") + .getMember("ActionForm") + .getASubclass*() + or + result = + API::moduleImport("django") + .getMember("contrib") + .getMember("admin") + .getMember("views") + .getMember("main") + .getMember("ChangeListSearchForm") + .getASubclass*() + or + result = + API::moduleImport("django") + .getMember("contrib") + .getMember("auth") .getMember("forms") .getMember([ - "Form" - // TODO: Known subclasses + "PasswordResetForm", "UserChangeForm", "SetPasswordForm", + "AdminPasswordChangeForm", "PasswordChangeForm", "AuthenticationForm", + "UserCreationForm" ]) .getASubclass*() + or + result = + API::moduleImport("django") + .getMember("contrib") + .getMember("flatpages") + .getMember("forms") + .getMember("FlatpageForm") + .getASubclass*() + or + result = + API::moduleImport("django") + .getMember("forms") + .getMember("formsets") + .getMember("ManagementForm") + .getASubclass*() + or + result = + API::moduleImport("django") + .getMember("forms") + .getMember("models") + .getMember(["ModelForm", "BaseModelForm"]) + .getASubclass*() } } /** - * Provides models for the `django.forms.Field` class and subclasses. + * Provides models for the `django.forms.fields.Field` class and subclasses. This is + * also available under the more commonly used alias `django.forms.Field`. * * See https://docs.djangoproject.com/en/3.1/ref/forms/fields/ */ module Field { - /** Gets a reference to the `django.forms.Form` class or any subclass. */ + /** Gets a reference to the `django.forms.fields.Field` class or any subclass. */ API::Node subclassRef() { + exists(string modName, string clsName | + // canonical definition + result = + API::moduleImport("django") + .getMember("forms") + .getMember(modName) + .getMember(clsName) + .getASubclass*() + or + // alias from `django.forms` + result = API::moduleImport("django").getMember("forms").getMember(clsName).getASubclass*() + | + modName = "fields" and + clsName in [ + "Field", + // Known subclasses + "BooleanField", "IntegerField", "CharField", "SlugField", "DateTimeField", + "EmailField", "DateField", "TimeField", "DurationField", "DecimalField", "FloatField", + "GenericIPAddressField", "UUIDField", "JSONField", "FilePathField", + "NullBooleanField", "URLField", "TypedChoiceField", "FileField", "ImageField", + "RegexField", "ChoiceField", "MultipleChoiceField", "ComboField", "MultiValueField", + "SplitDateTimeField", "TypedMultipleChoiceField", "BaseTemporalField" + ] + or + // Known subclasses from `django.forms.models` + modName = "models" and + clsName in ["ModelChoiceField", "ModelMultipleChoiceField", "InlineForeignKeyField"] + ) + or + // other Field subclasses defined in Django + result = + API::moduleImport("django") + .getMember("contrib") + .getMember("auth") + .getMember("forms") + .getMember(["ReadOnlyPasswordHashField", "UsernameField"]) + .getASubclass*() + or + result = + API::moduleImport("django") + .getMember("contrib") + .getMember("gis") + .getMember("forms") + .getMember("fields") + .getMember([ + "GeometryCollectionField", "GeometryField", "LineStringField", + "MultiLineStringField", "MultiPointField", "MultiPolygonField", "PointField", + "PolygonField" + ]) + .getASubclass*() + or + result = + API::moduleImport("django") + .getMember("contrib") + .getMember("postgres") + .getMember("forms") + .getMember("array") + .getMember(["SimpleArrayField", "SplitArrayField"]) + .getASubclass*() + or + result = + API::moduleImport("django") + .getMember("contrib") + .getMember("postgres") + .getMember("forms") + .getMember("hstore") + .getMember("HStoreField") + .getASubclass*() + or + result = + API::moduleImport("django") + .getMember("contrib") + .getMember("postgres") + .getMember("forms") + .getMember("ranges") + .getMember([ + "BaseRangeField", "DateRangeField", "DateTimeRangeField", "DecimalRangeField", + "IntegerRangeField" + ]) + .getASubclass*() + or result = API::moduleImport("django") .getMember("forms") - .getMember([ - "Field" - // TODO: Known subclasses - ]) + .getMember("models") + .getMember(["InlineForeignKeyField", "ModelChoiceField", "ModelMultipleChoiceField"]) .getASubclass*() } } From f2bc413318de820259cff338fd4115b2ad941b39 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 23 Mar 2021 14:00:16 +0100 Subject: [PATCH 263/725] Python: remove single commented out line of code --- python/ql/src/semmle/python/frameworks/Django.qll | 1 - 1 file changed, 1 deletion(-) diff --git a/python/ql/src/semmle/python/frameworks/Django.qll b/python/ql/src/semmle/python/frameworks/Django.qll index 6cc71922caa..ce96c64fed7 100644 --- a/python/ql/src/semmle/python/frameworks/Django.qll +++ b/python/ql/src/semmle/python/frameworks/Django.qll @@ -2251,7 +2251,6 @@ private module Django { class DjangoFormFieldClass extends Class { DjangoFormFieldClass() { this.getABase() = Django::Forms::Field::subclassRef().getAUse().asExpr() - // api_node.getAnImmediateUse().asExpr().(ClassExpr) = this.getParent() } } From 3d94ccf5dd24ba2613ab1c159e6f62e4db0d9c48 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Tue, 23 Mar 2021 14:16:06 +0000 Subject: [PATCH 264/725] JS: Support accessor-calls in object literals via local flow --- .../src/semmle/javascript/dataflow/Nodes.qll | 10 ++++++++++ .../dataflow/internal/CallGraphs.qll | 8 ++++++++ .../TaintTracking/BasicTaintTracking.expected | 2 ++ .../TaintTracking/DataFlowTracking.expected | 2 ++ .../TaintTracking/getters-and-setters.js | 19 +++++++++++++++++++ 5 files changed, 41 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll b/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll index 35a40044097..927df6864ad 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll @@ -546,6 +546,16 @@ class ObjectLiteralNode extends DataFlow::ValueNode, DataFlow::SourceNode { DataFlow::Node getASpreadProperty() { result = astNode.getAProperty().(SpreadProperty).getInit().(SpreadElement).getOperand().flow() } + + /** Gets the property getter of the given name, installed on this object literal. */ + DataFlow::FunctionNode getPropertyGetter(string name) { + result = astNode.getPropertyByName(name).(PropertyGetter).getInit().flow() + } + + /** Gets the property setter of the given name, installed on this object literal. */ + DataFlow::FunctionNode getPropertySetter(string name) { + result = astNode.getPropertyByName(name).(PropertySetter).getInit().flow() + } } /** diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/CallGraphs.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/CallGraphs.qll index 651c97feb6c..e37a4714fd8 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/CallGraphs.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/CallGraphs.qll @@ -175,5 +175,13 @@ module CallGraph { ref = cls.getAnInstanceReference().getAPropertyWrite(name) and result = cls.getInstanceMember(name, DataFlow::MemberKind::setter()) ) + or + exists(DataFlow::ObjectLiteralNode object, string name | + ref = object.getAPropertyRead(name) and + result = object.getPropertyGetter(name) + or + ref = object.getAPropertyWrite(name) and + result = object.getPropertySetter(name) + ) } } diff --git a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected index b35dff0c16f..27800cd8e70 100644 --- a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected @@ -70,6 +70,8 @@ typeInferenceMismatch | getters-and-setters.js:6:20:6:27 | source() | getters-and-setters.js:13:18:13:20 | c.x | | getters-and-setters.js:27:15:27:22 | source() | getters-and-setters.js:23:18:23:18 | v | | getters-and-setters.js:47:23:47:30 | source() | getters-and-setters.js:45:14:45:16 | c.x | +| getters-and-setters.js:60:20:60:27 | source() | getters-and-setters.js:66:10:66:14 | obj.x | +| getters-and-setters.js:67:13:67:20 | source() | getters-and-setters.js:63:18:63:22 | value | | importedReactComponent.jsx:4:40:4:47 | source() | exportedReactComponent.jsx:2:10:2:19 | props.text | | indexOf.js:4:11:4:18 | source() | indexOf.js:9:10:9:10 | x | | json-stringify.js:2:16:2:23 | source() | json-stringify.js:5:8:5:29 | JSON.st ... source) | diff --git a/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected b/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected index fd9e0fe2b46..3dd1a1ccf91 100644 --- a/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected @@ -45,6 +45,8 @@ | getters-and-setters.js:6:20:6:27 | source() | getters-and-setters.js:13:18:13:20 | c.x | | getters-and-setters.js:27:15:27:22 | source() | getters-and-setters.js:23:18:23:18 | v | | getters-and-setters.js:47:23:47:30 | source() | getters-and-setters.js:45:14:45:16 | c.x | +| getters-and-setters.js:60:20:60:27 | source() | getters-and-setters.js:66:10:66:14 | obj.x | +| getters-and-setters.js:67:13:67:20 | source() | getters-and-setters.js:63:18:63:22 | value | | indexOf.js:4:11:4:18 | source() | indexOf.js:9:10:9:10 | x | | indexOf.js:4:11:4:18 | source() | indexOf.js:13:10:13:10 | x | | nested-props.js:4:13:4:20 | source() | nested-props.js:5:10:5:14 | obj.x | diff --git a/javascript/ql/test/library-tests/TaintTracking/getters-and-setters.js b/javascript/ql/test/library-tests/TaintTracking/getters-and-setters.js index 00691e4987d..f61711e11ac 100644 --- a/javascript/ql/test/library-tests/TaintTracking/getters-and-setters.js +++ b/javascript/ql/test/library-tests/TaintTracking/getters-and-setters.js @@ -53,3 +53,22 @@ function testFlowThroughGetter() { sink(getX(new C(source()))); // NOT OK - but not flagged getX(null); } + +function testFlowThroughObjectLiteralAccessors() { + let obj = { + get x() { + return source(); + }, + set y(value) { + sink(value); // NOT OK + } + }; + sink(obj.x); // NOT OK + obj.y = source(); + + function indirection(c) { + sink(c.x); // NOT OK - but not currently flagged + } + indirection(obj); + indirection(null); +} From fa90655dd0a9380f466af16f8eabc8d954f7802e Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Tue, 23 Mar 2021 14:35:03 +0000 Subject: [PATCH 265/725] Partial revert: only introduce inferred taint edges from callsite-crossing value edges if an original taint edge targets the *start* of the value edge. Previously we would also take a taint edge targeting a result and a value-preserving edge propagating another argument to the result to imply a taint edge targeting that argument. --- .../java/dataflow/internal/TaintTrackingUtil.qll | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll b/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll index 2e27a390bdc..d7cf0a8440a 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll @@ -67,8 +67,8 @@ private predicate localAdditionalBasicTaintStep(DataFlow::Node src, DataFlow::No * Holds if an additional step from `src` to `sink` through a call can be inferred from the * combination of a value-preserving step providing an alias between an input and the output * and a taint step from `src` to one the aliased nodes. For example, if we know that `f(a, b)` returns - * the exact value of `a` and also propagates taint from `b` to its result, then we also know that - * `a` is tainted after `f` completes, and vice versa. + * the exact value of `a` and also propagates taint from `b` to `a`, then we also know that + * the return value is tainted after `f` completes. */ private predicate composedValueAndTaintModelStep(ArgumentNode src, DataFlow::Node sink) { exists(Call call, ArgumentNode valueSource, DataFlow::PostUpdateNode valueSourcePost | @@ -76,16 +76,10 @@ private predicate composedValueAndTaintModelStep(ArgumentNode src, DataFlow::Nod valueSource.argumentOf(call, _) and src != valueSource and valueSourcePost.getPreUpdateNode() = valueSource and + // in-x -value-> out-y and in-z -taint-> in-x ==> in-z -taint-> out-y + localAdditionalBasicTaintStep(src, valueSourcePost) and DataFlow::localFlowStep(valueSource, DataFlow::exprNode(call)) and - ( - // in-x -value-> out-y and in-z -taint-> out-y ==> in-z -taint-> in-x - localAdditionalBasicTaintStep(src, DataFlow::exprNode(call)) and - sink = valueSourcePost - or - // in-x -value-> out-y and in-z -taint-> in-x ==> in-z -taint-> out-y - localAdditionalBasicTaintStep(src, valueSourcePost) and - sink = DataFlow::exprNode(call) - ) + sink = DataFlow::exprNode(call) ) } From 23d2f11840dc76cd7afadb2372ee1e547cd91187 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Tue, 23 Mar 2021 14:39:37 +0000 Subject: [PATCH 266/725] JS: Handle inheritance --- .../dataflow/internal/CallGraphs.qll | 24 ++++++++++++++-- .../TaintTracking/BasicTaintTracking.expected | 4 +++ .../TaintTracking/DataFlowTracking.expected | 4 +++ .../TaintTracking/getters-and-setters.js | 28 +++++++++++++++++++ 4 files changed, 58 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/CallGraphs.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/CallGraphs.qll index e37a4714fd8..0863cf8a895 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/CallGraphs.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/CallGraphs.qll @@ -163,16 +163,36 @@ module CallGraph { ) } + /** Holds if a property setter named `name` exists in a class. */ + private predicate isSetterName(string name) { + exists(any(DataFlow::ClassNode cls).getInstanceMember(name, DataFlow::MemberKind::setter())) + } + + /** + * Gets a property write that assigns to the property `name` on an instance of this class, + * and `name` is the name of a property setter. + */ + private DataFlow::PropWrite getAnInstanceMemberAssignment(DataFlow::ClassNode cls, string name) { + isSetterName(name) and // restrict size of predicate + result = cls.getAnInstanceReference().getAPropertyWrite(name) + or + exists(DataFlow::ClassNode subclass | + result = getAnInstanceMemberAssignment(subclass, name) and + not exists(subclass.getInstanceMember(name, DataFlow::MemberKind::setter())) and + cls = subclass.getADirectSuperClass() + ) + } + /** * Gets a getter or setter invoked as a result of the given property access. */ cached DataFlow::FunctionNode getAnAccessorCallee(DataFlow::PropRef ref) { exists(DataFlow::ClassNode cls, string name | - ref = cls.getAnInstanceReference().getAPropertyRead(name) and + ref = cls.getAnInstanceMemberAccess(name) and result = cls.getInstanceMember(name, DataFlow::MemberKind::getter()) or - ref = cls.getAnInstanceReference().getAPropertyWrite(name) and + ref = getAnInstanceMemberAssignment(cls, name) and result = cls.getInstanceMember(name, DataFlow::MemberKind::setter()) ) or diff --git a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected index 27800cd8e70..8b51848a56d 100644 --- a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected @@ -72,6 +72,10 @@ typeInferenceMismatch | getters-and-setters.js:47:23:47:30 | source() | getters-and-setters.js:45:14:45:16 | c.x | | getters-and-setters.js:60:20:60:27 | source() | getters-and-setters.js:66:10:66:14 | obj.x | | getters-and-setters.js:67:13:67:20 | source() | getters-and-setters.js:63:18:63:22 | value | +| getters-and-setters.js:79:20:79:27 | source() | getters-and-setters.js:88:10:88:18 | new C().x | +| getters-and-setters.js:79:20:79:27 | source() | getters-and-setters.js:92:14:92:16 | c.x | +| getters-and-setters.js:79:20:79:27 | source() | getters-and-setters.js:100:10:100:22 | getX(new C()) | +| getters-and-setters.js:89:17:89:24 | source() | getters-and-setters.js:82:18:82:22 | value | | importedReactComponent.jsx:4:40:4:47 | source() | exportedReactComponent.jsx:2:10:2:19 | props.text | | indexOf.js:4:11:4:18 | source() | indexOf.js:9:10:9:10 | x | | json-stringify.js:2:16:2:23 | source() | json-stringify.js:5:8:5:29 | JSON.st ... source) | diff --git a/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected b/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected index 3dd1a1ccf91..c269ebc1a18 100644 --- a/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected @@ -47,6 +47,10 @@ | getters-and-setters.js:47:23:47:30 | source() | getters-and-setters.js:45:14:45:16 | c.x | | getters-and-setters.js:60:20:60:27 | source() | getters-and-setters.js:66:10:66:14 | obj.x | | getters-and-setters.js:67:13:67:20 | source() | getters-and-setters.js:63:18:63:22 | value | +| getters-and-setters.js:79:20:79:27 | source() | getters-and-setters.js:88:10:88:18 | new C().x | +| getters-and-setters.js:79:20:79:27 | source() | getters-and-setters.js:92:14:92:16 | c.x | +| getters-and-setters.js:79:20:79:27 | source() | getters-and-setters.js:100:10:100:22 | getX(new C()) | +| getters-and-setters.js:89:17:89:24 | source() | getters-and-setters.js:82:18:82:22 | value | | indexOf.js:4:11:4:18 | source() | indexOf.js:9:10:9:10 | x | | indexOf.js:4:11:4:18 | source() | indexOf.js:13:10:13:10 | x | | nested-props.js:4:13:4:20 | source() | nested-props.js:5:10:5:14 | obj.x | diff --git a/javascript/ql/test/library-tests/TaintTracking/getters-and-setters.js b/javascript/ql/test/library-tests/TaintTracking/getters-and-setters.js index f61711e11ac..4fae44d083c 100644 --- a/javascript/ql/test/library-tests/TaintTracking/getters-and-setters.js +++ b/javascript/ql/test/library-tests/TaintTracking/getters-and-setters.js @@ -72,3 +72,31 @@ function testFlowThroughObjectLiteralAccessors() { indirection(obj); indirection(null); } + +function testFlowThroughSubclass() { + class Base { + get x() { + return source(); + } + set y(value) { + sink(value); // NOT OK + } + }; + class C extends Base { + } + + sink(new C().x); // NOT OK + new C().y = source(); + + function indirection(c) { + sink(c.x); // NOT OK + } + indirection(new C()); + indirection(null); + + function getX(c) { + return c.x; + } + sink(getX(new C())); // NOT OK - but not flagged + getX(null); +} From 24539dc0ee25780734519c1d628d586453876863 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 17 Mar 2021 10:51:45 +0000 Subject: [PATCH 267/725] JS: Remove unneeded default case in loadStoreStep --- javascript/ql/src/semmle/javascript/dataflow/Configuration.qll | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll index 9c4587d1414..d3d71a878a8 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll @@ -605,8 +605,7 @@ abstract class AdditionalFlowStep extends DataFlow::Node { predicate loadStoreStep( DataFlow::Node pred, DataFlow::Node succ, string loadProp, string storeProp ) { - loadProp = storeProp and - loadStoreStep(pred, succ, loadProp) + none() } } From e42f8439dea5f650244a7b55b02aaf6fab404419 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 17 Mar 2021 11:23:12 +0000 Subject: [PATCH 268/725] JS: Replace uses of AdditionalFlowStep with SharedFlowStep --- .../src/meta/analysis-quality/TaintSteps.ql | 12 +- .../javascript/dataflow/Configuration.qll | 133 ++++++++++++++++-- .../javascript/dataflow/TrackedNodes.qll | 2 +- .../dataflow/internal/FlowSteps.qll | 4 +- .../javascript/internal/CachedStages.qll | 2 +- .../dataflow/PrototypePollutingAssignment.qll | 4 +- 6 files changed, 131 insertions(+), 26 deletions(-) diff --git a/javascript/ql/src/meta/analysis-quality/TaintSteps.ql b/javascript/ql/src/meta/analysis-quality/TaintSteps.ql index 0d136b111b8..be16675f849 100644 --- a/javascript/ql/src/meta/analysis-quality/TaintSteps.ql +++ b/javascript/ql/src/meta/analysis-quality/TaintSteps.ql @@ -15,17 +15,17 @@ predicate relevantStep(DataFlow::Node pred, DataFlow::Node succ) { ( TaintTracking::sharedTaintStep(pred, succ) or - any(DataFlow::AdditionalFlowStep cfg).step(pred, succ) + DataFlow::SharedFlowStep::step(pred, succ) or - any(DataFlow::AdditionalFlowStep cfg).step(pred, succ, _, _) + DataFlow::SharedFlowStep::step(pred, succ, _, _) or - any(DataFlow::AdditionalFlowStep cfg).loadStep(pred, succ, _) + DataFlow::SharedFlowStep::loadStep(pred, succ, _) or - any(DataFlow::AdditionalFlowStep cfg).storeStep(pred, succ, _) + DataFlow::SharedFlowStep::storeStep(pred, succ, _) or - any(DataFlow::AdditionalFlowStep cfg).loadStoreStep(pred, succ, _, _) + DataFlow::SharedFlowStep::loadStoreStep(pred, succ, _, _) or - any(DataFlow::AdditionalFlowStep cfg).loadStoreStep(pred, succ, _) + DataFlow::SharedFlowStep::loadStoreStep(pred, succ, _) ) and not pred.getFile() instanceof IgnoredFile and not succ.getFile() instanceof IgnoredFile diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll index d3d71a878a8..77ea2b8d08a 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll @@ -635,28 +635,133 @@ class SharedFlowStep extends Unit { ) { none() } + + /** + * Holds if `pred` should be stored in the object `succ` under the property `prop`. + * The object `succ` must be a `DataFlow::SourceNode` for the object wherein the value is stored. + */ + predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { none() } + + /** + * Holds if the property `prop` of the object `pred` should be loaded into `succ`. + */ + predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() } + + /** + * Holds if the property `prop` should be copied from the object `pred` to the object `succ`. + */ + predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() } + + /** + * Holds if the property `loadProp` should be copied from the object `pred` to the property `storeProp` of object `succ`. + */ + predicate loadStoreStep( + DataFlow::Node pred, DataFlow::Node succ, string loadProp, string storeProp + ) { + none() + } } /** - * Contributes subclasses of `SharedFlowStep` to `AdditionalFlowStep`. - * - * This is a placeholder until we migrate to the `SharedFlowStep` class and deprecate `AdditionalFlowStep`. + * Contains predicates for accessing the steps contributed by `SharedFlowStep` subclasses. */ -private class SharedStepAsAdditionalFlowStep extends AdditionalFlowStep { - SharedStepAsAdditionalFlowStep() { - any(SharedFlowStep st).step(_, this) or - any(SharedFlowStep st).step(_, this, _, _) +cached +module SharedFlowStep { + cached + private module Internal { + // Forces this to be part of the `FlowSteps` stage. + // We use a public predicate in a private module to avoid warnings about this being unused. + cached + predicate forceStage() { Stages::FlowSteps::ref() } } + /** + * Holds if `pred` → `succ` should be considered a data flow edge. + */ + cached + predicate step(DataFlow::Node pred, DataFlow::Node succ) { + any(SharedFlowStep s).step(pred, succ) + } + + /** + * Holds if `pred` → `succ` should be considered a data flow edge + * transforming values with label `predlbl` to have label `succlbl`. + */ + cached + predicate step( + DataFlow::Node pred, DataFlow::Node succ, DataFlow::FlowLabel predlbl, + DataFlow::FlowLabel succlbl + ) { + any(SharedFlowStep s).step(pred, succ, predlbl, succlbl) + } + + /** + * Holds if `pred` should be stored in the object `succ` under the property `prop`. + * The object `succ` must be a `DataFlow::SourceNode` for the object wherein the value is stored. + */ + cached + predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { + any(SharedFlowStep s).storeStep(pred, succ, prop) + } + + /** + * Holds if the property `prop` of the object `pred` should be loaded into `succ`. + */ + cached + predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { + any(SharedFlowStep s).loadStep(pred, succ, prop) + } + + /** + * Holds if the property `prop` should be copied from the object `pred` to the object `succ`. + */ + cached + predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { + any(SharedFlowStep s).loadStoreStep(pred, succ, prop) + } + + /** + * Holds if the property `loadProp` should be copied from the object `pred` to the property `storeProp` of object `succ`. + */ + cached + predicate loadStoreStep( + DataFlow::Node pred, DataFlow::Node succ, string loadProp, string storeProp + ) { + any(SharedFlowStep s).loadStoreStep(pred, succ, loadProp, storeProp) + } +} + +/** + * Contributes subclasses of `AdditionalFlowStep` to `SharedFlowStep`. + */ +private class AdditionalFlowStepAsSharedStep extends SharedFlowStep { override predicate step(DataFlow::Node pred, DataFlow::Node succ) { - any(SharedFlowStep st).step(pred, succ) and succ = this + any(AdditionalFlowStep s).step(pred, succ) } override predicate step( DataFlow::Node pred, DataFlow::Node succ, DataFlow::FlowLabel predlbl, DataFlow::FlowLabel succlbl ) { - any(SharedFlowStep st).step(pred, succ, predlbl, succlbl) and succ = this + any(AdditionalFlowStep s).step(pred, succ, predlbl, succlbl) + } + + override predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { + any(AdditionalFlowStep s).storeStep(pred, succ, prop) + } + + override predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { + any(AdditionalFlowStep s).loadStep(pred, succ, prop) + } + + override predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { + any(AdditionalFlowStep s).loadStoreStep(pred, succ, prop) + } + + override predicate loadStoreStep( + DataFlow::Node pred, DataFlow::Node succ, string loadProp, string storeProp + ) { + any(AdditionalFlowStep s).loadStoreStep(pred, succ, loadProp, storeProp) } } @@ -665,7 +770,7 @@ private class SharedStepAsAdditionalFlowStep extends AdditionalFlowStep { * * A pseudo-property represents the location where some value is stored in an object. * - * For use with load/store steps in `DataFlow::AdditionalFlowStep` and TypeTracking. + * For use with load/store steps in `DataFlow::SharedFlowStep` and TypeTracking. */ module PseudoProperties { bindingset[s] @@ -1201,7 +1306,7 @@ private predicate reachesReturn( private predicate isAdditionalLoadStep( DataFlow::Node pred, DataFlow::Node succ, string prop, DataFlow::Configuration cfg ) { - any(AdditionalFlowStep s).loadStep(pred, succ, prop) + SharedFlowStep::loadStep(pred, succ, prop) or cfg.isAdditionalLoadStep(pred, succ, prop) } @@ -1212,7 +1317,7 @@ private predicate isAdditionalLoadStep( private predicate isAdditionalStoreStep( DataFlow::Node pred, DataFlow::Node succ, string prop, DataFlow::Configuration cfg ) { - any(AdditionalFlowStep s).storeStep(pred, succ, prop) + SharedFlowStep::storeStep(pred, succ, prop) or cfg.isAdditionalStoreStep(pred, succ, prop) } @@ -1224,13 +1329,13 @@ private predicate isAdditionalLoadStoreStep( DataFlow::Node pred, DataFlow::Node succ, string loadProp, string storeProp, DataFlow::Configuration cfg ) { - any(AdditionalFlowStep s).loadStoreStep(pred, succ, loadProp, storeProp) + SharedFlowStep::loadStoreStep(pred, succ, loadProp, storeProp) or cfg.isAdditionalLoadStoreStep(pred, succ, loadProp, storeProp) or loadProp = storeProp and ( - any(AdditionalFlowStep s).loadStoreStep(pred, succ, loadProp) + SharedFlowStep::loadStoreStep(pred, succ, loadProp) or cfg.isAdditionalLoadStoreStep(pred, succ, loadProp) ) diff --git a/javascript/ql/src/semmle/javascript/dataflow/TrackedNodes.qll b/javascript/ql/src/semmle/javascript/dataflow/TrackedNodes.qll index 1080d5f4dc6..28d9a432341 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TrackedNodes.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TrackedNodes.qll @@ -102,7 +102,7 @@ private module NodeTracking { predicate localFlowStep(DataFlow::Node pred, DataFlow::Node succ) { pred = succ.getAPredecessor() or - any(DataFlow::AdditionalFlowStep afs).step(pred, succ) + DataFlow::SharedFlowStep::step(pred, succ) or localExceptionStep(pred, succ) } diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll index 4b9158d3575..0c0f242fb91 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll @@ -39,9 +39,9 @@ predicate localFlowStep( ) { pred = succ.getAPredecessor() and predlbl = succlbl or - any(DataFlow::AdditionalFlowStep afs).step(pred, succ) and predlbl = succlbl + DataFlow::SharedFlowStep::step(pred, succ) and predlbl = succlbl or - any(DataFlow::AdditionalFlowStep afs).step(pred, succ, predlbl, succlbl) + DataFlow::SharedFlowStep::step(pred, succ, predlbl, succlbl) or exists(boolean vp | configuration.isAdditionalFlowStep(pred, succ, vp) | vp = true and diff --git a/javascript/ql/src/semmle/javascript/internal/CachedStages.qll b/javascript/ql/src/semmle/javascript/internal/CachedStages.qll index b5a2a5ac3ef..b56a1324e77 100644 --- a/javascript/ql/src/semmle/javascript/internal/CachedStages.qll +++ b/javascript/ql/src/semmle/javascript/internal/CachedStages.qll @@ -219,7 +219,7 @@ module Stages { or AccessPath::DominatingPaths::hasDominatingWrite(_) or - any(DataFlow::AdditionalFlowStep s).step(_, _) + DataFlow::SharedFlowStep::step(_, _) } } diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/PrototypePollutingAssignment.qll b/javascript/ql/src/semmle/javascript/security/dataflow/PrototypePollutingAssignment.qll index 85dde941e37..c6fc119190e 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/PrototypePollutingAssignment.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/PrototypePollutingAssignment.qll @@ -100,10 +100,10 @@ module PrototypePollutingAssignment { // users wouldn't bother to call Object.create in that case. result = DataFlow::globalVarRef("Object").getAMemberCall("create") or - // Allow use of AdditionalFlowSteps to track a bit further + // Allow use of SharedFlowSteps to track a bit further exists(DataFlow::Node mid | prototypeLessObject(t.continue()).flowsTo(mid) and - any(DataFlow::AdditionalFlowStep s).step(mid, result) + DataFlow::SharedFlowStep::step(mid, result) ) or exists(DataFlow::TypeTracker t2 | result = prototypeLessObject(t2).track(t2, t)) From 151420fd0f1c4aa54fff628a750292f96b12c420 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 17 Mar 2021 11:31:57 +0000 Subject: [PATCH 269/725] JS: ArrayFrom --- javascript/ql/src/semmle/javascript/Arrays.qll | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Arrays.qll b/javascript/ql/src/semmle/javascript/Arrays.qll index a61ff57475e..b37b3404344 100644 --- a/javascript/ql/src/semmle/javascript/Arrays.qll +++ b/javascript/ql/src/semmle/javascript/Arrays.qll @@ -84,16 +84,17 @@ private module ArrayDataFlow { * A step modelling the creation of an Array using the `Array.from(x)` method. * The step copies the elements of the argument (set, array, or iterator elements) into the resulting array. */ - private class ArrayFrom extends DataFlow::AdditionalFlowStep, DataFlow::CallNode { - ArrayFrom() { this = DataFlow::globalVarRef("Array").getAMemberCall("from") } - + private class ArrayFrom extends DataFlow::SharedFlowStep { override predicate loadStoreStep( DataFlow::Node pred, DataFlow::Node succ, string fromProp, string toProp ) { - pred = this.getArgument(0) and - succ = this and - fromProp = arrayLikeElement() and - toProp = arrayElement() + exists(DataFlow::CallNode call | + call = DataFlow::globalVarRef("Array").getAMemberCall("from") and + pred = call.getArgument(0) and + succ = call and + fromProp = arrayLikeElement() and + toProp = arrayElement() + ) } } From 1c815f12da9ac4b1544429b8a02c66ff8f0fcea4 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 17 Mar 2021 11:35:37 +0000 Subject: [PATCH 270/725] JS: ArrayCopySpread --- .../ql/src/semmle/javascript/Arrays.qll | 29 +++++++------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Arrays.qll b/javascript/ql/src/semmle/javascript/Arrays.qll index b37b3404344..b17b3ba1862 100644 --- a/javascript/ql/src/semmle/javascript/Arrays.qll +++ b/javascript/ql/src/semmle/javascript/Arrays.qll @@ -104,28 +104,21 @@ private module ArrayDataFlow { * * Such a step can occur both with the `push` and `unshift` methods, or when creating a new array. */ - private class ArrayCopySpread extends DataFlow::AdditionalFlowStep { - DataFlow::Node spreadArgument; // the spread argument containing the elements to be copied. - DataFlow::Node base; // the object where the elements should be copied to. - - ArrayCopySpread() { - exists(DataFlow::MethodCallNode mcn | mcn = this | - mcn.getMethodName() = ["push", "unshift"] and - spreadArgument = mcn.getASpreadArgument() and - base = mcn.getReceiver().getALocalSource() - ) - or - spreadArgument = this.(DataFlow::ArrayCreationNode).getASpreadArgument() and - base = this - } - + private class ArrayCopySpread extends DataFlow::SharedFlowStep { override predicate loadStoreStep( DataFlow::Node pred, DataFlow::Node succ, string fromProp, string toProp ) { - pred = spreadArgument and - succ = base and fromProp = arrayLikeElement() and - toProp = arrayElement() + toProp = arrayElement() and + ( + exists(DataFlow::MethodCallNode mcn | + mcn.getMethodName() = ["push", "unshift"] and + pred = mcn.getASpreadArgument() and + succ = mcn.getReceiver().getALocalSource() + ) + or + pred = succ.(DataFlow::ArrayCreationNode).getASpreadArgument() + ) } } From b7ae62c3a38aa6222965bd088297b449013fd69a Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 17 Mar 2021 11:37:13 +0000 Subject: [PATCH 271/725] JS: ArrayAppendStep --- javascript/ql/src/semmle/javascript/Arrays.qll | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Arrays.qll b/javascript/ql/src/semmle/javascript/Arrays.qll index b17b3ba1862..34d900766c9 100644 --- a/javascript/ql/src/semmle/javascript/Arrays.qll +++ b/javascript/ql/src/semmle/javascript/Arrays.qll @@ -125,16 +125,14 @@ private module ArrayDataFlow { /** * A step for storing an element on an array using `arr.push(e)` or `arr.unshift(e)`. */ - private class ArrayAppendStep extends DataFlow::AdditionalFlowStep, DataFlow::MethodCallNode { - ArrayAppendStep() { - this.getMethodName() = "push" or - this.getMethodName() = "unshift" - } - + private class ArrayAppendStep extends DataFlow::SharedFlowStep { override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) { prop = arrayElement() and - element = this.getAnArgument() and - obj.getAMethodCall() = this + exists(DataFlow::MethodCallNode call | + call.getMethodName() = ["push", "unshift"] and + element = call.getAnArgument() and + obj.getAMethodCall() = call + ) } } From 36a813449069e37dde49dc6cf4582b6f1f4d3bd0 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 17 Mar 2021 11:40:05 +0000 Subject: [PATCH 272/725] JS: ArrayIndexingAccess --- .../ql/src/semmle/javascript/Arrays.qll | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Arrays.qll b/javascript/ql/src/semmle/javascript/Arrays.qll index 34d900766c9..9f6f8b6eb1b 100644 --- a/javascript/ql/src/semmle/javascript/Arrays.qll +++ b/javascript/ql/src/semmle/javascript/Arrays.qll @@ -137,13 +137,12 @@ private module ArrayDataFlow { } /** - * A step for reading/writing an element from an array inside a for-loop. - * E.g. a read from `foo[i]` to `bar` in `for(var i = 0; i < arr.length; i++) {bar = foo[i]}`. + * A node that reads or writes an element from an array inside a for-loop. */ - private class ArrayIndexingStep extends DataFlow::AdditionalFlowStep, DataFlow::Node { + private class ArrayIndexingAccess extends DataFlow::Node { DataFlow::PropRef read; - ArrayIndexingStep() { + ArrayIndexingAccess() { read = this and TTNumber() = unique(InferredType type | type = read.getPropertyNameExpr().flow().analyze().getAType()) and @@ -154,17 +153,27 @@ private module ArrayDataFlow { i.getVariable().getADefinition().(VariableDeclarator).getDeclStmt() = init ) } + } + /** + * A step for reading/writing an element from an array inside a for-loop. + * E.g. a read from `foo[i]` to `bar` in `for(var i = 0; i < arr.length; i++) {bar = foo[i]}`. + */ + private class ArrayIndexingStep extends DataFlow::SharedFlowStep { override predicate loadStep(DataFlow::Node obj, DataFlow::Node element, string prop) { - prop = arrayElement() and - obj = this.(DataFlow::PropRead).getBase() and - element = this + exists(ArrayIndexingAccess access | + prop = arrayElement() and + obj = access.(DataFlow::PropRead).getBase() and + element = access + ) } override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) { - prop = arrayElement() and - element = this.(DataFlow::PropWrite).getRhs() and - this = obj.getAPropertyWrite() + exists(ArrayIndexingAccess access | + prop = arrayElement() and + element = access.(DataFlow::PropWrite).getRhs() and + access = obj.getAPropertyWrite() + ) } } From 5bfd2ad07f703956f4557a02c5592ab2f43aac04 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 17 Mar 2021 11:41:08 +0000 Subject: [PATCH 273/725] JS: ArrayPopStep --- javascript/ql/src/semmle/javascript/Arrays.qll | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Arrays.qll b/javascript/ql/src/semmle/javascript/Arrays.qll index 9f6f8b6eb1b..9f4c812ea37 100644 --- a/javascript/ql/src/semmle/javascript/Arrays.qll +++ b/javascript/ql/src/semmle/javascript/Arrays.qll @@ -181,16 +181,14 @@ private module ArrayDataFlow { * A step for retrieving an element from an array using `.pop()` or `.shift()`. * E.g. `array.pop()`. */ - private class ArrayPopStep extends DataFlow::AdditionalFlowStep, DataFlow::MethodCallNode { - ArrayPopStep() { - getMethodName() = "pop" or - getMethodName() = "shift" - } - + private class ArrayPopStep extends DataFlow::SharedFlowStep { override predicate loadStep(DataFlow::Node obj, DataFlow::Node element, string prop) { - prop = arrayElement() and - obj = this.getReceiver() and - element = this + exists(DataFlow::MethodCallNode call | + call.getMethodName() = ["pop", "shift"] and + prop = arrayElement() and + obj = call.getReceiver() and + element = call + ) } } From 5d6c6b4b9bb9e4adba2c39af151fec09539f503a Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 17 Mar 2021 11:41:55 +0000 Subject: [PATCH 274/725] JS: ArrayCreationStep --- javascript/ql/src/semmle/javascript/Arrays.qll | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Arrays.qll b/javascript/ql/src/semmle/javascript/Arrays.qll index 9f4c812ea37..fe3e5749273 100644 --- a/javascript/ql/src/semmle/javascript/Arrays.qll +++ b/javascript/ql/src/semmle/javascript/Arrays.qll @@ -234,12 +234,12 @@ private module ArrayDataFlow { /** * A step for creating an array and storing the elements in the array. */ - private class ArrayCreationStep extends DataFlow::AdditionalFlowStep, DataFlow::ArrayCreationNode { + private class ArrayCreationStep extends DataFlow::SharedFlowStep { override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) { - exists(int i | - element = this.getElement(i) and - obj = this and - if this = any(PromiseAllCreation c).getArrayNode() + exists(DataFlow::ArrayCreationNode array, int i | + element = array.getElement(i) and + obj = array and + if array = any(PromiseAllCreation c).getArrayNode() then prop = arrayElement(i) else prop = arrayElement() ) From 17d1e6d614f584ebe5ca531c860cdf15c2b07bc9 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 17 Mar 2021 11:42:49 +0000 Subject: [PATCH 275/725] JS: ArraySpliceStep --- javascript/ql/src/semmle/javascript/Arrays.qll | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Arrays.qll b/javascript/ql/src/semmle/javascript/Arrays.qll index fe3e5749273..a89abe83567 100644 --- a/javascript/ql/src/semmle/javascript/Arrays.qll +++ b/javascript/ql/src/semmle/javascript/Arrays.qll @@ -250,13 +250,14 @@ private module ArrayDataFlow { * A step modelling that `splice` can insert elements into an array. * For example in `array.splice(i, del, e)`: if `e` is tainted, then so is `array */ - private class ArraySpliceStep extends DataFlow::AdditionalFlowStep, DataFlow::MethodCallNode { - ArraySpliceStep() { this.getMethodName() = "splice" } - + private class ArraySpliceStep extends DataFlow::SharedFlowStep { override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) { - prop = arrayElement() and - element = getArgument(2) and - this = obj.getAMethodCall() + exists(DataFlow::MethodCallNode call | + call.getMethodName() = "splice" and + prop = arrayElement() and + element = call.getArgument(2) and + call = obj.getAMethodCall() + ) } } From 633152940ce7415e831b95e2d8c3f56bd0e19063 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 17 Mar 2021 11:43:37 +0000 Subject: [PATCH 276/725] JS: ArrayConcatStep --- javascript/ql/src/semmle/javascript/Arrays.qll | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Arrays.qll b/javascript/ql/src/semmle/javascript/Arrays.qll index a89abe83567..31ab537f32e 100644 --- a/javascript/ql/src/semmle/javascript/Arrays.qll +++ b/javascript/ql/src/semmle/javascript/Arrays.qll @@ -265,13 +265,14 @@ private module ArrayDataFlow { * A step for modelling `concat`. * For example in `e = arr1.concat(arr2, arr3)`: if any of the `arr` is tainted, then so is `e`. */ - private class ArrayConcatStep extends DataFlow::AdditionalFlowStep, DataFlow::MethodCallNode { - ArrayConcatStep() { this.getMethodName() = "concat" } - + private class ArrayConcatStep extends DataFlow::SharedFlowStep { override predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { - prop = arrayElement() and - (pred = this.getReceiver() or pred = this.getAnArgument()) and - succ = this + exists(DataFlow::MethodCallNode call | + call.getMethodName() = "concat" and + prop = arrayElement() and + (pred = call.getReceiver() or pred = call.getAnArgument()) and + succ = call + ) } } From f84a05526d21a1a1bd6a1b067778b548bb2e5f12 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 17 Mar 2021 11:44:51 +0000 Subject: [PATCH 277/725] JS: ArraySliceStep --- javascript/ql/src/semmle/javascript/Arrays.qll | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Arrays.qll b/javascript/ql/src/semmle/javascript/Arrays.qll index 31ab537f32e..693cac6bf47 100644 --- a/javascript/ql/src/semmle/javascript/Arrays.qll +++ b/javascript/ql/src/semmle/javascript/Arrays.qll @@ -279,17 +279,14 @@ private module ArrayDataFlow { /** * A step for modelling that elements from an array `arr` also appear in the result from calling `slice`/`splice`/`filter`. */ - private class ArraySliceStep extends DataFlow::AdditionalFlowStep, DataFlow::MethodCallNode { - ArraySliceStep() { - this.getMethodName() = "slice" or - this.getMethodName() = "splice" or - this.getMethodName() = "filter" - } - + private class ArraySliceStep extends DataFlow::SharedFlowStep { override predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { - prop = arrayElement() and - pred = this.getReceiver() and - succ = this + exists(DataFlow::MethodCallNode call | + call.getMethodName() = ["slice", "splice", "filter"] and + prop = arrayElement() and + pred = call.getReceiver() and + succ = call + ) } } From 8f750d4ad33ce7c70ea59e265438eccdc2727ef1 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 17 Mar 2021 11:59:14 +0000 Subject: [PATCH 278/725] JS: UrlSearchParamsTaintStep --- .../javascript/dataflow/TaintTracking.qll | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll index de41392cada..805f3a832a6 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll @@ -828,13 +828,13 @@ module TaintTracking { /** * A taint propagating data flow edge arising from URL parameter parsing. */ - private class UrlSearchParamsTaintStep extends DataFlow::AdditionalFlowStep, DataFlow::ValueNode { + private class UrlSearchParamsTaintStep extends DataFlow::SharedFlowStep { /** * Holds if `succ` is a `URLSearchParams` providing access to the * parameters encoded in `pred`. */ override predicate step(DataFlow::Node pred, DataFlow::Node succ) { - isUrlSearchParams(succ, pred) and succ = this + isUrlSearchParams(succ, pred) } /** @@ -847,17 +847,14 @@ module TaintTracking { * which can be accessed using a `get` or `getAll` call. (See getableUrlPseudoProperty()) */ override predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { - succ = this and - ( - prop = ["searchParams", "hash", "search", hiddenUrlPseudoProperty()] and - exists(DataFlow::NewNode newUrl | succ = newUrl | - newUrl = DataFlow::globalVarRef("URL").getAnInstantiation() and - pred = newUrl.getArgument(0) - ) - or - prop = getableUrlPseudoProperty() and - isUrlSearchParams(succ, pred) + prop = ["searchParams", "hash", "search", hiddenUrlPseudoProperty()] and + exists(DataFlow::NewNode newUrl | succ = newUrl | + newUrl = DataFlow::globalVarRef("URL").getAnInstantiation() and + pred = newUrl.getArgument(0) ) + or + prop = getableUrlPseudoProperty() and + isUrlSearchParams(succ, pred) } /** @@ -869,7 +866,6 @@ module TaintTracking { override predicate loadStoreStep( DataFlow::Node pred, DataFlow::Node succ, string loadProp, string storeProp ) { - succ = this and loadProp = hiddenUrlPseudoProperty() and storeProp = getableUrlPseudoProperty() and exists(DataFlow::PropRead read | read = succ | @@ -884,7 +880,6 @@ module TaintTracking { * This step is used to load the value stored in the pseudo-property `getableUrlPseudoProperty()`. */ override predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { - succ = this and prop = getableUrlPseudoProperty() and // this is a call to `get` or `getAll` on a `URLSearchParams` object exists(string m, DataFlow::MethodCallNode call | call = succ | From b8049f19e24fcd8f7bebcfc218371278f4986160 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 17 Mar 2021 12:02:23 +0000 Subject: [PATCH 279/725] JS: SharedFlowStepFromPreCallGraph --- .../dataflow/internal/PreCallGraphStep.qll | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/PreCallGraphStep.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/PreCallGraphStep.qll index 5b800f3f717..c0dd53c6e7b 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/PreCallGraphStep.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/PreCallGraphStep.qll @@ -89,26 +89,21 @@ private class NodeWithPreCallGraphStep extends DataFlow::Node { } } -private class AdditionalFlowStepFromPreCallGraph extends NodeWithPreCallGraphStep, - DataFlow::AdditionalFlowStep { +private class SharedFlowStepFromPreCallGraph extends DataFlow::SharedFlowStep { override predicate step(DataFlow::Node pred, DataFlow::Node succ) { - pred = this and - PreCallGraphStep::step(this, succ) + PreCallGraphStep::step(pred, succ) } override predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { - pred = this and - PreCallGraphStep::storeStep(this, succ, prop) + PreCallGraphStep::storeStep(pred, succ, prop) } override predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { - pred = this and - PreCallGraphStep::loadStep(this, succ, prop) + PreCallGraphStep::loadStep(pred, succ, prop) } override predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { - pred = this and - PreCallGraphStep::loadStoreStep(this, succ, prop) + PreCallGraphStep::loadStoreStep(pred, succ, prop) } } From 3a2f87f0a7718db60ed35e0bacb535652449c652 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 17 Mar 2021 12:13:28 +0000 Subject: [PATCH 280/725] JS: AdditionalTypeTrackingStep -> SharedTypeTrackingStep --- .../javascript/dataflow/TypeTracking.qll | 91 ++++++++++++++++++- .../dataflow/internal/PreCallGraphStep.qll | 29 ++---- .../dataflow/internal/StepSummary.qll | 8 +- 3 files changed, 99 insertions(+), 29 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/TypeTracking.qll b/javascript/ql/src/semmle/javascript/dataflow/TypeTracking.qll index 0996fc5c0ac..0dc7921f0db 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TypeTracking.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TypeTracking.qll @@ -9,6 +9,7 @@ private import javascript private import internal.FlowSteps private import internal.StepSummary +private import internal.Unit private import semmle.javascript.internal.CachedStages private newtype TTypeTracker = MkTypeTracker(Boolean hasCall, OptionalPropertyName prop) @@ -330,14 +331,14 @@ module TypeBackTracker { /** * A data flow edge that should be followed by type tracking. * - * Unlike `AdditionalFlowStep`, this type of edge does not affect + * Unlike `SharedFlowStep`, this type of edge does not affect * the local data flow graph, and is not used by data-flow configurations. * * Note: For performance reasons, all subclasses of this class should be part * of the standard library. For query-specific steps, consider including the * custom steps in the type-tracking predicate itself. */ -abstract class AdditionalTypeTrackingStep extends DataFlow::Node { +class SharedTypeTrackingStep extends Unit { /** * Holds if type-tracking should step from `pred` to `succ`. */ @@ -358,3 +359,89 @@ abstract class AdditionalTypeTrackingStep extends DataFlow::Node { */ predicate loadStoreStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { none() } } + +/** Provides access to the steps contributed by subclasses of `SharedTypeTrackingStep`. */ +module SharedTypeTrackingStep { + /** + * Holds if type-tracking should step from `pred` to `succ`. + */ + predicate step(DataFlow::Node pred, DataFlow::Node succ) { + any(SharedTypeTrackingStep s).step(pred, succ) + } + + /** + * Holds if type-tracking should step from `pred` into the `prop` property of `succ`. + */ + predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { + any(SharedTypeTrackingStep s).storeStep(pred, succ, prop) + } + + /** + * Holds if type-tracking should step from the `prop` property of `pred` to `succ`. + */ + predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { + any(SharedTypeTrackingStep s).loadStep(pred, succ, prop) + } + + /** + * Holds if type-tracking should step from the `prop` property of `pred` to the same property in `succ`. + */ + predicate loadStoreStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { + any(SharedTypeTrackingStep s).loadStoreStep(pred, succ, prop) + } +} + +/** + * DEPRECATED. Use `SharedTypeTrackingStep` instead. + * + * A data flow edge that should be followed by type tracking. + * + * Unlike `AdditionalFlowStep`, this type of edge does not affect + * the local data flow graph, and is not used by data-flow configurations. + * + * Note: For performance reasons, all subclasses of this class should be part + * of the standard library. For query-specific steps, consider including the + * custom steps in the type-tracking predicate itself. + */ +deprecated class AdditionalTypeTrackingStep = LegacyTypeTrackingStep; + +// Internal version of AdditionalTypeTrackingStep that we can reference without deprecation warnings. +abstract private class LegacyTypeTrackingStep extends DataFlow::Node { + /** + * Holds if type-tracking should step from `pred` to `succ`. + */ + predicate step(DataFlow::Node pred, DataFlow::Node succ) { none() } + + /** + * Holds if type-tracking should step from `pred` into the `prop` property of `succ`. + */ + predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { none() } + + /** + * Holds if type-tracking should step from the `prop` property of `pred` to `succ`. + */ + predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() } + + /** + * Holds if type-tracking should step from the `prop` property of `pred` to the same property in `succ`. + */ + predicate loadStoreStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { none() } +} + +private class LegacyStepAsSharedTypeTrackingStep extends SharedTypeTrackingStep { + override predicate step(DataFlow::Node pred, DataFlow::Node succ) { + any(LegacyTypeTrackingStep s).step(pred, succ) + } + + override predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { + any(LegacyTypeTrackingStep s).storeStep(pred, succ, prop) + } + + override predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { + any(LegacyTypeTrackingStep s).loadStep(pred, succ, prop) + } + + override predicate loadStoreStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { + any(LegacyTypeTrackingStep s).loadStoreStep(pred, succ, prop) + } +} diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/PreCallGraphStep.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/PreCallGraphStep.qll index c0dd53c6e7b..520fa376b22 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/PreCallGraphStep.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/PreCallGraphStep.qll @@ -16,7 +16,7 @@ private class Unit extends TUnit { * Internal extension point for adding flow edges prior to call graph construction * and type tracking. * - * Steps added here will be added to both `AdditionalFlowStep` and `AdditionalTypeTrackingStep`. + * Steps added here will be added to both `SharedFlowStep` and `SharedTypeTrackingStep`. * * Contributing steps that rely on type tracking will lead to negative recursion. */ @@ -77,18 +77,6 @@ module PreCallGraphStep { } } -private class NodeWithPreCallGraphStep extends DataFlow::Node { - NodeWithPreCallGraphStep() { - PreCallGraphStep::step(this, _) - or - PreCallGraphStep::storeStep(this, _, _) - or - PreCallGraphStep::loadStep(this, _, _) - or - PreCallGraphStep::loadStoreStep(this, _, _) - } -} - private class SharedFlowStepFromPreCallGraph extends DataFlow::SharedFlowStep { override predicate step(DataFlow::Node pred, DataFlow::Node succ) { PreCallGraphStep::step(pred, succ) @@ -107,25 +95,20 @@ private class SharedFlowStepFromPreCallGraph extends DataFlow::SharedFlowStep { } } -private class AdditionalTypeTrackingStepFromPreCallGraph extends NodeWithPreCallGraphStep, - DataFlow::AdditionalTypeTrackingStep { +private class SharedTypeTrackingStepFromPreCallGraph extends DataFlow::SharedTypeTrackingStep { override predicate step(DataFlow::Node pred, DataFlow::Node succ) { - pred = this and - PreCallGraphStep::step(this, succ) + PreCallGraphStep::step(pred, succ) } override predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { - pred = this and - PreCallGraphStep::storeStep(this, succ, prop) + PreCallGraphStep::storeStep(pred, succ, prop) } override predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { - pred = this and - PreCallGraphStep::loadStep(this, succ, prop) + PreCallGraphStep::loadStep(pred, succ, prop) } override predicate loadStoreStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { - pred = this and - PreCallGraphStep::loadStoreStep(this, succ, prop) + PreCallGraphStep::loadStoreStep(pred, succ, prop) } } diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll index 13450438e52..fb859fd3d7e 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll @@ -111,17 +111,17 @@ module StepSummary { basicLoadStep(pred, succ, prop) and summary = LoadStep(prop) or - any(AdditionalTypeTrackingStep st).storeStep(pred, succ, prop) and + SharedTypeTrackingStep::storeStep(pred, succ, prop) and summary = StoreStep(prop) or - any(AdditionalTypeTrackingStep st).loadStep(pred, succ, prop) and + SharedTypeTrackingStep::loadStep(pred, succ, prop) and summary = LoadStep(prop) or - any(AdditionalTypeTrackingStep st).loadStoreStep(pred, succ, prop) and + SharedTypeTrackingStep::loadStoreStep(pred, succ, prop) and summary = CopyStep(prop) ) or - any(AdditionalTypeTrackingStep st).step(pred, succ) and + SharedTypeTrackingStep::step(pred, succ) and summary = LevelStep() or // Store to global access path From 5fe3c1a0a969c252e7a83c32756295b085d24bb7 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 17 Mar 2021 12:19:57 +0000 Subject: [PATCH 281/725] JS: EventEmitterTaintStep --- .../javascript/frameworks/EventEmitter.qll | 30 ++++++++----------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/EventEmitter.qll b/javascript/ql/src/semmle/javascript/frameworks/EventEmitter.qll index 4db64ad0ab7..6a8e556f659 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/EventEmitter.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/EventEmitter.qll @@ -196,24 +196,20 @@ module EventDispatch { /** * A taint-step that models data-flow between event handlers and event dispatchers. */ -private class EventEmitterTaintStep extends DataFlow::AdditionalFlowStep { - EventRegistration reg; - EventDispatch dispatch; - - EventEmitterTaintStep() { - this = dispatch and - reg = dispatch.getAReceiver() and - not dispatch.getChannel() != reg.getChannel() - } - +private class EventEmitterTaintStep extends DataFlow::SharedFlowStep { override predicate step(DataFlow::Node pred, DataFlow::Node succ) { - exists(int i | i >= 0 | - pred = dispatch.getSentItem(i) and - succ = reg.getReceivedItem(i) + exists(EventRegistration reg, EventDispatch dispatch | + reg = dispatch.getAReceiver() and + not dispatch.getChannel() != reg.getChannel() + | + exists(int i | i >= 0 | + pred = dispatch.getSentItem(i) and + succ = reg.getReceivedItem(i) + ) + or + dispatch = reg.getAReturnDispatch() and + pred = reg.getAReturnedValue() and + succ = dispatch ) - or - dispatch = reg.getAReturnDispatch() and - pred = reg.getAReturnedValue() and - succ = dispatch } } From 3e5413608674c3877ca745a316074839d416554b Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 17 Mar 2021 12:20:39 +0000 Subject: [PATCH 282/725] JS: Rename EventEmitterFlowStep to reflect reality --- .../ql/src/semmle/javascript/frameworks/EventEmitter.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/EventEmitter.qll b/javascript/ql/src/semmle/javascript/frameworks/EventEmitter.qll index 6a8e556f659..f044d69524d 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/EventEmitter.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/EventEmitter.qll @@ -194,9 +194,9 @@ module EventDispatch { } /** - * A taint-step that models data-flow between event handlers and event dispatchers. + * A flow-step that models data-flow between event handlers and event dispatchers. */ -private class EventEmitterTaintStep extends DataFlow::SharedFlowStep { +private class EventEmitterFlowStep extends DataFlow::SharedFlowStep { override predicate step(DataFlow::Node pred, DataFlow::Node succ) { exists(EventRegistration reg, EventDispatch dispatch | reg = dispatch.getAReceiver() and From 5051f105869f285dcd2bbd9406612c334e5203ed Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 17 Mar 2021 12:26:47 +0000 Subject: [PATCH 283/725] JS: ImmutableConstructionStep --- .../semmle/javascript/frameworks/Immutable.qll | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll b/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll index 16cf7de2cc0..c039199bbd4 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll @@ -164,22 +164,15 @@ private module Immutable { /** * A dataflow step for an immutable collection. */ - class ImmutableConstructionStep extends DataFlow::AdditionalFlowStep { - ImmutableConstructionStep() { this = [loadStep(_, _), storeStep(_, _), step(_)] } - + class ImmutableConstructionStep extends DataFlow::SharedFlowStep { override predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { - this = loadStep(pred, prop) and - succ = this + succ = loadStep(pred, prop) } override predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { - this = storeStep(pred, prop) and - succ = this + succ = storeStep(pred, prop) } - override predicate step(DataFlow::Node pred, DataFlow::Node succ) { - this = step(pred) and - succ = this - } + override predicate step(DataFlow::Node pred, DataFlow::Node succ) { succ = step(pred) } } } From 0035defd72f70fa74fc56780f503b6571d9feb3d Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 17 Mar 2021 12:32:48 +0000 Subject: [PATCH 284/725] JS: ExceptionStep --- .../javascript/frameworks/LodashUnderscore.qll | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/LodashUnderscore.qll b/javascript/ql/src/semmle/javascript/frameworks/LodashUnderscore.qll index 49bb8806fe7..bca3c7b606b 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/LodashUnderscore.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/LodashUnderscore.qll @@ -360,9 +360,9 @@ module LodashUnderscore { /** * A data flow step propagating an exception thrown from a callback to a Lodash/Underscore function. */ - private class ExceptionStep extends DataFlow::CallNode, DataFlow::AdditionalFlowStep { - ExceptionStep() { - exists(string name | this = member(name).getACall() | + private class ExceptionStep extends DataFlow::SharedFlowStep { + override predicate step(DataFlow::Node pred, DataFlow::Node succ) { + exists(DataFlow::CallNode call, string name | // Members ending with By, With, or While indicate that they are a variant of // another function that takes a callback. name.matches("%By") or @@ -386,13 +386,12 @@ module LodashUnderscore { name = "replace" or name = "some" or name = "transform" + | + call = member(name).getACall() and + pred = call.getAnArgument().(DataFlow::FunctionNode).getExceptionalReturn() and + succ = call.getExceptionalReturn() ) } - - override predicate step(DataFlow::Node pred, DataFlow::Node succ) { - pred = getAnArgument().(DataFlow::FunctionNode).getExceptionalReturn() and - succ = this.getExceptionalReturn() - } } /** From 64c7d4e59795ebb888c584b5251e1d701540ab05 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 17 Mar 2021 12:33:55 +0000 Subject: [PATCH 285/725] JS: NextJSStaticPropsStep --- .../src/semmle/javascript/frameworks/Next.qll | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Next.qll b/javascript/ql/src/semmle/javascript/frameworks/Next.qll index 27f85924f16..6bad1b53799 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Next.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Next.qll @@ -126,17 +126,14 @@ module NextJS { /** * A step modelling the flow from the server-computed props object to the default exported function that renders the page. */ - class NextJSStaticPropsStep extends DataFlow::AdditionalFlowStep, DataFlow::FunctionNode { - Module pageModule; - - NextJSStaticPropsStep() { - pageModule = getAPagesModule() and - this = pageModule.getAnExportedValue("default").getAFunctionValue() - } - + class NextJSStaticPropsStep extends DataFlow::SharedFlowStep { override predicate step(DataFlow::Node pred, DataFlow::Node succ) { - pred = getAPropsSource(pageModule) and - succ = this.getParameter(0) + exists(Module pageModule, DataFlow::FunctionNode function | + pageModule = getAPagesModule() and + function = pageModule.getAnExportedValue("default").getAFunctionValue() and + pred = getAPropsSource(pageModule) and + succ = function.getParameter(0) + ) } } From 2012e97842e9968481cc664a14f88db93f6f0fd4 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 17 Mar 2021 12:37:11 +0000 Subject: [PATCH 286/725] JS: NextJSStaticReactComponentPropsStep --- .../src/semmle/javascript/frameworks/Next.qll | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Next.qll b/javascript/ql/src/semmle/javascript/frameworks/Next.qll index 6bad1b53799..3ad0486e805 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Next.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Next.qll @@ -140,20 +140,14 @@ module NextJS { /** * A step modelling the flow from the server-computed props object to the default exported React component that renders the page. */ - class NextJSStaticReactComponentPropsStep extends DataFlow::AdditionalFlowStep, - DataFlow::ValueNode { - Module pageModule; - ReactComponent component; - - NextJSStaticReactComponentPropsStep() { - pageModule = getAPagesModule() and - this.getAstNode() = component and - this = pageModule.getAnExportedValue("default").getALocalSource() - } - + class NextJSStaticReactComponentPropsStep extends DataFlow::SharedFlowStep { override predicate step(DataFlow::Node pred, DataFlow::Node succ) { - pred = getAPropsSource(pageModule) and - succ = component.getADirectPropsAccess() + exists(Module pageModule, ReactComponent component | + pageModule = getAPagesModule() and + pageModule.getAnExportedValue("default").getALocalSource() = DataFlow::valueNode(component) and + pred = getAPropsSource(pageModule) and + succ = component.getADirectPropsAccess() + ) } } From bda074835e6ed7a9916210f94e301cad7dd1e9bf Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 17 Mar 2021 12:38:33 +0000 Subject: [PATCH 287/725] JS: Replace uses in ExternalApiUsedWithUntrustedData --- ...rnalAPIUsedWithUntrustedDataCustomizations.qll | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ExternalAPIUsedWithUntrustedDataCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ExternalAPIUsedWithUntrustedDataCustomizations.qll index 9b1a582fd9d..f9eaa7c7ce7 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/ExternalAPIUsedWithUntrustedDataCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/ExternalAPIUsedWithUntrustedDataCustomizations.qll @@ -255,15 +255,12 @@ module ExternalAPIUsedWithUntrustedData { not exists(DataFlow::Node arg | arg = this.getAnArgument() and not arg instanceof DeepObjectSink | - TaintTracking::sharedTaintStep(arg, _) - or - exists(DataFlow::AdditionalFlowStep s | - s.step(arg, _) or - s.step(arg, _, _, _) or - s.loadStep(arg, _, _) or - s.storeStep(arg, _, _) or - s.loadStoreStep(arg, _, _) - ) + TaintTracking::sharedTaintStep(arg, _) or + DataFlow::SharedFlowStep::step(arg, _) or + DataFlow::SharedFlowStep::step(arg, _, _, _) or + DataFlow::SharedFlowStep::loadStep(arg, _, _) or + DataFlow::SharedFlowStep::storeStep(arg, _, _) or + DataFlow::SharedFlowStep::loadStoreStep(arg, _, _) ) } From fae907df654efd463efa02f9e8c5e91ed06def35 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 17 Mar 2021 12:40:34 +0000 Subject: [PATCH 288/725] JS: Update some uses in tests --- javascript/ql/test/library-tests/frameworks/Electron/tests.ql | 2 +- .../ql/test/library-tests/frameworks/EventEmitter/test.ql | 2 +- .../library-tests/frameworks/SocketIO/AdditionalFlowStep.qll | 2 +- javascript/ql/test/library-tests/frameworks/WebSocket/test.ql | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/javascript/ql/test/library-tests/frameworks/Electron/tests.ql b/javascript/ql/test/library-tests/frameworks/Electron/tests.ql index 536760f5447..d8684c7d5c1 100644 --- a/javascript/ql/test/library-tests/frameworks/Electron/tests.ql +++ b/javascript/ql/test/library-tests/frameworks/Electron/tests.ql @@ -9,7 +9,7 @@ query predicate clientRequest_getADataNode(Electron::ElectronClientRequest cr, D query predicate clientRequest(Electron::ElectronClientRequest cr) { any() } query predicate ipcFlow(DataFlow::Node pred, DataFlow::Node succ) { - exists(DataFlow::AdditionalFlowStep afs | afs.step(pred, succ)) + DataFlow::SharedFlowStep::step(pred, succ) } query predicate remoteFlowSources(RemoteFlowSource source) { any() } diff --git a/javascript/ql/test/library-tests/frameworks/EventEmitter/test.ql b/javascript/ql/test/library-tests/frameworks/EventEmitter/test.ql index 9b0f16161c4..cc811503232 100644 --- a/javascript/ql/test/library-tests/frameworks/EventEmitter/test.ql +++ b/javascript/ql/test/library-tests/frameworks/EventEmitter/test.ql @@ -1,7 +1,7 @@ import javascript query predicate taintSteps(DataFlow::Node pred, DataFlow::Node succ) { - exists(DataFlow::AdditionalFlowStep step | step.step(pred, succ)) + DataFlow::SharedFlowStep::step(pred, succ) } query predicate eventEmitter(EventEmitter e) { any() } diff --git a/javascript/ql/test/library-tests/frameworks/SocketIO/AdditionalFlowStep.qll b/javascript/ql/test/library-tests/frameworks/SocketIO/AdditionalFlowStep.qll index 5cc19dee55c..26fd1693140 100644 --- a/javascript/ql/test/library-tests/frameworks/SocketIO/AdditionalFlowStep.qll +++ b/javascript/ql/test/library-tests/frameworks/SocketIO/AdditionalFlowStep.qll @@ -1,5 +1,5 @@ import javascript query predicate test_AdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) { - exists(DataFlow::AdditionalFlowStep step | step.step(pred, succ) | any()) + DataFlow::SharedFlowStep::step(pred, succ) } diff --git a/javascript/ql/test/library-tests/frameworks/WebSocket/test.ql b/javascript/ql/test/library-tests/frameworks/WebSocket/test.ql index dd2165e37c9..69ea33677e4 100644 --- a/javascript/ql/test/library-tests/frameworks/WebSocket/test.ql +++ b/javascript/ql/test/library-tests/frameworks/WebSocket/test.ql @@ -13,7 +13,7 @@ query ServerWebSocket::SendNode serverSend() { any() } query ServerWebSocket::ReceiveNode serverReceive() { any() } query predicate taintStep(DataFlow::Node pred, DataFlow::Node succ) { - any(DataFlow::AdditionalFlowStep s).step(pred, succ) + DataFlow::SharedFlowStep::step(pred, succ) } query RemoteFlowSource remoteFlow() { any() } From 52279d4bea2108517803aebb21af0f74798a8c4f Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 17 Mar 2021 12:49:15 +0000 Subject: [PATCH 289/725] JS: Rename some test predicates to reflect reality --- .../ql/test/library-tests/frameworks/EventEmitter/test.expected | 2 +- .../ql/test/library-tests/frameworks/EventEmitter/test.ql | 2 +- .../ql/test/library-tests/frameworks/WebSocket/test.expected | 2 +- javascript/ql/test/library-tests/frameworks/WebSocket/test.ql | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/javascript/ql/test/library-tests/frameworks/EventEmitter/test.expected b/javascript/ql/test/library-tests/frameworks/EventEmitter/test.expected index 4918d26fa9f..5ebd5c8a069 100644 --- a/javascript/ql/test/library-tests/frameworks/EventEmitter/test.expected +++ b/javascript/ql/test/library-tests/frameworks/EventEmitter/test.expected @@ -1,4 +1,4 @@ -taintSteps +flowSteps | customEmitter.js:5:20:5:24 | "bar" | customEmitter.js:6:19:6:22 | data | | customEmitter.js:12:21:12:25 | "baz" | customEmitter.js:13:23:13:26 | data | | customEmitter.js:12:21:12:25 | "baz" | customEmitter.js:22:14:22:18 | yData | diff --git a/javascript/ql/test/library-tests/frameworks/EventEmitter/test.ql b/javascript/ql/test/library-tests/frameworks/EventEmitter/test.ql index cc811503232..9c53c7d7dcc 100644 --- a/javascript/ql/test/library-tests/frameworks/EventEmitter/test.ql +++ b/javascript/ql/test/library-tests/frameworks/EventEmitter/test.ql @@ -1,6 +1,6 @@ import javascript -query predicate taintSteps(DataFlow::Node pred, DataFlow::Node succ) { +query predicate flowSteps(DataFlow::Node pred, DataFlow::Node succ) { DataFlow::SharedFlowStep::step(pred, succ) } diff --git a/javascript/ql/test/library-tests/frameworks/WebSocket/test.expected b/javascript/ql/test/library-tests/frameworks/WebSocket/test.expected index c3942b8660b..96c5aedb737 100644 --- a/javascript/ql/test/library-tests/frameworks/WebSocket/test.expected +++ b/javascript/ql/test/library-tests/frameworks/WebSocket/test.expected @@ -21,7 +21,7 @@ serverSend serverReceive | server.js:7:3:9:4 | ws.on(' ... );\\n\\t\\t}) | | sockjs.js:9:5:12:6 | conn.on ... \\n }) | -taintStep +flowSteps | browser.js:5:15:5:32 | 'Hi from browser!' | server.js:7:38:7:44 | message | | browser.js:21:13:21:18 | 'test' | sockjs.js:9:31:9:37 | message | | client.js:7:11:7:27 | 'Hi from client!' | server.js:7:38:7:44 | message | diff --git a/javascript/ql/test/library-tests/frameworks/WebSocket/test.ql b/javascript/ql/test/library-tests/frameworks/WebSocket/test.ql index 69ea33677e4..fb658c2f195 100644 --- a/javascript/ql/test/library-tests/frameworks/WebSocket/test.ql +++ b/javascript/ql/test/library-tests/frameworks/WebSocket/test.ql @@ -12,7 +12,7 @@ query ServerWebSocket::SendNode serverSend() { any() } query ServerWebSocket::ReceiveNode serverReceive() { any() } -query predicate taintStep(DataFlow::Node pred, DataFlow::Node succ) { +query predicate flowSteps(DataFlow::Node pred, DataFlow::Node succ) { DataFlow::SharedFlowStep::step(pred, succ) } From 7021be05c5aae25083a827a6e9a5ecb9d7ba07fc Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 17 Mar 2021 12:56:17 +0000 Subject: [PATCH 290/725] JS: FlowStepThroughImport --- .../src/semmle/javascript/dataflow/Configuration.qll | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll index 77ea2b8d08a..da2c9276a17 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll @@ -886,13 +886,12 @@ abstract class AdditionalSink extends DataFlow::Node { * Additional flow step to model flow from import specifiers into the SSA variable * corresponding to the imported variable. */ -private class FlowStepThroughImport extends AdditionalFlowStep, DataFlow::ValueNode { - override ImportSpecifier astNode; - +private class FlowStepThroughImport extends SharedFlowStep { override predicate step(DataFlow::Node pred, DataFlow::Node succ) { - Stages::FlowSteps::ref() and - pred = this and - succ = DataFlow::ssaDefinitionNode(SSA::definition(astNode)) + exists(ImportSpecifier specifier | + pred = DataFlow::valueNode(specifier) and + succ = DataFlow::ssaDefinitionNode(SSA::definition(specifier)) + ) } } From adaf3234ecb20197c3b7de217a353f2afdb1104c Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 17 Mar 2021 13:03:53 +0000 Subject: [PATCH 291/725] JS: IteratorExceptionStep --- .../src/semmle/javascript/StandardLibrary.qll | 22 +++++-------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/StandardLibrary.qll b/javascript/ql/src/semmle/javascript/StandardLibrary.qll index 5a019ee9a69..9ca2bf1725f 100644 --- a/javascript/ql/src/semmle/javascript/StandardLibrary.qll +++ b/javascript/ql/src/semmle/javascript/StandardLibrary.qll @@ -74,23 +74,13 @@ private class ArrayIterationCallbackAsPartialInvoke extends DataFlow::PartialInv * A flow step propagating the exception thrown from a callback to a method whose name coincides * a built-in Array iteration method, such as `forEach` or `map`. */ -private class IteratorExceptionStep extends DataFlow::MethodCallNode, DataFlow::AdditionalFlowStep { - IteratorExceptionStep() { - exists(string name | name = getMethodName() | - name = "forEach" or - name = "each" or - name = "map" or - name = "filter" or - name = "some" or - name = "every" or - name = "fold" or - name = "reduce" - ) - } - +private class IteratorExceptionStep extends DataFlow::SharedFlowStep { override predicate step(DataFlow::Node pred, DataFlow::Node succ) { - pred = getAnArgument().(DataFlow::FunctionNode).getExceptionalReturn() and - succ = this.getExceptionalReturn() + exists(DataFlow::MethodCallNode call | + call.getMethodName() = ["forEach", "each", "map", "filter", "some", "every", "fold", "reduce"] and + pred = call.getAnArgument().(DataFlow::FunctionNode).getExceptionalReturn() and + succ = call.getExceptionalReturn() + ) } } From 67ec5d325c0f57b6f3442275a79c2acf42d899d4 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 17 Mar 2021 13:08:12 +0000 Subject: [PATCH 292/725] JS: Stop caching AdditionalFlowStep --- .../ql/src/semmle/javascript/dataflow/Configuration.qll | 7 ------- 1 file changed, 7 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll index da2c9276a17..169e687412f 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll @@ -551,19 +551,16 @@ abstract class LabeledBarrierGuardNode extends BarrierGuardNode { * of the standard library. Override `Configuration::isAdditionalFlowStep` * for analysis-specific flow steps. */ -cached abstract class AdditionalFlowStep extends DataFlow::Node { /** * Holds if `pred` → `succ` should be considered a data flow edge. */ - cached predicate step(DataFlow::Node pred, DataFlow::Node succ) { none() } /** * Holds if `pred` → `succ` should be considered a data flow edge * transforming values with label `predlbl` to have label `succlbl`. */ - cached predicate step( DataFlow::Node pred, DataFlow::Node succ, DataFlow::FlowLabel predlbl, DataFlow::FlowLabel succlbl @@ -577,7 +574,6 @@ abstract class AdditionalFlowStep extends DataFlow::Node { * Holds if `pred` should be stored in the object `succ` under the property `prop`. * The object `succ` must be a `DataFlow::SourceNode` for the object wherein the value is stored. */ - cached predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { none() } /** @@ -585,7 +581,6 @@ abstract class AdditionalFlowStep extends DataFlow::Node { * * Holds if the property `prop` of the object `pred` should be loaded into `succ`. */ - cached predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() } /** @@ -593,7 +588,6 @@ abstract class AdditionalFlowStep extends DataFlow::Node { * * Holds if the property `prop` should be copied from the object `pred` to the object `succ`. */ - cached predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() } /** @@ -601,7 +595,6 @@ abstract class AdditionalFlowStep extends DataFlow::Node { * * Holds if the property `loadProp` should be copied from the object `pred` to the property `storeProp` of object `succ`. */ - cached predicate loadStoreStep( DataFlow::Node pred, DataFlow::Node succ, string loadProp, string storeProp ) { From 98398a9efd3c85bea5754ab5cc171b7ce987df6c Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 18 Mar 2021 12:40:34 +0000 Subject: [PATCH 293/725] JS: add two-prop version of loadStoreStep and infer pseudo properties Initial step towards migrating CollectionFlowStep to PreCallGraphStep --- .../ql/src/semmle/javascript/Collections.qll | 8 +---- .../ql/src/semmle/javascript/Promises.qll | 7 ----- .../javascript/dataflow/TypeTracking.qll | 18 +++++++++++ .../dataflow/internal/PreCallGraphStep.qll | 30 +++++++++++++++++++ .../dataflow/internal/StepSummary.qll | 28 ++++++++--------- .../src/semmle/javascript/frameworks/HTTP.qll | 4 +-- 6 files changed, 64 insertions(+), 31 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Collections.qll b/javascript/ql/src/semmle/javascript/Collections.qll index de51afc77ef..332d787160e 100644 --- a/javascript/ql/src/semmle/javascript/Collections.qll +++ b/javascript/ql/src/semmle/javascript/Collections.qll @@ -10,18 +10,12 @@ private import DataFlow::PseudoProperties /** * A pseudo-property used in a data-flow/type-tracking step for collections. - * - * By extending `TypeTrackingPseudoProperty` the class enables the use of the collection related pseudo-properties in type-tracking predicates. */ -private class PseudoProperty extends TypeTrackingPseudoProperty { +private class PseudoProperty extends string { PseudoProperty() { this = [arrayLikeElement(), "1"] or // the "1" is required for the `ForOfStep`. this = any(CollectionDataFlow::MapSet step).getAPseudoProperty() } - - override PseudoProperty getLoadStoreToProp() { - exists(CollectionFlowStep step | step.loadStore(_, _, this, result)) - } } /** diff --git a/javascript/ql/src/semmle/javascript/Promises.qll b/javascript/ql/src/semmle/javascript/Promises.qll index f0fae1ea802..9190473201e 100644 --- a/javascript/ql/src/semmle/javascript/Promises.qll +++ b/javascript/ql/src/semmle/javascript/Promises.qll @@ -214,13 +214,6 @@ module PromiseTypeTracking { result = PromiseTypeTracking::promiseStep(mid, summary) ) } - - /** - * A class enabling the use of the `resolveField` as a pseudo-property in type-tracking predicates. - */ - private class ResolveFieldAsTypeTrackingProperty extends TypeTrackingPseudoProperty { - ResolveFieldAsTypeTrackingProperty() { this = Promises::valueProp() } - } } private import semmle.javascript.dataflow.internal.PreCallGraphStep diff --git a/javascript/ql/src/semmle/javascript/dataflow/TypeTracking.qll b/javascript/ql/src/semmle/javascript/dataflow/TypeTracking.qll index 0dc7921f0db..b1a6e197523 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TypeTracking.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TypeTracking.qll @@ -358,6 +358,15 @@ class SharedTypeTrackingStep extends Unit { * Holds if type-tracking should step from the `prop` property of `pred` to the same property in `succ`. */ predicate loadStoreStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { none() } + + /** + * Holds if type-tracking should step from the `loadProp` property of `pred` to the `storeProp` property in `succ`. + */ + predicate loadStoreStep( + DataFlow::Node pred, DataFlow::SourceNode succ, string loadProp, string storeProp + ) { + none() + } } /** Provides access to the steps contributed by subclasses of `SharedTypeTrackingStep`. */ @@ -389,6 +398,15 @@ module SharedTypeTrackingStep { predicate loadStoreStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { any(SharedTypeTrackingStep s).loadStoreStep(pred, succ, prop) } + + /** + * Holds if type-tracking should step from the `loadProp` property of `pred` to the `storeProp` property in `succ`. + */ + predicate loadStoreStep( + DataFlow::Node pred, DataFlow::SourceNode succ, string loadProp, string storeProp + ) { + any(SharedTypeTrackingStep s).loadStoreStep(pred, succ, loadProp, storeProp) + } } /** diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/PreCallGraphStep.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/PreCallGraphStep.qll index 520fa376b22..7020353ca0b 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/PreCallGraphStep.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/PreCallGraphStep.qll @@ -40,6 +40,15 @@ class PreCallGraphStep extends Unit { * Holds if there is a step from the `prop` property of `pred` to the same property in `succ`. */ predicate loadStoreStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { none() } + + /** + * Holds if there is a step from the `loadProp` property of `pred` to the `storeProp` property in `succ`. + */ + predicate loadStoreStep( + DataFlow::Node pred, DataFlow::SourceNode succ, string loadProp, string storeProp + ) { + none() + } } module PreCallGraphStep { @@ -75,6 +84,15 @@ module PreCallGraphStep { predicate loadStoreStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { any(PreCallGraphStep s).loadStoreStep(pred, succ, prop) } + + /** + * Holds if there is a step from the `loadProp` property of `pred` to the `storeProp` property in `succ`. + */ + predicate loadStoreStep( + DataFlow::Node pred, DataFlow::SourceNode succ, string loadProp, string storeProp + ) { + any(PreCallGraphStep s).loadStoreStep(pred, succ, loadProp, storeProp) + } } private class SharedFlowStepFromPreCallGraph extends DataFlow::SharedFlowStep { @@ -93,6 +111,12 @@ private class SharedFlowStepFromPreCallGraph extends DataFlow::SharedFlowStep { override predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { PreCallGraphStep::loadStoreStep(pred, succ, prop) } + + override predicate loadStoreStep( + DataFlow::Node pred, DataFlow::Node succ, string loadProp, string storeProp + ) { + PreCallGraphStep::loadStoreStep(pred, succ, loadProp, storeProp) + } } private class SharedTypeTrackingStepFromPreCallGraph extends DataFlow::SharedTypeTrackingStep { @@ -111,4 +135,10 @@ private class SharedTypeTrackingStepFromPreCallGraph extends DataFlow::SharedTyp override predicate loadStoreStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { PreCallGraphStep::loadStoreStep(pred, succ, prop) } + + override predicate loadStoreStep( + DataFlow::Node pred, DataFlow::SourceNode succ, string loadProp, string storeProp + ) { + PreCallGraphStep::loadStoreStep(pred, succ, loadProp, storeProp) + } } diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll index fb859fd3d7e..b6529ad84e0 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll @@ -10,7 +10,13 @@ class PropertyName extends string { or exists(AccessPath::getAnAssignmentTo(_, this)) or - this instanceof TypeTrackingPseudoProperty + SharedTypeTrackingStep::loadStep(_, _, this) + or + SharedTypeTrackingStep::storeStep(_, _, this) + or + SharedTypeTrackingStep::loadStoreStep(_, _, this, _) + or + SharedTypeTrackingStep::loadStoreStep(_, _, _, this) } } @@ -18,19 +24,6 @@ class OptionalPropertyName extends string { OptionalPropertyName() { this instanceof PropertyName or this = "" } } -/** - * A pseudo-property that can be used in type-tracking. - */ -abstract class TypeTrackingPseudoProperty extends string { - bindingset[this] - TypeTrackingPseudoProperty() { any() } - - /** - * Gets a property name that `this` can be copied to in a `LoadStoreStep(this, result)`. - */ - string getLoadStoreToProp() { none() } -} - /** * A description of a step on an inter-procedural data flow path. */ @@ -42,7 +35,7 @@ newtype TStepSummary = LoadStep(PropertyName prop) or CopyStep(PropertyName prop) or LoadStoreStep(PropertyName fromProp, PropertyName toProp) { - exists(TypeTrackingPseudoProperty prop | fromProp = prop and toProp = prop.getLoadStoreToProp()) + SharedTypeTrackingStep::loadStoreStep(_, _, fromProp, toProp) } /** @@ -121,6 +114,11 @@ module StepSummary { summary = CopyStep(prop) ) or + exists(string fromProp, string toProp | + SharedTypeTrackingStep::loadStoreStep(pred, succ, fromProp, toProp) and + summary = LoadStoreStep(fromProp, toProp) + ) + or SharedTypeTrackingStep::step(pred, succ) and summary = LevelStep() or diff --git a/javascript/ql/src/semmle/javascript/frameworks/HTTP.qll b/javascript/ql/src/semmle/javascript/frameworks/HTTP.qll index 225c9b2de53..bd4b5788e65 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/HTTP.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/HTTP.qll @@ -708,8 +708,8 @@ module HTTP { override DataFlow::SourceNode getRouteHandler(DataFlow::SourceNode access) { result instanceof RouteHandlerCandidate and exists( - DataFlow::Node input, TypeTrackingPseudoProperty key, CollectionFlowStep store, - CollectionFlowStep load, DataFlow::Node storeTo, DataFlow::Node loadFrom + DataFlow::Node input, string key, CollectionFlowStep store, CollectionFlowStep load, + DataFlow::Node storeTo, DataFlow::Node loadFrom | this.flowsTo(storeTo) and store.store(input, storeTo, key) and From 5c9a239776bf32abba4a6d7bf66c63db5d5c4ae1 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 18 Mar 2021 12:42:29 +0000 Subject: [PATCH 294/725] JS: SetAdd --- .../ql/src/semmle/javascript/Collections.qll | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Collections.qll b/javascript/ql/src/semmle/javascript/Collections.qll index 332d787160e..dc5288fd015 100644 --- a/javascript/ql/src/semmle/javascript/Collections.qll +++ b/javascript/ql/src/semmle/javascript/Collections.qll @@ -6,6 +6,7 @@ import javascript private import semmle.javascript.dataflow.internal.StepSummary +private import semmle.javascript.dataflow.internal.PreCallGraphStep private import DataFlow::PseudoProperties /** @@ -123,13 +124,13 @@ private module CollectionDataFlow { /** * A step for `Set.add()` method, which adds an element to a Set. */ - private class SetAdd extends CollectionFlowStep, DataFlow::MethodCallNode { - SetAdd() { this.getMethodName() = "add" } - - override predicate store(DataFlow::Node element, DataFlow::SourceNode obj, PseudoProperty prop) { - this = obj.getAMethodCall() and - element = this.getArgument(0) and - prop = setElement() + private class SetAdd extends PreCallGraphStep { + override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) { + exists(DataFlow::MethodCallNode call | + call = obj.getAMethodCall("add") and + element = call.getArgument(0) and + prop = setElement() + ) } } From 1a5eede39f62aeb39266d95df521e5509cb33121 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 18 Mar 2021 12:43:24 +0000 Subject: [PATCH 295/725] JS: SetConstructor --- .../ql/src/semmle/javascript/Collections.qll | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Collections.qll b/javascript/ql/src/semmle/javascript/Collections.qll index dc5288fd015..eda39c24832 100644 --- a/javascript/ql/src/semmle/javascript/Collections.qll +++ b/javascript/ql/src/semmle/javascript/Collections.qll @@ -137,16 +137,17 @@ private module CollectionDataFlow { /** * A step for the `Set` constructor, which copies any elements from the first argument into the resulting set. */ - private class SetConstructor extends CollectionFlowStep, DataFlow::NewNode { - SetConstructor() { this = DataFlow::globalVarRef("Set").getAnInstantiation() } - - override predicate loadStore( - DataFlow::Node pred, DataFlow::Node succ, PseudoProperty fromProp, PseudoProperty toProp + private class SetConstructor extends PreCallGraphStep { + override predicate loadStoreStep( + DataFlow::Node pred, DataFlow::SourceNode succ, string fromProp, string toProp ) { - pred = this.getArgument(0) and - succ = this and - fromProp = arrayLikeElement() and - toProp = setElement() + exists(DataFlow::NewNode invoke | + invoke = DataFlow::globalVarRef("Set").getAnInstantiation() and + pred = invoke.getArgument(0) and + succ = invoke and + fromProp = arrayLikeElement() and + toProp = setElement() + ) } } From c9c99464cfd8af7a44b7f296bc6192474cde4ff2 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 18 Mar 2021 12:51:06 +0000 Subject: [PATCH 296/725] JS: ForOfStep (unify with Arrays version) --- .../ql/src/semmle/javascript/Arrays.qll | 13 ------ .../ql/src/semmle/javascript/Collections.qll | 43 ++++++++----------- 2 files changed, 19 insertions(+), 37 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Arrays.qll b/javascript/ql/src/semmle/javascript/Arrays.qll index 693cac6bf47..e33d62437ba 100644 --- a/javascript/ql/src/semmle/javascript/Arrays.qll +++ b/javascript/ql/src/semmle/javascript/Arrays.qll @@ -289,17 +289,4 @@ private module ArrayDataFlow { ) } } - - /** - * A step for modelling `for of` iteration on arrays. - */ - private class ForOfStep extends PreCallGraphStep { - override predicate loadStep(DataFlow::Node obj, DataFlow::Node e, string prop) { - exists(ForOfStmt forOf | - obj = forOf.getIterationDomain().flow() and - e = DataFlow::lvalueNode(forOf.getLValue()) and - prop = arrayElement() - ) - } - } } diff --git a/javascript/ql/src/semmle/javascript/Collections.qll b/javascript/ql/src/semmle/javascript/Collections.qll index eda39c24832..c725cdc0ad3 100644 --- a/javascript/ql/src/semmle/javascript/Collections.qll +++ b/javascript/ql/src/semmle/javascript/Collections.qll @@ -152,34 +152,29 @@ private module CollectionDataFlow { } /** - * A step for a `for of` statement on a Map, Set, or Iterator. - * For Sets and iterators the l-value are the elements of the set/iterator. - * For Maps the l-value is a tuple containing a key and a value. + * A step for modelling `for of` iteration on arrays, maps, sets, and iterators. + * + * For sets and iterators the l-value are the elements of the set/iterator. + * For maps the l-value is a tuple containing a key and a value. */ - // This is partially duplicated behavior with the `for of` step for Arrays (`ArrayDataFlow::ForOfStep`). - // This duplication is required for the type-tracking steps defined in `CollectionsTypeTracking`. - private class ForOfStep extends CollectionFlowStep, DataFlow::ValueNode { - ForOfStmt forOf; - DataFlow::Node element; - - ForOfStep() { - this.asExpr() = forOf.getIterationDomain() and - element = DataFlow::lvalueNode(forOf.getLValue()) + private class ForOfStep extends PreCallGraphStep { + override predicate loadStep(DataFlow::Node obj, DataFlow::Node e, string prop) { + exists(ForOfStmt forOf | + obj = forOf.getIterationDomain().flow() and + e = DataFlow::lvalueNode(forOf.getLValue()) and + prop = arrayLikeElement() + ) } - override predicate load(DataFlow::Node obj, DataFlow::Node e, PseudoProperty prop) { - obj = this and - e = element and - prop = arrayLikeElement() - } - - override predicate loadStore( - DataFlow::Node pred, DataFlow::Node succ, PseudoProperty fromProp, PseudoProperty toProp + override predicate loadStoreStep( + DataFlow::Node pred, DataFlow::SourceNode succ, string fromProp, string toProp ) { - pred = this and - succ = element and - fromProp = mapValueAll() and - toProp = "1" + exists(ForOfStmt forOf | + pred = forOf.getIterationDomain().flow() and + succ = DataFlow::lvalueNode(forOf.getLValue()) and + fromProp = mapValueAll() and + toProp = "1" + ) } } From 4a45731c853a2d7b8483569e72b8861a682cd425 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 18 Mar 2021 12:52:19 +0000 Subject: [PATCH 297/725] JS: SetMapForEach --- .../ql/src/semmle/javascript/Collections.qll | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Collections.qll b/javascript/ql/src/semmle/javascript/Collections.qll index c725cdc0ad3..647ce94ed5d 100644 --- a/javascript/ql/src/semmle/javascript/Collections.qll +++ b/javascript/ql/src/semmle/javascript/Collections.qll @@ -181,13 +181,14 @@ private module CollectionDataFlow { /** * A step for a call to `forEach` on a Set or Map. */ - private class SetMapForEach extends CollectionFlowStep, DataFlow::MethodCallNode { - SetMapForEach() { this.getMethodName() = "forEach" } - - override predicate load(DataFlow::Node obj, DataFlow::Node element, PseudoProperty prop) { - obj = this.getReceiver() and - element = this.getCallback(0).getParameter(0) and - prop = [setElement(), mapValueAll()] + private class SetMapForEach extends PreCallGraphStep { + override predicate loadStep(DataFlow::Node obj, DataFlow::Node element, string prop) { + exists(DataFlow::MethodCallNode call | + call.getMethodName() = "forEach" and + obj = call.getReceiver() and + element = call.getCallback(0).getParameter(0) and + prop = [setElement(), mapValueAll()] + ) } } From 530be38b84132b5d9373af772882ea0613114293 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 18 Mar 2021 12:53:10 +0000 Subject: [PATCH 298/725] JS: MapGet --- .../ql/src/semmle/javascript/Collections.qll | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Collections.qll b/javascript/ql/src/semmle/javascript/Collections.qll index 647ce94ed5d..90d7200846b 100644 --- a/javascript/ql/src/semmle/javascript/Collections.qll +++ b/javascript/ql/src/semmle/javascript/Collections.qll @@ -196,14 +196,15 @@ private module CollectionDataFlow { * A call to the `get` method on a Map. * If the key of the call to `get` has a known string value, then only the value corresponding to that key will be retrieved. (The known string value is encoded as part of the pseudo-property) */ - private class MapGet extends CollectionFlowStep, DataFlow::MethodCallNode { - MapGet() { this.getMethodName() = "get" } - - override predicate load(DataFlow::Node obj, DataFlow::Node element, PseudoProperty prop) { - obj = this.getReceiver() and - element = this and - // reading the join of known and unknown values - (prop = mapValue(this.getArgument(0)) or prop = mapValueUnknownKey()) + private class MapGet extends PreCallGraphStep { + override predicate loadStep(DataFlow::Node obj, DataFlow::Node element, string prop) { + exists(DataFlow::MethodCallNode call | + call.getMethodName() = "get" and + obj = call.getReceiver() and + element = call and + // reading the join of known and unknown values + (prop = mapValue(call.getArgument(0)) or prop = mapValueUnknownKey()) + ) } } From 9abaad65c642b7c9ea4900c48dd6b334253c5d37 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 18 Mar 2021 12:56:32 +0000 Subject: [PATCH 299/725] JS: MapSet --- .../ql/src/semmle/javascript/Collections.qll | 31 +++++++------------ 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Collections.qll b/javascript/ql/src/semmle/javascript/Collections.qll index 90d7200846b..6979701ea50 100644 --- a/javascript/ql/src/semmle/javascript/Collections.qll +++ b/javascript/ql/src/semmle/javascript/Collections.qll @@ -15,7 +15,11 @@ private import DataFlow::PseudoProperties private class PseudoProperty extends string { PseudoProperty() { this = [arrayLikeElement(), "1"] or // the "1" is required for the `ForOfStep`. - this = any(CollectionDataFlow::MapSet step).getAPseudoProperty() + this = + [ + mapValue(any(DataFlow::CallNode c | c.getCalleeName() = "set").getArgument(0)), + mapValueAll() + ] } } @@ -216,25 +220,14 @@ private module CollectionDataFlow { * Otherwise the value will be stored into a pseudo-property corresponding to values with unknown keys. * The value will additionally be stored into a pseudo-property corresponding to all values. */ - class MapSet extends CollectionFlowStep, DataFlow::MethodCallNode { - MapSet() { this.getMethodName() = "set" } - - override predicate store(DataFlow::Node element, DataFlow::SourceNode obj, PseudoProperty prop) { - this = obj.getAMethodCall() and - element = this.getArgument(1) and - prop = getAPseudoProperty() + class MapSet extends PreCallGraphStep { + override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) { + exists(DataFlow::MethodCallNode call | + call = obj.getAMethodCall("set") and + element = call.getArgument(1) and + prop = [mapValue(call.getArgument(0)), mapValueAll()] + ) } - - /** - * Gets a pseudo-property used to store an element in a map. - * The pseudo-property represents both values where the key is a known string value (which is encoded in the pseudo-property), - * and values where the key is unknown. - * - * Additionally, all elements are stored into the pseudo-property `mapValueAll()`. - * - * The return-type is `string` as this predicate is used to define which pseudo-properties exist. - */ - string getAPseudoProperty() { result = [mapValue(this.getArgument(0)), mapValueAll()] } } /** From c5ddd40dc3e34aca19e86fa3494b1b8fdf32b0d6 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 18 Mar 2021 12:57:52 +0000 Subject: [PATCH 300/725] JS: MapAndSetValues --- .../ql/src/semmle/javascript/Collections.qll | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Collections.qll b/javascript/ql/src/semmle/javascript/Collections.qll index 6979701ea50..a0ee544e578 100644 --- a/javascript/ql/src/semmle/javascript/Collections.qll +++ b/javascript/ql/src/semmle/javascript/Collections.qll @@ -233,16 +233,17 @@ private module CollectionDataFlow { /** * A step for a call to `values` on a Map or a Set. */ - private class MapAndSetValues extends CollectionFlowStep, DataFlow::MethodCallNode { - MapAndSetValues() { this.getMethodName() = "values" } - - override predicate loadStore( - DataFlow::Node pred, DataFlow::Node succ, PseudoProperty fromProp, PseudoProperty toProp + private class MapAndSetValues extends PreCallGraphStep { + override predicate loadStoreStep( + DataFlow::Node pred, DataFlow::SourceNode succ, string fromProp, string toProp ) { - pred = this.getReceiver() and - succ = this and - fromProp = [mapValueAll(), setElement()] and - toProp = iteratorElement() + exists(DataFlow::MethodCallNode call | + call.getMethodName() = "values" and + pred = call.getReceiver() and + succ = call and + fromProp = [mapValueAll(), setElement()] and + toProp = iteratorElement() + ) } } From 2759d53f4236f93a337c03eb4304166770484512 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 18 Mar 2021 12:58:48 +0000 Subject: [PATCH 301/725] JS: SetKeys --- .../ql/src/semmle/javascript/Collections.qll | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Collections.qll b/javascript/ql/src/semmle/javascript/Collections.qll index a0ee544e578..f20c771f22d 100644 --- a/javascript/ql/src/semmle/javascript/Collections.qll +++ b/javascript/ql/src/semmle/javascript/Collections.qll @@ -250,16 +250,17 @@ private module CollectionDataFlow { /** * A step for a call to `keys` on a Set. */ - private class SetKeys extends CollectionFlowStep, DataFlow::MethodCallNode { - SetKeys() { this.getMethodName() = "keys" } - - override predicate loadStore( - DataFlow::Node pred, DataFlow::Node succ, PseudoProperty fromProp, PseudoProperty toProp + private class SetKeys extends PreCallGraphStep { + override predicate loadStoreStep( + DataFlow::Node pred, DataFlow::SourceNode succ, string fromProp, string toProp ) { - pred = this.getReceiver() and - succ = this and - fromProp = setElement() and - toProp = iteratorElement() + exists(DataFlow::MethodCallNode call | + call.getMethodName() = "keys" and + pred = call.getReceiver() and + succ = call and + fromProp = setElement() and + toProp = iteratorElement() + ) } } } From 52c2e37acafdda19eb66678d463aaeed9ab151a1 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 18 Mar 2021 13:51:16 +0000 Subject: [PATCH 302/725] JS: Update CollectionStep usage in HTTP --- .../src/semmle/javascript/frameworks/HTTP.qll | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/HTTP.qll b/javascript/ql/src/semmle/javascript/frameworks/HTTP.qll index bd4b5788e65..435ea94fd72 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/HTTP.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/HTTP.qll @@ -6,6 +6,7 @@ import javascript private import semmle.javascript.DynamicPropertyAccess private import semmle.javascript.dataflow.internal.StepSummary private import semmle.javascript.dataflow.internal.CallGraphs +private import DataFlow::PseudoProperties as PseudoProperties module HTTP { /** @@ -689,33 +690,30 @@ module HTTP { isDecoratedCall(result, candidate) } + private string mapValueProp() { + result = [PseudoProperties::mapValueAll(), PseudoProperties::mapValueUnknownKey()] + } + /** * A collection that contains one or more route potential handlers. */ - private class ContainerCollection extends HTTP::RouteHandlerCandidateContainer::Range { + private class ContainerCollection extends HTTP::RouteHandlerCandidateContainer::Range, + DataFlow::NewNode { ContainerCollection() { this = DataFlow::globalVarRef("Map").getAnInstantiation() and // restrict to Map for now - exists( - CollectionFlowStep store, DataFlow::Node storeTo, DataFlow::Node input, - RouteHandlerCandidate candidate - | - this.flowsTo(storeTo) and - store.store(input, storeTo, _) and - candidate.flowsTo(input) + exists(DataFlow::Node use | + DataFlow::SharedTypeTrackingStep::storeStep(use, this, mapValueProp()) and + use.getALocalSource() instanceof RouteHandlerCandidate ) } override DataFlow::SourceNode getRouteHandler(DataFlow::SourceNode access) { - result instanceof RouteHandlerCandidate and - exists( - DataFlow::Node input, string key, CollectionFlowStep store, CollectionFlowStep load, - DataFlow::Node storeTo, DataFlow::Node loadFrom - | - this.flowsTo(storeTo) and - store.store(input, storeTo, key) and + exists(DataFlow::Node input, string key, DataFlow::Node loadFrom | getAPossiblyDecoratedHandler(result).flowsTo(input) and + DataFlow::SharedTypeTrackingStep::storeStep(input, this, key) and ref(this).flowsTo(loadFrom) and - load.load(loadFrom, access, key) + DataFlow::SharedTypeTrackingStep::loadStep(loadFrom, access, + [key, PseudoProperties::mapValueAll()]) ) } } From f8f3770a58eb0a7e5c4e61e54e8d52367f8e5de4 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 18 Mar 2021 14:24:04 +0000 Subject: [PATCH 303/725] JS: BadRandomness can just use type-tracking now --- javascript/ql/src/Security/CWE-327/BadRandomness.ql | 5 ----- 1 file changed, 5 deletions(-) diff --git a/javascript/ql/src/Security/CWE-327/BadRandomness.ql b/javascript/ql/src/Security/CWE-327/BadRandomness.ql index 84f720571da..1168af1d448 100644 --- a/javascript/ql/src/Security/CWE-327/BadRandomness.ql +++ b/javascript/ql/src/Security/CWE-327/BadRandomness.ql @@ -87,11 +87,6 @@ private DataFlow::Node goodRandom(DataFlow::TypeTracker t, DataFlow::SourceNode or exists(DataFlow::TypeTracker t2 | t = t2.smallstep(goodRandom(t2, source), result)) or - // re-using the collection steps for `Set`. - exists(DataFlow::TypeTracker t2 | - result = CollectionsTypeTracking::collectionStep(goodRandom(t2, source), t, t2) - ) - or InsecureRandomness::isAdditionalTaintStep(goodRandom(t.continue(), source), result) and // bit shifts and multiplication by powers of two are generally used for constructing larger numbers from smaller numbers. not exists(BinaryExpr binop | binop = result.asExpr() | From 9e6aac8ef4c3648855ed6446d0b5fc161bde5459 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 18 Mar 2021 14:35:30 +0000 Subject: [PATCH 304/725] JS: Deprecate CollectionFlowStep --- .../ql/src/semmle/javascript/Collections.qll | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Collections.qll b/javascript/ql/src/semmle/javascript/Collections.qll index f20c771f22d..69849d18caf 100644 --- a/javascript/ql/src/semmle/javascript/Collections.qll +++ b/javascript/ql/src/semmle/javascript/Collections.qll @@ -10,9 +10,12 @@ private import semmle.javascript.dataflow.internal.PreCallGraphStep private import DataFlow::PseudoProperties /** - * A pseudo-property used in a data-flow/type-tracking step for collections. + * DEPRECATED. Exists only to support other deprecated elements. + * + * Type-tracking now automatically determines the set of pseudo-properties to include + * ased on which properties are contributed by `SharedTaintStep`s. */ -private class PseudoProperty extends string { +deprecated private class PseudoProperty extends string { PseudoProperty() { this = [arrayLikeElement(), "1"] or // the "1" is required for the `ForOfStep`. this = @@ -24,13 +27,9 @@ private class PseudoProperty extends string { } /** - * An `AdditionalFlowStep` used to model a data-flow step related to standard library collections. - * - * The `loadStep`/`storeStep`/`loadStoreStep` methods are overloaded such that the new predicates - * `load`/`store`/`loadStore` can be used in the `CollectionsTypeTracking` module. - * (Thereby avoiding naming conflicts with a "cousin" `AdditionalFlowStep` implementation.) + * DEPRECATED. Use `SharedFlowStep` or `SharedTaintTrackingStep` instead. */ -abstract class CollectionFlowStep extends DataFlow::AdditionalFlowStep { +abstract deprecated class CollectionFlowStep extends DataFlow::AdditionalFlowStep { final override predicate step(DataFlow::Node pred, DataFlow::Node succ) { none() } final override predicate step( @@ -83,27 +82,28 @@ abstract class CollectionFlowStep extends DataFlow::AdditionalFlowStep { } /** - * Provides predicates and clases for type-tracking collections. + * DEPRECATED. These steps are now included in the default type tracking steps, + * in most cases one can simply use those instead. */ -module CollectionsTypeTracking { +deprecated module CollectionsTypeTracking { /** * Gets the result from a single step through a collection, from `pred` to `result` summarized by `summary`. */ pragma[inline] DataFlow::SourceNode collectionStep(DataFlow::Node pred, StepSummary summary) { - exists(CollectionFlowStep step, PseudoProperty field | + exists(PseudoProperty field | summary = LoadStep(field) and - step.load(pred, result, field) and + DataFlow::SharedTypeTrackingStep::loadStep(pred, result, field) and not field = mapValueUnknownKey() // prune unknown reads in type-tracking or summary = StoreStep(field) and - step.store(pred, result, field) + DataFlow::SharedTypeTrackingStep::storeStep(pred, result, field) or summary = CopyStep(field) and - step.loadStore(pred, result, field) + DataFlow::SharedTypeTrackingStep::loadStoreStep(pred, result, field) or exists(PseudoProperty toField | summary = LoadStoreStep(field, toField) | - step.loadStore(pred, result, field, toField) + DataFlow::SharedTypeTrackingStep::loadStoreStep(pred, result, field, toField) ) ) } From 0056c39bdd71bd108833097978b6c6ace01b7db2 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 18 Mar 2021 14:56:03 +0000 Subject: [PATCH 305/725] JS: Deprecate AdditionalFlowStep --- .../javascript/dataflow/Configuration.qll | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll index 169e687412f..4d01159a51b 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll @@ -544,6 +544,12 @@ abstract class LabeledBarrierGuardNode extends BarrierGuardNode { } /** + * DEPRECATED. Subclasses should extend `SharedFlowStep` instead, unless the subclass + * is part of a query, in which case it should be moved into the `isAdditionalFlowStep` predicate + * of the relevant data-flow configuration. + * Other uses of the predicate in this class should instead reference the predicates in the + * `SharedFlowStep::` module, such as `SharedFlowStep::step`. + * * A data flow edge that should be added to all data flow configurations in * addition to standard data flow edges. * @@ -551,7 +557,10 @@ abstract class LabeledBarrierGuardNode extends BarrierGuardNode { * of the standard library. Override `Configuration::isAdditionalFlowStep` * for analysis-specific flow steps. */ -abstract class AdditionalFlowStep extends DataFlow::Node { +deprecated class AdditionalFlowStep = LegacyAdditionalFlowStep; + +// Internal version of AdditionalFlowStep that we can reference without deprecation warnings. +abstract private class LegacyAdditionalFlowStep extends DataFlow::Node { /** * Holds if `pred` → `succ` should be considered a data flow edge. */ @@ -729,32 +738,32 @@ module SharedFlowStep { */ private class AdditionalFlowStepAsSharedStep extends SharedFlowStep { override predicate step(DataFlow::Node pred, DataFlow::Node succ) { - any(AdditionalFlowStep s).step(pred, succ) + any(LegacyAdditionalFlowStep s).step(pred, succ) } override predicate step( DataFlow::Node pred, DataFlow::Node succ, DataFlow::FlowLabel predlbl, DataFlow::FlowLabel succlbl ) { - any(AdditionalFlowStep s).step(pred, succ, predlbl, succlbl) + any(LegacyAdditionalFlowStep s).step(pred, succ, predlbl, succlbl) } override predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { - any(AdditionalFlowStep s).storeStep(pred, succ, prop) + any(LegacyAdditionalFlowStep s).storeStep(pred, succ, prop) } override predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { - any(AdditionalFlowStep s).loadStep(pred, succ, prop) + any(LegacyAdditionalFlowStep s).loadStep(pred, succ, prop) } override predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { - any(AdditionalFlowStep s).loadStoreStep(pred, succ, prop) + any(LegacyAdditionalFlowStep s).loadStoreStep(pred, succ, prop) } override predicate loadStoreStep( DataFlow::Node pred, DataFlow::Node succ, string loadProp, string storeProp ) { - any(AdditionalFlowStep s).loadStoreStep(pred, succ, loadProp, storeProp) + any(LegacyAdditionalFlowStep s).loadStoreStep(pred, succ, loadProp, storeProp) } } From 61e89d4841171c625ff5f3b11a0d1366a2d653f9 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 19 Mar 2021 09:55:32 +0000 Subject: [PATCH 306/725] JS: Cache StepSummary and PropertyName --- .../dataflow/internal/StepSummary.qll | 86 ++++++++++++------- 1 file changed, 53 insertions(+), 33 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll index b6529ad84e0..5869444053f 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll @@ -1,43 +1,66 @@ import javascript private import semmle.javascript.dataflow.TypeTracking +private import semmle.javascript.internal.CachedStages private import FlowSteps -class PropertyName extends string { - PropertyName() { - this = any(DataFlow::PropRef pr).getPropertyName() - or - AccessPath::isAssignedInUniqueFile(this) - or - exists(AccessPath::getAnAssignmentTo(_, this)) - or - SharedTypeTrackingStep::loadStep(_, _, this) - or - SharedTypeTrackingStep::storeStep(_, _, this) - or - SharedTypeTrackingStep::loadStoreStep(_, _, this, _) - or - SharedTypeTrackingStep::loadStoreStep(_, _, _, this) +cached +private module Cached { + cached + module Public { + cached + predicate forceStage() { Stages::TypeTracking::ref() } + + cached + class PropertyName extends string { + cached + PropertyName() { + this = any(DataFlow::PropRef pr).getPropertyName() + or + AccessPath::isAssignedInUniqueFile(this) + or + exists(AccessPath::getAnAssignmentTo(_, this)) + or + SharedTypeTrackingStep::loadStep(_, _, this) + or + SharedTypeTrackingStep::storeStep(_, _, this) + or + SharedTypeTrackingStep::loadStoreStep(_, _, this, _) + or + SharedTypeTrackingStep::loadStoreStep(_, _, _, this) + } + } + + /** + * A description of a step on an inter-procedural data flow path. + */ + cached + newtype TStepSummary = + LevelStep() or + CallStep() or + ReturnStep() or + StoreStep(PropertyName prop) or + LoadStep(PropertyName prop) or + CopyStep(PropertyName prop) or + LoadStoreStep(PropertyName fromProp, PropertyName toProp) { + SharedTypeTrackingStep::loadStoreStep(_, _, fromProp, toProp) + } + } + + /** + * INTERNAL: Use `SourceNode.track()` or `SourceNode.backtrack()` instead. + */ + cached + predicate step(DataFlow::SourceNode pred, DataFlow::SourceNode succ, StepSummary summary) { + exists(DataFlow::Node mid | pred.flowsTo(mid) | StepSummary::smallstep(mid, succ, summary)) } } +import Cached::Public + class OptionalPropertyName extends string { OptionalPropertyName() { this instanceof PropertyName or this = "" } } -/** - * A description of a step on an inter-procedural data flow path. - */ -newtype TStepSummary = - LevelStep() or - CallStep() or - ReturnStep() or - StoreStep(PropertyName prop) or - LoadStep(PropertyName prop) or - CopyStep(PropertyName prop) or - LoadStoreStep(PropertyName fromProp, PropertyName toProp) { - SharedTypeTrackingStep::loadStoreStep(_, _, fromProp, toProp) - } - /** * INTERNAL: Use `TypeTracker` or `TypeBackTracker` instead. * @@ -68,10 +91,7 @@ module StepSummary { /** * INTERNAL: Use `SourceNode.track()` or `SourceNode.backtrack()` instead. */ - cached - predicate step(DataFlow::SourceNode pred, DataFlow::SourceNode succ, StepSummary summary) { - exists(DataFlow::Node mid | pred.flowsTo(mid) | smallstep(mid, succ, summary)) - } + predicate step = Cached::step/3; /** * INTERNAL: Use `TypeBackTracker.smallstep()` instead. From c067d519d902a3cb7a7f5daf5bd8f9c0d0a745fa Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 19 Mar 2021 09:55:42 +0000 Subject: [PATCH 307/725] JS: Inline some public predicates in GlobalAccessPaths --- javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll b/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll index 68b343b3578..57cf0dcee5e 100644 --- a/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll +++ b/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll @@ -305,6 +305,7 @@ module AccessPath { * } * ``` */ + pragma[inline] DataFlow::Node getAReferenceTo(Root root, string path) { path = fromReference(result, root) and not root.isGlobal() @@ -327,6 +328,7 @@ module AccessPath { * })(NS = NS || {}); * ``` */ + pragma[inline] DataFlow::Node getAReferenceTo(string path) { path = fromReference(result, DataFlow::globalAccessPathRootPseudoNode()) } @@ -347,6 +349,7 @@ module AccessPath { * } * ``` */ + pragma[inline] DataFlow::Node getAnAssignmentTo(Root root, string path) { path = fromRhs(result, root) and not root.isGlobal() @@ -367,6 +370,7 @@ module AccessPath { * })(foo = foo || {}); * ``` */ + pragma[inline] DataFlow::Node getAnAssignmentTo(string path) { path = fromRhs(result, DataFlow::globalAccessPathRootPseudoNode()) } @@ -376,6 +380,7 @@ module AccessPath { * * See `getAReferenceTo` and `getAnAssignmentTo` for more details. */ + pragma[inline] DataFlow::Node getAReferenceOrAssignmentTo(string path) { result = getAReferenceTo(path) or @@ -387,6 +392,7 @@ module AccessPath { * * See `getAReferenceTo` and `getAnAssignmentTo` for more details. */ + pragma[inline] DataFlow::Node getAReferenceOrAssignmentTo(Root root, string path) { result = getAReferenceTo(root, path) or From 98cee7d339c15e2a69b49c7e796c8774767a36bc Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 22 Mar 2021 11:08:42 +0000 Subject: [PATCH 308/725] JS: Update Collection step test and its output --- .../frameworks/Collections/test.expected | 3 +++ .../library-tests/frameworks/Collections/test.ql | 4 ---- .../test/library-tests/frameworks/Collections/tst.js | 12 ++++++------ 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/javascript/ql/test/library-tests/frameworks/Collections/test.expected b/javascript/ql/test/library-tests/frameworks/Collections/test.expected index c391fbf4f79..9edf3093caa 100644 --- a/javascript/ql/test/library-tests/frameworks/Collections/test.expected +++ b/javascript/ql/test/library-tests/frameworks/Collections/test.expected @@ -26,3 +26,6 @@ typeTracking | tst.js:2:16:2:23 | source() | tst.js:37:14:37:14 | e | | tst.js:2:16:2:23 | source() | tst.js:45:14:45:14 | e | | tst.js:2:16:2:23 | source() | tst.js:53:8:53:21 | map.get("key") | +| tst.js:2:16:2:23 | source() | tst.js:59:8:59:22 | map2.get("foo") | +| tst.js:2:16:2:23 | source() | tst.js:64:8:64:26 | map3.get(unknown()) | +| tst.js:2:16:2:23 | source() | tst.js:69:8:69:26 | map3.get(unknown()) | diff --git a/javascript/ql/test/library-tests/frameworks/Collections/test.ql b/javascript/ql/test/library-tests/frameworks/Collections/test.ql index 61da4ade4ab..9e3561fa844 100644 --- a/javascript/ql/test/library-tests/frameworks/Collections/test.ql +++ b/javascript/ql/test/library-tests/frameworks/Collections/test.ql @@ -22,10 +22,6 @@ DataFlow::SourceNode trackSource(DataFlow::TypeTracker t, DataFlow::SourceNode s start = result or exists(DataFlow::TypeTracker t2 | t = t2.step(trackSource(t2, start), result)) - or - exists(DataFlow::TypeTracker t2 | - result = CollectionsTypeTracking::collectionStep(trackSource(t2, start), t, t2) - ) } query DataFlow::SourceNode typeTracking(DataFlow::Node start) { diff --git a/javascript/ql/test/library-tests/frameworks/Collections/tst.js b/javascript/ql/test/library-tests/frameworks/Collections/tst.js index bc7b52081d0..e5d84ddfd65 100644 --- a/javascript/ql/test/library-tests/frameworks/Collections/tst.js +++ b/javascript/ql/test/library-tests/frameworks/Collections/tst.js @@ -54,17 +54,17 @@ sink(map.get("nonExistingKey")); // OK. // unknown write, known read - var map2 = new map(); + var map2 = new Map(); map2.set(unknown(), source); - sink(map2.get("foo")); // NOT OK (for data-flow). OK for type-tracking. + sink(map2.get("foo")); // NOT OK (for data-flow). // unknown write, unknown read - var map3 = new map(); + var map3 = new Map(); map3.set(unknown(), source); - sink(map3.get(unknown())); // NOT OK (for data-flow). OK for type-tracking. + sink(map3.get(unknown())); // NOT OK (for data-flow). // known write, unknown read - var map4 = new map(); + var map4 = new Map(); map4.set("foo", source); - sink(map3.get(unknown())); // NOT OK (for data-flow). OK for type-tracking. + sink(map3.get(unknown())); // NOT OK (for data-flow). })(); From 1f5e52e82240a97518487fde5633f35a879a00cd Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 23 Mar 2021 16:40:56 +0100 Subject: [PATCH 309/725] Python: Cleanup "first" type-tracking predicate to be private Since it's exposed nicely in the version that doesn't have a `DataFlow::TypeTracker` parameter, these should be private. Also found one instance where I had accidentially used DataFlow::Node instead of LocalSourceNode --- python/ql/src/semmle/python/Concepts.qll | 4 +++- python/ql/src/semmle/python/dataflow/new/TypeTracker.qll | 4 ++-- python/ql/src/semmle/python/frameworks/Cryptography.qll | 2 +- .../test/experimental/dataflow/typetracking/moduleattr.ql | 4 ++-- .../ql/test/experimental/dataflow/typetracking/tracked.ql | 8 ++++---- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/python/ql/src/semmle/python/Concepts.qll b/python/ql/src/semmle/python/Concepts.qll index 0e5814d203b..d8e65cb2e09 100644 --- a/python/ql/src/semmle/python/Concepts.qll +++ b/python/ql/src/semmle/python/Concepts.qll @@ -563,7 +563,9 @@ module Cryptography { /** Provides classes for modeling new key-pair generation APIs. */ module KeyGeneration { /** Gets a back-reference to the keysize argument `arg` that was used to generate a new key-pair. */ - DataFlow::LocalSourceNode keysizeBacktracker(DataFlow::TypeBackTracker t, DataFlow::Node arg) { + private DataFlow::LocalSourceNode keysizeBacktracker( + DataFlow::TypeBackTracker t, DataFlow::Node arg + ) { t.start() and arg = any(KeyGeneration::Range r).getKeySizeArg() and result = arg.getALocalSource() diff --git a/python/ql/src/semmle/python/dataflow/new/TypeTracker.qll b/python/ql/src/semmle/python/dataflow/new/TypeTracker.qll index b6c4bdb06ea..d4ce5f606ac 100644 --- a/python/ql/src/semmle/python/dataflow/new/TypeTracker.qll +++ b/python/ql/src/semmle/python/dataflow/new/TypeTracker.qll @@ -180,7 +180,7 @@ private newtype TTypeTracker = MkTypeTracker(Boolean hasCall, OptionalAttributeN * It is recommended that all uses of this type are written in the following form, * for tracking some type `myType`: * ``` - * DataFlow::LocalSourceNode myType(DataFlow::TypeTracker t) { + * private DataFlow::LocalSourceNode myType(DataFlow::TypeTracker t) { * t.start() and * result = < source of myType > * or @@ -341,7 +341,7 @@ private newtype TTypeBackTracker = MkTypeBackTracker(Boolean hasReturn, Optional * for back-tracking some callback type `myCallback`: * * ``` - * DataFlow::LocalSourceNode myCallback(DataFlow::TypeBackTracker t) { + * private DataFlow::LocalSourceNode myCallback(DataFlow::TypeBackTracker t) { * t.start() and * result = (< some API call >).getArgument(< n >).getALocalSource() * or diff --git a/python/ql/src/semmle/python/frameworks/Cryptography.qll b/python/ql/src/semmle/python/frameworks/Cryptography.qll index ec929e78836..d777423c76f 100644 --- a/python/ql/src/semmle/python/frameworks/Cryptography.qll +++ b/python/ql/src/semmle/python/frameworks/Cryptography.qll @@ -76,7 +76,7 @@ private module CryptographyModel { } /** Gets a reference to a predefined curve class instance with a specific key size (in bits), as well as the origin of the class. */ - private DataFlow::Node curveClassInstanceWithKeySize( + private DataFlow::LocalSourceNode curveClassInstanceWithKeySize( DataFlow::TypeTracker t, int keySize, DataFlow::Node origin ) { t.start() and diff --git a/python/ql/test/experimental/dataflow/typetracking/moduleattr.ql b/python/ql/test/experimental/dataflow/typetracking/moduleattr.ql index b546dc7491d..0a0d5df105f 100644 --- a/python/ql/test/experimental/dataflow/typetracking/moduleattr.ql +++ b/python/ql/test/experimental/dataflow/typetracking/moduleattr.ql @@ -2,7 +2,7 @@ import python import semmle.python.dataflow.new.DataFlow import semmle.python.dataflow.new.TypeTracker -DataFlow::LocalSourceNode module_tracker(TypeTracker t) { +private DataFlow::LocalSourceNode module_tracker(TypeTracker t) { t.start() and result = DataFlow::importNode("module") or @@ -13,7 +13,7 @@ query DataFlow::Node module_tracker() { module_tracker(DataFlow::TypeTracker::end()).flowsTo(result) } -DataFlow::LocalSourceNode module_attr_tracker(TypeTracker t) { +private DataFlow::LocalSourceNode module_attr_tracker(TypeTracker t) { t.startInAttr("attr") and result = module_tracker() or diff --git a/python/ql/test/experimental/dataflow/typetracking/tracked.ql b/python/ql/test/experimental/dataflow/typetracking/tracked.ql index 91ffe7e47c1..3d46c05e456 100644 --- a/python/ql/test/experimental/dataflow/typetracking/tracked.ql +++ b/python/ql/test/experimental/dataflow/typetracking/tracked.ql @@ -6,7 +6,7 @@ import TestUtilities.InlineExpectationsTest // ----------------------------------------------------------------------------- // tracked // ----------------------------------------------------------------------------- -DataFlow::LocalSourceNode tracked(TypeTracker t) { +private DataFlow::LocalSourceNode tracked(TypeTracker t) { t.start() and result.asCfgNode() = any(NameNode n | n.getId() = "tracked") or @@ -34,14 +34,14 @@ class TrackedTest extends InlineExpectationsTest { // ----------------------------------------------------------------------------- // int + str // ----------------------------------------------------------------------------- -DataFlow::LocalSourceNode int_type(TypeTracker t) { +private DataFlow::LocalSourceNode int_type(TypeTracker t) { t.start() and result.asCfgNode() = any(CallNode c | c.getFunction().(NameNode).getId() = "int") or exists(TypeTracker t2 | result = int_type(t2).track(t2, t)) } -DataFlow::LocalSourceNode string_type(TypeTracker t) { +private DataFlow::LocalSourceNode string_type(TypeTracker t) { t.start() and result.asCfgNode() = any(CallNode c | c.getFunction().(NameNode).getId() = "str") or @@ -83,7 +83,7 @@ class TrackedStringTest extends InlineExpectationsTest { // ----------------------------------------------------------------------------- // tracked_self // ----------------------------------------------------------------------------- -DataFlow::LocalSourceNode tracked_self(TypeTracker t) { +private DataFlow::LocalSourceNode tracked_self(TypeTracker t) { t.start() and exists(Function f | f.isMethod() and From deefbefffc06d692b53bece819e5ebf039a650c5 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 23 Mar 2021 16:42:41 +0100 Subject: [PATCH 310/725] Python: Minor refactor to use CallCfgNode --- python/ql/src/semmle/python/frameworks/Cryptography.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/frameworks/Cryptography.qll b/python/ql/src/semmle/python/frameworks/Cryptography.qll index d777423c76f..a3254fdc6da 100644 --- a/python/ql/src/semmle/python/frameworks/Cryptography.qll +++ b/python/ql/src/semmle/python/frameworks/Cryptography.qll @@ -80,7 +80,7 @@ private module CryptographyModel { DataFlow::TypeTracker t, int keySize, DataFlow::Node origin ) { t.start() and - result.asCfgNode().(CallNode).getFunction() = curveClassWithKeySize(keySize).asCfgNode() and + result.(DataFlow::CallCfgNode).getFunction() = curveClassWithKeySize(keySize) and origin = result or // Due to bad performance when using normal setup with we have inlined that code and forced a join From 6d6150d0515e733a3ccc86b103c4f473fb01f6c0 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 3 Mar 2021 10:27:11 +0100 Subject: [PATCH 311/725] C#: Change some data-flow `toString()`s --- .../dataflow/internal/DataFlowDispatch.qll | 18 +- .../dataflow/internal/DataFlowPublic.qll | 6 +- .../library-tests/csharp7/GlobalFlow.expected | 10 +- .../csharp7/GlobalTaintTracking.expected | 10 +- .../dataflow/async/Async.expected | 36 +- .../collections/CollectionFlow.expected | 526 +-- .../dataflow/fields/FieldFlow.expected | 766 ++-- .../dataflow/global/DataFlowPath.expected | 160 +- .../dataflow/global/GetAnOutNode.expected | 606 +-- .../global/TaintTrackingPath.expected | 180 +- .../dataflow/library/FlowSummaries.expected | 3902 ++++++++--------- .../dataflow/tuples/Tuples.expected | 198 +- .../dataflow/types/Types.expected | 44 +- .../EntityFramework/Dataflow.expected | 604 +-- .../EntityFramework/FlowSummaries.expected | 312 +- .../CWE-079/StoredXSS/XSS.expected | 14 +- .../CWE-338/InsecureRandomness.expected | 20 +- 17 files changed, 3710 insertions(+), 3702 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll index 8df750cd429..025175061ae 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll @@ -175,7 +175,7 @@ abstract class ReturnKind extends TReturnKind { * body, that is, a "normal" return. */ class NormalReturnKind extends ReturnKind, TNormalReturnKind { - override string toString() { result = "return" } + override string toString() { result = "normal" } } /** A value returned from a callable using an `out` or a `ref` parameter. */ @@ -186,16 +186,24 @@ abstract class OutRefReturnKind extends ReturnKind { /** A value returned from a callable using an `out` parameter. */ class OutReturnKind extends OutRefReturnKind, TOutReturnKind { - override int getPosition() { this = TOutReturnKind(result) } + private int pos; - override string toString() { result = "out" } + OutReturnKind() { this = TOutReturnKind(pos) } + + override int getPosition() { result = pos } + + override string toString() { result = "out parameter " + pos } } /** A value returned from a callable using a `ref` parameter. */ class RefReturnKind extends OutRefReturnKind, TRefReturnKind { - override int getPosition() { this = TRefReturnKind(result) } + private int pos; - override string toString() { result = "ref" } + RefReturnKind() { this = TRefReturnKind(pos) } + + override int getPosition() { result = pos } + + override string toString() { result = "ref parameter " + pos } } /** A value implicitly returned from a callable using a captured variable. */ diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll index 13ca7658240..662276497ab 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll @@ -236,7 +236,7 @@ class FieldContent extends Content, TFieldContent { /** Gets the field that is referenced. */ Field getField() { result = f } - override string toString() { result = f.toString() } + override string toString() { result = "field " + f.getName() } override Location getLocation() { result = f.getLocation() } @@ -256,7 +256,7 @@ class PropertyContent extends Content, TPropertyContent { /** Gets the property that is referenced. */ Property getProperty() { result = p } - override string toString() { result = p.toString() } + override string toString() { result = "property " + p.getName() } override Location getLocation() { result = p.getLocation() } @@ -269,7 +269,7 @@ class PropertyContent extends Content, TPropertyContent { /** A reference to an element in a collection. */ class ElementContent extends Content, TElementContent { - override string toString() { result = "[]" } + override string toString() { result = "element" } override Location getLocation() { result instanceof EmptyLocation } } diff --git a/csharp/ql/test/library-tests/csharp7/GlobalFlow.expected b/csharp/ql/test/library-tests/csharp7/GlobalFlow.expected index 9e928eddbf9..1c058bc57f8 100644 --- a/csharp/ql/test/library-tests/csharp7/GlobalFlow.expected +++ b/csharp/ql/test/library-tests/csharp7/GlobalFlow.expected @@ -4,9 +4,9 @@ edges | CSharp7.cs:51:22:51:23 | SSA def(t1) : String | CSharp7.cs:53:18:53:19 | access to local variable t1 | | CSharp7.cs:57:11:57:19 | "tainted" : String | CSharp7.cs:57:30:57:31 | SSA def(t4) : String | | CSharp7.cs:57:30:57:31 | SSA def(t4) : String | CSharp7.cs:58:18:58:19 | access to local variable t4 | -| CSharp7.cs:89:18:89:34 | (..., ...) [Item1] : String | CSharp7.cs:92:20:92:21 | access to local variable t1 [Item1] : String | -| CSharp7.cs:89:19:89:27 | "tainted" : String | CSharp7.cs:89:18:89:34 | (..., ...) [Item1] : String | -| CSharp7.cs:92:20:92:21 | access to local variable t1 [Item1] : String | CSharp7.cs:92:20:92:27 | access to field Item1 : String | +| CSharp7.cs:89:18:89:34 | (..., ...) [field Item1] : String | CSharp7.cs:92:20:92:21 | access to local variable t1 [field Item1] : String | +| CSharp7.cs:89:19:89:27 | "tainted" : String | CSharp7.cs:89:18:89:34 | (..., ...) [field Item1] : String | +| CSharp7.cs:92:20:92:21 | access to local variable t1 [field Item1] : String | CSharp7.cs:92:20:92:27 | access to field Item1 : String | | CSharp7.cs:92:20:92:27 | access to field Item1 : String | CSharp7.cs:92:18:92:28 | call to method I | | CSharp7.cs:177:22:177:30 | "tainted" : String | CSharp7.cs:183:23:183:25 | access to local variable src : String | | CSharp7.cs:177:22:177:30 | "tainted" : String | CSharp7.cs:184:23:184:25 | access to local variable src : String | @@ -20,10 +20,10 @@ nodes | CSharp7.cs:57:11:57:19 | "tainted" : String | semmle.label | "tainted" : String | | CSharp7.cs:57:30:57:31 | SSA def(t4) : String | semmle.label | SSA def(t4) : String | | CSharp7.cs:58:18:58:19 | access to local variable t4 | semmle.label | access to local variable t4 | -| CSharp7.cs:89:18:89:34 | (..., ...) [Item1] : String | semmle.label | (..., ...) [Item1] : String | +| CSharp7.cs:89:18:89:34 | (..., ...) [field Item1] : String | semmle.label | (..., ...) [field Item1] : String | | CSharp7.cs:89:19:89:27 | "tainted" : String | semmle.label | "tainted" : String | | CSharp7.cs:92:18:92:28 | call to method I | semmle.label | call to method I | -| CSharp7.cs:92:20:92:21 | access to local variable t1 [Item1] : String | semmle.label | access to local variable t1 [Item1] : String | +| CSharp7.cs:92:20:92:21 | access to local variable t1 [field Item1] : String | semmle.label | access to local variable t1 [field Item1] : String | | CSharp7.cs:92:20:92:27 | access to field Item1 : String | semmle.label | access to field Item1 : String | | CSharp7.cs:177:22:177:30 | "tainted" | semmle.label | "tainted" | | CSharp7.cs:177:22:177:30 | "tainted" : String | semmle.label | "tainted" : String | diff --git a/csharp/ql/test/library-tests/csharp7/GlobalTaintTracking.expected b/csharp/ql/test/library-tests/csharp7/GlobalTaintTracking.expected index 5a04e010d6b..905162f0bbb 100644 --- a/csharp/ql/test/library-tests/csharp7/GlobalTaintTracking.expected +++ b/csharp/ql/test/library-tests/csharp7/GlobalTaintTracking.expected @@ -4,9 +4,9 @@ edges | CSharp7.cs:51:22:51:23 | SSA def(t1) : String | CSharp7.cs:53:18:53:19 | access to local variable t1 | | CSharp7.cs:57:11:57:19 | "tainted" : String | CSharp7.cs:57:30:57:31 | SSA def(t4) : String | | CSharp7.cs:57:30:57:31 | SSA def(t4) : String | CSharp7.cs:58:18:58:19 | access to local variable t4 | -| CSharp7.cs:89:18:89:34 | (..., ...) [Item1] : String | CSharp7.cs:92:20:92:21 | access to local variable t1 [Item1] : String | -| CSharp7.cs:89:19:89:27 | "tainted" : String | CSharp7.cs:89:18:89:34 | (..., ...) [Item1] : String | -| CSharp7.cs:92:20:92:21 | access to local variable t1 [Item1] : String | CSharp7.cs:92:20:92:27 | access to field Item1 : String | +| CSharp7.cs:89:18:89:34 | (..., ...) [field Item1] : String | CSharp7.cs:92:20:92:21 | access to local variable t1 [field Item1] : String | +| CSharp7.cs:89:19:89:27 | "tainted" : String | CSharp7.cs:89:18:89:34 | (..., ...) [field Item1] : String | +| CSharp7.cs:92:20:92:21 | access to local variable t1 [field Item1] : String | CSharp7.cs:92:20:92:27 | access to field Item1 : String | | CSharp7.cs:92:20:92:27 | access to field Item1 : String | CSharp7.cs:92:18:92:28 | call to method I | | CSharp7.cs:177:22:177:30 | "tainted" : String | CSharp7.cs:182:23:182:25 | access to local variable src : String | | CSharp7.cs:177:22:177:30 | "tainted" : String | CSharp7.cs:183:23:183:25 | access to local variable src : String | @@ -22,10 +22,10 @@ nodes | CSharp7.cs:57:11:57:19 | "tainted" : String | semmle.label | "tainted" : String | | CSharp7.cs:57:30:57:31 | SSA def(t4) : String | semmle.label | SSA def(t4) : String | | CSharp7.cs:58:18:58:19 | access to local variable t4 | semmle.label | access to local variable t4 | -| CSharp7.cs:89:18:89:34 | (..., ...) [Item1] : String | semmle.label | (..., ...) [Item1] : String | +| CSharp7.cs:89:18:89:34 | (..., ...) [field Item1] : String | semmle.label | (..., ...) [field Item1] : String | | CSharp7.cs:89:19:89:27 | "tainted" : String | semmle.label | "tainted" : String | | CSharp7.cs:92:18:92:28 | call to method I | semmle.label | call to method I | -| CSharp7.cs:92:20:92:21 | access to local variable t1 [Item1] : String | semmle.label | access to local variable t1 [Item1] : String | +| CSharp7.cs:92:20:92:21 | access to local variable t1 [field Item1] : String | semmle.label | access to local variable t1 [field Item1] : String | | CSharp7.cs:92:20:92:27 | access to field Item1 : String | semmle.label | access to field Item1 : String | | CSharp7.cs:177:22:177:30 | "tainted" | semmle.label | "tainted" | | CSharp7.cs:177:22:177:30 | "tainted" : String | semmle.label | "tainted" : String | diff --git a/csharp/ql/test/library-tests/dataflow/async/Async.expected b/csharp/ql/test/library-tests/dataflow/async/Async.expected index 1b7ec20d98e..6e1434dcf68 100644 --- a/csharp/ql/test/library-tests/dataflow/async/Async.expected +++ b/csharp/ql/test/library-tests/dataflow/async/Async.expected @@ -4,26 +4,26 @@ edges | Async.cs:14:34:14:34 | x : String | Async.cs:16:16:16:16 | access to parameter x : String | | Async.cs:16:16:16:16 | access to parameter x : String | Async.cs:11:14:11:26 | call to method Return | | Async.cs:19:41:19:45 | input : String | Async.cs:21:32:21:36 | access to parameter input : String | -| Async.cs:21:20:21:37 | call to method ReturnAwait [Result] : String | Async.cs:21:14:21:37 | await ... | -| Async.cs:21:32:21:36 | access to parameter input : String | Async.cs:21:20:21:37 | call to method ReturnAwait [Result] : String | +| Async.cs:21:20:21:37 | call to method ReturnAwait [property Result] : String | Async.cs:21:14:21:37 | await ... | +| Async.cs:21:32:21:36 | access to parameter input : String | Async.cs:21:20:21:37 | call to method ReturnAwait [property Result] : String | | Async.cs:24:41:24:45 | input : String | Async.cs:26:35:26:39 | access to parameter input : String | | Async.cs:26:17:26:40 | await ... : String | Async.cs:27:14:27:14 | access to local variable x | -| Async.cs:26:23:26:40 | call to method ReturnAwait [Result] : String | Async.cs:26:17:26:40 | await ... : String | -| Async.cs:26:35:26:39 | access to parameter input : String | Async.cs:26:23:26:40 | call to method ReturnAwait [Result] : String | +| Async.cs:26:23:26:40 | call to method ReturnAwait [property Result] : String | Async.cs:26:17:26:40 | await ... : String | +| Async.cs:26:35:26:39 | access to parameter input : String | Async.cs:26:23:26:40 | call to method ReturnAwait [property Result] : String | | Async.cs:30:35:30:39 | input : String | Async.cs:32:27:32:31 | access to parameter input : String | -| Async.cs:32:14:32:32 | call to method ReturnAwait2 [Result] : String | Async.cs:32:14:32:39 | access to property Result | -| Async.cs:32:27:32:31 | access to parameter input : String | Async.cs:32:14:32:32 | call to method ReturnAwait2 [Result] : String | +| Async.cs:32:14:32:32 | call to method ReturnAwait2 [property Result] : String | Async.cs:32:14:32:39 | access to property Result | +| Async.cs:32:27:32:31 | access to parameter input : String | Async.cs:32:14:32:32 | call to method ReturnAwait2 [property Result] : String | | Async.cs:35:51:35:51 | x : String | Async.cs:38:16:38:16 | access to parameter x : String | -| Async.cs:38:16:38:16 | access to parameter x : String | Async.cs:21:20:21:37 | call to method ReturnAwait [Result] : String | -| Async.cs:38:16:38:16 | access to parameter x : String | Async.cs:26:23:26:40 | call to method ReturnAwait [Result] : String | +| Async.cs:38:16:38:16 | access to parameter x : String | Async.cs:21:20:21:37 | call to method ReturnAwait [property Result] : String | +| Async.cs:38:16:38:16 | access to parameter x : String | Async.cs:26:23:26:40 | call to method ReturnAwait [property Result] : String | | Async.cs:41:33:41:37 | input : String | Async.cs:43:25:43:29 | access to parameter input : String | -| Async.cs:43:14:43:30 | call to method ReturnTask [Result] : String | Async.cs:43:14:43:37 | access to property Result | -| Async.cs:43:25:43:29 | access to parameter input : String | Async.cs:43:14:43:30 | call to method ReturnTask [Result] : String | +| Async.cs:43:14:43:30 | call to method ReturnTask [property Result] : String | Async.cs:43:14:43:37 | access to property Result | +| Async.cs:43:25:43:29 | access to parameter input : String | Async.cs:43:14:43:30 | call to method ReturnTask [property Result] : String | | Async.cs:46:44:46:44 | x : String | Async.cs:48:32:48:32 | access to parameter x : String | -| Async.cs:48:16:48:33 | call to method FromResult [Result] : String | Async.cs:43:14:43:30 | call to method ReturnTask [Result] : String | -| Async.cs:48:32:48:32 | access to parameter x : String | Async.cs:48:16:48:33 | call to method FromResult [Result] : String | +| Async.cs:48:16:48:33 | call to method FromResult [property Result] : String | Async.cs:43:14:43:30 | call to method ReturnTask [property Result] : String | +| Async.cs:48:32:48:32 | access to parameter x : String | Async.cs:48:16:48:33 | call to method FromResult [property Result] : String | | Async.cs:51:52:51:52 | x : String | Async.cs:51:58:51:58 | access to parameter x : String | -| Async.cs:51:58:51:58 | access to parameter x : String | Async.cs:32:14:32:32 | call to method ReturnAwait2 [Result] : String | +| Async.cs:51:58:51:58 | access to parameter x : String | Async.cs:32:14:32:32 | call to method ReturnAwait2 [property Result] : String | nodes | Async.cs:9:37:9:41 | input : String | semmle.label | input : String | | Async.cs:11:14:11:26 | call to method Return | semmle.label | call to method Return | @@ -32,25 +32,25 @@ nodes | Async.cs:16:16:16:16 | access to parameter x : String | semmle.label | access to parameter x : String | | Async.cs:19:41:19:45 | input : String | semmle.label | input : String | | Async.cs:21:14:21:37 | await ... | semmle.label | await ... | -| Async.cs:21:20:21:37 | call to method ReturnAwait [Result] : String | semmle.label | call to method ReturnAwait [Result] : String | +| Async.cs:21:20:21:37 | call to method ReturnAwait [property Result] : String | semmle.label | call to method ReturnAwait [property Result] : String | | Async.cs:21:32:21:36 | access to parameter input : String | semmle.label | access to parameter input : String | | Async.cs:24:41:24:45 | input : String | semmle.label | input : String | | Async.cs:26:17:26:40 | await ... : String | semmle.label | await ... : String | -| Async.cs:26:23:26:40 | call to method ReturnAwait [Result] : String | semmle.label | call to method ReturnAwait [Result] : String | +| Async.cs:26:23:26:40 | call to method ReturnAwait [property Result] : String | semmle.label | call to method ReturnAwait [property Result] : String | | Async.cs:26:35:26:39 | access to parameter input : String | semmle.label | access to parameter input : String | | Async.cs:27:14:27:14 | access to local variable x | semmle.label | access to local variable x | | Async.cs:30:35:30:39 | input : String | semmle.label | input : String | -| Async.cs:32:14:32:32 | call to method ReturnAwait2 [Result] : String | semmle.label | call to method ReturnAwait2 [Result] : String | +| Async.cs:32:14:32:32 | call to method ReturnAwait2 [property Result] : String | semmle.label | call to method ReturnAwait2 [property Result] : String | | Async.cs:32:14:32:39 | access to property Result | semmle.label | access to property Result | | Async.cs:32:27:32:31 | access to parameter input : String | semmle.label | access to parameter input : String | | Async.cs:35:51:35:51 | x : String | semmle.label | x : String | | Async.cs:38:16:38:16 | access to parameter x : String | semmle.label | access to parameter x : String | | Async.cs:41:33:41:37 | input : String | semmle.label | input : String | -| Async.cs:43:14:43:30 | call to method ReturnTask [Result] : String | semmle.label | call to method ReturnTask [Result] : String | +| Async.cs:43:14:43:30 | call to method ReturnTask [property Result] : String | semmle.label | call to method ReturnTask [property Result] : String | | Async.cs:43:14:43:37 | access to property Result | semmle.label | access to property Result | | Async.cs:43:25:43:29 | access to parameter input : String | semmle.label | access to parameter input : String | | Async.cs:46:44:46:44 | x : String | semmle.label | x : String | -| Async.cs:48:16:48:33 | call to method FromResult [Result] : String | semmle.label | call to method FromResult [Result] : String | +| Async.cs:48:16:48:33 | call to method FromResult [property Result] : String | semmle.label | call to method FromResult [property Result] : String | | Async.cs:48:32:48:32 | access to parameter x : String | semmle.label | access to parameter x : String | | Async.cs:51:52:51:52 | x : String | semmle.label | x : String | | Async.cs:51:58:51:58 | access to parameter x : String | semmle.label | access to parameter x : String | diff --git a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected index 3c27e96311b..efffa47040c 100644 --- a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected @@ -1,367 +1,367 @@ edges | CollectionFlow.cs:14:17:14:23 | object creation of type A : A | CollectionFlow.cs:15:27:15:27 | access to local variable a : A | -| CollectionFlow.cs:15:25:15:29 | { ..., ... } [[]] : A | CollectionFlow.cs:16:14:16:16 | access to local variable as [[]] : A | -| CollectionFlow.cs:15:25:15:29 | { ..., ... } [[]] : A | CollectionFlow.cs:17:18:17:20 | access to local variable as [[]] : A | -| CollectionFlow.cs:15:25:15:29 | { ..., ... } [[]] : A | CollectionFlow.cs:18:20:18:22 | access to local variable as [[]] : A | -| CollectionFlow.cs:15:27:15:27 | access to local variable a : A | CollectionFlow.cs:15:25:15:29 | { ..., ... } [[]] : A | -| CollectionFlow.cs:16:14:16:16 | access to local variable as [[]] : A | CollectionFlow.cs:16:14:16:19 | access to array element | -| CollectionFlow.cs:17:18:17:20 | access to local variable as [[]] : A | CollectionFlow.cs:374:40:374:41 | ts [[]] : A | -| CollectionFlow.cs:18:20:18:22 | access to local variable as [[]] : A | CollectionFlow.cs:18:14:18:23 | call to method First | +| CollectionFlow.cs:15:25:15:29 | { ..., ... } [element] : A | CollectionFlow.cs:16:14:16:16 | access to local variable as [element] : A | +| CollectionFlow.cs:15:25:15:29 | { ..., ... } [element] : A | CollectionFlow.cs:17:18:17:20 | access to local variable as [element] : A | +| CollectionFlow.cs:15:25:15:29 | { ..., ... } [element] : A | CollectionFlow.cs:18:20:18:22 | access to local variable as [element] : A | +| CollectionFlow.cs:15:27:15:27 | access to local variable a : A | CollectionFlow.cs:15:25:15:29 | { ..., ... } [element] : A | +| CollectionFlow.cs:16:14:16:16 | access to local variable as [element] : A | CollectionFlow.cs:16:14:16:19 | access to array element | +| CollectionFlow.cs:17:18:17:20 | access to local variable as [element] : A | CollectionFlow.cs:374:40:374:41 | ts [element] : A | +| CollectionFlow.cs:18:20:18:22 | access to local variable as [element] : A | CollectionFlow.cs:18:14:18:23 | call to method First | | CollectionFlow.cs:32:17:32:23 | object creation of type A : A | CollectionFlow.cs:33:53:33:53 | access to local variable a : A | -| CollectionFlow.cs:33:38:33:57 | { ..., ... } [As, []] : A | CollectionFlow.cs:34:14:34:14 | access to local variable c [As, []] : A | -| CollectionFlow.cs:33:38:33:57 | { ..., ... } [As, []] : A | CollectionFlow.cs:35:18:35:18 | access to local variable c [As, []] : A | -| CollectionFlow.cs:33:38:33:57 | { ..., ... } [As, []] : A | CollectionFlow.cs:36:20:36:20 | access to local variable c [As, []] : A | -| CollectionFlow.cs:33:45:33:55 | { ..., ... } [[]] : A | CollectionFlow.cs:33:38:33:57 | { ..., ... } [As, []] : A | -| CollectionFlow.cs:33:53:33:53 | access to local variable a : A | CollectionFlow.cs:33:45:33:55 | { ..., ... } [[]] : A | -| CollectionFlow.cs:34:14:34:14 | access to local variable c [As, []] : A | CollectionFlow.cs:34:14:34:17 | access to field As [[]] : A | -| CollectionFlow.cs:34:14:34:17 | access to field As [[]] : A | CollectionFlow.cs:34:14:34:20 | access to array element | -| CollectionFlow.cs:35:18:35:18 | access to local variable c [As, []] : A | CollectionFlow.cs:35:18:35:21 | access to field As [[]] : A | -| CollectionFlow.cs:35:18:35:21 | access to field As [[]] : A | CollectionFlow.cs:374:40:374:41 | ts [[]] : A | -| CollectionFlow.cs:36:20:36:20 | access to local variable c [As, []] : A | CollectionFlow.cs:36:20:36:23 | access to field As [[]] : A | -| CollectionFlow.cs:36:20:36:23 | access to field As [[]] : A | CollectionFlow.cs:36:14:36:24 | call to method First | +| CollectionFlow.cs:33:38:33:57 | { ..., ... } [field As, element] : A | CollectionFlow.cs:34:14:34:14 | access to local variable c [field As, element] : A | +| CollectionFlow.cs:33:38:33:57 | { ..., ... } [field As, element] : A | CollectionFlow.cs:35:18:35:18 | access to local variable c [field As, element] : A | +| CollectionFlow.cs:33:38:33:57 | { ..., ... } [field As, element] : A | CollectionFlow.cs:36:20:36:20 | access to local variable c [field As, element] : A | +| CollectionFlow.cs:33:45:33:55 | { ..., ... } [element] : A | CollectionFlow.cs:33:38:33:57 | { ..., ... } [field As, element] : A | +| CollectionFlow.cs:33:53:33:53 | access to local variable a : A | CollectionFlow.cs:33:45:33:55 | { ..., ... } [element] : A | +| CollectionFlow.cs:34:14:34:14 | access to local variable c [field As, element] : A | CollectionFlow.cs:34:14:34:17 | access to field As [element] : A | +| CollectionFlow.cs:34:14:34:17 | access to field As [element] : A | CollectionFlow.cs:34:14:34:20 | access to array element | +| CollectionFlow.cs:35:18:35:18 | access to local variable c [field As, element] : A | CollectionFlow.cs:35:18:35:21 | access to field As [element] : A | +| CollectionFlow.cs:35:18:35:21 | access to field As [element] : A | CollectionFlow.cs:374:40:374:41 | ts [element] : A | +| CollectionFlow.cs:36:20:36:20 | access to local variable c [field As, element] : A | CollectionFlow.cs:36:20:36:23 | access to field As [element] : A | +| CollectionFlow.cs:36:20:36:23 | access to field As [element] : A | CollectionFlow.cs:36:14:36:24 | call to method First | | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:52:18:52:18 | access to local variable a : A | -| CollectionFlow.cs:52:9:52:11 | [post] access to local variable as [[]] : A | CollectionFlow.cs:53:14:53:16 | access to local variable as [[]] : A | -| CollectionFlow.cs:52:9:52:11 | [post] access to local variable as [[]] : A | CollectionFlow.cs:54:18:54:20 | access to local variable as [[]] : A | -| CollectionFlow.cs:52:9:52:11 | [post] access to local variable as [[]] : A | CollectionFlow.cs:55:20:55:22 | access to local variable as [[]] : A | -| CollectionFlow.cs:52:18:52:18 | access to local variable a : A | CollectionFlow.cs:52:9:52:11 | [post] access to local variable as [[]] : A | -| CollectionFlow.cs:53:14:53:16 | access to local variable as [[]] : A | CollectionFlow.cs:53:14:53:19 | access to array element | -| CollectionFlow.cs:54:18:54:20 | access to local variable as [[]] : A | CollectionFlow.cs:374:40:374:41 | ts [[]] : A | -| CollectionFlow.cs:55:20:55:22 | access to local variable as [[]] : A | CollectionFlow.cs:55:14:55:23 | call to method First | +| CollectionFlow.cs:52:9:52:11 | [post] access to local variable as [element] : A | CollectionFlow.cs:53:14:53:16 | access to local variable as [element] : A | +| CollectionFlow.cs:52:9:52:11 | [post] access to local variable as [element] : A | CollectionFlow.cs:54:18:54:20 | access to local variable as [element] : A | +| CollectionFlow.cs:52:9:52:11 | [post] access to local variable as [element] : A | CollectionFlow.cs:55:20:55:22 | access to local variable as [element] : A | +| CollectionFlow.cs:52:18:52:18 | access to local variable a : A | CollectionFlow.cs:52:9:52:11 | [post] access to local variable as [element] : A | +| CollectionFlow.cs:53:14:53:16 | access to local variable as [element] : A | CollectionFlow.cs:53:14:53:19 | access to array element | +| CollectionFlow.cs:54:18:54:20 | access to local variable as [element] : A | CollectionFlow.cs:374:40:374:41 | ts [element] : A | +| CollectionFlow.cs:55:20:55:22 | access to local variable as [element] : A | CollectionFlow.cs:55:14:55:23 | call to method First | | CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:72:19:72:19 | access to local variable a : A | -| CollectionFlow.cs:72:9:72:12 | [post] access to local variable list [[]] : A | CollectionFlow.cs:73:14:73:17 | access to local variable list [[]] : A | -| CollectionFlow.cs:72:9:72:12 | [post] access to local variable list [[]] : A | CollectionFlow.cs:74:22:74:25 | access to local variable list [[]] : A | -| CollectionFlow.cs:72:9:72:12 | [post] access to local variable list [[]] : A | CollectionFlow.cs:75:24:75:27 | access to local variable list [[]] : A | -| CollectionFlow.cs:72:19:72:19 | access to local variable a : A | CollectionFlow.cs:72:9:72:12 | [post] access to local variable list [[]] : A | -| CollectionFlow.cs:73:14:73:17 | access to local variable list [[]] : A | CollectionFlow.cs:73:14:73:20 | access to indexer | -| CollectionFlow.cs:74:22:74:25 | access to local variable list [[]] : A | CollectionFlow.cs:376:49:376:52 | list [[]] : A | -| CollectionFlow.cs:75:24:75:27 | access to local variable list [[]] : A | CollectionFlow.cs:75:14:75:28 | call to method ListFirst | +| CollectionFlow.cs:72:9:72:12 | [post] access to local variable list [element] : A | CollectionFlow.cs:73:14:73:17 | access to local variable list [element] : A | +| CollectionFlow.cs:72:9:72:12 | [post] access to local variable list [element] : A | CollectionFlow.cs:74:22:74:25 | access to local variable list [element] : A | +| CollectionFlow.cs:72:9:72:12 | [post] access to local variable list [element] : A | CollectionFlow.cs:75:24:75:27 | access to local variable list [element] : A | +| CollectionFlow.cs:72:19:72:19 | access to local variable a : A | CollectionFlow.cs:72:9:72:12 | [post] access to local variable list [element] : A | +| CollectionFlow.cs:73:14:73:17 | access to local variable list [element] : A | CollectionFlow.cs:73:14:73:20 | access to indexer | +| CollectionFlow.cs:74:22:74:25 | access to local variable list [element] : A | CollectionFlow.cs:376:49:376:52 | list [element] : A | +| CollectionFlow.cs:75:24:75:27 | access to local variable list [element] : A | CollectionFlow.cs:75:14:75:28 | call to method ListFirst | | CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:90:36:90:36 | access to local variable a : A | -| CollectionFlow.cs:90:34:90:38 | { ..., ... } [[]] : A | CollectionFlow.cs:91:14:91:17 | access to local variable list [[]] : A | -| CollectionFlow.cs:90:34:90:38 | { ..., ... } [[]] : A | CollectionFlow.cs:92:22:92:25 | access to local variable list [[]] : A | -| CollectionFlow.cs:90:34:90:38 | { ..., ... } [[]] : A | CollectionFlow.cs:93:24:93:27 | access to local variable list [[]] : A | -| CollectionFlow.cs:90:36:90:36 | access to local variable a : A | CollectionFlow.cs:90:34:90:38 | { ..., ... } [[]] : A | -| CollectionFlow.cs:91:14:91:17 | access to local variable list [[]] : A | CollectionFlow.cs:91:14:91:20 | access to indexer | -| CollectionFlow.cs:92:22:92:25 | access to local variable list [[]] : A | CollectionFlow.cs:376:49:376:52 | list [[]] : A | -| CollectionFlow.cs:93:24:93:27 | access to local variable list [[]] : A | CollectionFlow.cs:93:14:93:28 | call to method ListFirst | +| CollectionFlow.cs:90:34:90:38 | { ..., ... } [element] : A | CollectionFlow.cs:91:14:91:17 | access to local variable list [element] : A | +| CollectionFlow.cs:90:34:90:38 | { ..., ... } [element] : A | CollectionFlow.cs:92:22:92:25 | access to local variable list [element] : A | +| CollectionFlow.cs:90:34:90:38 | { ..., ... } [element] : A | CollectionFlow.cs:93:24:93:27 | access to local variable list [element] : A | +| CollectionFlow.cs:90:36:90:36 | access to local variable a : A | CollectionFlow.cs:90:34:90:38 | { ..., ... } [element] : A | +| CollectionFlow.cs:91:14:91:17 | access to local variable list [element] : A | CollectionFlow.cs:91:14:91:20 | access to indexer | +| CollectionFlow.cs:92:22:92:25 | access to local variable list [element] : A | CollectionFlow.cs:376:49:376:52 | list [element] : A | +| CollectionFlow.cs:93:24:93:27 | access to local variable list [element] : A | CollectionFlow.cs:93:14:93:28 | call to method ListFirst | | CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:108:18:108:18 | access to local variable a : A | -| CollectionFlow.cs:108:9:108:12 | [post] access to local variable list [[]] : A | CollectionFlow.cs:109:14:109:17 | access to local variable list [[]] : A | -| CollectionFlow.cs:108:9:108:12 | [post] access to local variable list [[]] : A | CollectionFlow.cs:110:22:110:25 | access to local variable list [[]] : A | -| CollectionFlow.cs:108:9:108:12 | [post] access to local variable list [[]] : A | CollectionFlow.cs:111:24:111:27 | access to local variable list [[]] : A | -| CollectionFlow.cs:108:18:108:18 | access to local variable a : A | CollectionFlow.cs:108:9:108:12 | [post] access to local variable list [[]] : A | -| CollectionFlow.cs:109:14:109:17 | access to local variable list [[]] : A | CollectionFlow.cs:109:14:109:20 | access to indexer | -| CollectionFlow.cs:110:22:110:25 | access to local variable list [[]] : A | CollectionFlow.cs:376:49:376:52 | list [[]] : A | -| CollectionFlow.cs:111:24:111:27 | access to local variable list [[]] : A | CollectionFlow.cs:111:14:111:28 | call to method ListFirst | +| CollectionFlow.cs:108:9:108:12 | [post] access to local variable list [element] : A | CollectionFlow.cs:109:14:109:17 | access to local variable list [element] : A | +| CollectionFlow.cs:108:9:108:12 | [post] access to local variable list [element] : A | CollectionFlow.cs:110:22:110:25 | access to local variable list [element] : A | +| CollectionFlow.cs:108:9:108:12 | [post] access to local variable list [element] : A | CollectionFlow.cs:111:24:111:27 | access to local variable list [element] : A | +| CollectionFlow.cs:108:18:108:18 | access to local variable a : A | CollectionFlow.cs:108:9:108:12 | [post] access to local variable list [element] : A | +| CollectionFlow.cs:109:14:109:17 | access to local variable list [element] : A | CollectionFlow.cs:109:14:109:20 | access to indexer | +| CollectionFlow.cs:110:22:110:25 | access to local variable list [element] : A | CollectionFlow.cs:376:49:376:52 | list [element] : A | +| CollectionFlow.cs:111:24:111:27 | access to local variable list [element] : A | CollectionFlow.cs:111:14:111:28 | call to method ListFirst | | CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:127:19:127:19 | access to local variable a : A | -| CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [[], Value] : A | CollectionFlow.cs:128:14:128:17 | access to local variable dict [[], Value] : A | -| CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [[], Value] : A | CollectionFlow.cs:129:23:129:26 | access to local variable dict [[], Value] : A | -| CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [[], Value] : A | CollectionFlow.cs:130:28:130:31 | access to local variable dict [[], Value] : A | -| CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [[], Value] : A | CollectionFlow.cs:131:29:131:32 | access to local variable dict [[], Value] : A | -| CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [[], Value] : A | CollectionFlow.cs:132:30:132:33 | access to local variable dict [[], Value] : A | -| CollectionFlow.cs:127:19:127:19 | access to local variable a : A | CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [[], Value] : A | -| CollectionFlow.cs:128:14:128:17 | access to local variable dict [[], Value] : A | CollectionFlow.cs:128:14:128:20 | access to indexer | -| CollectionFlow.cs:129:23:129:26 | access to local variable dict [[], Value] : A | CollectionFlow.cs:378:61:378:64 | dict [[], Value] : A | -| CollectionFlow.cs:130:28:130:31 | access to local variable dict [[], Value] : A | CollectionFlow.cs:130:14:130:32 | call to method DictIndexZero | -| CollectionFlow.cs:131:29:131:32 | access to local variable dict [[], Value] : A | CollectionFlow.cs:131:14:131:33 | call to method DictFirstValue | -| CollectionFlow.cs:132:30:132:33 | access to local variable dict [[], Value] : A | CollectionFlow.cs:132:14:132:34 | call to method DictValuesFirst | +| CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [element, property Value] : A | CollectionFlow.cs:128:14:128:17 | access to local variable dict [element, property Value] : A | +| CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [element, property Value] : A | CollectionFlow.cs:129:23:129:26 | access to local variable dict [element, property Value] : A | +| CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [element, property Value] : A | CollectionFlow.cs:130:28:130:31 | access to local variable dict [element, property Value] : A | +| CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [element, property Value] : A | CollectionFlow.cs:131:29:131:32 | access to local variable dict [element, property Value] : A | +| CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [element, property Value] : A | CollectionFlow.cs:132:30:132:33 | access to local variable dict [element, property Value] : A | +| CollectionFlow.cs:127:19:127:19 | access to local variable a : A | CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [element, property Value] : A | +| CollectionFlow.cs:128:14:128:17 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:128:14:128:20 | access to indexer | +| CollectionFlow.cs:129:23:129:26 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:378:61:378:64 | dict [element, property Value] : A | +| CollectionFlow.cs:130:28:130:31 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:130:14:130:32 | call to method DictIndexZero | +| CollectionFlow.cs:131:29:131:32 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:131:14:131:33 | call to method DictFirstValue | +| CollectionFlow.cs:132:30:132:33 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:132:14:132:34 | call to method DictValuesFirst | | CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:149:52:149:52 | access to local variable a : A | -| CollectionFlow.cs:149:45:149:56 | { ..., ... } [[], Value] : A | CollectionFlow.cs:150:14:150:17 | access to local variable dict [[], Value] : A | -| CollectionFlow.cs:149:45:149:56 | { ..., ... } [[], Value] : A | CollectionFlow.cs:151:23:151:26 | access to local variable dict [[], Value] : A | -| CollectionFlow.cs:149:45:149:56 | { ..., ... } [[], Value] : A | CollectionFlow.cs:152:28:152:31 | access to local variable dict [[], Value] : A | -| CollectionFlow.cs:149:45:149:56 | { ..., ... } [[], Value] : A | CollectionFlow.cs:153:29:153:32 | access to local variable dict [[], Value] : A | -| CollectionFlow.cs:149:45:149:56 | { ..., ... } [[], Value] : A | CollectionFlow.cs:154:30:154:33 | access to local variable dict [[], Value] : A | -| CollectionFlow.cs:149:52:149:52 | access to local variable a : A | CollectionFlow.cs:149:45:149:56 | { ..., ... } [[], Value] : A | -| CollectionFlow.cs:150:14:150:17 | access to local variable dict [[], Value] : A | CollectionFlow.cs:150:14:150:20 | access to indexer | -| CollectionFlow.cs:151:23:151:26 | access to local variable dict [[], Value] : A | CollectionFlow.cs:378:61:378:64 | dict [[], Value] : A | -| CollectionFlow.cs:152:28:152:31 | access to local variable dict [[], Value] : A | CollectionFlow.cs:152:14:152:32 | call to method DictIndexZero | -| CollectionFlow.cs:153:29:153:32 | access to local variable dict [[], Value] : A | CollectionFlow.cs:153:14:153:33 | call to method DictFirstValue | -| CollectionFlow.cs:154:30:154:33 | access to local variable dict [[], Value] : A | CollectionFlow.cs:154:14:154:34 | call to method DictValuesFirst | +| CollectionFlow.cs:149:45:149:56 | { ..., ... } [element, property Value] : A | CollectionFlow.cs:150:14:150:17 | access to local variable dict [element, property Value] : A | +| CollectionFlow.cs:149:45:149:56 | { ..., ... } [element, property Value] : A | CollectionFlow.cs:151:23:151:26 | access to local variable dict [element, property Value] : A | +| CollectionFlow.cs:149:45:149:56 | { ..., ... } [element, property Value] : A | CollectionFlow.cs:152:28:152:31 | access to local variable dict [element, property Value] : A | +| CollectionFlow.cs:149:45:149:56 | { ..., ... } [element, property Value] : A | CollectionFlow.cs:153:29:153:32 | access to local variable dict [element, property Value] : A | +| CollectionFlow.cs:149:45:149:56 | { ..., ... } [element, property Value] : A | CollectionFlow.cs:154:30:154:33 | access to local variable dict [element, property Value] : A | +| CollectionFlow.cs:149:52:149:52 | access to local variable a : A | CollectionFlow.cs:149:45:149:56 | { ..., ... } [element, property Value] : A | +| CollectionFlow.cs:150:14:150:17 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:150:14:150:20 | access to indexer | +| CollectionFlow.cs:151:23:151:26 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:378:61:378:64 | dict [element, property Value] : A | +| CollectionFlow.cs:152:28:152:31 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:152:14:152:32 | call to method DictIndexZero | +| CollectionFlow.cs:153:29:153:32 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:153:14:153:33 | call to method DictFirstValue | +| CollectionFlow.cs:154:30:154:33 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:154:14:154:34 | call to method DictValuesFirst | | CollectionFlow.cs:169:17:169:23 | object creation of type A : A | CollectionFlow.cs:170:53:170:53 | access to local variable a : A | -| CollectionFlow.cs:170:45:170:55 | { ..., ... } [[], Value] : A | CollectionFlow.cs:171:14:171:17 | access to local variable dict [[], Value] : A | -| CollectionFlow.cs:170:45:170:55 | { ..., ... } [[], Value] : A | CollectionFlow.cs:172:23:172:26 | access to local variable dict [[], Value] : A | -| CollectionFlow.cs:170:45:170:55 | { ..., ... } [[], Value] : A | CollectionFlow.cs:173:28:173:31 | access to local variable dict [[], Value] : A | -| CollectionFlow.cs:170:45:170:55 | { ..., ... } [[], Value] : A | CollectionFlow.cs:174:29:174:32 | access to local variable dict [[], Value] : A | -| CollectionFlow.cs:170:45:170:55 | { ..., ... } [[], Value] : A | CollectionFlow.cs:175:30:175:33 | access to local variable dict [[], Value] : A | -| CollectionFlow.cs:170:53:170:53 | access to local variable a : A | CollectionFlow.cs:170:45:170:55 | { ..., ... } [[], Value] : A | -| CollectionFlow.cs:171:14:171:17 | access to local variable dict [[], Value] : A | CollectionFlow.cs:171:14:171:20 | access to indexer | -| CollectionFlow.cs:172:23:172:26 | access to local variable dict [[], Value] : A | CollectionFlow.cs:378:61:378:64 | dict [[], Value] : A | -| CollectionFlow.cs:173:28:173:31 | access to local variable dict [[], Value] : A | CollectionFlow.cs:173:14:173:32 | call to method DictIndexZero | -| CollectionFlow.cs:174:29:174:32 | access to local variable dict [[], Value] : A | CollectionFlow.cs:174:14:174:33 | call to method DictFirstValue | -| CollectionFlow.cs:175:30:175:33 | access to local variable dict [[], Value] : A | CollectionFlow.cs:175:14:175:34 | call to method DictValuesFirst | +| CollectionFlow.cs:170:45:170:55 | { ..., ... } [element, property Value] : A | CollectionFlow.cs:171:14:171:17 | access to local variable dict [element, property Value] : A | +| CollectionFlow.cs:170:45:170:55 | { ..., ... } [element, property Value] : A | CollectionFlow.cs:172:23:172:26 | access to local variable dict [element, property Value] : A | +| CollectionFlow.cs:170:45:170:55 | { ..., ... } [element, property Value] : A | CollectionFlow.cs:173:28:173:31 | access to local variable dict [element, property Value] : A | +| CollectionFlow.cs:170:45:170:55 | { ..., ... } [element, property Value] : A | CollectionFlow.cs:174:29:174:32 | access to local variable dict [element, property Value] : A | +| CollectionFlow.cs:170:45:170:55 | { ..., ... } [element, property Value] : A | CollectionFlow.cs:175:30:175:33 | access to local variable dict [element, property Value] : A | +| CollectionFlow.cs:170:53:170:53 | access to local variable a : A | CollectionFlow.cs:170:45:170:55 | { ..., ... } [element, property Value] : A | +| CollectionFlow.cs:171:14:171:17 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:171:14:171:20 | access to indexer | +| CollectionFlow.cs:172:23:172:26 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:378:61:378:64 | dict [element, property Value] : A | +| CollectionFlow.cs:173:28:173:31 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:173:14:173:32 | call to method DictIndexZero | +| CollectionFlow.cs:174:29:174:32 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:174:14:174:33 | call to method DictFirstValue | +| CollectionFlow.cs:175:30:175:33 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:175:14:175:34 | call to method DictValuesFirst | | CollectionFlow.cs:191:17:191:23 | object creation of type A : A | CollectionFlow.cs:192:49:192:49 | access to local variable a : A | -| CollectionFlow.cs:192:45:192:56 | { ..., ... } [[], Key] : A | CollectionFlow.cs:193:14:193:17 | access to local variable dict [[], Key] : A | -| CollectionFlow.cs:192:45:192:56 | { ..., ... } [[], Key] : A | CollectionFlow.cs:194:21:194:24 | access to local variable dict [[], Key] : A | -| CollectionFlow.cs:192:45:192:56 | { ..., ... } [[], Key] : A | CollectionFlow.cs:195:28:195:31 | access to local variable dict [[], Key] : A | -| CollectionFlow.cs:192:45:192:56 | { ..., ... } [[], Key] : A | CollectionFlow.cs:196:27:196:30 | access to local variable dict [[], Key] : A | -| CollectionFlow.cs:192:49:192:49 | access to local variable a : A | CollectionFlow.cs:192:45:192:56 | { ..., ... } [[], Key] : A | -| CollectionFlow.cs:193:14:193:17 | access to local variable dict [[], Key] : A | CollectionFlow.cs:193:14:193:22 | access to property Keys [[]] : A | -| CollectionFlow.cs:193:14:193:22 | access to property Keys [[]] : A | CollectionFlow.cs:193:14:193:30 | call to method First | -| CollectionFlow.cs:194:21:194:24 | access to local variable dict [[], Key] : A | CollectionFlow.cs:380:59:380:62 | dict [[], Key] : A | -| CollectionFlow.cs:195:28:195:31 | access to local variable dict [[], Key] : A | CollectionFlow.cs:195:14:195:32 | call to method DictKeysFirst | -| CollectionFlow.cs:196:27:196:30 | access to local variable dict [[], Key] : A | CollectionFlow.cs:196:14:196:31 | call to method DictFirstKey | +| CollectionFlow.cs:192:45:192:56 | { ..., ... } [element, property Key] : A | CollectionFlow.cs:193:14:193:17 | access to local variable dict [element, property Key] : A | +| CollectionFlow.cs:192:45:192:56 | { ..., ... } [element, property Key] : A | CollectionFlow.cs:194:21:194:24 | access to local variable dict [element, property Key] : A | +| CollectionFlow.cs:192:45:192:56 | { ..., ... } [element, property Key] : A | CollectionFlow.cs:195:28:195:31 | access to local variable dict [element, property Key] : A | +| CollectionFlow.cs:192:45:192:56 | { ..., ... } [element, property Key] : A | CollectionFlow.cs:196:27:196:30 | access to local variable dict [element, property Key] : A | +| CollectionFlow.cs:192:49:192:49 | access to local variable a : A | CollectionFlow.cs:192:45:192:56 | { ..., ... } [element, property Key] : A | +| CollectionFlow.cs:193:14:193:17 | access to local variable dict [element, property Key] : A | CollectionFlow.cs:193:14:193:22 | access to property Keys [element] : A | +| CollectionFlow.cs:193:14:193:22 | access to property Keys [element] : A | CollectionFlow.cs:193:14:193:30 | call to method First | +| CollectionFlow.cs:194:21:194:24 | access to local variable dict [element, property Key] : A | CollectionFlow.cs:380:59:380:62 | dict [element, property Key] : A | +| CollectionFlow.cs:195:28:195:31 | access to local variable dict [element, property Key] : A | CollectionFlow.cs:195:14:195:32 | call to method DictKeysFirst | +| CollectionFlow.cs:196:27:196:30 | access to local variable dict [element, property Key] : A | CollectionFlow.cs:196:14:196:31 | call to method DictFirstKey | | CollectionFlow.cs:210:17:210:23 | object creation of type A : A | CollectionFlow.cs:211:48:211:48 | access to local variable a : A | -| CollectionFlow.cs:211:45:211:55 | { ..., ... } [[], Key] : A | CollectionFlow.cs:212:14:212:17 | access to local variable dict [[], Key] : A | -| CollectionFlow.cs:211:45:211:55 | { ..., ... } [[], Key] : A | CollectionFlow.cs:213:21:213:24 | access to local variable dict [[], Key] : A | -| CollectionFlow.cs:211:45:211:55 | { ..., ... } [[], Key] : A | CollectionFlow.cs:214:28:214:31 | access to local variable dict [[], Key] : A | -| CollectionFlow.cs:211:45:211:55 | { ..., ... } [[], Key] : A | CollectionFlow.cs:215:27:215:30 | access to local variable dict [[], Key] : A | -| CollectionFlow.cs:211:48:211:48 | access to local variable a : A | CollectionFlow.cs:211:45:211:55 | { ..., ... } [[], Key] : A | -| CollectionFlow.cs:212:14:212:17 | access to local variable dict [[], Key] : A | CollectionFlow.cs:212:14:212:22 | access to property Keys [[]] : A | -| CollectionFlow.cs:212:14:212:22 | access to property Keys [[]] : A | CollectionFlow.cs:212:14:212:30 | call to method First | -| CollectionFlow.cs:213:21:213:24 | access to local variable dict [[], Key] : A | CollectionFlow.cs:380:59:380:62 | dict [[], Key] : A | -| CollectionFlow.cs:214:28:214:31 | access to local variable dict [[], Key] : A | CollectionFlow.cs:214:14:214:32 | call to method DictKeysFirst | -| CollectionFlow.cs:215:27:215:30 | access to local variable dict [[], Key] : A | CollectionFlow.cs:215:14:215:31 | call to method DictFirstKey | +| CollectionFlow.cs:211:45:211:55 | { ..., ... } [element, property Key] : A | CollectionFlow.cs:212:14:212:17 | access to local variable dict [element, property Key] : A | +| CollectionFlow.cs:211:45:211:55 | { ..., ... } [element, property Key] : A | CollectionFlow.cs:213:21:213:24 | access to local variable dict [element, property Key] : A | +| CollectionFlow.cs:211:45:211:55 | { ..., ... } [element, property Key] : A | CollectionFlow.cs:214:28:214:31 | access to local variable dict [element, property Key] : A | +| CollectionFlow.cs:211:45:211:55 | { ..., ... } [element, property Key] : A | CollectionFlow.cs:215:27:215:30 | access to local variable dict [element, property Key] : A | +| CollectionFlow.cs:211:48:211:48 | access to local variable a : A | CollectionFlow.cs:211:45:211:55 | { ..., ... } [element, property Key] : A | +| CollectionFlow.cs:212:14:212:17 | access to local variable dict [element, property Key] : A | CollectionFlow.cs:212:14:212:22 | access to property Keys [element] : A | +| CollectionFlow.cs:212:14:212:22 | access to property Keys [element] : A | CollectionFlow.cs:212:14:212:30 | call to method First | +| CollectionFlow.cs:213:21:213:24 | access to local variable dict [element, property Key] : A | CollectionFlow.cs:380:59:380:62 | dict [element, property Key] : A | +| CollectionFlow.cs:214:28:214:31 | access to local variable dict [element, property Key] : A | CollectionFlow.cs:214:14:214:32 | call to method DictKeysFirst | +| CollectionFlow.cs:215:27:215:30 | access to local variable dict [element, property Key] : A | CollectionFlow.cs:215:14:215:31 | call to method DictFirstKey | | CollectionFlow.cs:229:17:229:23 | object creation of type A : A | CollectionFlow.cs:230:27:230:27 | access to local variable a : A | -| CollectionFlow.cs:230:25:230:29 | { ..., ... } [[]] : A | CollectionFlow.cs:231:27:231:29 | access to local variable as [[]] : A | -| CollectionFlow.cs:230:27:230:27 | access to local variable a : A | CollectionFlow.cs:230:25:230:29 | { ..., ... } [[]] : A | +| CollectionFlow.cs:230:25:230:29 | { ..., ... } [element] : A | CollectionFlow.cs:231:27:231:29 | access to local variable as [element] : A | +| CollectionFlow.cs:230:27:230:27 | access to local variable a : A | CollectionFlow.cs:230:25:230:29 | { ..., ... } [element] : A | | CollectionFlow.cs:231:22:231:22 | SSA def(x) : A | CollectionFlow.cs:232:18:232:18 | access to local variable x | -| CollectionFlow.cs:231:27:231:29 | access to local variable as [[]] : A | CollectionFlow.cs:231:22:231:22 | SSA def(x) : A | +| CollectionFlow.cs:231:27:231:29 | access to local variable as [element] : A | CollectionFlow.cs:231:22:231:22 | SSA def(x) : A | | CollectionFlow.cs:244:17:244:23 | object creation of type A : A | CollectionFlow.cs:245:27:245:27 | access to local variable a : A | -| CollectionFlow.cs:245:25:245:29 | { ..., ... } [[]] : A | CollectionFlow.cs:246:26:246:28 | access to local variable as [[]] : A | -| CollectionFlow.cs:245:27:245:27 | access to local variable a : A | CollectionFlow.cs:245:25:245:29 | { ..., ... } [[]] : A | -| CollectionFlow.cs:246:26:246:28 | access to local variable as [[]] : A | CollectionFlow.cs:246:26:246:44 | call to method GetEnumerator [Current] : A | -| CollectionFlow.cs:246:26:246:44 | call to method GetEnumerator [Current] : A | CollectionFlow.cs:248:18:248:27 | access to local variable enumerator [Current] : A | -| CollectionFlow.cs:248:18:248:27 | access to local variable enumerator [Current] : A | CollectionFlow.cs:248:18:248:35 | access to property Current | +| CollectionFlow.cs:245:25:245:29 | { ..., ... } [element] : A | CollectionFlow.cs:246:26:246:28 | access to local variable as [element] : A | +| CollectionFlow.cs:245:27:245:27 | access to local variable a : A | CollectionFlow.cs:245:25:245:29 | { ..., ... } [element] : A | +| CollectionFlow.cs:246:26:246:28 | access to local variable as [element] : A | CollectionFlow.cs:246:26:246:44 | call to method GetEnumerator [property Current] : A | +| CollectionFlow.cs:246:26:246:44 | call to method GetEnumerator [property Current] : A | CollectionFlow.cs:248:18:248:27 | access to local variable enumerator [property Current] : A | +| CollectionFlow.cs:248:18:248:27 | access to local variable enumerator [property Current] : A | CollectionFlow.cs:248:18:248:35 | access to property Current | | CollectionFlow.cs:261:17:261:23 | object creation of type A : A | CollectionFlow.cs:263:18:263:18 | access to local variable a : A | -| CollectionFlow.cs:263:9:263:12 | [post] access to local variable list [[]] : A | CollectionFlow.cs:264:26:264:29 | access to local variable list [[]] : A | -| CollectionFlow.cs:263:18:263:18 | access to local variable a : A | CollectionFlow.cs:263:9:263:12 | [post] access to local variable list [[]] : A | -| CollectionFlow.cs:264:26:264:29 | access to local variable list [[]] : A | CollectionFlow.cs:264:26:264:45 | call to method GetEnumerator [Current] : A | -| CollectionFlow.cs:264:26:264:45 | call to method GetEnumerator [Current] : A | CollectionFlow.cs:266:18:266:27 | access to local variable enumerator [Current] : A | -| CollectionFlow.cs:266:18:266:27 | access to local variable enumerator [Current] : A | CollectionFlow.cs:266:18:266:35 | access to property Current | +| CollectionFlow.cs:263:9:263:12 | [post] access to local variable list [element] : A | CollectionFlow.cs:264:26:264:29 | access to local variable list [element] : A | +| CollectionFlow.cs:263:18:263:18 | access to local variable a : A | CollectionFlow.cs:263:9:263:12 | [post] access to local variable list [element] : A | +| CollectionFlow.cs:264:26:264:29 | access to local variable list [element] : A | CollectionFlow.cs:264:26:264:45 | call to method GetEnumerator [property Current] : A | +| CollectionFlow.cs:264:26:264:45 | call to method GetEnumerator [property Current] : A | CollectionFlow.cs:266:18:266:27 | access to local variable enumerator [property Current] : A | +| CollectionFlow.cs:266:18:266:27 | access to local variable enumerator [property Current] : A | CollectionFlow.cs:266:18:266:35 | access to property Current | | CollectionFlow.cs:280:17:280:23 | object creation of type A : A | CollectionFlow.cs:282:43:282:43 | access to local variable a : A | -| CollectionFlow.cs:282:9:282:12 | [post] access to local variable list [[], Key] : A | CollectionFlow.cs:283:9:283:12 | access to local variable list [[], Key] : A | -| CollectionFlow.cs:282:18:282:47 | object creation of type KeyValuePair [Key] : A | CollectionFlow.cs:282:9:282:12 | [post] access to local variable list [[], Key] : A | -| CollectionFlow.cs:282:43:282:43 | access to local variable a : A | CollectionFlow.cs:282:18:282:47 | object creation of type KeyValuePair [Key] : A | -| CollectionFlow.cs:283:9:283:12 | access to local variable list [[], Key] : A | CollectionFlow.cs:283:21:283:23 | kvp [Key] : A | -| CollectionFlow.cs:283:21:283:23 | kvp [Key] : A | CollectionFlow.cs:285:18:285:20 | access to parameter kvp [Key] : A | -| CollectionFlow.cs:285:18:285:20 | access to parameter kvp [Key] : A | CollectionFlow.cs:285:18:285:24 | access to property Key | +| CollectionFlow.cs:282:9:282:12 | [post] access to local variable list [element, property Key] : A | CollectionFlow.cs:283:9:283:12 | access to local variable list [element, property Key] : A | +| CollectionFlow.cs:282:18:282:47 | object creation of type KeyValuePair [property Key] : A | CollectionFlow.cs:282:9:282:12 | [post] access to local variable list [element, property Key] : A | +| CollectionFlow.cs:282:43:282:43 | access to local variable a : A | CollectionFlow.cs:282:18:282:47 | object creation of type KeyValuePair [property Key] : A | +| CollectionFlow.cs:283:9:283:12 | access to local variable list [element, property Key] : A | CollectionFlow.cs:283:21:283:23 | kvp [property Key] : A | +| CollectionFlow.cs:283:21:283:23 | kvp [property Key] : A | CollectionFlow.cs:285:18:285:20 | access to parameter kvp [property Key] : A | +| CollectionFlow.cs:285:18:285:20 | access to parameter kvp [property Key] : A | CollectionFlow.cs:285:18:285:24 | access to property Key | | CollectionFlow.cs:306:17:306:23 | object creation of type A : A | CollectionFlow.cs:308:23:308:23 | access to local variable a : A | -| CollectionFlow.cs:308:18:308:20 | [post] access to local variable as [[]] : A | CollectionFlow.cs:309:14:309:16 | access to local variable as [[]] : A | -| CollectionFlow.cs:308:18:308:20 | [post] access to local variable as [[]] : A | CollectionFlow.cs:310:18:310:20 | access to local variable as [[]] : A | -| CollectionFlow.cs:308:18:308:20 | [post] access to local variable as [[]] : A | CollectionFlow.cs:311:20:311:22 | access to local variable as [[]] : A | -| CollectionFlow.cs:308:23:308:23 | access to local variable a : A | CollectionFlow.cs:308:18:308:20 | [post] access to local variable as [[]] : A | -| CollectionFlow.cs:309:14:309:16 | access to local variable as [[]] : A | CollectionFlow.cs:309:14:309:19 | access to array element | -| CollectionFlow.cs:310:18:310:20 | access to local variable as [[]] : A | CollectionFlow.cs:374:40:374:41 | ts [[]] : A | -| CollectionFlow.cs:311:20:311:22 | access to local variable as [[]] : A | CollectionFlow.cs:311:14:311:23 | call to method First | +| CollectionFlow.cs:308:18:308:20 | [post] access to local variable as [element] : A | CollectionFlow.cs:309:14:309:16 | access to local variable as [element] : A | +| CollectionFlow.cs:308:18:308:20 | [post] access to local variable as [element] : A | CollectionFlow.cs:310:18:310:20 | access to local variable as [element] : A | +| CollectionFlow.cs:308:18:308:20 | [post] access to local variable as [element] : A | CollectionFlow.cs:311:20:311:22 | access to local variable as [element] : A | +| CollectionFlow.cs:308:23:308:23 | access to local variable a : A | CollectionFlow.cs:308:18:308:20 | [post] access to local variable as [element] : A | +| CollectionFlow.cs:309:14:309:16 | access to local variable as [element] : A | CollectionFlow.cs:309:14:309:19 | access to array element | +| CollectionFlow.cs:310:18:310:20 | access to local variable as [element] : A | CollectionFlow.cs:374:40:374:41 | ts [element] : A | +| CollectionFlow.cs:311:20:311:22 | access to local variable as [element] : A | CollectionFlow.cs:311:14:311:23 | call to method First | | CollectionFlow.cs:328:17:328:23 | object creation of type A : A | CollectionFlow.cs:330:23:330:23 | access to local variable a : A | -| CollectionFlow.cs:330:17:330:20 | [post] access to local variable list [[]] : A | CollectionFlow.cs:331:14:331:17 | access to local variable list [[]] : A | -| CollectionFlow.cs:330:17:330:20 | [post] access to local variable list [[]] : A | CollectionFlow.cs:332:22:332:25 | access to local variable list [[]] : A | -| CollectionFlow.cs:330:17:330:20 | [post] access to local variable list [[]] : A | CollectionFlow.cs:333:24:333:27 | access to local variable list [[]] : A | -| CollectionFlow.cs:330:23:330:23 | access to local variable a : A | CollectionFlow.cs:330:17:330:20 | [post] access to local variable list [[]] : A | -| CollectionFlow.cs:331:14:331:17 | access to local variable list [[]] : A | CollectionFlow.cs:331:14:331:20 | access to indexer | -| CollectionFlow.cs:332:22:332:25 | access to local variable list [[]] : A | CollectionFlow.cs:376:49:376:52 | list [[]] : A | -| CollectionFlow.cs:333:24:333:27 | access to local variable list [[]] : A | CollectionFlow.cs:333:14:333:28 | call to method ListFirst | -| CollectionFlow.cs:347:20:347:26 | object creation of type A : A | CollectionFlow.cs:396:49:396:52 | args [[]] : A | -| CollectionFlow.cs:348:26:348:32 | object creation of type A : A | CollectionFlow.cs:396:49:396:52 | args [[]] : A | -| CollectionFlow.cs:349:26:349:32 | object creation of type A : A | CollectionFlow.cs:396:49:396:52 | args [[]] : A | -| CollectionFlow.cs:350:20:350:38 | array creation of type A[] [[]] : A | CollectionFlow.cs:396:49:396:52 | args [[]] : A | -| CollectionFlow.cs:350:28:350:38 | { ..., ... } [[]] : A | CollectionFlow.cs:350:20:350:38 | array creation of type A[] [[]] : A | -| CollectionFlow.cs:350:30:350:36 | object creation of type A : A | CollectionFlow.cs:350:28:350:38 | { ..., ... } [[]] : A | -| CollectionFlow.cs:374:40:374:41 | ts [[]] : A | CollectionFlow.cs:374:52:374:53 | access to parameter ts [[]] : A | -| CollectionFlow.cs:374:40:374:41 | ts [[]] : A | CollectionFlow.cs:374:52:374:53 | access to parameter ts [[]] : A | -| CollectionFlow.cs:374:52:374:53 | access to parameter ts [[]] : A | CollectionFlow.cs:374:52:374:56 | access to array element | -| CollectionFlow.cs:374:52:374:53 | access to parameter ts [[]] : A | CollectionFlow.cs:374:52:374:56 | access to array element | -| CollectionFlow.cs:376:49:376:52 | list [[]] : A | CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | -| CollectionFlow.cs:376:49:376:52 | list [[]] : A | CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | -| CollectionFlow.cs:376:49:376:52 | list [[]] : A | CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | -| CollectionFlow.cs:376:49:376:52 | list [[]] : A | CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | -| CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | CollectionFlow.cs:376:63:376:69 | access to indexer | -| CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | CollectionFlow.cs:376:63:376:69 | access to indexer | -| CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | CollectionFlow.cs:376:63:376:69 | access to indexer | -| CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | CollectionFlow.cs:376:63:376:69 | access to indexer | -| CollectionFlow.cs:378:61:378:64 | dict [[], Value] : A | CollectionFlow.cs:378:75:378:78 | access to parameter dict [[], Value] : A | -| CollectionFlow.cs:378:75:378:78 | access to parameter dict [[], Value] : A | CollectionFlow.cs:378:75:378:81 | access to indexer | -| CollectionFlow.cs:380:59:380:62 | dict [[], Key] : A | CollectionFlow.cs:380:73:380:76 | access to parameter dict [[], Key] : A | -| CollectionFlow.cs:380:73:380:76 | access to parameter dict [[], Key] : A | CollectionFlow.cs:380:73:380:81 | access to property Keys [[]] : A | -| CollectionFlow.cs:380:73:380:81 | access to property Keys [[]] : A | CollectionFlow.cs:380:73:380:89 | call to method First | -| CollectionFlow.cs:396:49:396:52 | args [[]] : A | CollectionFlow.cs:396:63:396:66 | access to parameter args [[]] : A | -| CollectionFlow.cs:396:49:396:52 | args [[]] : A | CollectionFlow.cs:396:63:396:66 | access to parameter args [[]] : A | -| CollectionFlow.cs:396:63:396:66 | access to parameter args [[]] : A | CollectionFlow.cs:396:63:396:69 | access to array element | -| CollectionFlow.cs:396:63:396:66 | access to parameter args [[]] : A | CollectionFlow.cs:396:63:396:69 | access to array element | +| CollectionFlow.cs:330:17:330:20 | [post] access to local variable list [element] : A | CollectionFlow.cs:331:14:331:17 | access to local variable list [element] : A | +| CollectionFlow.cs:330:17:330:20 | [post] access to local variable list [element] : A | CollectionFlow.cs:332:22:332:25 | access to local variable list [element] : A | +| CollectionFlow.cs:330:17:330:20 | [post] access to local variable list [element] : A | CollectionFlow.cs:333:24:333:27 | access to local variable list [element] : A | +| CollectionFlow.cs:330:23:330:23 | access to local variable a : A | CollectionFlow.cs:330:17:330:20 | [post] access to local variable list [element] : A | +| CollectionFlow.cs:331:14:331:17 | access to local variable list [element] : A | CollectionFlow.cs:331:14:331:20 | access to indexer | +| CollectionFlow.cs:332:22:332:25 | access to local variable list [element] : A | CollectionFlow.cs:376:49:376:52 | list [element] : A | +| CollectionFlow.cs:333:24:333:27 | access to local variable list [element] : A | CollectionFlow.cs:333:14:333:28 | call to method ListFirst | +| CollectionFlow.cs:347:20:347:26 | object creation of type A : A | CollectionFlow.cs:396:49:396:52 | args [element] : A | +| CollectionFlow.cs:348:26:348:32 | object creation of type A : A | CollectionFlow.cs:396:49:396:52 | args [element] : A | +| CollectionFlow.cs:349:26:349:32 | object creation of type A : A | CollectionFlow.cs:396:49:396:52 | args [element] : A | +| CollectionFlow.cs:350:20:350:38 | array creation of type A[] [element] : A | CollectionFlow.cs:396:49:396:52 | args [element] : A | +| CollectionFlow.cs:350:28:350:38 | { ..., ... } [element] : A | CollectionFlow.cs:350:20:350:38 | array creation of type A[] [element] : A | +| CollectionFlow.cs:350:30:350:36 | object creation of type A : A | CollectionFlow.cs:350:28:350:38 | { ..., ... } [element] : A | +| CollectionFlow.cs:374:40:374:41 | ts [element] : A | CollectionFlow.cs:374:52:374:53 | access to parameter ts [element] : A | +| CollectionFlow.cs:374:40:374:41 | ts [element] : A | CollectionFlow.cs:374:52:374:53 | access to parameter ts [element] : A | +| CollectionFlow.cs:374:52:374:53 | access to parameter ts [element] : A | CollectionFlow.cs:374:52:374:56 | access to array element | +| CollectionFlow.cs:374:52:374:53 | access to parameter ts [element] : A | CollectionFlow.cs:374:52:374:56 | access to array element | +| CollectionFlow.cs:376:49:376:52 | list [element] : A | CollectionFlow.cs:376:63:376:66 | access to parameter list [element] : A | +| CollectionFlow.cs:376:49:376:52 | list [element] : A | CollectionFlow.cs:376:63:376:66 | access to parameter list [element] : A | +| CollectionFlow.cs:376:49:376:52 | list [element] : A | CollectionFlow.cs:376:63:376:66 | access to parameter list [element] : A | +| CollectionFlow.cs:376:49:376:52 | list [element] : A | CollectionFlow.cs:376:63:376:66 | access to parameter list [element] : A | +| CollectionFlow.cs:376:63:376:66 | access to parameter list [element] : A | CollectionFlow.cs:376:63:376:69 | access to indexer | +| CollectionFlow.cs:376:63:376:66 | access to parameter list [element] : A | CollectionFlow.cs:376:63:376:69 | access to indexer | +| CollectionFlow.cs:376:63:376:66 | access to parameter list [element] : A | CollectionFlow.cs:376:63:376:69 | access to indexer | +| CollectionFlow.cs:376:63:376:66 | access to parameter list [element] : A | CollectionFlow.cs:376:63:376:69 | access to indexer | +| CollectionFlow.cs:378:61:378:64 | dict [element, property Value] : A | CollectionFlow.cs:378:75:378:78 | access to parameter dict [element, property Value] : A | +| CollectionFlow.cs:378:75:378:78 | access to parameter dict [element, property Value] : A | CollectionFlow.cs:378:75:378:81 | access to indexer | +| CollectionFlow.cs:380:59:380:62 | dict [element, property Key] : A | CollectionFlow.cs:380:73:380:76 | access to parameter dict [element, property Key] : A | +| CollectionFlow.cs:380:73:380:76 | access to parameter dict [element, property Key] : A | CollectionFlow.cs:380:73:380:81 | access to property Keys [element] : A | +| CollectionFlow.cs:380:73:380:81 | access to property Keys [element] : A | CollectionFlow.cs:380:73:380:89 | call to method First | +| CollectionFlow.cs:396:49:396:52 | args [element] : A | CollectionFlow.cs:396:63:396:66 | access to parameter args [element] : A | +| CollectionFlow.cs:396:49:396:52 | args [element] : A | CollectionFlow.cs:396:63:396:66 | access to parameter args [element] : A | +| CollectionFlow.cs:396:63:396:66 | access to parameter args [element] : A | CollectionFlow.cs:396:63:396:69 | access to array element | +| CollectionFlow.cs:396:63:396:66 | access to parameter args [element] : A | CollectionFlow.cs:396:63:396:69 | access to array element | nodes | CollectionFlow.cs:14:17:14:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:15:25:15:29 | { ..., ... } [[]] : A | semmle.label | { ..., ... } [[]] : A | +| CollectionFlow.cs:15:25:15:29 | { ..., ... } [element] : A | semmle.label | { ..., ... } [element] : A | | CollectionFlow.cs:15:27:15:27 | access to local variable a : A | semmle.label | access to local variable a : A | -| CollectionFlow.cs:16:14:16:16 | access to local variable as [[]] : A | semmle.label | access to local variable as [[]] : A | +| CollectionFlow.cs:16:14:16:16 | access to local variable as [element] : A | semmle.label | access to local variable as [element] : A | | CollectionFlow.cs:16:14:16:19 | access to array element | semmle.label | access to array element | -| CollectionFlow.cs:17:18:17:20 | access to local variable as [[]] : A | semmle.label | access to local variable as [[]] : A | +| CollectionFlow.cs:17:18:17:20 | access to local variable as [element] : A | semmle.label | access to local variable as [element] : A | | CollectionFlow.cs:18:14:18:23 | call to method First | semmle.label | call to method First | -| CollectionFlow.cs:18:20:18:22 | access to local variable as [[]] : A | semmle.label | access to local variable as [[]] : A | +| CollectionFlow.cs:18:20:18:22 | access to local variable as [element] : A | semmle.label | access to local variable as [element] : A | | CollectionFlow.cs:32:17:32:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:33:38:33:57 | { ..., ... } [As, []] : A | semmle.label | { ..., ... } [As, []] : A | -| CollectionFlow.cs:33:45:33:55 | { ..., ... } [[]] : A | semmle.label | { ..., ... } [[]] : A | +| CollectionFlow.cs:33:38:33:57 | { ..., ... } [field As, element] : A | semmle.label | { ..., ... } [field As, element] : A | +| CollectionFlow.cs:33:45:33:55 | { ..., ... } [element] : A | semmle.label | { ..., ... } [element] : A | | CollectionFlow.cs:33:53:33:53 | access to local variable a : A | semmle.label | access to local variable a : A | -| CollectionFlow.cs:34:14:34:14 | access to local variable c [As, []] : A | semmle.label | access to local variable c [As, []] : A | -| CollectionFlow.cs:34:14:34:17 | access to field As [[]] : A | semmle.label | access to field As [[]] : A | +| CollectionFlow.cs:34:14:34:14 | access to local variable c [field As, element] : A | semmle.label | access to local variable c [field As, element] : A | +| CollectionFlow.cs:34:14:34:17 | access to field As [element] : A | semmle.label | access to field As [element] : A | | CollectionFlow.cs:34:14:34:20 | access to array element | semmle.label | access to array element | -| CollectionFlow.cs:35:18:35:18 | access to local variable c [As, []] : A | semmle.label | access to local variable c [As, []] : A | -| CollectionFlow.cs:35:18:35:21 | access to field As [[]] : A | semmle.label | access to field As [[]] : A | +| CollectionFlow.cs:35:18:35:18 | access to local variable c [field As, element] : A | semmle.label | access to local variable c [field As, element] : A | +| CollectionFlow.cs:35:18:35:21 | access to field As [element] : A | semmle.label | access to field As [element] : A | | CollectionFlow.cs:36:14:36:24 | call to method First | semmle.label | call to method First | -| CollectionFlow.cs:36:20:36:20 | access to local variable c [As, []] : A | semmle.label | access to local variable c [As, []] : A | -| CollectionFlow.cs:36:20:36:23 | access to field As [[]] : A | semmle.label | access to field As [[]] : A | +| CollectionFlow.cs:36:20:36:20 | access to local variable c [field As, element] : A | semmle.label | access to local variable c [field As, element] : A | +| CollectionFlow.cs:36:20:36:23 | access to field As [element] : A | semmle.label | access to field As [element] : A | | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:52:9:52:11 | [post] access to local variable as [[]] : A | semmle.label | [post] access to local variable as [[]] : A | +| CollectionFlow.cs:52:9:52:11 | [post] access to local variable as [element] : A | semmle.label | [post] access to local variable as [element] : A | | CollectionFlow.cs:52:18:52:18 | access to local variable a : A | semmle.label | access to local variable a : A | -| CollectionFlow.cs:53:14:53:16 | access to local variable as [[]] : A | semmle.label | access to local variable as [[]] : A | +| CollectionFlow.cs:53:14:53:16 | access to local variable as [element] : A | semmle.label | access to local variable as [element] : A | | CollectionFlow.cs:53:14:53:19 | access to array element | semmle.label | access to array element | -| CollectionFlow.cs:54:18:54:20 | access to local variable as [[]] : A | semmle.label | access to local variable as [[]] : A | +| CollectionFlow.cs:54:18:54:20 | access to local variable as [element] : A | semmle.label | access to local variable as [element] : A | | CollectionFlow.cs:55:14:55:23 | call to method First | semmle.label | call to method First | -| CollectionFlow.cs:55:20:55:22 | access to local variable as [[]] : A | semmle.label | access to local variable as [[]] : A | +| CollectionFlow.cs:55:20:55:22 | access to local variable as [element] : A | semmle.label | access to local variable as [element] : A | | CollectionFlow.cs:70:17:70:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:72:9:72:12 | [post] access to local variable list [[]] : A | semmle.label | [post] access to local variable list [[]] : A | +| CollectionFlow.cs:72:9:72:12 | [post] access to local variable list [element] : A | semmle.label | [post] access to local variable list [element] : A | | CollectionFlow.cs:72:19:72:19 | access to local variable a : A | semmle.label | access to local variable a : A | -| CollectionFlow.cs:73:14:73:17 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | +| CollectionFlow.cs:73:14:73:17 | access to local variable list [element] : A | semmle.label | access to local variable list [element] : A | | CollectionFlow.cs:73:14:73:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:74:22:74:25 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | +| CollectionFlow.cs:74:22:74:25 | access to local variable list [element] : A | semmle.label | access to local variable list [element] : A | | CollectionFlow.cs:75:14:75:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| CollectionFlow.cs:75:24:75:27 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | +| CollectionFlow.cs:75:24:75:27 | access to local variable list [element] : A | semmle.label | access to local variable list [element] : A | | CollectionFlow.cs:89:17:89:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:90:34:90:38 | { ..., ... } [[]] : A | semmle.label | { ..., ... } [[]] : A | +| CollectionFlow.cs:90:34:90:38 | { ..., ... } [element] : A | semmle.label | { ..., ... } [element] : A | | CollectionFlow.cs:90:36:90:36 | access to local variable a : A | semmle.label | access to local variable a : A | -| CollectionFlow.cs:91:14:91:17 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | +| CollectionFlow.cs:91:14:91:17 | access to local variable list [element] : A | semmle.label | access to local variable list [element] : A | | CollectionFlow.cs:91:14:91:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:92:22:92:25 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | +| CollectionFlow.cs:92:22:92:25 | access to local variable list [element] : A | semmle.label | access to local variable list [element] : A | | CollectionFlow.cs:93:14:93:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| CollectionFlow.cs:93:24:93:27 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | +| CollectionFlow.cs:93:24:93:27 | access to local variable list [element] : A | semmle.label | access to local variable list [element] : A | | CollectionFlow.cs:106:17:106:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:108:9:108:12 | [post] access to local variable list [[]] : A | semmle.label | [post] access to local variable list [[]] : A | +| CollectionFlow.cs:108:9:108:12 | [post] access to local variable list [element] : A | semmle.label | [post] access to local variable list [element] : A | | CollectionFlow.cs:108:18:108:18 | access to local variable a : A | semmle.label | access to local variable a : A | -| CollectionFlow.cs:109:14:109:17 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | +| CollectionFlow.cs:109:14:109:17 | access to local variable list [element] : A | semmle.label | access to local variable list [element] : A | | CollectionFlow.cs:109:14:109:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:110:22:110:25 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | +| CollectionFlow.cs:110:22:110:25 | access to local variable list [element] : A | semmle.label | access to local variable list [element] : A | | CollectionFlow.cs:111:14:111:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| CollectionFlow.cs:111:24:111:27 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | +| CollectionFlow.cs:111:24:111:27 | access to local variable list [element] : A | semmle.label | access to local variable list [element] : A | | CollectionFlow.cs:125:17:125:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [[], Value] : A | semmle.label | [post] access to local variable dict [[], Value] : A | +| CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [element, property Value] : A | semmle.label | [post] access to local variable dict [element, property Value] : A | | CollectionFlow.cs:127:19:127:19 | access to local variable a : A | semmle.label | access to local variable a : A | -| CollectionFlow.cs:128:14:128:17 | access to local variable dict [[], Value] : A | semmle.label | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:128:14:128:17 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A | | CollectionFlow.cs:128:14:128:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:129:23:129:26 | access to local variable dict [[], Value] : A | semmle.label | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:129:23:129:26 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A | | CollectionFlow.cs:130:14:130:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero | -| CollectionFlow.cs:130:28:130:31 | access to local variable dict [[], Value] : A | semmle.label | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:130:28:130:31 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A | | CollectionFlow.cs:131:14:131:33 | call to method DictFirstValue | semmle.label | call to method DictFirstValue | -| CollectionFlow.cs:131:29:131:32 | access to local variable dict [[], Value] : A | semmle.label | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:131:29:131:32 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A | | CollectionFlow.cs:132:14:132:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst | -| CollectionFlow.cs:132:30:132:33 | access to local variable dict [[], Value] : A | semmle.label | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:132:30:132:33 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A | | CollectionFlow.cs:148:17:148:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:149:45:149:56 | { ..., ... } [[], Value] : A | semmle.label | { ..., ... } [[], Value] : A | +| CollectionFlow.cs:149:45:149:56 | { ..., ... } [element, property Value] : A | semmle.label | { ..., ... } [element, property Value] : A | | CollectionFlow.cs:149:52:149:52 | access to local variable a : A | semmle.label | access to local variable a : A | -| CollectionFlow.cs:150:14:150:17 | access to local variable dict [[], Value] : A | semmle.label | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:150:14:150:17 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A | | CollectionFlow.cs:150:14:150:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:151:23:151:26 | access to local variable dict [[], Value] : A | semmle.label | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:151:23:151:26 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A | | CollectionFlow.cs:152:14:152:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero | -| CollectionFlow.cs:152:28:152:31 | access to local variable dict [[], Value] : A | semmle.label | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:152:28:152:31 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A | | CollectionFlow.cs:153:14:153:33 | call to method DictFirstValue | semmle.label | call to method DictFirstValue | -| CollectionFlow.cs:153:29:153:32 | access to local variable dict [[], Value] : A | semmle.label | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:153:29:153:32 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A | | CollectionFlow.cs:154:14:154:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst | -| CollectionFlow.cs:154:30:154:33 | access to local variable dict [[], Value] : A | semmle.label | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:154:30:154:33 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A | | CollectionFlow.cs:169:17:169:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:170:45:170:55 | { ..., ... } [[], Value] : A | semmle.label | { ..., ... } [[], Value] : A | +| CollectionFlow.cs:170:45:170:55 | { ..., ... } [element, property Value] : A | semmle.label | { ..., ... } [element, property Value] : A | | CollectionFlow.cs:170:53:170:53 | access to local variable a : A | semmle.label | access to local variable a : A | -| CollectionFlow.cs:171:14:171:17 | access to local variable dict [[], Value] : A | semmle.label | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:171:14:171:17 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A | | CollectionFlow.cs:171:14:171:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:172:23:172:26 | access to local variable dict [[], Value] : A | semmle.label | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:172:23:172:26 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A | | CollectionFlow.cs:173:14:173:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero | -| CollectionFlow.cs:173:28:173:31 | access to local variable dict [[], Value] : A | semmle.label | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:173:28:173:31 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A | | CollectionFlow.cs:174:14:174:33 | call to method DictFirstValue | semmle.label | call to method DictFirstValue | -| CollectionFlow.cs:174:29:174:32 | access to local variable dict [[], Value] : A | semmle.label | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:174:29:174:32 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A | | CollectionFlow.cs:175:14:175:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst | -| CollectionFlow.cs:175:30:175:33 | access to local variable dict [[], Value] : A | semmle.label | access to local variable dict [[], Value] : A | +| CollectionFlow.cs:175:30:175:33 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A | | CollectionFlow.cs:191:17:191:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:192:45:192:56 | { ..., ... } [[], Key] : A | semmle.label | { ..., ... } [[], Key] : A | +| CollectionFlow.cs:192:45:192:56 | { ..., ... } [element, property Key] : A | semmle.label | { ..., ... } [element, property Key] : A | | CollectionFlow.cs:192:49:192:49 | access to local variable a : A | semmle.label | access to local variable a : A | -| CollectionFlow.cs:193:14:193:17 | access to local variable dict [[], Key] : A | semmle.label | access to local variable dict [[], Key] : A | -| CollectionFlow.cs:193:14:193:22 | access to property Keys [[]] : A | semmle.label | access to property Keys [[]] : A | +| CollectionFlow.cs:193:14:193:17 | access to local variable dict [element, property Key] : A | semmle.label | access to local variable dict [element, property Key] : A | +| CollectionFlow.cs:193:14:193:22 | access to property Keys [element] : A | semmle.label | access to property Keys [element] : A | | CollectionFlow.cs:193:14:193:30 | call to method First | semmle.label | call to method First | -| CollectionFlow.cs:194:21:194:24 | access to local variable dict [[], Key] : A | semmle.label | access to local variable dict [[], Key] : A | +| CollectionFlow.cs:194:21:194:24 | access to local variable dict [element, property Key] : A | semmle.label | access to local variable dict [element, property Key] : A | | CollectionFlow.cs:195:14:195:32 | call to method DictKeysFirst | semmle.label | call to method DictKeysFirst | -| CollectionFlow.cs:195:28:195:31 | access to local variable dict [[], Key] : A | semmle.label | access to local variable dict [[], Key] : A | +| CollectionFlow.cs:195:28:195:31 | access to local variable dict [element, property Key] : A | semmle.label | access to local variable dict [element, property Key] : A | | CollectionFlow.cs:196:14:196:31 | call to method DictFirstKey | semmle.label | call to method DictFirstKey | -| CollectionFlow.cs:196:27:196:30 | access to local variable dict [[], Key] : A | semmle.label | access to local variable dict [[], Key] : A | +| CollectionFlow.cs:196:27:196:30 | access to local variable dict [element, property Key] : A | semmle.label | access to local variable dict [element, property Key] : A | | CollectionFlow.cs:210:17:210:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:211:45:211:55 | { ..., ... } [[], Key] : A | semmle.label | { ..., ... } [[], Key] : A | +| CollectionFlow.cs:211:45:211:55 | { ..., ... } [element, property Key] : A | semmle.label | { ..., ... } [element, property Key] : A | | CollectionFlow.cs:211:48:211:48 | access to local variable a : A | semmle.label | access to local variable a : A | -| CollectionFlow.cs:212:14:212:17 | access to local variable dict [[], Key] : A | semmle.label | access to local variable dict [[], Key] : A | -| CollectionFlow.cs:212:14:212:22 | access to property Keys [[]] : A | semmle.label | access to property Keys [[]] : A | +| CollectionFlow.cs:212:14:212:17 | access to local variable dict [element, property Key] : A | semmle.label | access to local variable dict [element, property Key] : A | +| CollectionFlow.cs:212:14:212:22 | access to property Keys [element] : A | semmle.label | access to property Keys [element] : A | | CollectionFlow.cs:212:14:212:30 | call to method First | semmle.label | call to method First | -| CollectionFlow.cs:213:21:213:24 | access to local variable dict [[], Key] : A | semmle.label | access to local variable dict [[], Key] : A | +| CollectionFlow.cs:213:21:213:24 | access to local variable dict [element, property Key] : A | semmle.label | access to local variable dict [element, property Key] : A | | CollectionFlow.cs:214:14:214:32 | call to method DictKeysFirst | semmle.label | call to method DictKeysFirst | -| CollectionFlow.cs:214:28:214:31 | access to local variable dict [[], Key] : A | semmle.label | access to local variable dict [[], Key] : A | +| CollectionFlow.cs:214:28:214:31 | access to local variable dict [element, property Key] : A | semmle.label | access to local variable dict [element, property Key] : A | | CollectionFlow.cs:215:14:215:31 | call to method DictFirstKey | semmle.label | call to method DictFirstKey | -| CollectionFlow.cs:215:27:215:30 | access to local variable dict [[], Key] : A | semmle.label | access to local variable dict [[], Key] : A | +| CollectionFlow.cs:215:27:215:30 | access to local variable dict [element, property Key] : A | semmle.label | access to local variable dict [element, property Key] : A | | CollectionFlow.cs:229:17:229:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:230:25:230:29 | { ..., ... } [[]] : A | semmle.label | { ..., ... } [[]] : A | +| CollectionFlow.cs:230:25:230:29 | { ..., ... } [element] : A | semmle.label | { ..., ... } [element] : A | | CollectionFlow.cs:230:27:230:27 | access to local variable a : A | semmle.label | access to local variable a : A | | CollectionFlow.cs:231:22:231:22 | SSA def(x) : A | semmle.label | SSA def(x) : A | -| CollectionFlow.cs:231:27:231:29 | access to local variable as [[]] : A | semmle.label | access to local variable as [[]] : A | +| CollectionFlow.cs:231:27:231:29 | access to local variable as [element] : A | semmle.label | access to local variable as [element] : A | | CollectionFlow.cs:232:18:232:18 | access to local variable x | semmle.label | access to local variable x | | CollectionFlow.cs:244:17:244:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:245:25:245:29 | { ..., ... } [[]] : A | semmle.label | { ..., ... } [[]] : A | +| CollectionFlow.cs:245:25:245:29 | { ..., ... } [element] : A | semmle.label | { ..., ... } [element] : A | | CollectionFlow.cs:245:27:245:27 | access to local variable a : A | semmle.label | access to local variable a : A | -| CollectionFlow.cs:246:26:246:28 | access to local variable as [[]] : A | semmle.label | access to local variable as [[]] : A | -| CollectionFlow.cs:246:26:246:44 | call to method GetEnumerator [Current] : A | semmle.label | call to method GetEnumerator [Current] : A | -| CollectionFlow.cs:248:18:248:27 | access to local variable enumerator [Current] : A | semmle.label | access to local variable enumerator [Current] : A | +| CollectionFlow.cs:246:26:246:28 | access to local variable as [element] : A | semmle.label | access to local variable as [element] : A | +| CollectionFlow.cs:246:26:246:44 | call to method GetEnumerator [property Current] : A | semmle.label | call to method GetEnumerator [property Current] : A | +| CollectionFlow.cs:248:18:248:27 | access to local variable enumerator [property Current] : A | semmle.label | access to local variable enumerator [property Current] : A | | CollectionFlow.cs:248:18:248:35 | access to property Current | semmle.label | access to property Current | | CollectionFlow.cs:261:17:261:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:263:9:263:12 | [post] access to local variable list [[]] : A | semmle.label | [post] access to local variable list [[]] : A | +| CollectionFlow.cs:263:9:263:12 | [post] access to local variable list [element] : A | semmle.label | [post] access to local variable list [element] : A | | CollectionFlow.cs:263:18:263:18 | access to local variable a : A | semmle.label | access to local variable a : A | -| CollectionFlow.cs:264:26:264:29 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | -| CollectionFlow.cs:264:26:264:45 | call to method GetEnumerator [Current] : A | semmle.label | call to method GetEnumerator [Current] : A | -| CollectionFlow.cs:266:18:266:27 | access to local variable enumerator [Current] : A | semmle.label | access to local variable enumerator [Current] : A | +| CollectionFlow.cs:264:26:264:29 | access to local variable list [element] : A | semmle.label | access to local variable list [element] : A | +| CollectionFlow.cs:264:26:264:45 | call to method GetEnumerator [property Current] : A | semmle.label | call to method GetEnumerator [property Current] : A | +| CollectionFlow.cs:266:18:266:27 | access to local variable enumerator [property Current] : A | semmle.label | access to local variable enumerator [property Current] : A | | CollectionFlow.cs:266:18:266:35 | access to property Current | semmle.label | access to property Current | | CollectionFlow.cs:280:17:280:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:282:9:282:12 | [post] access to local variable list [[], Key] : A | semmle.label | [post] access to local variable list [[], Key] : A | -| CollectionFlow.cs:282:18:282:47 | object creation of type KeyValuePair [Key] : A | semmle.label | object creation of type KeyValuePair [Key] : A | +| CollectionFlow.cs:282:9:282:12 | [post] access to local variable list [element, property Key] : A | semmle.label | [post] access to local variable list [element, property Key] : A | +| CollectionFlow.cs:282:18:282:47 | object creation of type KeyValuePair [property Key] : A | semmle.label | object creation of type KeyValuePair [property Key] : A | | CollectionFlow.cs:282:43:282:43 | access to local variable a : A | semmle.label | access to local variable a : A | -| CollectionFlow.cs:283:9:283:12 | access to local variable list [[], Key] : A | semmle.label | access to local variable list [[], Key] : A | -| CollectionFlow.cs:283:21:283:23 | kvp [Key] : A | semmle.label | kvp [Key] : A | -| CollectionFlow.cs:285:18:285:20 | access to parameter kvp [Key] : A | semmle.label | access to parameter kvp [Key] : A | +| CollectionFlow.cs:283:9:283:12 | access to local variable list [element, property Key] : A | semmle.label | access to local variable list [element, property Key] : A | +| CollectionFlow.cs:283:21:283:23 | kvp [property Key] : A | semmle.label | kvp [property Key] : A | +| CollectionFlow.cs:285:18:285:20 | access to parameter kvp [property Key] : A | semmle.label | access to parameter kvp [property Key] : A | | CollectionFlow.cs:285:18:285:24 | access to property Key | semmle.label | access to property Key | | CollectionFlow.cs:306:17:306:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:308:18:308:20 | [post] access to local variable as [[]] : A | semmle.label | [post] access to local variable as [[]] : A | +| CollectionFlow.cs:308:18:308:20 | [post] access to local variable as [element] : A | semmle.label | [post] access to local variable as [element] : A | | CollectionFlow.cs:308:23:308:23 | access to local variable a : A | semmle.label | access to local variable a : A | -| CollectionFlow.cs:309:14:309:16 | access to local variable as [[]] : A | semmle.label | access to local variable as [[]] : A | +| CollectionFlow.cs:309:14:309:16 | access to local variable as [element] : A | semmle.label | access to local variable as [element] : A | | CollectionFlow.cs:309:14:309:19 | access to array element | semmle.label | access to array element | -| CollectionFlow.cs:310:18:310:20 | access to local variable as [[]] : A | semmle.label | access to local variable as [[]] : A | +| CollectionFlow.cs:310:18:310:20 | access to local variable as [element] : A | semmle.label | access to local variable as [element] : A | | CollectionFlow.cs:311:14:311:23 | call to method First | semmle.label | call to method First | -| CollectionFlow.cs:311:20:311:22 | access to local variable as [[]] : A | semmle.label | access to local variable as [[]] : A | +| CollectionFlow.cs:311:20:311:22 | access to local variable as [element] : A | semmle.label | access to local variable as [element] : A | | CollectionFlow.cs:328:17:328:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:330:17:330:20 | [post] access to local variable list [[]] : A | semmle.label | [post] access to local variable list [[]] : A | +| CollectionFlow.cs:330:17:330:20 | [post] access to local variable list [element] : A | semmle.label | [post] access to local variable list [element] : A | | CollectionFlow.cs:330:23:330:23 | access to local variable a : A | semmle.label | access to local variable a : A | -| CollectionFlow.cs:331:14:331:17 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | +| CollectionFlow.cs:331:14:331:17 | access to local variable list [element] : A | semmle.label | access to local variable list [element] : A | | CollectionFlow.cs:331:14:331:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:332:22:332:25 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | +| CollectionFlow.cs:332:22:332:25 | access to local variable list [element] : A | semmle.label | access to local variable list [element] : A | | CollectionFlow.cs:333:14:333:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| CollectionFlow.cs:333:24:333:27 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | +| CollectionFlow.cs:333:24:333:27 | access to local variable list [element] : A | semmle.label | access to local variable list [element] : A | | CollectionFlow.cs:347:20:347:26 | object creation of type A : A | semmle.label | object creation of type A : A | | CollectionFlow.cs:348:26:348:32 | object creation of type A : A | semmle.label | object creation of type A : A | | CollectionFlow.cs:349:26:349:32 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:350:20:350:38 | array creation of type A[] [[]] : A | semmle.label | array creation of type A[] [[]] : A | -| CollectionFlow.cs:350:28:350:38 | { ..., ... } [[]] : A | semmle.label | { ..., ... } [[]] : A | +| CollectionFlow.cs:350:20:350:38 | array creation of type A[] [element] : A | semmle.label | array creation of type A[] [element] : A | +| CollectionFlow.cs:350:28:350:38 | { ..., ... } [element] : A | semmle.label | { ..., ... } [element] : A | | CollectionFlow.cs:350:30:350:36 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:374:40:374:41 | ts [[]] : A | semmle.label | ts [[]] : A | -| CollectionFlow.cs:374:40:374:41 | ts [[]] : A | semmle.label | ts [[]] : A | -| CollectionFlow.cs:374:52:374:53 | access to parameter ts [[]] : A | semmle.label | access to parameter ts [[]] : A | -| CollectionFlow.cs:374:52:374:53 | access to parameter ts [[]] : A | semmle.label | access to parameter ts [[]] : A | +| CollectionFlow.cs:374:40:374:41 | ts [element] : A | semmle.label | ts [element] : A | +| CollectionFlow.cs:374:40:374:41 | ts [element] : A | semmle.label | ts [element] : A | +| CollectionFlow.cs:374:52:374:53 | access to parameter ts [element] : A | semmle.label | access to parameter ts [element] : A | +| CollectionFlow.cs:374:52:374:53 | access to parameter ts [element] : A | semmle.label | access to parameter ts [element] : A | | CollectionFlow.cs:374:52:374:56 | access to array element | semmle.label | access to array element | -| CollectionFlow.cs:376:49:376:52 | list [[]] : A | semmle.label | list [[]] : A | -| CollectionFlow.cs:376:49:376:52 | list [[]] : A | semmle.label | list [[]] : A | -| CollectionFlow.cs:376:49:376:52 | list [[]] : A | semmle.label | list [[]] : A | -| CollectionFlow.cs:376:49:376:52 | list [[]] : A | semmle.label | list [[]] : A | -| CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | semmle.label | access to parameter list [[]] : A | -| CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | semmle.label | access to parameter list [[]] : A | -| CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | semmle.label | access to parameter list [[]] : A | -| CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | semmle.label | access to parameter list [[]] : A | +| CollectionFlow.cs:376:49:376:52 | list [element] : A | semmle.label | list [element] : A | +| CollectionFlow.cs:376:49:376:52 | list [element] : A | semmle.label | list [element] : A | +| CollectionFlow.cs:376:49:376:52 | list [element] : A | semmle.label | list [element] : A | +| CollectionFlow.cs:376:49:376:52 | list [element] : A | semmle.label | list [element] : A | +| CollectionFlow.cs:376:63:376:66 | access to parameter list [element] : A | semmle.label | access to parameter list [element] : A | +| CollectionFlow.cs:376:63:376:66 | access to parameter list [element] : A | semmle.label | access to parameter list [element] : A | +| CollectionFlow.cs:376:63:376:66 | access to parameter list [element] : A | semmle.label | access to parameter list [element] : A | +| CollectionFlow.cs:376:63:376:66 | access to parameter list [element] : A | semmle.label | access to parameter list [element] : A | | CollectionFlow.cs:376:63:376:69 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:378:61:378:64 | dict [[], Value] : A | semmle.label | dict [[], Value] : A | -| CollectionFlow.cs:378:75:378:78 | access to parameter dict [[], Value] : A | semmle.label | access to parameter dict [[], Value] : A | +| CollectionFlow.cs:378:61:378:64 | dict [element, property Value] : A | semmle.label | dict [element, property Value] : A | +| CollectionFlow.cs:378:75:378:78 | access to parameter dict [element, property Value] : A | semmle.label | access to parameter dict [element, property Value] : A | | CollectionFlow.cs:378:75:378:81 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:380:59:380:62 | dict [[], Key] : A | semmle.label | dict [[], Key] : A | -| CollectionFlow.cs:380:73:380:76 | access to parameter dict [[], Key] : A | semmle.label | access to parameter dict [[], Key] : A | -| CollectionFlow.cs:380:73:380:81 | access to property Keys [[]] : A | semmle.label | access to property Keys [[]] : A | +| CollectionFlow.cs:380:59:380:62 | dict [element, property Key] : A | semmle.label | dict [element, property Key] : A | +| CollectionFlow.cs:380:73:380:76 | access to parameter dict [element, property Key] : A | semmle.label | access to parameter dict [element, property Key] : A | +| CollectionFlow.cs:380:73:380:81 | access to property Keys [element] : A | semmle.label | access to property Keys [element] : A | | CollectionFlow.cs:380:73:380:89 | call to method First | semmle.label | call to method First | -| CollectionFlow.cs:396:49:396:52 | args [[]] : A | semmle.label | args [[]] : A | -| CollectionFlow.cs:396:49:396:52 | args [[]] : A | semmle.label | args [[]] : A | -| CollectionFlow.cs:396:63:396:66 | access to parameter args [[]] : A | semmle.label | access to parameter args [[]] : A | -| CollectionFlow.cs:396:63:396:66 | access to parameter args [[]] : A | semmle.label | access to parameter args [[]] : A | +| CollectionFlow.cs:396:49:396:52 | args [element] : A | semmle.label | args [element] : A | +| CollectionFlow.cs:396:49:396:52 | args [element] : A | semmle.label | args [element] : A | +| CollectionFlow.cs:396:63:396:66 | access to parameter args [element] : A | semmle.label | access to parameter args [element] : A | +| CollectionFlow.cs:396:63:396:66 | access to parameter args [element] : A | semmle.label | access to parameter args [element] : A | | CollectionFlow.cs:396:63:396:69 | access to array element | semmle.label | access to array element | #select | CollectionFlow.cs:14:17:14:23 | object creation of type A : A | CollectionFlow.cs:14:17:14:23 | object creation of type A : A | CollectionFlow.cs:16:14:16:19 | access to array element | $@ | CollectionFlow.cs:16:14:16:19 | access to array element | access to array element | diff --git a/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected b/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected index e776b086467..46dfd50b07a 100644 --- a/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected @@ -1,542 +1,542 @@ edges | A.cs:5:17:5:23 | object creation of type C : C | A.cs:6:24:6:24 | access to local variable c : C | -| A.cs:6:17:6:25 | call to method Make [c] : C | A.cs:7:14:7:14 | access to local variable b [c] : C | -| A.cs:6:24:6:24 | access to local variable c : C | A.cs:6:17:6:25 | call to method Make [c] : C | -| A.cs:7:14:7:14 | access to local variable b [c] : C | A.cs:7:14:7:16 | access to field c | -| A.cs:13:9:13:9 | [post] access to local variable b [c] : C1 | A.cs:14:14:14:14 | access to local variable b [c] : C1 | -| A.cs:13:15:13:22 | object creation of type C1 : C1 | A.cs:13:9:13:9 | [post] access to local variable b [c] : C1 | -| A.cs:14:14:14:14 | access to local variable b [c] : C1 | A.cs:14:14:14:20 | call to method Get | -| A.cs:15:15:15:28 | object creation of type B [c] : C | A.cs:15:14:15:35 | call to method Get | -| A.cs:15:21:15:27 | object creation of type C : C | A.cs:15:15:15:28 | object creation of type B [c] : C | -| A.cs:22:14:22:33 | call to method SetOnB [c] : C2 | A.cs:24:14:24:15 | access to local variable b2 [c] : C2 | -| A.cs:22:25:22:32 | object creation of type C2 : C2 | A.cs:22:14:22:33 | call to method SetOnB [c] : C2 | -| A.cs:24:14:24:15 | access to local variable b2 [c] : C2 | A.cs:24:14:24:17 | access to field c | -| A.cs:31:14:31:37 | call to method SetOnBWrap [c] : C2 | A.cs:33:14:33:15 | access to local variable b2 [c] : C2 | -| A.cs:31:29:31:36 | object creation of type C2 : C2 | A.cs:31:14:31:37 | call to method SetOnBWrap [c] : C2 | -| A.cs:33:14:33:15 | access to local variable b2 [c] : C2 | A.cs:33:14:33:17 | access to field c | +| A.cs:6:17:6:25 | call to method Make [field c] : C | A.cs:7:14:7:14 | access to local variable b [field c] : C | +| A.cs:6:24:6:24 | access to local variable c : C | A.cs:6:17:6:25 | call to method Make [field c] : C | +| A.cs:7:14:7:14 | access to local variable b [field c] : C | A.cs:7:14:7:16 | access to field c | +| A.cs:13:9:13:9 | [post] access to local variable b [field c] : C1 | A.cs:14:14:14:14 | access to local variable b [field c] : C1 | +| A.cs:13:15:13:22 | object creation of type C1 : C1 | A.cs:13:9:13:9 | [post] access to local variable b [field c] : C1 | +| A.cs:14:14:14:14 | access to local variable b [field c] : C1 | A.cs:14:14:14:20 | call to method Get | +| A.cs:15:15:15:28 | object creation of type B [field c] : C | A.cs:15:14:15:35 | call to method Get | +| A.cs:15:21:15:27 | object creation of type C : C | A.cs:15:15:15:28 | object creation of type B [field c] : C | +| A.cs:22:14:22:33 | call to method SetOnB [field c] : C2 | A.cs:24:14:24:15 | access to local variable b2 [field c] : C2 | +| A.cs:22:25:22:32 | object creation of type C2 : C2 | A.cs:22:14:22:33 | call to method SetOnB [field c] : C2 | +| A.cs:24:14:24:15 | access to local variable b2 [field c] : C2 | A.cs:24:14:24:17 | access to field c | +| A.cs:31:14:31:37 | call to method SetOnBWrap [field c] : C2 | A.cs:33:14:33:15 | access to local variable b2 [field c] : C2 | +| A.cs:31:29:31:36 | object creation of type C2 : C2 | A.cs:31:14:31:37 | call to method SetOnBWrap [field c] : C2 | +| A.cs:33:14:33:15 | access to local variable b2 [field c] : C2 | A.cs:33:14:33:17 | access to field c | | A.cs:55:17:55:23 | object creation of type A : A | A.cs:57:16:57:16 | access to local variable a : A | -| A.cs:57:9:57:10 | [post] access to local variable c1 [a] : A | A.cs:58:12:58:13 | access to local variable c1 [a] : A | -| A.cs:57:16:57:16 | access to local variable a : A | A.cs:57:9:57:10 | [post] access to local variable c1 [a] : A | -| A.cs:58:12:58:13 | access to local variable c1 [a] : A | A.cs:60:22:60:22 | c [a] : A | -| A.cs:60:22:60:22 | c [a] : A | A.cs:64:19:64:23 | (...) ... [a] : A | -| A.cs:64:19:64:23 | (...) ... [a] : A | A.cs:64:18:64:26 | access to field a | -| A.cs:83:9:83:9 | [post] access to parameter b [c] : C | A.cs:88:12:88:12 | [post] access to local variable b [c] : C | -| A.cs:83:15:83:21 | object creation of type C : C | A.cs:83:9:83:9 | [post] access to parameter b [c] : C | -| A.cs:88:12:88:12 | [post] access to local variable b [c] : C | A.cs:89:14:89:14 | access to local variable b [c] : C | -| A.cs:89:14:89:14 | access to local variable b [c] : C | A.cs:89:14:89:16 | access to field c | -| A.cs:97:13:97:13 | [post] access to parameter b [c] : C | A.cs:98:22:98:36 | ... ? ... : ... [c] : C | -| A.cs:97:13:97:13 | [post] access to parameter b [c] : C | A.cs:105:23:105:23 | [post] access to local variable b [c] : C | -| A.cs:97:19:97:25 | object creation of type C : C | A.cs:97:13:97:13 | [post] access to parameter b [c] : C | -| A.cs:98:13:98:16 | [post] this access [b, c] : C | A.cs:105:17:105:29 | object creation of type D [b, c] : C | -| A.cs:98:13:98:16 | [post] this access [b] : B | A.cs:105:17:105:29 | object creation of type D [b] : B | -| A.cs:98:22:98:36 | ... ? ... : ... : B | A.cs:98:13:98:16 | [post] this access [b] : B | -| A.cs:98:22:98:36 | ... ? ... : ... [c] : C | A.cs:98:13:98:16 | [post] this access [b, c] : C | +| A.cs:57:9:57:10 | [post] access to local variable c1 [field a] : A | A.cs:58:12:58:13 | access to local variable c1 [field a] : A | +| A.cs:57:16:57:16 | access to local variable a : A | A.cs:57:9:57:10 | [post] access to local variable c1 [field a] : A | +| A.cs:58:12:58:13 | access to local variable c1 [field a] : A | A.cs:60:22:60:22 | c [field a] : A | +| A.cs:60:22:60:22 | c [field a] : A | A.cs:64:19:64:23 | (...) ... [field a] : A | +| A.cs:64:19:64:23 | (...) ... [field a] : A | A.cs:64:18:64:26 | access to field a | +| A.cs:83:9:83:9 | [post] access to parameter b [field c] : C | A.cs:88:12:88:12 | [post] access to local variable b [field c] : C | +| A.cs:83:15:83:21 | object creation of type C : C | A.cs:83:9:83:9 | [post] access to parameter b [field c] : C | +| A.cs:88:12:88:12 | [post] access to local variable b [field c] : C | A.cs:89:14:89:14 | access to local variable b [field c] : C | +| A.cs:89:14:89:14 | access to local variable b [field c] : C | A.cs:89:14:89:16 | access to field c | +| A.cs:97:13:97:13 | [post] access to parameter b [field c] : C | A.cs:98:22:98:36 | ... ? ... : ... [field c] : C | +| A.cs:97:13:97:13 | [post] access to parameter b [field c] : C | A.cs:105:23:105:23 | [post] access to local variable b [field c] : C | +| A.cs:97:19:97:25 | object creation of type C : C | A.cs:97:13:97:13 | [post] access to parameter b [field c] : C | +| A.cs:98:13:98:16 | [post] this access [field b, field c] : C | A.cs:105:17:105:29 | object creation of type D [field b, field c] : C | +| A.cs:98:13:98:16 | [post] this access [field b] : B | A.cs:105:17:105:29 | object creation of type D [field b] : B | +| A.cs:98:22:98:36 | ... ? ... : ... : B | A.cs:98:13:98:16 | [post] this access [field b] : B | +| A.cs:98:22:98:36 | ... ? ... : ... [field c] : C | A.cs:98:13:98:16 | [post] this access [field b, field c] : C | | A.cs:98:30:98:36 | object creation of type B : B | A.cs:98:22:98:36 | ... ? ... : ... : B | | A.cs:104:17:104:23 | object creation of type B : B | A.cs:105:23:105:23 | access to local variable b : B | -| A.cs:105:17:105:29 | object creation of type D [b, c] : C | A.cs:107:14:107:14 | access to local variable d [b, c] : C | -| A.cs:105:17:105:29 | object creation of type D [b] : B | A.cs:106:14:106:14 | access to local variable d [b] : B | -| A.cs:105:23:105:23 | [post] access to local variable b [c] : C | A.cs:108:14:108:14 | access to local variable b [c] : C | -| A.cs:105:23:105:23 | access to local variable b : B | A.cs:105:17:105:29 | object creation of type D [b] : B | -| A.cs:106:14:106:14 | access to local variable d [b] : B | A.cs:106:14:106:16 | access to field b | -| A.cs:107:14:107:14 | access to local variable d [b, c] : C | A.cs:107:14:107:16 | access to field b [c] : C | -| A.cs:107:14:107:16 | access to field b [c] : C | A.cs:107:14:107:18 | access to field c | -| A.cs:108:14:108:14 | access to local variable b [c] : C | A.cs:108:14:108:16 | access to field c | +| A.cs:105:17:105:29 | object creation of type D [field b, field c] : C | A.cs:107:14:107:14 | access to local variable d [field b, field c] : C | +| A.cs:105:17:105:29 | object creation of type D [field b] : B | A.cs:106:14:106:14 | access to local variable d [field b] : B | +| A.cs:105:23:105:23 | [post] access to local variable b [field c] : C | A.cs:108:14:108:14 | access to local variable b [field c] : C | +| A.cs:105:23:105:23 | access to local variable b : B | A.cs:105:17:105:29 | object creation of type D [field b] : B | +| A.cs:106:14:106:14 | access to local variable d [field b] : B | A.cs:106:14:106:16 | access to field b | +| A.cs:107:14:107:14 | access to local variable d [field b, field c] : C | A.cs:107:14:107:16 | access to field b [field c] : C | +| A.cs:107:14:107:16 | access to field b [field c] : C | A.cs:107:14:107:18 | access to field c | +| A.cs:108:14:108:14 | access to local variable b [field c] : C | A.cs:108:14:108:16 | access to field c | | A.cs:113:17:113:23 | object creation of type B : B | A.cs:114:29:114:29 | access to local variable b : B | -| A.cs:114:18:114:54 | object creation of type MyList [head] : B | A.cs:115:35:115:36 | access to local variable l1 [head] : B | -| A.cs:114:29:114:29 | access to local variable b : B | A.cs:114:18:114:54 | object creation of type MyList [head] : B | -| A.cs:115:18:115:37 | object creation of type MyList [next, head] : B | A.cs:116:35:116:36 | access to local variable l2 [next, head] : B | -| A.cs:115:35:115:36 | access to local variable l1 [head] : B | A.cs:115:18:115:37 | object creation of type MyList [next, head] : B | -| A.cs:116:18:116:37 | object creation of type MyList [next, next, head] : B | A.cs:119:14:119:15 | access to local variable l3 [next, next, head] : B | -| A.cs:116:18:116:37 | object creation of type MyList [next, next, head] : B | A.cs:121:41:121:41 | access to local variable l [next, next, head] : B | -| A.cs:116:35:116:36 | access to local variable l2 [next, head] : B | A.cs:116:18:116:37 | object creation of type MyList [next, next, head] : B | -| A.cs:119:14:119:15 | access to local variable l3 [next, next, head] : B | A.cs:119:14:119:20 | access to field next [next, head] : B | -| A.cs:119:14:119:20 | access to field next [next, head] : B | A.cs:119:14:119:25 | access to field next [head] : B | -| A.cs:119:14:119:25 | access to field next [head] : B | A.cs:119:14:119:30 | access to field head | -| A.cs:121:41:121:41 | access to local variable l [next, head] : B | A.cs:121:41:121:46 | access to field next [head] : B | -| A.cs:121:41:121:41 | access to local variable l [next, next, head] : B | A.cs:121:41:121:46 | access to field next [next, head] : B | -| A.cs:121:41:121:46 | access to field next [head] : B | A.cs:123:18:123:18 | access to local variable l [head] : B | -| A.cs:121:41:121:46 | access to field next [next, head] : B | A.cs:121:41:121:41 | access to local variable l [next, head] : B | -| A.cs:123:18:123:18 | access to local variable l [head] : B | A.cs:123:18:123:23 | access to field head | +| A.cs:114:18:114:54 | object creation of type MyList [field head] : B | A.cs:115:35:115:36 | access to local variable l1 [field head] : B | +| A.cs:114:29:114:29 | access to local variable b : B | A.cs:114:18:114:54 | object creation of type MyList [field head] : B | +| A.cs:115:18:115:37 | object creation of type MyList [field next, field head] : B | A.cs:116:35:116:36 | access to local variable l2 [field next, field head] : B | +| A.cs:115:35:115:36 | access to local variable l1 [field head] : B | A.cs:115:18:115:37 | object creation of type MyList [field next, field head] : B | +| A.cs:116:18:116:37 | object creation of type MyList [field next, field next, field head] : B | A.cs:119:14:119:15 | access to local variable l3 [field next, field next, field head] : B | +| A.cs:116:18:116:37 | object creation of type MyList [field next, field next, field head] : B | A.cs:121:41:121:41 | access to local variable l [field next, field next, field head] : B | +| A.cs:116:35:116:36 | access to local variable l2 [field next, field head] : B | A.cs:116:18:116:37 | object creation of type MyList [field next, field next, field head] : B | +| A.cs:119:14:119:15 | access to local variable l3 [field next, field next, field head] : B | A.cs:119:14:119:20 | access to field next [field next, field head] : B | +| A.cs:119:14:119:20 | access to field next [field next, field head] : B | A.cs:119:14:119:25 | access to field next [field head] : B | +| A.cs:119:14:119:25 | access to field next [field head] : B | A.cs:119:14:119:30 | access to field head | +| A.cs:121:41:121:41 | access to local variable l [field next, field head] : B | A.cs:121:41:121:46 | access to field next [field head] : B | +| A.cs:121:41:121:41 | access to local variable l [field next, field next, field head] : B | A.cs:121:41:121:46 | access to field next [field next, field head] : B | +| A.cs:121:41:121:46 | access to field next [field head] : B | A.cs:123:18:123:18 | access to local variable l [field head] : B | +| A.cs:121:41:121:46 | access to field next [field next, field head] : B | A.cs:121:41:121:41 | access to local variable l [field next, field head] : B | +| A.cs:123:18:123:18 | access to local variable l [field head] : B | A.cs:123:18:123:23 | access to field head | | B.cs:5:17:5:26 | object creation of type Elem : Elem | B.cs:6:27:6:27 | access to local variable e : Elem | -| B.cs:6:18:6:34 | object creation of type Box1 [elem1] : Elem | B.cs:7:27:7:28 | access to local variable b1 [elem1] : Elem | -| B.cs:6:27:6:27 | access to local variable e : Elem | B.cs:6:18:6:34 | object creation of type Box1 [elem1] : Elem | -| B.cs:7:18:7:29 | object creation of type Box2 [box1, elem1] : Elem | B.cs:8:14:8:15 | access to local variable b2 [box1, elem1] : Elem | -| B.cs:7:27:7:28 | access to local variable b1 [elem1] : Elem | B.cs:7:18:7:29 | object creation of type Box2 [box1, elem1] : Elem | -| B.cs:8:14:8:15 | access to local variable b2 [box1, elem1] : Elem | B.cs:8:14:8:20 | access to field box1 [elem1] : Elem | -| B.cs:8:14:8:20 | access to field box1 [elem1] : Elem | B.cs:8:14:8:26 | access to field elem1 | +| B.cs:6:18:6:34 | object creation of type Box1 [field elem1] : Elem | B.cs:7:27:7:28 | access to local variable b1 [field elem1] : Elem | +| B.cs:6:27:6:27 | access to local variable e : Elem | B.cs:6:18:6:34 | object creation of type Box1 [field elem1] : Elem | +| B.cs:7:18:7:29 | object creation of type Box2 [field box1, field elem1] : Elem | B.cs:8:14:8:15 | access to local variable b2 [field box1, field elem1] : Elem | +| B.cs:7:27:7:28 | access to local variable b1 [field elem1] : Elem | B.cs:7:18:7:29 | object creation of type Box2 [field box1, field elem1] : Elem | +| B.cs:8:14:8:15 | access to local variable b2 [field box1, field elem1] : Elem | B.cs:8:14:8:20 | access to field box1 [field elem1] : Elem | +| B.cs:8:14:8:20 | access to field box1 [field elem1] : Elem | B.cs:8:14:8:26 | access to field elem1 | | B.cs:14:17:14:26 | object creation of type Elem : Elem | B.cs:15:33:15:33 | access to local variable e : Elem | -| B.cs:15:18:15:34 | object creation of type Box1 [elem2] : Elem | B.cs:16:27:16:28 | access to local variable b1 [elem2] : Elem | -| B.cs:15:33:15:33 | access to local variable e : Elem | B.cs:15:18:15:34 | object creation of type Box1 [elem2] : Elem | -| B.cs:16:18:16:29 | object creation of type Box2 [box1, elem2] : Elem | B.cs:18:14:18:15 | access to local variable b2 [box1, elem2] : Elem | -| B.cs:16:27:16:28 | access to local variable b1 [elem2] : Elem | B.cs:16:18:16:29 | object creation of type Box2 [box1, elem2] : Elem | -| B.cs:18:14:18:15 | access to local variable b2 [box1, elem2] : Elem | B.cs:18:14:18:20 | access to field box1 [elem2] : Elem | -| B.cs:18:14:18:20 | access to field box1 [elem2] : Elem | B.cs:18:14:18:26 | access to field elem2 | -| C.cs:3:18:3:19 | [post] this access [s1] : Elem | C.cs:12:15:12:21 | object creation of type C [s1] : Elem | -| C.cs:3:23:3:32 | object creation of type Elem : Elem | C.cs:3:18:3:19 | [post] this access [s1] : Elem | -| C.cs:4:27:4:28 | [post] this access [s2] : Elem | C.cs:12:15:12:21 | object creation of type C [s2] : Elem | -| C.cs:4:32:4:41 | object creation of type Elem : Elem | C.cs:4:27:4:28 | [post] this access [s2] : Elem | +| B.cs:15:18:15:34 | object creation of type Box1 [field elem2] : Elem | B.cs:16:27:16:28 | access to local variable b1 [field elem2] : Elem | +| B.cs:15:33:15:33 | access to local variable e : Elem | B.cs:15:18:15:34 | object creation of type Box1 [field elem2] : Elem | +| B.cs:16:18:16:29 | object creation of type Box2 [field box1, field elem2] : Elem | B.cs:18:14:18:15 | access to local variable b2 [field box1, field elem2] : Elem | +| B.cs:16:27:16:28 | access to local variable b1 [field elem2] : Elem | B.cs:16:18:16:29 | object creation of type Box2 [field box1, field elem2] : Elem | +| B.cs:18:14:18:15 | access to local variable b2 [field box1, field elem2] : Elem | B.cs:18:14:18:20 | access to field box1 [field elem2] : Elem | +| B.cs:18:14:18:20 | access to field box1 [field elem2] : Elem | B.cs:18:14:18:26 | access to field elem2 | +| C.cs:3:18:3:19 | [post] this access [field s1] : Elem | C.cs:12:15:12:21 | object creation of type C [field s1] : Elem | +| C.cs:3:23:3:32 | object creation of type Elem : Elem | C.cs:3:18:3:19 | [post] this access [field s1] : Elem | +| C.cs:4:27:4:28 | [post] this access [field s2] : Elem | C.cs:12:15:12:21 | object creation of type C [field s2] : Elem | +| C.cs:4:32:4:41 | object creation of type Elem : Elem | C.cs:4:27:4:28 | [post] this access [field s2] : Elem | | C.cs:6:30:6:39 | object creation of type Elem : Elem | C.cs:26:14:26:15 | access to field s4 | -| C.cs:7:18:7:19 | [post] this access [s5] : Elem | C.cs:12:15:12:21 | object creation of type C [s5] : Elem | -| C.cs:7:37:7:46 | object creation of type Elem : Elem | C.cs:7:18:7:19 | [post] this access [s5] : Elem | +| C.cs:7:18:7:19 | [post] this access [property s5] : Elem | C.cs:12:15:12:21 | object creation of type C [property s5] : Elem | +| C.cs:7:37:7:46 | object creation of type Elem : Elem | C.cs:7:18:7:19 | [post] this access [property s5] : Elem | | C.cs:8:30:8:39 | object creation of type Elem : Elem | C.cs:28:14:28:15 | access to property s6 | -| C.cs:12:15:12:21 | object creation of type C [s1] : Elem | C.cs:13:9:13:9 | access to local variable c [s1] : Elem | -| C.cs:12:15:12:21 | object creation of type C [s2] : Elem | C.cs:13:9:13:9 | access to local variable c [s2] : Elem | -| C.cs:12:15:12:21 | object creation of type C [s3] : Elem | C.cs:13:9:13:9 | access to local variable c [s3] : Elem | -| C.cs:12:15:12:21 | object creation of type C [s5] : Elem | C.cs:13:9:13:9 | access to local variable c [s5] : Elem | -| C.cs:13:9:13:9 | access to local variable c [s1] : Elem | C.cs:21:17:21:18 | this [s1] : Elem | -| C.cs:13:9:13:9 | access to local variable c [s2] : Elem | C.cs:21:17:21:18 | this [s2] : Elem | -| C.cs:13:9:13:9 | access to local variable c [s3] : Elem | C.cs:21:17:21:18 | this [s3] : Elem | -| C.cs:13:9:13:9 | access to local variable c [s5] : Elem | C.cs:21:17:21:18 | this [s5] : Elem | -| C.cs:18:9:18:12 | [post] this access [s3] : Elem | C.cs:12:15:12:21 | object creation of type C [s3] : Elem | -| C.cs:18:19:18:28 | object creation of type Elem : Elem | C.cs:18:9:18:12 | [post] this access [s3] : Elem | -| C.cs:21:17:21:18 | this [s1] : Elem | C.cs:23:14:23:15 | this access [s1] : Elem | -| C.cs:21:17:21:18 | this [s2] : Elem | C.cs:24:14:24:15 | this access [s2] : Elem | -| C.cs:21:17:21:18 | this [s3] : Elem | C.cs:25:14:25:15 | this access [s3] : Elem | -| C.cs:21:17:21:18 | this [s5] : Elem | C.cs:27:14:27:15 | this access [s5] : Elem | -| C.cs:23:14:23:15 | this access [s1] : Elem | C.cs:23:14:23:15 | access to field s1 | -| C.cs:24:14:24:15 | this access [s2] : Elem | C.cs:24:14:24:15 | access to field s2 | -| C.cs:25:14:25:15 | this access [s3] : Elem | C.cs:25:14:25:15 | access to field s3 | -| C.cs:27:14:27:15 | this access [s5] : Elem | C.cs:27:14:27:15 | access to property s5 | +| C.cs:12:15:12:21 | object creation of type C [field s1] : Elem | C.cs:13:9:13:9 | access to local variable c [field s1] : Elem | +| C.cs:12:15:12:21 | object creation of type C [field s2] : Elem | C.cs:13:9:13:9 | access to local variable c [field s2] : Elem | +| C.cs:12:15:12:21 | object creation of type C [field s3] : Elem | C.cs:13:9:13:9 | access to local variable c [field s3] : Elem | +| C.cs:12:15:12:21 | object creation of type C [property s5] : Elem | C.cs:13:9:13:9 | access to local variable c [property s5] : Elem | +| C.cs:13:9:13:9 | access to local variable c [field s1] : Elem | C.cs:21:17:21:18 | this [field s1] : Elem | +| C.cs:13:9:13:9 | access to local variable c [field s2] : Elem | C.cs:21:17:21:18 | this [field s2] : Elem | +| C.cs:13:9:13:9 | access to local variable c [field s3] : Elem | C.cs:21:17:21:18 | this [field s3] : Elem | +| C.cs:13:9:13:9 | access to local variable c [property s5] : Elem | C.cs:21:17:21:18 | this [property s5] : Elem | +| C.cs:18:9:18:12 | [post] this access [field s3] : Elem | C.cs:12:15:12:21 | object creation of type C [field s3] : Elem | +| C.cs:18:19:18:28 | object creation of type Elem : Elem | C.cs:18:9:18:12 | [post] this access [field s3] : Elem | +| C.cs:21:17:21:18 | this [field s1] : Elem | C.cs:23:14:23:15 | this access [field s1] : Elem | +| C.cs:21:17:21:18 | this [field s2] : Elem | C.cs:24:14:24:15 | this access [field s2] : Elem | +| C.cs:21:17:21:18 | this [field s3] : Elem | C.cs:25:14:25:15 | this access [field s3] : Elem | +| C.cs:21:17:21:18 | this [property s5] : Elem | C.cs:27:14:27:15 | this access [property s5] : Elem | +| C.cs:23:14:23:15 | this access [field s1] : Elem | C.cs:23:14:23:15 | access to field s1 | +| C.cs:24:14:24:15 | this access [field s2] : Elem | C.cs:24:14:24:15 | access to field s2 | +| C.cs:25:14:25:15 | this access [field s3] : Elem | C.cs:25:14:25:15 | access to field s3 | +| C.cs:27:14:27:15 | this access [property s5] : Elem | C.cs:27:14:27:15 | access to property s5 | | D.cs:29:17:29:28 | object creation of type Object : Object | D.cs:31:24:31:24 | access to local variable o : Object | | D.cs:29:17:29:28 | object creation of type Object : Object | D.cs:37:26:37:26 | access to local variable o : Object | | D.cs:29:17:29:28 | object creation of type Object : Object | D.cs:43:32:43:32 | access to local variable o : Object | -| D.cs:31:17:31:37 | call to method Create [AutoProp] : Object | D.cs:32:14:32:14 | access to local variable d [AutoProp] : Object | -| D.cs:31:24:31:24 | access to local variable o : Object | D.cs:31:17:31:37 | call to method Create [AutoProp] : Object | -| D.cs:32:14:32:14 | access to local variable d [AutoProp] : Object | D.cs:32:14:32:23 | access to property AutoProp | -| D.cs:37:13:37:33 | call to method Create [trivialPropField] : Object | D.cs:39:14:39:14 | access to local variable d [trivialPropField] : Object | -| D.cs:37:13:37:33 | call to method Create [trivialPropField] : Object | D.cs:40:14:40:14 | access to local variable d [trivialPropField] : Object | -| D.cs:37:13:37:33 | call to method Create [trivialPropField] : Object | D.cs:41:14:41:14 | access to local variable d [trivialPropField] : Object | -| D.cs:37:26:37:26 | access to local variable o : Object | D.cs:37:13:37:33 | call to method Create [trivialPropField] : Object | -| D.cs:39:14:39:14 | access to local variable d [trivialPropField] : Object | D.cs:39:14:39:26 | access to property TrivialProp | -| D.cs:40:14:40:14 | access to local variable d [trivialPropField] : Object | D.cs:40:14:40:31 | access to field trivialPropField | -| D.cs:41:14:41:14 | access to local variable d [trivialPropField] : Object | D.cs:41:14:41:26 | access to property ComplexProp | -| D.cs:43:13:43:33 | call to method Create [trivialPropField] : Object | D.cs:45:14:45:14 | access to local variable d [trivialPropField] : Object | -| D.cs:43:13:43:33 | call to method Create [trivialPropField] : Object | D.cs:46:14:46:14 | access to local variable d [trivialPropField] : Object | -| D.cs:43:13:43:33 | call to method Create [trivialPropField] : Object | D.cs:47:14:47:14 | access to local variable d [trivialPropField] : Object | -| D.cs:43:32:43:32 | access to local variable o : Object | D.cs:43:13:43:33 | call to method Create [trivialPropField] : Object | -| D.cs:45:14:45:14 | access to local variable d [trivialPropField] : Object | D.cs:45:14:45:26 | access to property TrivialProp | -| D.cs:46:14:46:14 | access to local variable d [trivialPropField] : Object | D.cs:46:14:46:31 | access to field trivialPropField | -| D.cs:47:14:47:14 | access to local variable d [trivialPropField] : Object | D.cs:47:14:47:26 | access to property ComplexProp | +| D.cs:31:17:31:37 | call to method Create [property AutoProp] : Object | D.cs:32:14:32:14 | access to local variable d [property AutoProp] : Object | +| D.cs:31:24:31:24 | access to local variable o : Object | D.cs:31:17:31:37 | call to method Create [property AutoProp] : Object | +| D.cs:32:14:32:14 | access to local variable d [property AutoProp] : Object | D.cs:32:14:32:23 | access to property AutoProp | +| D.cs:37:13:37:33 | call to method Create [field trivialPropField] : Object | D.cs:39:14:39:14 | access to local variable d [field trivialPropField] : Object | +| D.cs:37:13:37:33 | call to method Create [field trivialPropField] : Object | D.cs:40:14:40:14 | access to local variable d [field trivialPropField] : Object | +| D.cs:37:13:37:33 | call to method Create [field trivialPropField] : Object | D.cs:41:14:41:14 | access to local variable d [field trivialPropField] : Object | +| D.cs:37:26:37:26 | access to local variable o : Object | D.cs:37:13:37:33 | call to method Create [field trivialPropField] : Object | +| D.cs:39:14:39:14 | access to local variable d [field trivialPropField] : Object | D.cs:39:14:39:26 | access to property TrivialProp | +| D.cs:40:14:40:14 | access to local variable d [field trivialPropField] : Object | D.cs:40:14:40:31 | access to field trivialPropField | +| D.cs:41:14:41:14 | access to local variable d [field trivialPropField] : Object | D.cs:41:14:41:26 | access to property ComplexProp | +| D.cs:43:13:43:33 | call to method Create [field trivialPropField] : Object | D.cs:45:14:45:14 | access to local variable d [field trivialPropField] : Object | +| D.cs:43:13:43:33 | call to method Create [field trivialPropField] : Object | D.cs:46:14:46:14 | access to local variable d [field trivialPropField] : Object | +| D.cs:43:13:43:33 | call to method Create [field trivialPropField] : Object | D.cs:47:14:47:14 | access to local variable d [field trivialPropField] : Object | +| D.cs:43:32:43:32 | access to local variable o : Object | D.cs:43:13:43:33 | call to method Create [field trivialPropField] : Object | +| D.cs:45:14:45:14 | access to local variable d [field trivialPropField] : Object | D.cs:45:14:45:26 | access to property TrivialProp | +| D.cs:46:14:46:14 | access to local variable d [field trivialPropField] : Object | D.cs:46:14:46:31 | access to field trivialPropField | +| D.cs:47:14:47:14 | access to local variable d [field trivialPropField] : Object | D.cs:47:14:47:26 | access to property ComplexProp | | E.cs:22:17:22:28 | object creation of type Object : Object | E.cs:23:25:23:25 | access to local variable o : Object | -| E.cs:23:17:23:26 | call to method CreateS [Field] : Object | E.cs:24:14:24:14 | access to local variable s [Field] : Object | -| E.cs:23:25:23:25 | access to local variable o : Object | E.cs:23:17:23:26 | call to method CreateS [Field] : Object | -| E.cs:24:14:24:14 | access to local variable s [Field] : Object | E.cs:24:14:24:20 | access to field Field | +| E.cs:23:17:23:26 | call to method CreateS [field Field] : Object | E.cs:24:14:24:14 | access to local variable s [field Field] : Object | +| E.cs:23:25:23:25 | access to local variable o : Object | E.cs:23:17:23:26 | call to method CreateS [field Field] : Object | +| E.cs:24:14:24:14 | access to local variable s [field Field] : Object | E.cs:24:14:24:20 | access to field Field | | F.cs:10:17:10:28 | object creation of type Object : Object | F.cs:11:24:11:24 | access to local variable o : Object | | F.cs:10:17:10:28 | object creation of type Object : Object | F.cs:15:26:15:26 | access to local variable o : Object | | F.cs:10:17:10:28 | object creation of type Object : Object | F.cs:19:32:19:32 | access to local variable o : Object | | F.cs:10:17:10:28 | object creation of type Object : Object | F.cs:23:32:23:32 | access to local variable o : Object | -| F.cs:11:17:11:31 | call to method Create [Field1] : Object | F.cs:12:14:12:14 | access to local variable f [Field1] : Object | -| F.cs:11:24:11:24 | access to local variable o : Object | F.cs:11:17:11:31 | call to method Create [Field1] : Object | -| F.cs:12:14:12:14 | access to local variable f [Field1] : Object | F.cs:12:14:12:21 | access to field Field1 | -| F.cs:15:13:15:27 | call to method Create [Field2] : Object | F.cs:17:14:17:14 | access to local variable f [Field2] : Object | -| F.cs:15:26:15:26 | access to local variable o : Object | F.cs:15:13:15:27 | call to method Create [Field2] : Object | -| F.cs:17:14:17:14 | access to local variable f [Field2] : Object | F.cs:17:14:17:21 | access to field Field2 | -| F.cs:19:21:19:34 | { ..., ... } [Field1] : Object | F.cs:20:14:20:14 | access to local variable f [Field1] : Object | -| F.cs:19:32:19:32 | access to local variable o : Object | F.cs:19:21:19:34 | { ..., ... } [Field1] : Object | -| F.cs:20:14:20:14 | access to local variable f [Field1] : Object | F.cs:20:14:20:21 | access to field Field1 | -| F.cs:23:21:23:34 | { ..., ... } [Field2] : Object | F.cs:25:14:25:14 | access to local variable f [Field2] : Object | -| F.cs:23:32:23:32 | access to local variable o : Object | F.cs:23:21:23:34 | { ..., ... } [Field2] : Object | -| F.cs:25:14:25:14 | access to local variable f [Field2] : Object | F.cs:25:14:25:21 | access to field Field2 | +| F.cs:11:17:11:31 | call to method Create [field Field1] : Object | F.cs:12:14:12:14 | access to local variable f [field Field1] : Object | +| F.cs:11:24:11:24 | access to local variable o : Object | F.cs:11:17:11:31 | call to method Create [field Field1] : Object | +| F.cs:12:14:12:14 | access to local variable f [field Field1] : Object | F.cs:12:14:12:21 | access to field Field1 | +| F.cs:15:13:15:27 | call to method Create [field Field2] : Object | F.cs:17:14:17:14 | access to local variable f [field Field2] : Object | +| F.cs:15:26:15:26 | access to local variable o : Object | F.cs:15:13:15:27 | call to method Create [field Field2] : Object | +| F.cs:17:14:17:14 | access to local variable f [field Field2] : Object | F.cs:17:14:17:21 | access to field Field2 | +| F.cs:19:21:19:34 | { ..., ... } [field Field1] : Object | F.cs:20:14:20:14 | access to local variable f [field Field1] : Object | +| F.cs:19:32:19:32 | access to local variable o : Object | F.cs:19:21:19:34 | { ..., ... } [field Field1] : Object | +| F.cs:20:14:20:14 | access to local variable f [field Field1] : Object | F.cs:20:14:20:21 | access to field Field1 | +| F.cs:23:21:23:34 | { ..., ... } [field Field2] : Object | F.cs:25:14:25:14 | access to local variable f [field Field2] : Object | +| F.cs:23:32:23:32 | access to local variable o : Object | F.cs:23:21:23:34 | { ..., ... } [field Field2] : Object | +| F.cs:25:14:25:14 | access to local variable f [field Field2] : Object | F.cs:25:14:25:21 | access to field Field2 | | G.cs:7:18:7:27 | object creation of type Elem : Elem | G.cs:9:23:9:23 | access to local variable e : Elem | -| G.cs:9:9:9:9 | [post] access to local variable b [Box1, Elem] : Elem | G.cs:10:18:10:18 | access to local variable b [Box1, Elem] : Elem | -| G.cs:9:9:9:14 | [post] access to field Box1 [Elem] : Elem | G.cs:9:9:9:9 | [post] access to local variable b [Box1, Elem] : Elem | -| G.cs:9:23:9:23 | access to local variable e : Elem | G.cs:9:9:9:14 | [post] access to field Box1 [Elem] : Elem | -| G.cs:10:18:10:18 | access to local variable b [Box1, Elem] : Elem | G.cs:37:38:37:39 | b2 [Box1, Elem] : Elem | +| G.cs:9:9:9:9 | [post] access to local variable b [field Box1, field Elem] : Elem | G.cs:10:18:10:18 | access to local variable b [field Box1, field Elem] : Elem | +| G.cs:9:9:9:14 | [post] access to field Box1 [field Elem] : Elem | G.cs:9:9:9:9 | [post] access to local variable b [field Box1, field Elem] : Elem | +| G.cs:9:23:9:23 | access to local variable e : Elem | G.cs:9:9:9:14 | [post] access to field Box1 [field Elem] : Elem | +| G.cs:10:18:10:18 | access to local variable b [field Box1, field Elem] : Elem | G.cs:37:38:37:39 | b2 [field Box1, field Elem] : Elem | | G.cs:15:18:15:27 | object creation of type Elem : Elem | G.cs:17:24:17:24 | access to local variable e : Elem | -| G.cs:17:9:17:9 | [post] access to local variable b [Box1, Elem] : Elem | G.cs:18:18:18:18 | access to local variable b [Box1, Elem] : Elem | -| G.cs:17:9:17:14 | [post] access to field Box1 [Elem] : Elem | G.cs:17:9:17:9 | [post] access to local variable b [Box1, Elem] : Elem | -| G.cs:17:24:17:24 | access to local variable e : Elem | G.cs:17:9:17:14 | [post] access to field Box1 [Elem] : Elem | -| G.cs:18:18:18:18 | access to local variable b [Box1, Elem] : Elem | G.cs:37:38:37:39 | b2 [Box1, Elem] : Elem | +| G.cs:17:9:17:9 | [post] access to local variable b [field Box1, field Elem] : Elem | G.cs:18:18:18:18 | access to local variable b [field Box1, field Elem] : Elem | +| G.cs:17:9:17:14 | [post] access to field Box1 [field Elem] : Elem | G.cs:17:9:17:9 | [post] access to local variable b [field Box1, field Elem] : Elem | +| G.cs:17:24:17:24 | access to local variable e : Elem | G.cs:17:9:17:14 | [post] access to field Box1 [field Elem] : Elem | +| G.cs:18:18:18:18 | access to local variable b [field Box1, field Elem] : Elem | G.cs:37:38:37:39 | b2 [field Box1, field Elem] : Elem | | G.cs:23:18:23:27 | object creation of type Elem : Elem | G.cs:25:28:25:28 | access to local variable e : Elem | -| G.cs:25:9:25:9 | [post] access to local variable b [Box1, Elem] : Elem | G.cs:26:18:26:18 | access to local variable b [Box1, Elem] : Elem | -| G.cs:25:9:25:19 | [post] call to method GetBox1 [Elem] : Elem | G.cs:25:9:25:9 | [post] access to local variable b [Box1, Elem] : Elem | -| G.cs:25:28:25:28 | access to local variable e : Elem | G.cs:25:9:25:19 | [post] call to method GetBox1 [Elem] : Elem | -| G.cs:26:18:26:18 | access to local variable b [Box1, Elem] : Elem | G.cs:37:38:37:39 | b2 [Box1, Elem] : Elem | +| G.cs:25:9:25:9 | [post] access to local variable b [field Box1, field Elem] : Elem | G.cs:26:18:26:18 | access to local variable b [field Box1, field Elem] : Elem | +| G.cs:25:9:25:19 | [post] call to method GetBox1 [field Elem] : Elem | G.cs:25:9:25:9 | [post] access to local variable b [field Box1, field Elem] : Elem | +| G.cs:25:28:25:28 | access to local variable e : Elem | G.cs:25:9:25:19 | [post] call to method GetBox1 [field Elem] : Elem | +| G.cs:26:18:26:18 | access to local variable b [field Box1, field Elem] : Elem | G.cs:37:38:37:39 | b2 [field Box1, field Elem] : Elem | | G.cs:31:18:31:27 | object creation of type Elem : Elem | G.cs:33:29:33:29 | access to local variable e : Elem | -| G.cs:33:9:33:9 | [post] access to local variable b [Box1, Elem] : Elem | G.cs:34:18:34:18 | access to local variable b [Box1, Elem] : Elem | -| G.cs:33:9:33:19 | [post] call to method GetBox1 [Elem] : Elem | G.cs:33:9:33:9 | [post] access to local variable b [Box1, Elem] : Elem | -| G.cs:33:29:33:29 | access to local variable e : Elem | G.cs:33:9:33:19 | [post] call to method GetBox1 [Elem] : Elem | -| G.cs:34:18:34:18 | access to local variable b [Box1, Elem] : Elem | G.cs:37:38:37:39 | b2 [Box1, Elem] : Elem | -| G.cs:37:38:37:39 | b2 [Box1, Elem] : Elem | G.cs:39:14:39:15 | access to parameter b2 [Box1, Elem] : Elem | -| G.cs:39:14:39:15 | access to parameter b2 [Box1, Elem] : Elem | G.cs:39:14:39:25 | call to method GetBox1 [Elem] : Elem | -| G.cs:39:14:39:25 | call to method GetBox1 [Elem] : Elem | G.cs:39:14:39:35 | call to method GetElem | +| G.cs:33:9:33:9 | [post] access to local variable b [field Box1, field Elem] : Elem | G.cs:34:18:34:18 | access to local variable b [field Box1, field Elem] : Elem | +| G.cs:33:9:33:19 | [post] call to method GetBox1 [field Elem] : Elem | G.cs:33:9:33:9 | [post] access to local variable b [field Box1, field Elem] : Elem | +| G.cs:33:29:33:29 | access to local variable e : Elem | G.cs:33:9:33:19 | [post] call to method GetBox1 [field Elem] : Elem | +| G.cs:34:18:34:18 | access to local variable b [field Box1, field Elem] : Elem | G.cs:37:38:37:39 | b2 [field Box1, field Elem] : Elem | +| G.cs:37:38:37:39 | b2 [field Box1, field Elem] : Elem | G.cs:39:14:39:15 | access to parameter b2 [field Box1, field Elem] : Elem | +| G.cs:39:14:39:15 | access to parameter b2 [field Box1, field Elem] : Elem | G.cs:39:14:39:25 | call to method GetBox1 [field Elem] : Elem | +| G.cs:39:14:39:25 | call to method GetBox1 [field Elem] : Elem | G.cs:39:14:39:35 | call to method GetElem | | G.cs:44:18:44:27 | object creation of type Elem : Elem | G.cs:46:30:46:30 | access to local variable e : Elem | -| G.cs:46:9:46:16 | [post] access to field boxfield [Box1, Elem] : Elem | G.cs:46:9:46:16 | [post] this access [boxfield, Box1, Elem] : Elem | -| G.cs:46:9:46:16 | [post] this access [boxfield, Box1, Elem] : Elem | G.cs:47:9:47:13 | this access [boxfield, Box1, Elem] : Elem | -| G.cs:46:9:46:21 | [post] access to field Box1 [Elem] : Elem | G.cs:46:9:46:16 | [post] access to field boxfield [Box1, Elem] : Elem | -| G.cs:46:30:46:30 | access to local variable e : Elem | G.cs:46:9:46:21 | [post] access to field Box1 [Elem] : Elem | -| G.cs:47:9:47:13 | this access [boxfield, Box1, Elem] : Elem | G.cs:50:18:50:20 | this [boxfield, Box1, Elem] : Elem | -| G.cs:50:18:50:20 | this [boxfield, Box1, Elem] : Elem | G.cs:52:14:52:21 | this access [boxfield, Box1, Elem] : Elem | -| G.cs:52:14:52:21 | access to field boxfield [Box1, Elem] : Elem | G.cs:52:14:52:26 | access to field Box1 [Elem] : Elem | -| G.cs:52:14:52:21 | this access [boxfield, Box1, Elem] : Elem | G.cs:52:14:52:21 | access to field boxfield [Box1, Elem] : Elem | -| G.cs:52:14:52:26 | access to field Box1 [Elem] : Elem | G.cs:52:14:52:31 | access to field Elem | -| H.cs:23:9:23:9 | [post] access to local variable a [FieldA] : Object | H.cs:24:27:24:27 | access to local variable a [FieldA] : Object | -| H.cs:23:20:23:31 | object creation of type Object : Object | H.cs:23:9:23:9 | [post] access to local variable a [FieldA] : Object | -| H.cs:24:21:24:28 | call to method Clone [FieldA] : Object | H.cs:25:14:25:18 | access to local variable clone [FieldA] : Object | -| H.cs:24:27:24:27 | access to local variable a [FieldA] : Object | H.cs:24:21:24:28 | call to method Clone [FieldA] : Object | -| H.cs:25:14:25:18 | access to local variable clone [FieldA] : Object | H.cs:25:14:25:25 | access to field FieldA | -| H.cs:43:9:43:9 | [post] access to local variable a [FieldA] : Object | H.cs:44:27:44:27 | access to local variable a [FieldA] : Object | -| H.cs:43:20:43:31 | object creation of type Object : Object | H.cs:43:9:43:9 | [post] access to local variable a [FieldA] : Object | -| H.cs:44:17:44:28 | call to method Transform [FieldB] : Object | H.cs:45:14:45:14 | access to local variable b [FieldB] : Object | -| H.cs:44:27:44:27 | access to local variable a [FieldA] : Object | H.cs:44:17:44:28 | call to method Transform [FieldB] : Object | -| H.cs:45:14:45:14 | access to local variable b [FieldB] : Object | H.cs:45:14:45:21 | access to field FieldB | -| H.cs:63:9:63:9 | [post] access to local variable a [FieldA] : Object | H.cs:64:22:64:22 | access to local variable a [FieldA] : Object | -| H.cs:63:20:63:31 | object creation of type Object : Object | H.cs:63:9:63:9 | [post] access to local variable a [FieldA] : Object | -| H.cs:64:22:64:22 | access to local variable a [FieldA] : Object | H.cs:64:25:64:26 | [post] access to local variable b1 [FieldB] : Object | -| H.cs:64:25:64:26 | [post] access to local variable b1 [FieldB] : Object | H.cs:65:14:65:15 | access to local variable b1 [FieldB] : Object | -| H.cs:65:14:65:15 | access to local variable b1 [FieldB] : Object | H.cs:65:14:65:22 | access to field FieldB | -| H.cs:88:17:88:17 | [post] access to local variable a [FieldA] : Object | H.cs:89:14:89:14 | access to local variable a [FieldA] : Object | -| H.cs:88:20:88:31 | object creation of type Object : Object | H.cs:88:17:88:17 | [post] access to local variable a [FieldA] : Object | -| H.cs:88:20:88:31 | object creation of type Object : Object | H.cs:88:34:88:35 | [post] access to local variable b1 [FieldB] : Object | -| H.cs:88:34:88:35 | [post] access to local variable b1 [FieldB] : Object | H.cs:90:14:90:15 | access to local variable b1 [FieldB] : Object | -| H.cs:89:14:89:14 | access to local variable a [FieldA] : Object | H.cs:89:14:89:21 | access to field FieldA | -| H.cs:90:14:90:15 | access to local variable b1 [FieldB] : Object | H.cs:90:14:90:22 | access to field FieldB | -| H.cs:112:9:112:9 | [post] access to local variable a [FieldA] : Object | H.cs:113:31:113:31 | access to local variable a [FieldA] : Object | -| H.cs:112:20:112:31 | object creation of type Object : Object | H.cs:112:9:112:9 | [post] access to local variable a [FieldA] : Object | -| H.cs:113:17:113:32 | call to method TransformWrap [FieldB] : Object | H.cs:114:14:114:14 | access to local variable b [FieldB] : Object | -| H.cs:113:31:113:31 | access to local variable a [FieldA] : Object | H.cs:113:17:113:32 | call to method TransformWrap [FieldB] : Object | -| H.cs:114:14:114:14 | access to local variable b [FieldB] : Object | H.cs:114:14:114:21 | access to field FieldB | -| H.cs:130:9:130:9 | [post] access to local variable a [FieldA] : Object | H.cs:131:18:131:18 | access to local variable a [FieldA] : Object | -| H.cs:130:20:130:31 | object creation of type Object : Object | H.cs:130:9:130:9 | [post] access to local variable a [FieldA] : Object | -| H.cs:131:18:131:18 | access to local variable a [FieldA] : Object | H.cs:131:14:131:19 | call to method Get | +| G.cs:46:9:46:16 | [post] access to field boxfield [field Box1, field Elem] : Elem | G.cs:46:9:46:16 | [post] this access [field boxfield, field Box1, field Elem] : Elem | +| G.cs:46:9:46:16 | [post] this access [field boxfield, field Box1, field Elem] : Elem | G.cs:47:9:47:13 | this access [field boxfield, field Box1, field Elem] : Elem | +| G.cs:46:9:46:21 | [post] access to field Box1 [field Elem] : Elem | G.cs:46:9:46:16 | [post] access to field boxfield [field Box1, field Elem] : Elem | +| G.cs:46:30:46:30 | access to local variable e : Elem | G.cs:46:9:46:21 | [post] access to field Box1 [field Elem] : Elem | +| G.cs:47:9:47:13 | this access [field boxfield, field Box1, field Elem] : Elem | G.cs:50:18:50:20 | this [field boxfield, field Box1, field Elem] : Elem | +| G.cs:50:18:50:20 | this [field boxfield, field Box1, field Elem] : Elem | G.cs:52:14:52:21 | this access [field boxfield, field Box1, field Elem] : Elem | +| G.cs:52:14:52:21 | access to field boxfield [field Box1, field Elem] : Elem | G.cs:52:14:52:26 | access to field Box1 [field Elem] : Elem | +| G.cs:52:14:52:21 | this access [field boxfield, field Box1, field Elem] : Elem | G.cs:52:14:52:21 | access to field boxfield [field Box1, field Elem] : Elem | +| G.cs:52:14:52:26 | access to field Box1 [field Elem] : Elem | G.cs:52:14:52:31 | access to field Elem | +| H.cs:23:9:23:9 | [post] access to local variable a [field FieldA] : Object | H.cs:24:27:24:27 | access to local variable a [field FieldA] : Object | +| H.cs:23:20:23:31 | object creation of type Object : Object | H.cs:23:9:23:9 | [post] access to local variable a [field FieldA] : Object | +| H.cs:24:21:24:28 | call to method Clone [field FieldA] : Object | H.cs:25:14:25:18 | access to local variable clone [field FieldA] : Object | +| H.cs:24:27:24:27 | access to local variable a [field FieldA] : Object | H.cs:24:21:24:28 | call to method Clone [field FieldA] : Object | +| H.cs:25:14:25:18 | access to local variable clone [field FieldA] : Object | H.cs:25:14:25:25 | access to field FieldA | +| H.cs:43:9:43:9 | [post] access to local variable a [field FieldA] : Object | H.cs:44:27:44:27 | access to local variable a [field FieldA] : Object | +| H.cs:43:20:43:31 | object creation of type Object : Object | H.cs:43:9:43:9 | [post] access to local variable a [field FieldA] : Object | +| H.cs:44:17:44:28 | call to method Transform [field FieldB] : Object | H.cs:45:14:45:14 | access to local variable b [field FieldB] : Object | +| H.cs:44:27:44:27 | access to local variable a [field FieldA] : Object | H.cs:44:17:44:28 | call to method Transform [field FieldB] : Object | +| H.cs:45:14:45:14 | access to local variable b [field FieldB] : Object | H.cs:45:14:45:21 | access to field FieldB | +| H.cs:63:9:63:9 | [post] access to local variable a [field FieldA] : Object | H.cs:64:22:64:22 | access to local variable a [field FieldA] : Object | +| H.cs:63:20:63:31 | object creation of type Object : Object | H.cs:63:9:63:9 | [post] access to local variable a [field FieldA] : Object | +| H.cs:64:22:64:22 | access to local variable a [field FieldA] : Object | H.cs:64:25:64:26 | [post] access to local variable b1 [field FieldB] : Object | +| H.cs:64:25:64:26 | [post] access to local variable b1 [field FieldB] : Object | H.cs:65:14:65:15 | access to local variable b1 [field FieldB] : Object | +| H.cs:65:14:65:15 | access to local variable b1 [field FieldB] : Object | H.cs:65:14:65:22 | access to field FieldB | +| H.cs:88:17:88:17 | [post] access to local variable a [field FieldA] : Object | H.cs:89:14:89:14 | access to local variable a [field FieldA] : Object | +| H.cs:88:20:88:31 | object creation of type Object : Object | H.cs:88:17:88:17 | [post] access to local variable a [field FieldA] : Object | +| H.cs:88:20:88:31 | object creation of type Object : Object | H.cs:88:34:88:35 | [post] access to local variable b1 [field FieldB] : Object | +| H.cs:88:34:88:35 | [post] access to local variable b1 [field FieldB] : Object | H.cs:90:14:90:15 | access to local variable b1 [field FieldB] : Object | +| H.cs:89:14:89:14 | access to local variable a [field FieldA] : Object | H.cs:89:14:89:21 | access to field FieldA | +| H.cs:90:14:90:15 | access to local variable b1 [field FieldB] : Object | H.cs:90:14:90:22 | access to field FieldB | +| H.cs:112:9:112:9 | [post] access to local variable a [field FieldA] : Object | H.cs:113:31:113:31 | access to local variable a [field FieldA] : Object | +| H.cs:112:20:112:31 | object creation of type Object : Object | H.cs:112:9:112:9 | [post] access to local variable a [field FieldA] : Object | +| H.cs:113:17:113:32 | call to method TransformWrap [field FieldB] : Object | H.cs:114:14:114:14 | access to local variable b [field FieldB] : Object | +| H.cs:113:31:113:31 | access to local variable a [field FieldA] : Object | H.cs:113:17:113:32 | call to method TransformWrap [field FieldB] : Object | +| H.cs:114:14:114:14 | access to local variable b [field FieldB] : Object | H.cs:114:14:114:21 | access to field FieldB | +| H.cs:130:9:130:9 | [post] access to local variable a [field FieldA] : Object | H.cs:131:18:131:18 | access to local variable a [field FieldA] : Object | +| H.cs:130:20:130:31 | object creation of type Object : Object | H.cs:130:9:130:9 | [post] access to local variable a [field FieldA] : Object | +| H.cs:131:18:131:18 | access to local variable a [field FieldA] : Object | H.cs:131:14:131:19 | call to method Get | | H.cs:147:17:147:32 | call to method Through : A | H.cs:148:14:148:14 | access to local variable a | | H.cs:147:25:147:31 | object creation of type A : A | H.cs:147:17:147:32 | call to method Through : A | | H.cs:155:17:155:23 | object creation of type B : B | H.cs:156:9:156:9 | access to local variable b : B | | H.cs:156:9:156:9 | access to local variable b : B | H.cs:157:20:157:20 | access to local variable b : B | -| H.cs:157:9:157:9 | [post] access to parameter a [FieldA] : B | H.cs:164:19:164:19 | [post] access to local variable a [FieldA] : B | -| H.cs:157:20:157:20 | access to local variable b : B | H.cs:157:9:157:9 | [post] access to parameter a [FieldA] : B | +| H.cs:157:9:157:9 | [post] access to parameter a [field FieldA] : B | H.cs:164:19:164:19 | [post] access to local variable a [field FieldA] : B | +| H.cs:157:20:157:20 | access to local variable b : B | H.cs:157:9:157:9 | [post] access to parameter a [field FieldA] : B | | H.cs:163:17:163:28 | object creation of type Object : Object | H.cs:164:22:164:22 | access to local variable o : Object | -| H.cs:164:19:164:19 | [post] access to local variable a [FieldA, FieldB] : Object | H.cs:165:21:165:21 | access to local variable a [FieldA, FieldB] : Object | -| H.cs:164:19:164:19 | [post] access to local variable a [FieldA] : B | H.cs:165:21:165:21 | access to local variable a [FieldA] : B | -| H.cs:164:22:164:22 | access to local variable o : Object | H.cs:164:19:164:19 | [post] access to local variable a [FieldA, FieldB] : Object | +| H.cs:164:19:164:19 | [post] access to local variable a [field FieldA, field FieldB] : Object | H.cs:165:21:165:21 | access to local variable a [field FieldA, field FieldB] : Object | +| H.cs:164:19:164:19 | [post] access to local variable a [field FieldA] : B | H.cs:165:21:165:21 | access to local variable a [field FieldA] : B | +| H.cs:164:22:164:22 | access to local variable o : Object | H.cs:164:19:164:19 | [post] access to local variable a [field FieldA, field FieldB] : Object | | H.cs:165:17:165:28 | (...) ... : B | H.cs:166:14:166:14 | access to local variable b | -| H.cs:165:17:165:28 | (...) ... [FieldB] : Object | H.cs:167:14:167:14 | access to local variable b [FieldB] : Object | -| H.cs:165:21:165:21 | access to local variable a [FieldA, FieldB] : Object | H.cs:165:21:165:28 | access to field FieldA [FieldB] : Object | -| H.cs:165:21:165:21 | access to local variable a [FieldA] : B | H.cs:165:21:165:28 | access to field FieldA : B | +| H.cs:165:17:165:28 | (...) ... [field FieldB] : Object | H.cs:167:14:167:14 | access to local variable b [field FieldB] : Object | +| H.cs:165:21:165:21 | access to local variable a [field FieldA, field FieldB] : Object | H.cs:165:21:165:28 | access to field FieldA [field FieldB] : Object | +| H.cs:165:21:165:21 | access to local variable a [field FieldA] : B | H.cs:165:21:165:28 | access to field FieldA : B | | H.cs:165:21:165:28 | access to field FieldA : B | H.cs:165:17:165:28 | (...) ... : B | -| H.cs:165:21:165:28 | access to field FieldA [FieldB] : Object | H.cs:165:17:165:28 | (...) ... [FieldB] : Object | -| H.cs:167:14:167:14 | access to local variable b [FieldB] : Object | H.cs:167:14:167:21 | access to field FieldB | -| I.cs:7:9:7:14 | [post] this access [Field1] : Object | I.cs:21:13:21:19 | object creation of type I [Field1] : Object | -| I.cs:7:9:7:14 | [post] this access [Field1] : Object | I.cs:26:13:26:37 | [pre-initializer] object creation of type I [Field1] : Object | -| I.cs:7:18:7:29 | object creation of type Object : Object | I.cs:7:9:7:14 | [post] this access [Field1] : Object | +| H.cs:165:21:165:28 | access to field FieldA [field FieldB] : Object | H.cs:165:17:165:28 | (...) ... [field FieldB] : Object | +| H.cs:167:14:167:14 | access to local variable b [field FieldB] : Object | H.cs:167:14:167:21 | access to field FieldB | +| I.cs:7:9:7:14 | [post] this access [field Field1] : Object | I.cs:21:13:21:19 | object creation of type I [field Field1] : Object | +| I.cs:7:9:7:14 | [post] this access [field Field1] : Object | I.cs:26:13:26:37 | [pre-initializer] object creation of type I [field Field1] : Object | +| I.cs:7:18:7:29 | object creation of type Object : Object | I.cs:7:9:7:14 | [post] this access [field Field1] : Object | | I.cs:13:17:13:28 | object creation of type Object : Object | I.cs:15:20:15:20 | access to local variable o : Object | -| I.cs:15:9:15:9 | [post] access to local variable i [Field1] : Object | I.cs:16:9:16:9 | access to local variable i [Field1] : Object | -| I.cs:15:20:15:20 | access to local variable o : Object | I.cs:15:9:15:9 | [post] access to local variable i [Field1] : Object | -| I.cs:16:9:16:9 | access to local variable i [Field1] : Object | I.cs:17:9:17:9 | access to local variable i [Field1] : Object | -| I.cs:17:9:17:9 | access to local variable i [Field1] : Object | I.cs:18:14:18:14 | access to local variable i [Field1] : Object | -| I.cs:18:14:18:14 | access to local variable i [Field1] : Object | I.cs:18:14:18:21 | access to field Field1 | -| I.cs:21:13:21:19 | object creation of type I [Field1] : Object | I.cs:22:9:22:9 | access to local variable i [Field1] : Object | -| I.cs:22:9:22:9 | access to local variable i [Field1] : Object | I.cs:23:14:23:14 | access to local variable i [Field1] : Object | -| I.cs:23:14:23:14 | access to local variable i [Field1] : Object | I.cs:23:14:23:21 | access to field Field1 | -| I.cs:26:13:26:37 | [pre-initializer] object creation of type I [Field1] : Object | I.cs:27:14:27:14 | access to local variable i [Field1] : Object | -| I.cs:27:14:27:14 | access to local variable i [Field1] : Object | I.cs:27:14:27:21 | access to field Field1 | +| I.cs:15:9:15:9 | [post] access to local variable i [field Field1] : Object | I.cs:16:9:16:9 | access to local variable i [field Field1] : Object | +| I.cs:15:20:15:20 | access to local variable o : Object | I.cs:15:9:15:9 | [post] access to local variable i [field Field1] : Object | +| I.cs:16:9:16:9 | access to local variable i [field Field1] : Object | I.cs:17:9:17:9 | access to local variable i [field Field1] : Object | +| I.cs:17:9:17:9 | access to local variable i [field Field1] : Object | I.cs:18:14:18:14 | access to local variable i [field Field1] : Object | +| I.cs:18:14:18:14 | access to local variable i [field Field1] : Object | I.cs:18:14:18:21 | access to field Field1 | +| I.cs:21:13:21:19 | object creation of type I [field Field1] : Object | I.cs:22:9:22:9 | access to local variable i [field Field1] : Object | +| I.cs:22:9:22:9 | access to local variable i [field Field1] : Object | I.cs:23:14:23:14 | access to local variable i [field Field1] : Object | +| I.cs:23:14:23:14 | access to local variable i [field Field1] : Object | I.cs:23:14:23:21 | access to field Field1 | +| I.cs:26:13:26:37 | [pre-initializer] object creation of type I [field Field1] : Object | I.cs:27:14:27:14 | access to local variable i [field Field1] : Object | +| I.cs:27:14:27:14 | access to local variable i [field Field1] : Object | I.cs:27:14:27:21 | access to field Field1 | | I.cs:31:13:31:24 | object creation of type Object : Object | I.cs:32:20:32:20 | access to local variable o : Object | -| I.cs:32:9:32:9 | [post] access to local variable i [Field1] : Object | I.cs:33:9:33:9 | access to local variable i [Field1] : Object | -| I.cs:32:20:32:20 | access to local variable o : Object | I.cs:32:9:32:9 | [post] access to local variable i [Field1] : Object | -| I.cs:33:9:33:9 | access to local variable i [Field1] : Object | I.cs:34:12:34:12 | access to local variable i [Field1] : Object | -| I.cs:34:12:34:12 | access to local variable i [Field1] : Object | I.cs:37:23:37:23 | i [Field1] : Object | -| I.cs:37:23:37:23 | i [Field1] : Object | I.cs:39:9:39:9 | access to parameter i [Field1] : Object | -| I.cs:39:9:39:9 | access to parameter i [Field1] : Object | I.cs:40:14:40:14 | access to parameter i [Field1] : Object | -| I.cs:40:14:40:14 | access to parameter i [Field1] : Object | I.cs:40:14:40:21 | access to field Field1 | +| I.cs:32:9:32:9 | [post] access to local variable i [field Field1] : Object | I.cs:33:9:33:9 | access to local variable i [field Field1] : Object | +| I.cs:32:20:32:20 | access to local variable o : Object | I.cs:32:9:32:9 | [post] access to local variable i [field Field1] : Object | +| I.cs:33:9:33:9 | access to local variable i [field Field1] : Object | I.cs:34:12:34:12 | access to local variable i [field Field1] : Object | +| I.cs:34:12:34:12 | access to local variable i [field Field1] : Object | I.cs:37:23:37:23 | i [field Field1] : Object | +| I.cs:37:23:37:23 | i [field Field1] : Object | I.cs:39:9:39:9 | access to parameter i [field Field1] : Object | +| I.cs:39:9:39:9 | access to parameter i [field Field1] : Object | I.cs:40:14:40:14 | access to parameter i [field Field1] : Object | +| I.cs:40:14:40:14 | access to parameter i [field Field1] : Object | I.cs:40:14:40:21 | access to field Field1 | | J.cs:12:17:12:28 | object creation of type Object : Object | J.cs:13:29:13:29 | access to local variable o : Object | | J.cs:12:17:12:28 | object creation of type Object : Object | J.cs:21:36:21:36 | access to local variable o : Object | -| J.cs:13:18:13:36 | object creation of type Record [Prop1] : Object | J.cs:14:14:14:15 | access to local variable r1 [Prop1] : Object | -| J.cs:13:18:13:36 | object creation of type Record [Prop1] : Object | J.cs:18:14:18:15 | access to local variable r2 [Prop1] : Object | -| J.cs:13:18:13:36 | object creation of type Record [Prop1] : Object | J.cs:22:14:22:15 | access to local variable r3 [Prop1] : Object | -| J.cs:13:29:13:29 | access to local variable o : Object | J.cs:13:18:13:36 | object creation of type Record [Prop1] : Object | -| J.cs:14:14:14:15 | access to local variable r1 [Prop1] : Object | J.cs:14:14:14:21 | access to property Prop1 | -| J.cs:18:14:18:15 | access to local variable r2 [Prop1] : Object | J.cs:18:14:18:21 | access to property Prop1 | -| J.cs:21:18:21:38 | ... with { ... } [Prop2] : Object | J.cs:23:14:23:15 | access to local variable r3 [Prop2] : Object | -| J.cs:21:36:21:36 | access to local variable o : Object | J.cs:21:18:21:38 | ... with { ... } [Prop2] : Object | -| J.cs:22:14:22:15 | access to local variable r3 [Prop1] : Object | J.cs:22:14:22:21 | access to property Prop1 | -| J.cs:23:14:23:15 | access to local variable r3 [Prop2] : Object | J.cs:23:14:23:21 | access to property Prop2 | +| J.cs:13:18:13:36 | object creation of type Record [property Prop1] : Object | J.cs:14:14:14:15 | access to local variable r1 [property Prop1] : Object | +| J.cs:13:18:13:36 | object creation of type Record [property Prop1] : Object | J.cs:18:14:18:15 | access to local variable r2 [property Prop1] : Object | +| J.cs:13:18:13:36 | object creation of type Record [property Prop1] : Object | J.cs:22:14:22:15 | access to local variable r3 [property Prop1] : Object | +| J.cs:13:29:13:29 | access to local variable o : Object | J.cs:13:18:13:36 | object creation of type Record [property Prop1] : Object | +| J.cs:14:14:14:15 | access to local variable r1 [property Prop1] : Object | J.cs:14:14:14:21 | access to property Prop1 | +| J.cs:18:14:18:15 | access to local variable r2 [property Prop1] : Object | J.cs:18:14:18:21 | access to property Prop1 | +| J.cs:21:18:21:38 | ... with { ... } [property Prop2] : Object | J.cs:23:14:23:15 | access to local variable r3 [property Prop2] : Object | +| J.cs:21:36:21:36 | access to local variable o : Object | J.cs:21:18:21:38 | ... with { ... } [property Prop2] : Object | +| J.cs:22:14:22:15 | access to local variable r3 [property Prop1] : Object | J.cs:22:14:22:21 | access to property Prop1 | +| J.cs:23:14:23:15 | access to local variable r3 [property Prop2] : Object | J.cs:23:14:23:21 | access to property Prop2 | nodes | A.cs:5:17:5:23 | object creation of type C : C | semmle.label | object creation of type C : C | -| A.cs:6:17:6:25 | call to method Make [c] : C | semmle.label | call to method Make [c] : C | +| A.cs:6:17:6:25 | call to method Make [field c] : C | semmle.label | call to method Make [field c] : C | | A.cs:6:24:6:24 | access to local variable c : C | semmle.label | access to local variable c : C | -| A.cs:7:14:7:14 | access to local variable b [c] : C | semmle.label | access to local variable b [c] : C | +| A.cs:7:14:7:14 | access to local variable b [field c] : C | semmle.label | access to local variable b [field c] : C | | A.cs:7:14:7:16 | access to field c | semmle.label | access to field c | -| A.cs:13:9:13:9 | [post] access to local variable b [c] : C1 | semmle.label | [post] access to local variable b [c] : C1 | +| A.cs:13:9:13:9 | [post] access to local variable b [field c] : C1 | semmle.label | [post] access to local variable b [field c] : C1 | | A.cs:13:15:13:22 | object creation of type C1 : C1 | semmle.label | object creation of type C1 : C1 | -| A.cs:14:14:14:14 | access to local variable b [c] : C1 | semmle.label | access to local variable b [c] : C1 | +| A.cs:14:14:14:14 | access to local variable b [field c] : C1 | semmle.label | access to local variable b [field c] : C1 | | A.cs:14:14:14:20 | call to method Get | semmle.label | call to method Get | | A.cs:15:14:15:35 | call to method Get | semmle.label | call to method Get | -| A.cs:15:15:15:28 | object creation of type B [c] : C | semmle.label | object creation of type B [c] : C | +| A.cs:15:15:15:28 | object creation of type B [field c] : C | semmle.label | object creation of type B [field c] : C | | A.cs:15:21:15:27 | object creation of type C : C | semmle.label | object creation of type C : C | -| A.cs:22:14:22:33 | call to method SetOnB [c] : C2 | semmle.label | call to method SetOnB [c] : C2 | +| A.cs:22:14:22:33 | call to method SetOnB [field c] : C2 | semmle.label | call to method SetOnB [field c] : C2 | | A.cs:22:25:22:32 | object creation of type C2 : C2 | semmle.label | object creation of type C2 : C2 | -| A.cs:24:14:24:15 | access to local variable b2 [c] : C2 | semmle.label | access to local variable b2 [c] : C2 | +| A.cs:24:14:24:15 | access to local variable b2 [field c] : C2 | semmle.label | access to local variable b2 [field c] : C2 | | A.cs:24:14:24:17 | access to field c | semmle.label | access to field c | -| A.cs:31:14:31:37 | call to method SetOnBWrap [c] : C2 | semmle.label | call to method SetOnBWrap [c] : C2 | +| A.cs:31:14:31:37 | call to method SetOnBWrap [field c] : C2 | semmle.label | call to method SetOnBWrap [field c] : C2 | | A.cs:31:29:31:36 | object creation of type C2 : C2 | semmle.label | object creation of type C2 : C2 | -| A.cs:33:14:33:15 | access to local variable b2 [c] : C2 | semmle.label | access to local variable b2 [c] : C2 | +| A.cs:33:14:33:15 | access to local variable b2 [field c] : C2 | semmle.label | access to local variable b2 [field c] : C2 | | A.cs:33:14:33:17 | access to field c | semmle.label | access to field c | | A.cs:55:17:55:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| A.cs:57:9:57:10 | [post] access to local variable c1 [a] : A | semmle.label | [post] access to local variable c1 [a] : A | +| A.cs:57:9:57:10 | [post] access to local variable c1 [field a] : A | semmle.label | [post] access to local variable c1 [field a] : A | | A.cs:57:16:57:16 | access to local variable a : A | semmle.label | access to local variable a : A | -| A.cs:58:12:58:13 | access to local variable c1 [a] : A | semmle.label | access to local variable c1 [a] : A | -| A.cs:60:22:60:22 | c [a] : A | semmle.label | c [a] : A | +| A.cs:58:12:58:13 | access to local variable c1 [field a] : A | semmle.label | access to local variable c1 [field a] : A | +| A.cs:60:22:60:22 | c [field a] : A | semmle.label | c [field a] : A | | A.cs:64:18:64:26 | access to field a | semmle.label | access to field a | -| A.cs:64:19:64:23 | (...) ... [a] : A | semmle.label | (...) ... [a] : A | -| A.cs:83:9:83:9 | [post] access to parameter b [c] : C | semmle.label | [post] access to parameter b [c] : C | +| A.cs:64:19:64:23 | (...) ... [field a] : A | semmle.label | (...) ... [field a] : A | +| A.cs:83:9:83:9 | [post] access to parameter b [field c] : C | semmle.label | [post] access to parameter b [field c] : C | | A.cs:83:15:83:21 | object creation of type C : C | semmle.label | object creation of type C : C | -| A.cs:88:12:88:12 | [post] access to local variable b [c] : C | semmle.label | [post] access to local variable b [c] : C | -| A.cs:89:14:89:14 | access to local variable b [c] : C | semmle.label | access to local variable b [c] : C | +| A.cs:88:12:88:12 | [post] access to local variable b [field c] : C | semmle.label | [post] access to local variable b [field c] : C | +| A.cs:89:14:89:14 | access to local variable b [field c] : C | semmle.label | access to local variable b [field c] : C | | A.cs:89:14:89:16 | access to field c | semmle.label | access to field c | -| A.cs:97:13:97:13 | [post] access to parameter b [c] : C | semmle.label | [post] access to parameter b [c] : C | +| A.cs:97:13:97:13 | [post] access to parameter b [field c] : C | semmle.label | [post] access to parameter b [field c] : C | | A.cs:97:19:97:25 | object creation of type C : C | semmle.label | object creation of type C : C | -| A.cs:98:13:98:16 | [post] this access [b, c] : C | semmle.label | [post] this access [b, c] : C | -| A.cs:98:13:98:16 | [post] this access [b] : B | semmle.label | [post] this access [b] : B | +| A.cs:98:13:98:16 | [post] this access [field b, field c] : C | semmle.label | [post] this access [field b, field c] : C | +| A.cs:98:13:98:16 | [post] this access [field b] : B | semmle.label | [post] this access [field b] : B | | A.cs:98:22:98:36 | ... ? ... : ... : B | semmle.label | ... ? ... : ... : B | -| A.cs:98:22:98:36 | ... ? ... : ... [c] : C | semmle.label | ... ? ... : ... [c] : C | +| A.cs:98:22:98:36 | ... ? ... : ... [field c] : C | semmle.label | ... ? ... : ... [field c] : C | | A.cs:98:30:98:36 | object creation of type B : B | semmle.label | object creation of type B : B | | A.cs:104:17:104:23 | object creation of type B : B | semmle.label | object creation of type B : B | -| A.cs:105:17:105:29 | object creation of type D [b, c] : C | semmle.label | object creation of type D [b, c] : C | -| A.cs:105:17:105:29 | object creation of type D [b] : B | semmle.label | object creation of type D [b] : B | -| A.cs:105:23:105:23 | [post] access to local variable b [c] : C | semmle.label | [post] access to local variable b [c] : C | +| A.cs:105:17:105:29 | object creation of type D [field b, field c] : C | semmle.label | object creation of type D [field b, field c] : C | +| A.cs:105:17:105:29 | object creation of type D [field b] : B | semmle.label | object creation of type D [field b] : B | +| A.cs:105:23:105:23 | [post] access to local variable b [field c] : C | semmle.label | [post] access to local variable b [field c] : C | | A.cs:105:23:105:23 | access to local variable b : B | semmle.label | access to local variable b : B | -| A.cs:106:14:106:14 | access to local variable d [b] : B | semmle.label | access to local variable d [b] : B | +| A.cs:106:14:106:14 | access to local variable d [field b] : B | semmle.label | access to local variable d [field b] : B | | A.cs:106:14:106:16 | access to field b | semmle.label | access to field b | -| A.cs:107:14:107:14 | access to local variable d [b, c] : C | semmle.label | access to local variable d [b, c] : C | -| A.cs:107:14:107:16 | access to field b [c] : C | semmle.label | access to field b [c] : C | +| A.cs:107:14:107:14 | access to local variable d [field b, field c] : C | semmle.label | access to local variable d [field b, field c] : C | +| A.cs:107:14:107:16 | access to field b [field c] : C | semmle.label | access to field b [field c] : C | | A.cs:107:14:107:18 | access to field c | semmle.label | access to field c | -| A.cs:108:14:108:14 | access to local variable b [c] : C | semmle.label | access to local variable b [c] : C | +| A.cs:108:14:108:14 | access to local variable b [field c] : C | semmle.label | access to local variable b [field c] : C | | A.cs:108:14:108:16 | access to field c | semmle.label | access to field c | | A.cs:113:17:113:23 | object creation of type B : B | semmle.label | object creation of type B : B | -| A.cs:114:18:114:54 | object creation of type MyList [head] : B | semmle.label | object creation of type MyList [head] : B | +| A.cs:114:18:114:54 | object creation of type MyList [field head] : B | semmle.label | object creation of type MyList [field head] : B | | A.cs:114:29:114:29 | access to local variable b : B | semmle.label | access to local variable b : B | -| A.cs:115:18:115:37 | object creation of type MyList [next, head] : B | semmle.label | object creation of type MyList [next, head] : B | -| A.cs:115:35:115:36 | access to local variable l1 [head] : B | semmle.label | access to local variable l1 [head] : B | -| A.cs:116:18:116:37 | object creation of type MyList [next, next, head] : B | semmle.label | object creation of type MyList [next, next, head] : B | -| A.cs:116:35:116:36 | access to local variable l2 [next, head] : B | semmle.label | access to local variable l2 [next, head] : B | -| A.cs:119:14:119:15 | access to local variable l3 [next, next, head] : B | semmle.label | access to local variable l3 [next, next, head] : B | -| A.cs:119:14:119:20 | access to field next [next, head] : B | semmle.label | access to field next [next, head] : B | -| A.cs:119:14:119:25 | access to field next [head] : B | semmle.label | access to field next [head] : B | +| A.cs:115:18:115:37 | object creation of type MyList [field next, field head] : B | semmle.label | object creation of type MyList [field next, field head] : B | +| A.cs:115:35:115:36 | access to local variable l1 [field head] : B | semmle.label | access to local variable l1 [field head] : B | +| A.cs:116:18:116:37 | object creation of type MyList [field next, field next, field head] : B | semmle.label | object creation of type MyList [field next, field next, field head] : B | +| A.cs:116:35:116:36 | access to local variable l2 [field next, field head] : B | semmle.label | access to local variable l2 [field next, field head] : B | +| A.cs:119:14:119:15 | access to local variable l3 [field next, field next, field head] : B | semmle.label | access to local variable l3 [field next, field next, field head] : B | +| A.cs:119:14:119:20 | access to field next [field next, field head] : B | semmle.label | access to field next [field next, field head] : B | +| A.cs:119:14:119:25 | access to field next [field head] : B | semmle.label | access to field next [field head] : B | | A.cs:119:14:119:30 | access to field head | semmle.label | access to field head | -| A.cs:121:41:121:41 | access to local variable l [next, head] : B | semmle.label | access to local variable l [next, head] : B | -| A.cs:121:41:121:41 | access to local variable l [next, next, head] : B | semmle.label | access to local variable l [next, next, head] : B | -| A.cs:121:41:121:46 | access to field next [head] : B | semmle.label | access to field next [head] : B | -| A.cs:121:41:121:46 | access to field next [next, head] : B | semmle.label | access to field next [next, head] : B | -| A.cs:123:18:123:18 | access to local variable l [head] : B | semmle.label | access to local variable l [head] : B | +| A.cs:121:41:121:41 | access to local variable l [field next, field head] : B | semmle.label | access to local variable l [field next, field head] : B | +| A.cs:121:41:121:41 | access to local variable l [field next, field next, field head] : B | semmle.label | access to local variable l [field next, field next, field head] : B | +| A.cs:121:41:121:46 | access to field next [field head] : B | semmle.label | access to field next [field head] : B | +| A.cs:121:41:121:46 | access to field next [field next, field head] : B | semmle.label | access to field next [field next, field head] : B | +| A.cs:123:18:123:18 | access to local variable l [field head] : B | semmle.label | access to local variable l [field head] : B | | A.cs:123:18:123:23 | access to field head | semmle.label | access to field head | | B.cs:5:17:5:26 | object creation of type Elem : Elem | semmle.label | object creation of type Elem : Elem | -| B.cs:6:18:6:34 | object creation of type Box1 [elem1] : Elem | semmle.label | object creation of type Box1 [elem1] : Elem | +| B.cs:6:18:6:34 | object creation of type Box1 [field elem1] : Elem | semmle.label | object creation of type Box1 [field elem1] : Elem | | B.cs:6:27:6:27 | access to local variable e : Elem | semmle.label | access to local variable e : Elem | -| B.cs:7:18:7:29 | object creation of type Box2 [box1, elem1] : Elem | semmle.label | object creation of type Box2 [box1, elem1] : Elem | -| B.cs:7:27:7:28 | access to local variable b1 [elem1] : Elem | semmle.label | access to local variable b1 [elem1] : Elem | -| B.cs:8:14:8:15 | access to local variable b2 [box1, elem1] : Elem | semmle.label | access to local variable b2 [box1, elem1] : Elem | -| B.cs:8:14:8:20 | access to field box1 [elem1] : Elem | semmle.label | access to field box1 [elem1] : Elem | +| B.cs:7:18:7:29 | object creation of type Box2 [field box1, field elem1] : Elem | semmle.label | object creation of type Box2 [field box1, field elem1] : Elem | +| B.cs:7:27:7:28 | access to local variable b1 [field elem1] : Elem | semmle.label | access to local variable b1 [field elem1] : Elem | +| B.cs:8:14:8:15 | access to local variable b2 [field box1, field elem1] : Elem | semmle.label | access to local variable b2 [field box1, field elem1] : Elem | +| B.cs:8:14:8:20 | access to field box1 [field elem1] : Elem | semmle.label | access to field box1 [field elem1] : Elem | | B.cs:8:14:8:26 | access to field elem1 | semmle.label | access to field elem1 | | B.cs:14:17:14:26 | object creation of type Elem : Elem | semmle.label | object creation of type Elem : Elem | -| B.cs:15:18:15:34 | object creation of type Box1 [elem2] : Elem | semmle.label | object creation of type Box1 [elem2] : Elem | +| B.cs:15:18:15:34 | object creation of type Box1 [field elem2] : Elem | semmle.label | object creation of type Box1 [field elem2] : Elem | | B.cs:15:33:15:33 | access to local variable e : Elem | semmle.label | access to local variable e : Elem | -| B.cs:16:18:16:29 | object creation of type Box2 [box1, elem2] : Elem | semmle.label | object creation of type Box2 [box1, elem2] : Elem | -| B.cs:16:27:16:28 | access to local variable b1 [elem2] : Elem | semmle.label | access to local variable b1 [elem2] : Elem | -| B.cs:18:14:18:15 | access to local variable b2 [box1, elem2] : Elem | semmle.label | access to local variable b2 [box1, elem2] : Elem | -| B.cs:18:14:18:20 | access to field box1 [elem2] : Elem | semmle.label | access to field box1 [elem2] : Elem | +| B.cs:16:18:16:29 | object creation of type Box2 [field box1, field elem2] : Elem | semmle.label | object creation of type Box2 [field box1, field elem2] : Elem | +| B.cs:16:27:16:28 | access to local variable b1 [field elem2] : Elem | semmle.label | access to local variable b1 [field elem2] : Elem | +| B.cs:18:14:18:15 | access to local variable b2 [field box1, field elem2] : Elem | semmle.label | access to local variable b2 [field box1, field elem2] : Elem | +| B.cs:18:14:18:20 | access to field box1 [field elem2] : Elem | semmle.label | access to field box1 [field elem2] : Elem | | B.cs:18:14:18:26 | access to field elem2 | semmle.label | access to field elem2 | -| C.cs:3:18:3:19 | [post] this access [s1] : Elem | semmle.label | [post] this access [s1] : Elem | +| C.cs:3:18:3:19 | [post] this access [field s1] : Elem | semmle.label | [post] this access [field s1] : Elem | | C.cs:3:23:3:32 | object creation of type Elem : Elem | semmle.label | object creation of type Elem : Elem | -| C.cs:4:27:4:28 | [post] this access [s2] : Elem | semmle.label | [post] this access [s2] : Elem | +| C.cs:4:27:4:28 | [post] this access [field s2] : Elem | semmle.label | [post] this access [field s2] : Elem | | C.cs:4:32:4:41 | object creation of type Elem : Elem | semmle.label | object creation of type Elem : Elem | | C.cs:6:30:6:39 | object creation of type Elem : Elem | semmle.label | object creation of type Elem : Elem | -| C.cs:7:18:7:19 | [post] this access [s5] : Elem | semmle.label | [post] this access [s5] : Elem | +| C.cs:7:18:7:19 | [post] this access [property s5] : Elem | semmle.label | [post] this access [property s5] : Elem | | C.cs:7:37:7:46 | object creation of type Elem : Elem | semmle.label | object creation of type Elem : Elem | | C.cs:8:30:8:39 | object creation of type Elem : Elem | semmle.label | object creation of type Elem : Elem | -| C.cs:12:15:12:21 | object creation of type C [s1] : Elem | semmle.label | object creation of type C [s1] : Elem | -| C.cs:12:15:12:21 | object creation of type C [s2] : Elem | semmle.label | object creation of type C [s2] : Elem | -| C.cs:12:15:12:21 | object creation of type C [s3] : Elem | semmle.label | object creation of type C [s3] : Elem | -| C.cs:12:15:12:21 | object creation of type C [s5] : Elem | semmle.label | object creation of type C [s5] : Elem | -| C.cs:13:9:13:9 | access to local variable c [s1] : Elem | semmle.label | access to local variable c [s1] : Elem | -| C.cs:13:9:13:9 | access to local variable c [s2] : Elem | semmle.label | access to local variable c [s2] : Elem | -| C.cs:13:9:13:9 | access to local variable c [s3] : Elem | semmle.label | access to local variable c [s3] : Elem | -| C.cs:13:9:13:9 | access to local variable c [s5] : Elem | semmle.label | access to local variable c [s5] : Elem | -| C.cs:18:9:18:12 | [post] this access [s3] : Elem | semmle.label | [post] this access [s3] : Elem | +| C.cs:12:15:12:21 | object creation of type C [field s1] : Elem | semmle.label | object creation of type C [field s1] : Elem | +| C.cs:12:15:12:21 | object creation of type C [field s2] : Elem | semmle.label | object creation of type C [field s2] : Elem | +| C.cs:12:15:12:21 | object creation of type C [field s3] : Elem | semmle.label | object creation of type C [field s3] : Elem | +| C.cs:12:15:12:21 | object creation of type C [property s5] : Elem | semmle.label | object creation of type C [property s5] : Elem | +| C.cs:13:9:13:9 | access to local variable c [field s1] : Elem | semmle.label | access to local variable c [field s1] : Elem | +| C.cs:13:9:13:9 | access to local variable c [field s2] : Elem | semmle.label | access to local variable c [field s2] : Elem | +| C.cs:13:9:13:9 | access to local variable c [field s3] : Elem | semmle.label | access to local variable c [field s3] : Elem | +| C.cs:13:9:13:9 | access to local variable c [property s5] : Elem | semmle.label | access to local variable c [property s5] : Elem | +| C.cs:18:9:18:12 | [post] this access [field s3] : Elem | semmle.label | [post] this access [field s3] : Elem | | C.cs:18:19:18:28 | object creation of type Elem : Elem | semmle.label | object creation of type Elem : Elem | -| C.cs:21:17:21:18 | this [s1] : Elem | semmle.label | this [s1] : Elem | -| C.cs:21:17:21:18 | this [s2] : Elem | semmle.label | this [s2] : Elem | -| C.cs:21:17:21:18 | this [s3] : Elem | semmle.label | this [s3] : Elem | -| C.cs:21:17:21:18 | this [s5] : Elem | semmle.label | this [s5] : Elem | +| C.cs:21:17:21:18 | this [field s1] : Elem | semmle.label | this [field s1] : Elem | +| C.cs:21:17:21:18 | this [field s2] : Elem | semmle.label | this [field s2] : Elem | +| C.cs:21:17:21:18 | this [field s3] : Elem | semmle.label | this [field s3] : Elem | +| C.cs:21:17:21:18 | this [property s5] : Elem | semmle.label | this [property s5] : Elem | | C.cs:23:14:23:15 | access to field s1 | semmle.label | access to field s1 | -| C.cs:23:14:23:15 | this access [s1] : Elem | semmle.label | this access [s1] : Elem | +| C.cs:23:14:23:15 | this access [field s1] : Elem | semmle.label | this access [field s1] : Elem | | C.cs:24:14:24:15 | access to field s2 | semmle.label | access to field s2 | -| C.cs:24:14:24:15 | this access [s2] : Elem | semmle.label | this access [s2] : Elem | +| C.cs:24:14:24:15 | this access [field s2] : Elem | semmle.label | this access [field s2] : Elem | | C.cs:25:14:25:15 | access to field s3 | semmle.label | access to field s3 | -| C.cs:25:14:25:15 | this access [s3] : Elem | semmle.label | this access [s3] : Elem | +| C.cs:25:14:25:15 | this access [field s3] : Elem | semmle.label | this access [field s3] : Elem | | C.cs:26:14:26:15 | access to field s4 | semmle.label | access to field s4 | | C.cs:27:14:27:15 | access to property s5 | semmle.label | access to property s5 | -| C.cs:27:14:27:15 | this access [s5] : Elem | semmle.label | this access [s5] : Elem | +| C.cs:27:14:27:15 | this access [property s5] : Elem | semmle.label | this access [property s5] : Elem | | C.cs:28:14:28:15 | access to property s6 | semmle.label | access to property s6 | | D.cs:29:17:29:28 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | -| D.cs:31:17:31:37 | call to method Create [AutoProp] : Object | semmle.label | call to method Create [AutoProp] : Object | +| D.cs:31:17:31:37 | call to method Create [property AutoProp] : Object | semmle.label | call to method Create [property AutoProp] : Object | | D.cs:31:24:31:24 | access to local variable o : Object | semmle.label | access to local variable o : Object | -| D.cs:32:14:32:14 | access to local variable d [AutoProp] : Object | semmle.label | access to local variable d [AutoProp] : Object | +| D.cs:32:14:32:14 | access to local variable d [property AutoProp] : Object | semmle.label | access to local variable d [property AutoProp] : Object | | D.cs:32:14:32:23 | access to property AutoProp | semmle.label | access to property AutoProp | -| D.cs:37:13:37:33 | call to method Create [trivialPropField] : Object | semmle.label | call to method Create [trivialPropField] : Object | +| D.cs:37:13:37:33 | call to method Create [field trivialPropField] : Object | semmle.label | call to method Create [field trivialPropField] : Object | | D.cs:37:26:37:26 | access to local variable o : Object | semmle.label | access to local variable o : Object | -| D.cs:39:14:39:14 | access to local variable d [trivialPropField] : Object | semmle.label | access to local variable d [trivialPropField] : Object | +| D.cs:39:14:39:14 | access to local variable d [field trivialPropField] : Object | semmle.label | access to local variable d [field trivialPropField] : Object | | D.cs:39:14:39:26 | access to property TrivialProp | semmle.label | access to property TrivialProp | -| D.cs:40:14:40:14 | access to local variable d [trivialPropField] : Object | semmle.label | access to local variable d [trivialPropField] : Object | +| D.cs:40:14:40:14 | access to local variable d [field trivialPropField] : Object | semmle.label | access to local variable d [field trivialPropField] : Object | | D.cs:40:14:40:31 | access to field trivialPropField | semmle.label | access to field trivialPropField | -| D.cs:41:14:41:14 | access to local variable d [trivialPropField] : Object | semmle.label | access to local variable d [trivialPropField] : Object | +| D.cs:41:14:41:14 | access to local variable d [field trivialPropField] : Object | semmle.label | access to local variable d [field trivialPropField] : Object | | D.cs:41:14:41:26 | access to property ComplexProp | semmle.label | access to property ComplexProp | -| D.cs:43:13:43:33 | call to method Create [trivialPropField] : Object | semmle.label | call to method Create [trivialPropField] : Object | +| D.cs:43:13:43:33 | call to method Create [field trivialPropField] : Object | semmle.label | call to method Create [field trivialPropField] : Object | | D.cs:43:32:43:32 | access to local variable o : Object | semmle.label | access to local variable o : Object | -| D.cs:45:14:45:14 | access to local variable d [trivialPropField] : Object | semmle.label | access to local variable d [trivialPropField] : Object | +| D.cs:45:14:45:14 | access to local variable d [field trivialPropField] : Object | semmle.label | access to local variable d [field trivialPropField] : Object | | D.cs:45:14:45:26 | access to property TrivialProp | semmle.label | access to property TrivialProp | -| D.cs:46:14:46:14 | access to local variable d [trivialPropField] : Object | semmle.label | access to local variable d [trivialPropField] : Object | +| D.cs:46:14:46:14 | access to local variable d [field trivialPropField] : Object | semmle.label | access to local variable d [field trivialPropField] : Object | | D.cs:46:14:46:31 | access to field trivialPropField | semmle.label | access to field trivialPropField | -| D.cs:47:14:47:14 | access to local variable d [trivialPropField] : Object | semmle.label | access to local variable d [trivialPropField] : Object | +| D.cs:47:14:47:14 | access to local variable d [field trivialPropField] : Object | semmle.label | access to local variable d [field trivialPropField] : Object | | D.cs:47:14:47:26 | access to property ComplexProp | semmle.label | access to property ComplexProp | | E.cs:22:17:22:28 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | -| E.cs:23:17:23:26 | call to method CreateS [Field] : Object | semmle.label | call to method CreateS [Field] : Object | +| E.cs:23:17:23:26 | call to method CreateS [field Field] : Object | semmle.label | call to method CreateS [field Field] : Object | | E.cs:23:25:23:25 | access to local variable o : Object | semmle.label | access to local variable o : Object | -| E.cs:24:14:24:14 | access to local variable s [Field] : Object | semmle.label | access to local variable s [Field] : Object | +| E.cs:24:14:24:14 | access to local variable s [field Field] : Object | semmle.label | access to local variable s [field Field] : Object | | E.cs:24:14:24:20 | access to field Field | semmle.label | access to field Field | | F.cs:10:17:10:28 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | -| F.cs:11:17:11:31 | call to method Create [Field1] : Object | semmle.label | call to method Create [Field1] : Object | +| F.cs:11:17:11:31 | call to method Create [field Field1] : Object | semmle.label | call to method Create [field Field1] : Object | | F.cs:11:24:11:24 | access to local variable o : Object | semmle.label | access to local variable o : Object | -| F.cs:12:14:12:14 | access to local variable f [Field1] : Object | semmle.label | access to local variable f [Field1] : Object | +| F.cs:12:14:12:14 | access to local variable f [field Field1] : Object | semmle.label | access to local variable f [field Field1] : Object | | F.cs:12:14:12:21 | access to field Field1 | semmle.label | access to field Field1 | -| F.cs:15:13:15:27 | call to method Create [Field2] : Object | semmle.label | call to method Create [Field2] : Object | +| F.cs:15:13:15:27 | call to method Create [field Field2] : Object | semmle.label | call to method Create [field Field2] : Object | | F.cs:15:26:15:26 | access to local variable o : Object | semmle.label | access to local variable o : Object | -| F.cs:17:14:17:14 | access to local variable f [Field2] : Object | semmle.label | access to local variable f [Field2] : Object | +| F.cs:17:14:17:14 | access to local variable f [field Field2] : Object | semmle.label | access to local variable f [field Field2] : Object | | F.cs:17:14:17:21 | access to field Field2 | semmle.label | access to field Field2 | -| F.cs:19:21:19:34 | { ..., ... } [Field1] : Object | semmle.label | { ..., ... } [Field1] : Object | +| F.cs:19:21:19:34 | { ..., ... } [field Field1] : Object | semmle.label | { ..., ... } [field Field1] : Object | | F.cs:19:32:19:32 | access to local variable o : Object | semmle.label | access to local variable o : Object | -| F.cs:20:14:20:14 | access to local variable f [Field1] : Object | semmle.label | access to local variable f [Field1] : Object | +| F.cs:20:14:20:14 | access to local variable f [field Field1] : Object | semmle.label | access to local variable f [field Field1] : Object | | F.cs:20:14:20:21 | access to field Field1 | semmle.label | access to field Field1 | -| F.cs:23:21:23:34 | { ..., ... } [Field2] : Object | semmle.label | { ..., ... } [Field2] : Object | +| F.cs:23:21:23:34 | { ..., ... } [field Field2] : Object | semmle.label | { ..., ... } [field Field2] : Object | | F.cs:23:32:23:32 | access to local variable o : Object | semmle.label | access to local variable o : Object | -| F.cs:25:14:25:14 | access to local variable f [Field2] : Object | semmle.label | access to local variable f [Field2] : Object | +| F.cs:25:14:25:14 | access to local variable f [field Field2] : Object | semmle.label | access to local variable f [field Field2] : Object | | F.cs:25:14:25:21 | access to field Field2 | semmle.label | access to field Field2 | | G.cs:7:18:7:27 | object creation of type Elem : Elem | semmle.label | object creation of type Elem : Elem | -| G.cs:9:9:9:9 | [post] access to local variable b [Box1, Elem] : Elem | semmle.label | [post] access to local variable b [Box1, Elem] : Elem | -| G.cs:9:9:9:14 | [post] access to field Box1 [Elem] : Elem | semmle.label | [post] access to field Box1 [Elem] : Elem | +| G.cs:9:9:9:9 | [post] access to local variable b [field Box1, field Elem] : Elem | semmle.label | [post] access to local variable b [field Box1, field Elem] : Elem | +| G.cs:9:9:9:14 | [post] access to field Box1 [field Elem] : Elem | semmle.label | [post] access to field Box1 [field Elem] : Elem | | G.cs:9:23:9:23 | access to local variable e : Elem | semmle.label | access to local variable e : Elem | -| G.cs:10:18:10:18 | access to local variable b [Box1, Elem] : Elem | semmle.label | access to local variable b [Box1, Elem] : Elem | +| G.cs:10:18:10:18 | access to local variable b [field Box1, field Elem] : Elem | semmle.label | access to local variable b [field Box1, field Elem] : Elem | | G.cs:15:18:15:27 | object creation of type Elem : Elem | semmle.label | object creation of type Elem : Elem | -| G.cs:17:9:17:9 | [post] access to local variable b [Box1, Elem] : Elem | semmle.label | [post] access to local variable b [Box1, Elem] : Elem | -| G.cs:17:9:17:14 | [post] access to field Box1 [Elem] : Elem | semmle.label | [post] access to field Box1 [Elem] : Elem | +| G.cs:17:9:17:9 | [post] access to local variable b [field Box1, field Elem] : Elem | semmle.label | [post] access to local variable b [field Box1, field Elem] : Elem | +| G.cs:17:9:17:14 | [post] access to field Box1 [field Elem] : Elem | semmle.label | [post] access to field Box1 [field Elem] : Elem | | G.cs:17:24:17:24 | access to local variable e : Elem | semmle.label | access to local variable e : Elem | -| G.cs:18:18:18:18 | access to local variable b [Box1, Elem] : Elem | semmle.label | access to local variable b [Box1, Elem] : Elem | +| G.cs:18:18:18:18 | access to local variable b [field Box1, field Elem] : Elem | semmle.label | access to local variable b [field Box1, field Elem] : Elem | | G.cs:23:18:23:27 | object creation of type Elem : Elem | semmle.label | object creation of type Elem : Elem | -| G.cs:25:9:25:9 | [post] access to local variable b [Box1, Elem] : Elem | semmle.label | [post] access to local variable b [Box1, Elem] : Elem | -| G.cs:25:9:25:19 | [post] call to method GetBox1 [Elem] : Elem | semmle.label | [post] call to method GetBox1 [Elem] : Elem | +| G.cs:25:9:25:9 | [post] access to local variable b [field Box1, field Elem] : Elem | semmle.label | [post] access to local variable b [field Box1, field Elem] : Elem | +| G.cs:25:9:25:19 | [post] call to method GetBox1 [field Elem] : Elem | semmle.label | [post] call to method GetBox1 [field Elem] : Elem | | G.cs:25:28:25:28 | access to local variable e : Elem | semmle.label | access to local variable e : Elem | -| G.cs:26:18:26:18 | access to local variable b [Box1, Elem] : Elem | semmle.label | access to local variable b [Box1, Elem] : Elem | +| G.cs:26:18:26:18 | access to local variable b [field Box1, field Elem] : Elem | semmle.label | access to local variable b [field Box1, field Elem] : Elem | | G.cs:31:18:31:27 | object creation of type Elem : Elem | semmle.label | object creation of type Elem : Elem | -| G.cs:33:9:33:9 | [post] access to local variable b [Box1, Elem] : Elem | semmle.label | [post] access to local variable b [Box1, Elem] : Elem | -| G.cs:33:9:33:19 | [post] call to method GetBox1 [Elem] : Elem | semmle.label | [post] call to method GetBox1 [Elem] : Elem | +| G.cs:33:9:33:9 | [post] access to local variable b [field Box1, field Elem] : Elem | semmle.label | [post] access to local variable b [field Box1, field Elem] : Elem | +| G.cs:33:9:33:19 | [post] call to method GetBox1 [field Elem] : Elem | semmle.label | [post] call to method GetBox1 [field Elem] : Elem | | G.cs:33:29:33:29 | access to local variable e : Elem | semmle.label | access to local variable e : Elem | -| G.cs:34:18:34:18 | access to local variable b [Box1, Elem] : Elem | semmle.label | access to local variable b [Box1, Elem] : Elem | -| G.cs:37:38:37:39 | b2 [Box1, Elem] : Elem | semmle.label | b2 [Box1, Elem] : Elem | -| G.cs:39:14:39:15 | access to parameter b2 [Box1, Elem] : Elem | semmle.label | access to parameter b2 [Box1, Elem] : Elem | -| G.cs:39:14:39:25 | call to method GetBox1 [Elem] : Elem | semmle.label | call to method GetBox1 [Elem] : Elem | +| G.cs:34:18:34:18 | access to local variable b [field Box1, field Elem] : Elem | semmle.label | access to local variable b [field Box1, field Elem] : Elem | +| G.cs:37:38:37:39 | b2 [field Box1, field Elem] : Elem | semmle.label | b2 [field Box1, field Elem] : Elem | +| G.cs:39:14:39:15 | access to parameter b2 [field Box1, field Elem] : Elem | semmle.label | access to parameter b2 [field Box1, field Elem] : Elem | +| G.cs:39:14:39:25 | call to method GetBox1 [field Elem] : Elem | semmle.label | call to method GetBox1 [field Elem] : Elem | | G.cs:39:14:39:35 | call to method GetElem | semmle.label | call to method GetElem | | G.cs:44:18:44:27 | object creation of type Elem : Elem | semmle.label | object creation of type Elem : Elem | -| G.cs:46:9:46:16 | [post] access to field boxfield [Box1, Elem] : Elem | semmle.label | [post] access to field boxfield [Box1, Elem] : Elem | -| G.cs:46:9:46:16 | [post] this access [boxfield, Box1, Elem] : Elem | semmle.label | [post] this access [boxfield, Box1, Elem] : Elem | -| G.cs:46:9:46:21 | [post] access to field Box1 [Elem] : Elem | semmle.label | [post] access to field Box1 [Elem] : Elem | +| G.cs:46:9:46:16 | [post] access to field boxfield [field Box1, field Elem] : Elem | semmle.label | [post] access to field boxfield [field Box1, field Elem] : Elem | +| G.cs:46:9:46:16 | [post] this access [field boxfield, field Box1, field Elem] : Elem | semmle.label | [post] this access [field boxfield, field Box1, field Elem] : Elem | +| G.cs:46:9:46:21 | [post] access to field Box1 [field Elem] : Elem | semmle.label | [post] access to field Box1 [field Elem] : Elem | | G.cs:46:30:46:30 | access to local variable e : Elem | semmle.label | access to local variable e : Elem | -| G.cs:47:9:47:13 | this access [boxfield, Box1, Elem] : Elem | semmle.label | this access [boxfield, Box1, Elem] : Elem | -| G.cs:50:18:50:20 | this [boxfield, Box1, Elem] : Elem | semmle.label | this [boxfield, Box1, Elem] : Elem | -| G.cs:52:14:52:21 | access to field boxfield [Box1, Elem] : Elem | semmle.label | access to field boxfield [Box1, Elem] : Elem | -| G.cs:52:14:52:21 | this access [boxfield, Box1, Elem] : Elem | semmle.label | this access [boxfield, Box1, Elem] : Elem | -| G.cs:52:14:52:26 | access to field Box1 [Elem] : Elem | semmle.label | access to field Box1 [Elem] : Elem | +| G.cs:47:9:47:13 | this access [field boxfield, field Box1, field Elem] : Elem | semmle.label | this access [field boxfield, field Box1, field Elem] : Elem | +| G.cs:50:18:50:20 | this [field boxfield, field Box1, field Elem] : Elem | semmle.label | this [field boxfield, field Box1, field Elem] : Elem | +| G.cs:52:14:52:21 | access to field boxfield [field Box1, field Elem] : Elem | semmle.label | access to field boxfield [field Box1, field Elem] : Elem | +| G.cs:52:14:52:21 | this access [field boxfield, field Box1, field Elem] : Elem | semmle.label | this access [field boxfield, field Box1, field Elem] : Elem | +| G.cs:52:14:52:26 | access to field Box1 [field Elem] : Elem | semmle.label | access to field Box1 [field Elem] : Elem | | G.cs:52:14:52:31 | access to field Elem | semmle.label | access to field Elem | -| H.cs:23:9:23:9 | [post] access to local variable a [FieldA] : Object | semmle.label | [post] access to local variable a [FieldA] : Object | +| H.cs:23:9:23:9 | [post] access to local variable a [field FieldA] : Object | semmle.label | [post] access to local variable a [field FieldA] : Object | | H.cs:23:20:23:31 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | -| H.cs:24:21:24:28 | call to method Clone [FieldA] : Object | semmle.label | call to method Clone [FieldA] : Object | -| H.cs:24:27:24:27 | access to local variable a [FieldA] : Object | semmle.label | access to local variable a [FieldA] : Object | -| H.cs:25:14:25:18 | access to local variable clone [FieldA] : Object | semmle.label | access to local variable clone [FieldA] : Object | +| H.cs:24:21:24:28 | call to method Clone [field FieldA] : Object | semmle.label | call to method Clone [field FieldA] : Object | +| H.cs:24:27:24:27 | access to local variable a [field FieldA] : Object | semmle.label | access to local variable a [field FieldA] : Object | +| H.cs:25:14:25:18 | access to local variable clone [field FieldA] : Object | semmle.label | access to local variable clone [field FieldA] : Object | | H.cs:25:14:25:25 | access to field FieldA | semmle.label | access to field FieldA | -| H.cs:43:9:43:9 | [post] access to local variable a [FieldA] : Object | semmle.label | [post] access to local variable a [FieldA] : Object | +| H.cs:43:9:43:9 | [post] access to local variable a [field FieldA] : Object | semmle.label | [post] access to local variable a [field FieldA] : Object | | H.cs:43:20:43:31 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | -| H.cs:44:17:44:28 | call to method Transform [FieldB] : Object | semmle.label | call to method Transform [FieldB] : Object | -| H.cs:44:27:44:27 | access to local variable a [FieldA] : Object | semmle.label | access to local variable a [FieldA] : Object | -| H.cs:45:14:45:14 | access to local variable b [FieldB] : Object | semmle.label | access to local variable b [FieldB] : Object | +| H.cs:44:17:44:28 | call to method Transform [field FieldB] : Object | semmle.label | call to method Transform [field FieldB] : Object | +| H.cs:44:27:44:27 | access to local variable a [field FieldA] : Object | semmle.label | access to local variable a [field FieldA] : Object | +| H.cs:45:14:45:14 | access to local variable b [field FieldB] : Object | semmle.label | access to local variable b [field FieldB] : Object | | H.cs:45:14:45:21 | access to field FieldB | semmle.label | access to field FieldB | -| H.cs:63:9:63:9 | [post] access to local variable a [FieldA] : Object | semmle.label | [post] access to local variable a [FieldA] : Object | +| H.cs:63:9:63:9 | [post] access to local variable a [field FieldA] : Object | semmle.label | [post] access to local variable a [field FieldA] : Object | | H.cs:63:20:63:31 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | -| H.cs:64:22:64:22 | access to local variable a [FieldA] : Object | semmle.label | access to local variable a [FieldA] : Object | -| H.cs:64:25:64:26 | [post] access to local variable b1 [FieldB] : Object | semmle.label | [post] access to local variable b1 [FieldB] : Object | -| H.cs:65:14:65:15 | access to local variable b1 [FieldB] : Object | semmle.label | access to local variable b1 [FieldB] : Object | +| H.cs:64:22:64:22 | access to local variable a [field FieldA] : Object | semmle.label | access to local variable a [field FieldA] : Object | +| H.cs:64:25:64:26 | [post] access to local variable b1 [field FieldB] : Object | semmle.label | [post] access to local variable b1 [field FieldB] : Object | +| H.cs:65:14:65:15 | access to local variable b1 [field FieldB] : Object | semmle.label | access to local variable b1 [field FieldB] : Object | | H.cs:65:14:65:22 | access to field FieldB | semmle.label | access to field FieldB | -| H.cs:88:17:88:17 | [post] access to local variable a [FieldA] : Object | semmle.label | [post] access to local variable a [FieldA] : Object | +| H.cs:88:17:88:17 | [post] access to local variable a [field FieldA] : Object | semmle.label | [post] access to local variable a [field FieldA] : Object | | H.cs:88:20:88:31 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | -| H.cs:88:34:88:35 | [post] access to local variable b1 [FieldB] : Object | semmle.label | [post] access to local variable b1 [FieldB] : Object | -| H.cs:89:14:89:14 | access to local variable a [FieldA] : Object | semmle.label | access to local variable a [FieldA] : Object | +| H.cs:88:34:88:35 | [post] access to local variable b1 [field FieldB] : Object | semmle.label | [post] access to local variable b1 [field FieldB] : Object | +| H.cs:89:14:89:14 | access to local variable a [field FieldA] : Object | semmle.label | access to local variable a [field FieldA] : Object | | H.cs:89:14:89:21 | access to field FieldA | semmle.label | access to field FieldA | -| H.cs:90:14:90:15 | access to local variable b1 [FieldB] : Object | semmle.label | access to local variable b1 [FieldB] : Object | +| H.cs:90:14:90:15 | access to local variable b1 [field FieldB] : Object | semmle.label | access to local variable b1 [field FieldB] : Object | | H.cs:90:14:90:22 | access to field FieldB | semmle.label | access to field FieldB | -| H.cs:112:9:112:9 | [post] access to local variable a [FieldA] : Object | semmle.label | [post] access to local variable a [FieldA] : Object | +| H.cs:112:9:112:9 | [post] access to local variable a [field FieldA] : Object | semmle.label | [post] access to local variable a [field FieldA] : Object | | H.cs:112:20:112:31 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | -| H.cs:113:17:113:32 | call to method TransformWrap [FieldB] : Object | semmle.label | call to method TransformWrap [FieldB] : Object | -| H.cs:113:31:113:31 | access to local variable a [FieldA] : Object | semmle.label | access to local variable a [FieldA] : Object | -| H.cs:114:14:114:14 | access to local variable b [FieldB] : Object | semmle.label | access to local variable b [FieldB] : Object | +| H.cs:113:17:113:32 | call to method TransformWrap [field FieldB] : Object | semmle.label | call to method TransformWrap [field FieldB] : Object | +| H.cs:113:31:113:31 | access to local variable a [field FieldA] : Object | semmle.label | access to local variable a [field FieldA] : Object | +| H.cs:114:14:114:14 | access to local variable b [field FieldB] : Object | semmle.label | access to local variable b [field FieldB] : Object | | H.cs:114:14:114:21 | access to field FieldB | semmle.label | access to field FieldB | -| H.cs:130:9:130:9 | [post] access to local variable a [FieldA] : Object | semmle.label | [post] access to local variable a [FieldA] : Object | +| H.cs:130:9:130:9 | [post] access to local variable a [field FieldA] : Object | semmle.label | [post] access to local variable a [field FieldA] : Object | | H.cs:130:20:130:31 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | | H.cs:131:14:131:19 | call to method Get | semmle.label | call to method Get | -| H.cs:131:18:131:18 | access to local variable a [FieldA] : Object | semmle.label | access to local variable a [FieldA] : Object | +| H.cs:131:18:131:18 | access to local variable a [field FieldA] : Object | semmle.label | access to local variable a [field FieldA] : Object | | H.cs:147:17:147:32 | call to method Through : A | semmle.label | call to method Through : A | | H.cs:147:25:147:31 | object creation of type A : A | semmle.label | object creation of type A : A | | H.cs:148:14:148:14 | access to local variable a | semmle.label | access to local variable a | | H.cs:155:17:155:23 | object creation of type B : B | semmle.label | object creation of type B : B | | H.cs:156:9:156:9 | access to local variable b : B | semmle.label | access to local variable b : B | -| H.cs:157:9:157:9 | [post] access to parameter a [FieldA] : B | semmle.label | [post] access to parameter a [FieldA] : B | +| H.cs:157:9:157:9 | [post] access to parameter a [field FieldA] : B | semmle.label | [post] access to parameter a [field FieldA] : B | | H.cs:157:20:157:20 | access to local variable b : B | semmle.label | access to local variable b : B | | H.cs:163:17:163:28 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | -| H.cs:164:19:164:19 | [post] access to local variable a [FieldA, FieldB] : Object | semmle.label | [post] access to local variable a [FieldA, FieldB] : Object | -| H.cs:164:19:164:19 | [post] access to local variable a [FieldA] : B | semmle.label | [post] access to local variable a [FieldA] : B | +| H.cs:164:19:164:19 | [post] access to local variable a [field FieldA, field FieldB] : Object | semmle.label | [post] access to local variable a [field FieldA, field FieldB] : Object | +| H.cs:164:19:164:19 | [post] access to local variable a [field FieldA] : B | semmle.label | [post] access to local variable a [field FieldA] : B | | H.cs:164:22:164:22 | access to local variable o : Object | semmle.label | access to local variable o : Object | | H.cs:165:17:165:28 | (...) ... : B | semmle.label | (...) ... : B | -| H.cs:165:17:165:28 | (...) ... [FieldB] : Object | semmle.label | (...) ... [FieldB] : Object | -| H.cs:165:21:165:21 | access to local variable a [FieldA, FieldB] : Object | semmle.label | access to local variable a [FieldA, FieldB] : Object | -| H.cs:165:21:165:21 | access to local variable a [FieldA] : B | semmle.label | access to local variable a [FieldA] : B | +| H.cs:165:17:165:28 | (...) ... [field FieldB] : Object | semmle.label | (...) ... [field FieldB] : Object | +| H.cs:165:21:165:21 | access to local variable a [field FieldA, field FieldB] : Object | semmle.label | access to local variable a [field FieldA, field FieldB] : Object | +| H.cs:165:21:165:21 | access to local variable a [field FieldA] : B | semmle.label | access to local variable a [field FieldA] : B | | H.cs:165:21:165:28 | access to field FieldA : B | semmle.label | access to field FieldA : B | -| H.cs:165:21:165:28 | access to field FieldA [FieldB] : Object | semmle.label | access to field FieldA [FieldB] : Object | +| H.cs:165:21:165:28 | access to field FieldA [field FieldB] : Object | semmle.label | access to field FieldA [field FieldB] : Object | | H.cs:166:14:166:14 | access to local variable b | semmle.label | access to local variable b | -| H.cs:167:14:167:14 | access to local variable b [FieldB] : Object | semmle.label | access to local variable b [FieldB] : Object | +| H.cs:167:14:167:14 | access to local variable b [field FieldB] : Object | semmle.label | access to local variable b [field FieldB] : Object | | H.cs:167:14:167:21 | access to field FieldB | semmle.label | access to field FieldB | -| I.cs:7:9:7:14 | [post] this access [Field1] : Object | semmle.label | [post] this access [Field1] : Object | +| I.cs:7:9:7:14 | [post] this access [field Field1] : Object | semmle.label | [post] this access [field Field1] : Object | | I.cs:7:18:7:29 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | | I.cs:13:17:13:28 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | -| I.cs:15:9:15:9 | [post] access to local variable i [Field1] : Object | semmle.label | [post] access to local variable i [Field1] : Object | +| I.cs:15:9:15:9 | [post] access to local variable i [field Field1] : Object | semmle.label | [post] access to local variable i [field Field1] : Object | | I.cs:15:20:15:20 | access to local variable o : Object | semmle.label | access to local variable o : Object | -| I.cs:16:9:16:9 | access to local variable i [Field1] : Object | semmle.label | access to local variable i [Field1] : Object | -| I.cs:17:9:17:9 | access to local variable i [Field1] : Object | semmle.label | access to local variable i [Field1] : Object | -| I.cs:18:14:18:14 | access to local variable i [Field1] : Object | semmle.label | access to local variable i [Field1] : Object | +| I.cs:16:9:16:9 | access to local variable i [field Field1] : Object | semmle.label | access to local variable i [field Field1] : Object | +| I.cs:17:9:17:9 | access to local variable i [field Field1] : Object | semmle.label | access to local variable i [field Field1] : Object | +| I.cs:18:14:18:14 | access to local variable i [field Field1] : Object | semmle.label | access to local variable i [field Field1] : Object | | I.cs:18:14:18:21 | access to field Field1 | semmle.label | access to field Field1 | -| I.cs:21:13:21:19 | object creation of type I [Field1] : Object | semmle.label | object creation of type I [Field1] : Object | -| I.cs:22:9:22:9 | access to local variable i [Field1] : Object | semmle.label | access to local variable i [Field1] : Object | -| I.cs:23:14:23:14 | access to local variable i [Field1] : Object | semmle.label | access to local variable i [Field1] : Object | +| I.cs:21:13:21:19 | object creation of type I [field Field1] : Object | semmle.label | object creation of type I [field Field1] : Object | +| I.cs:22:9:22:9 | access to local variable i [field Field1] : Object | semmle.label | access to local variable i [field Field1] : Object | +| I.cs:23:14:23:14 | access to local variable i [field Field1] : Object | semmle.label | access to local variable i [field Field1] : Object | | I.cs:23:14:23:21 | access to field Field1 | semmle.label | access to field Field1 | -| I.cs:26:13:26:37 | [pre-initializer] object creation of type I [Field1] : Object | semmle.label | [pre-initializer] object creation of type I [Field1] : Object | -| I.cs:27:14:27:14 | access to local variable i [Field1] : Object | semmle.label | access to local variable i [Field1] : Object | +| I.cs:26:13:26:37 | [pre-initializer] object creation of type I [field Field1] : Object | semmle.label | [pre-initializer] object creation of type I [field Field1] : Object | +| I.cs:27:14:27:14 | access to local variable i [field Field1] : Object | semmle.label | access to local variable i [field Field1] : Object | | I.cs:27:14:27:21 | access to field Field1 | semmle.label | access to field Field1 | | I.cs:31:13:31:24 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | -| I.cs:32:9:32:9 | [post] access to local variable i [Field1] : Object | semmle.label | [post] access to local variable i [Field1] : Object | +| I.cs:32:9:32:9 | [post] access to local variable i [field Field1] : Object | semmle.label | [post] access to local variable i [field Field1] : Object | | I.cs:32:20:32:20 | access to local variable o : Object | semmle.label | access to local variable o : Object | -| I.cs:33:9:33:9 | access to local variable i [Field1] : Object | semmle.label | access to local variable i [Field1] : Object | -| I.cs:34:12:34:12 | access to local variable i [Field1] : Object | semmle.label | access to local variable i [Field1] : Object | -| I.cs:37:23:37:23 | i [Field1] : Object | semmle.label | i [Field1] : Object | -| I.cs:39:9:39:9 | access to parameter i [Field1] : Object | semmle.label | access to parameter i [Field1] : Object | -| I.cs:40:14:40:14 | access to parameter i [Field1] : Object | semmle.label | access to parameter i [Field1] : Object | +| I.cs:33:9:33:9 | access to local variable i [field Field1] : Object | semmle.label | access to local variable i [field Field1] : Object | +| I.cs:34:12:34:12 | access to local variable i [field Field1] : Object | semmle.label | access to local variable i [field Field1] : Object | +| I.cs:37:23:37:23 | i [field Field1] : Object | semmle.label | i [field Field1] : Object | +| I.cs:39:9:39:9 | access to parameter i [field Field1] : Object | semmle.label | access to parameter i [field Field1] : Object | +| I.cs:40:14:40:14 | access to parameter i [field Field1] : Object | semmle.label | access to parameter i [field Field1] : Object | | I.cs:40:14:40:21 | access to field Field1 | semmle.label | access to field Field1 | | J.cs:12:17:12:28 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | -| J.cs:13:18:13:36 | object creation of type Record [Prop1] : Object | semmle.label | object creation of type Record [Prop1] : Object | +| J.cs:13:18:13:36 | object creation of type Record [property Prop1] : Object | semmle.label | object creation of type Record [property Prop1] : Object | | J.cs:13:29:13:29 | access to local variable o : Object | semmle.label | access to local variable o : Object | -| J.cs:14:14:14:15 | access to local variable r1 [Prop1] : Object | semmle.label | access to local variable r1 [Prop1] : Object | +| J.cs:14:14:14:15 | access to local variable r1 [property Prop1] : Object | semmle.label | access to local variable r1 [property Prop1] : Object | | J.cs:14:14:14:21 | access to property Prop1 | semmle.label | access to property Prop1 | -| J.cs:18:14:18:15 | access to local variable r2 [Prop1] : Object | semmle.label | access to local variable r2 [Prop1] : Object | +| J.cs:18:14:18:15 | access to local variable r2 [property Prop1] : Object | semmle.label | access to local variable r2 [property Prop1] : Object | | J.cs:18:14:18:21 | access to property Prop1 | semmle.label | access to property Prop1 | -| J.cs:21:18:21:38 | ... with { ... } [Prop2] : Object | semmle.label | ... with { ... } [Prop2] : Object | +| J.cs:21:18:21:38 | ... with { ... } [property Prop2] : Object | semmle.label | ... with { ... } [property Prop2] : Object | | J.cs:21:36:21:36 | access to local variable o : Object | semmle.label | access to local variable o : Object | -| J.cs:22:14:22:15 | access to local variable r3 [Prop1] : Object | semmle.label | access to local variable r3 [Prop1] : Object | +| J.cs:22:14:22:15 | access to local variable r3 [property Prop1] : Object | semmle.label | access to local variable r3 [property Prop1] : Object | | J.cs:22:14:22:21 | access to property Prop1 | semmle.label | access to property Prop1 | -| J.cs:23:14:23:15 | access to local variable r3 [Prop2] : Object | semmle.label | access to local variable r3 [Prop2] : Object | +| J.cs:23:14:23:15 | access to local variable r3 [property Prop2] : Object | semmle.label | access to local variable r3 [property Prop2] : Object | | J.cs:23:14:23:21 | access to property Prop2 | semmle.label | access to property Prop2 | #select | A.cs:7:14:7:16 | access to field c | A.cs:5:17:5:23 | object creation of type C : C | A.cs:7:14:7:16 | access to field c | $@ | A.cs:5:17:5:23 | object creation of type C : C | object creation of type C : C | diff --git a/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected b/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected index d07fcd39403..41258053f33 100644 --- a/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected +++ b/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected @@ -119,30 +119,30 @@ edges | GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:15:80:19 | access to local variable sink3 | | GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) : String | GlobalDataFlow.cs:81:59:81:63 | access to local variable sink3 : String | | GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) : String | GlobalDataFlow.cs:136:29:136:33 | access to local variable sink3 : String | -| GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven [[]] : String | GlobalDataFlow.cs:81:22:81:93 | call to method First : String | +| GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven [element] : String | GlobalDataFlow.cs:81:22:81:93 | call to method First : String | | GlobalDataFlow.cs:81:22:81:93 | call to method First : String | GlobalDataFlow.cs:82:15:82:20 | access to local variable sink13 | | GlobalDataFlow.cs:81:22:81:93 | call to method First : String | GlobalDataFlow.cs:83:59:83:64 | access to local variable sink13 : String | -| GlobalDataFlow.cs:81:23:81:65 | (...) ... [[]] : String | GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven [[]] : String | -| GlobalDataFlow.cs:81:57:81:65 | { ..., ... } [[]] : String | GlobalDataFlow.cs:81:23:81:65 | (...) ... [[]] : String | -| GlobalDataFlow.cs:81:59:81:63 | access to local variable sink3 : String | GlobalDataFlow.cs:81:57:81:65 | { ..., ... } [[]] : String | -| GlobalDataFlow.cs:83:22:83:87 | call to method Select [[]] : String | GlobalDataFlow.cs:83:22:83:95 | call to method First : String | +| GlobalDataFlow.cs:81:23:81:65 | (...) ... [element] : String | GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven [element] : String | +| GlobalDataFlow.cs:81:57:81:65 | { ..., ... } [element] : String | GlobalDataFlow.cs:81:23:81:65 | (...) ... [element] : String | +| GlobalDataFlow.cs:81:59:81:63 | access to local variable sink3 : String | GlobalDataFlow.cs:81:57:81:65 | { ..., ... } [element] : String | +| GlobalDataFlow.cs:83:22:83:87 | call to method Select [element] : String | GlobalDataFlow.cs:83:22:83:95 | call to method First : String | | GlobalDataFlow.cs:83:22:83:95 | call to method First : String | GlobalDataFlow.cs:84:15:84:20 | access to local variable sink14 | | GlobalDataFlow.cs:83:22:83:95 | call to method First : String | GlobalDataFlow.cs:85:59:85:64 | access to local variable sink14 : String | -| GlobalDataFlow.cs:83:23:83:66 | (...) ... [[]] : String | GlobalDataFlow.cs:83:22:83:87 | call to method Select [[]] : String | -| GlobalDataFlow.cs:83:23:83:66 | (...) ... [[]] : String | GlobalDataFlow.cs:312:31:312:40 | sinkParam8 : String | -| GlobalDataFlow.cs:83:57:83:66 | { ..., ... } [[]] : String | GlobalDataFlow.cs:83:23:83:66 | (...) ... [[]] : String | -| GlobalDataFlow.cs:83:59:83:64 | access to local variable sink13 : String | GlobalDataFlow.cs:83:57:83:66 | { ..., ... } [[]] : String | -| GlobalDataFlow.cs:85:22:85:128 | call to method Zip [[]] : String | GlobalDataFlow.cs:85:22:85:136 | call to method First : String | +| GlobalDataFlow.cs:83:23:83:66 | (...) ... [element] : String | GlobalDataFlow.cs:83:22:83:87 | call to method Select [element] : String | +| GlobalDataFlow.cs:83:23:83:66 | (...) ... [element] : String | GlobalDataFlow.cs:312:31:312:40 | sinkParam8 : String | +| GlobalDataFlow.cs:83:57:83:66 | { ..., ... } [element] : String | GlobalDataFlow.cs:83:23:83:66 | (...) ... [element] : String | +| GlobalDataFlow.cs:83:59:83:64 | access to local variable sink13 : String | GlobalDataFlow.cs:83:57:83:66 | { ..., ... } [element] : String | +| GlobalDataFlow.cs:85:22:85:128 | call to method Zip [element] : String | GlobalDataFlow.cs:85:22:85:136 | call to method First : String | | GlobalDataFlow.cs:85:22:85:136 | call to method First : String | GlobalDataFlow.cs:86:15:86:20 | access to local variable sink15 | | GlobalDataFlow.cs:85:22:85:136 | call to method First : String | GlobalDataFlow.cs:87:106:87:111 | access to local variable sink15 : String | -| GlobalDataFlow.cs:85:23:85:66 | (...) ... [[]] : String | GlobalDataFlow.cs:85:22:85:128 | call to method Zip [[]] : String | -| GlobalDataFlow.cs:85:57:85:66 | { ..., ... } [[]] : String | GlobalDataFlow.cs:85:23:85:66 | (...) ... [[]] : String | -| GlobalDataFlow.cs:85:59:85:64 | access to local variable sink14 : String | GlobalDataFlow.cs:85:57:85:66 | { ..., ... } [[]] : String | -| GlobalDataFlow.cs:87:22:87:128 | call to method Zip [[]] : String | GlobalDataFlow.cs:87:22:87:136 | call to method First : String | +| GlobalDataFlow.cs:85:23:85:66 | (...) ... [element] : String | GlobalDataFlow.cs:85:22:85:128 | call to method Zip [element] : String | +| GlobalDataFlow.cs:85:57:85:66 | { ..., ... } [element] : String | GlobalDataFlow.cs:85:23:85:66 | (...) ... [element] : String | +| GlobalDataFlow.cs:85:59:85:64 | access to local variable sink14 : String | GlobalDataFlow.cs:85:57:85:66 | { ..., ... } [element] : String | +| GlobalDataFlow.cs:87:22:87:128 | call to method Zip [element] : String | GlobalDataFlow.cs:87:22:87:136 | call to method First : String | | GlobalDataFlow.cs:87:22:87:136 | call to method First : String | GlobalDataFlow.cs:88:15:88:20 | access to local variable sink16 | -| GlobalDataFlow.cs:87:70:87:113 | (...) ... [[]] : String | GlobalDataFlow.cs:87:22:87:128 | call to method Zip [[]] : String | -| GlobalDataFlow.cs:87:104:87:113 | { ..., ... } [[]] : String | GlobalDataFlow.cs:87:70:87:113 | (...) ... [[]] : String | -| GlobalDataFlow.cs:87:106:87:111 | access to local variable sink15 : String | GlobalDataFlow.cs:87:104:87:113 | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:87:70:87:113 | (...) ... [element] : String | GlobalDataFlow.cs:87:22:87:128 | call to method Zip [element] : String | +| GlobalDataFlow.cs:87:104:87:113 | { ..., ... } [element] : String | GlobalDataFlow.cs:87:70:87:113 | (...) ... [element] : String | +| GlobalDataFlow.cs:87:106:87:111 | access to local variable sink15 : String | GlobalDataFlow.cs:87:104:87:113 | { ..., ... } [element] : String | | GlobalDataFlow.cs:136:21:136:34 | delegate call : String | GlobalDataFlow.cs:137:15:137:19 | access to local variable sink4 | | GlobalDataFlow.cs:136:21:136:34 | delegate call : String | GlobalDataFlow.cs:144:39:144:43 | access to local variable sink4 : String | | GlobalDataFlow.cs:136:29:136:33 | access to local variable sink3 : String | GlobalDataFlow.cs:136:21:136:34 | delegate call : String | @@ -151,42 +151,42 @@ edges | GlobalDataFlow.cs:154:21:154:25 | call to method Out : String | GlobalDataFlow.cs:155:15:155:19 | access to local variable sink6 | | GlobalDataFlow.cs:157:20:157:24 | SSA def(sink7) : String | GlobalDataFlow.cs:158:15:158:19 | access to local variable sink7 | | GlobalDataFlow.cs:160:20:160:24 | SSA def(sink8) : String | GlobalDataFlow.cs:161:15:161:19 | access to local variable sink8 | -| GlobalDataFlow.cs:162:22:162:31 | call to method OutYield [[]] : String | GlobalDataFlow.cs:162:22:162:39 | call to method First : String | +| GlobalDataFlow.cs:162:22:162:31 | call to method OutYield [element] : String | GlobalDataFlow.cs:162:22:162:39 | call to method First : String | | GlobalDataFlow.cs:162:22:162:39 | call to method First : String | GlobalDataFlow.cs:163:15:163:20 | access to local variable sink12 | | GlobalDataFlow.cs:164:22:164:43 | call to method TaintedParam : String | GlobalDataFlow.cs:165:15:165:20 | access to local variable sink23 | | GlobalDataFlow.cs:180:35:180:48 | "taint source" : String | GlobalDataFlow.cs:181:21:181:26 | delegate call : String | | GlobalDataFlow.cs:181:21:181:26 | delegate call : String | GlobalDataFlow.cs:182:15:182:19 | access to local variable sink9 | -| GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy [Value] : String | GlobalDataFlow.cs:190:22:190:48 | access to property Value : String | +| GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy [property Value] : String | GlobalDataFlow.cs:190:22:190:48 | access to property Value : String | | GlobalDataFlow.cs:190:22:190:48 | access to property Value : String | GlobalDataFlow.cs:191:15:191:20 | access to local variable sink10 | | GlobalDataFlow.cs:198:22:198:32 | access to property OutProperty : String | GlobalDataFlow.cs:199:15:199:20 | access to local variable sink19 | -| GlobalDataFlow.cs:208:38:208:61 | array creation of type String[] [[]] : String | GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [[]] : String | -| GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [[]] : String | GlobalDataFlow.cs:213:22:213:28 | access to local variable tainted [[]] : String | -| GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [[]] : String | GlobalDataFlow.cs:215:22:215:28 | access to local variable tainted [[]] : String | -| GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [[]] : String | GlobalDataFlow.cs:217:22:217:28 | access to local variable tainted [[]] : String | -| GlobalDataFlow.cs:208:44:208:61 | { ..., ... } [[]] : String | GlobalDataFlow.cs:208:38:208:61 | array creation of type String[] [[]] : String | -| GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:208:44:208:61 | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:208:38:208:61 | array creation of type String[] [element] : String | GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [element] : String | +| GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [element] : String | GlobalDataFlow.cs:213:22:213:28 | access to local variable tainted [element] : String | +| GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [element] : String | GlobalDataFlow.cs:215:22:215:28 | access to local variable tainted [element] : String | +| GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [element] : String | GlobalDataFlow.cs:217:22:217:28 | access to local variable tainted [element] : String | +| GlobalDataFlow.cs:208:44:208:61 | { ..., ... } [element] : String | GlobalDataFlow.cs:208:38:208:61 | array creation of type String[] [element] : String | +| GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:208:44:208:61 | { ..., ... } [element] : String | | GlobalDataFlow.cs:211:35:211:45 | sinkParam10 : String | GlobalDataFlow.cs:211:58:211:68 | access to parameter sinkParam10 | | GlobalDataFlow.cs:212:71:212:71 | x : String | GlobalDataFlow.cs:212:89:212:89 | access to parameter x : String | | GlobalDataFlow.cs:212:89:212:89 | access to parameter x : String | GlobalDataFlow.cs:318:32:318:41 | sinkParam9 : String | -| GlobalDataFlow.cs:213:22:213:28 | access to local variable tainted [[]] : String | GlobalDataFlow.cs:211:35:211:45 | sinkParam10 : String | -| GlobalDataFlow.cs:213:22:213:28 | access to local variable tainted [[]] : String | GlobalDataFlow.cs:213:22:213:39 | call to method Select [[]] : String | -| GlobalDataFlow.cs:213:22:213:39 | call to method Select [[]] : String | GlobalDataFlow.cs:213:22:213:47 | call to method First : String | +| GlobalDataFlow.cs:213:22:213:28 | access to local variable tainted [element] : String | GlobalDataFlow.cs:211:35:211:45 | sinkParam10 : String | +| GlobalDataFlow.cs:213:22:213:28 | access to local variable tainted [element] : String | GlobalDataFlow.cs:213:22:213:39 | call to method Select [element] : String | +| GlobalDataFlow.cs:213:22:213:39 | call to method Select [element] : String | GlobalDataFlow.cs:213:22:213:47 | call to method First : String | | GlobalDataFlow.cs:213:22:213:47 | call to method First : String | GlobalDataFlow.cs:214:15:214:20 | access to local variable sink24 | -| GlobalDataFlow.cs:215:22:215:28 | access to local variable tainted [[]] : String | GlobalDataFlow.cs:212:71:212:71 | x : String | -| GlobalDataFlow.cs:215:22:215:28 | access to local variable tainted [[]] : String | GlobalDataFlow.cs:215:22:215:39 | call to method Select [[]] : String | -| GlobalDataFlow.cs:215:22:215:39 | call to method Select [[]] : String | GlobalDataFlow.cs:215:22:215:47 | call to method First : String | +| GlobalDataFlow.cs:215:22:215:28 | access to local variable tainted [element] : String | GlobalDataFlow.cs:212:71:212:71 | x : String | +| GlobalDataFlow.cs:215:22:215:28 | access to local variable tainted [element] : String | GlobalDataFlow.cs:215:22:215:39 | call to method Select [element] : String | +| GlobalDataFlow.cs:215:22:215:39 | call to method Select [element] : String | GlobalDataFlow.cs:215:22:215:47 | call to method First : String | | GlobalDataFlow.cs:215:22:215:47 | call to method First : String | GlobalDataFlow.cs:216:15:216:20 | access to local variable sink25 | -| GlobalDataFlow.cs:217:22:217:28 | access to local variable tainted [[]] : String | GlobalDataFlow.cs:217:22:217:49 | call to method Select [[]] : String | -| GlobalDataFlow.cs:217:22:217:28 | access to local variable tainted [[]] : String | GlobalDataFlow.cs:324:32:324:42 | sinkParam11 : String | -| GlobalDataFlow.cs:217:22:217:49 | call to method Select [[]] : String | GlobalDataFlow.cs:217:22:217:57 | call to method First : String | +| GlobalDataFlow.cs:217:22:217:28 | access to local variable tainted [element] : String | GlobalDataFlow.cs:217:22:217:49 | call to method Select [element] : String | +| GlobalDataFlow.cs:217:22:217:28 | access to local variable tainted [element] : String | GlobalDataFlow.cs:324:32:324:42 | sinkParam11 : String | +| GlobalDataFlow.cs:217:22:217:49 | call to method Select [element] : String | GlobalDataFlow.cs:217:22:217:57 | call to method First : String | | GlobalDataFlow.cs:217:22:217:57 | call to method First : String | GlobalDataFlow.cs:218:15:218:20 | access to local variable sink26 | -| GlobalDataFlow.cs:238:20:238:49 | call to method Run [Result] : String | GlobalDataFlow.cs:239:22:239:25 | access to local variable task [Result] : String | -| GlobalDataFlow.cs:238:20:238:49 | call to method Run [Result] : String | GlobalDataFlow.cs:241:28:241:31 | access to local variable task [Result] : String | -| GlobalDataFlow.cs:238:35:238:48 | "taint source" : String | GlobalDataFlow.cs:238:20:238:49 | call to method Run [Result] : String | -| GlobalDataFlow.cs:239:22:239:25 | access to local variable task [Result] : String | GlobalDataFlow.cs:239:22:239:32 | access to property Result : String | +| GlobalDataFlow.cs:238:20:238:49 | call to method Run [property Result] : String | GlobalDataFlow.cs:239:22:239:25 | access to local variable task [property Result] : String | +| GlobalDataFlow.cs:238:20:238:49 | call to method Run [property Result] : String | GlobalDataFlow.cs:241:28:241:31 | access to local variable task [property Result] : String | +| GlobalDataFlow.cs:238:35:238:48 | "taint source" : String | GlobalDataFlow.cs:238:20:238:49 | call to method Run [property Result] : String | +| GlobalDataFlow.cs:239:22:239:25 | access to local variable task [property Result] : String | GlobalDataFlow.cs:239:22:239:32 | access to property Result : String | | GlobalDataFlow.cs:239:22:239:32 | access to property Result : String | GlobalDataFlow.cs:240:15:240:20 | access to local variable sink41 | | GlobalDataFlow.cs:241:22:241:31 | await ... : String | GlobalDataFlow.cs:242:15:242:20 | access to local variable sink42 | -| GlobalDataFlow.cs:241:28:241:31 | access to local variable task [Result] : String | GlobalDataFlow.cs:241:22:241:31 | await ... : String | +| GlobalDataFlow.cs:241:28:241:31 | access to local variable task [property Result] : String | GlobalDataFlow.cs:241:22:241:31 | await ... : String | | GlobalDataFlow.cs:254:26:254:35 | sinkParam0 : String | GlobalDataFlow.cs:256:16:256:25 | access to parameter sinkParam0 : String | | GlobalDataFlow.cs:254:26:254:35 | sinkParam0 : String | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam0 | | GlobalDataFlow.cs:256:16:256:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:254:26:254:35 | sinkParam0 : String | @@ -200,12 +200,12 @@ edges | GlobalDataFlow.cs:318:32:318:41 | sinkParam9 : String | GlobalDataFlow.cs:320:15:320:24 | access to parameter sinkParam9 | | GlobalDataFlow.cs:324:32:324:42 | sinkParam11 : String | GlobalDataFlow.cs:326:15:326:25 | access to parameter sinkParam11 | | GlobalDataFlow.cs:338:16:338:29 | "taint source" : String | GlobalDataFlow.cs:154:21:154:25 | call to method Out : String | -| GlobalDataFlow.cs:338:16:338:29 | "taint source" : String | GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy [Value] : String | +| GlobalDataFlow.cs:338:16:338:29 | "taint source" : String | GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy [property Value] : String | | GlobalDataFlow.cs:343:9:343:26 | SSA def(x) : String | GlobalDataFlow.cs:157:20:157:24 | SSA def(sink7) : String | | GlobalDataFlow.cs:343:13:343:26 | "taint source" : String | GlobalDataFlow.cs:343:9:343:26 | SSA def(x) : String | | GlobalDataFlow.cs:348:9:348:26 | SSA def(x) : String | GlobalDataFlow.cs:160:20:160:24 | SSA def(sink8) : String | | GlobalDataFlow.cs:348:13:348:26 | "taint source" : String | GlobalDataFlow.cs:348:9:348:26 | SSA def(x) : String | -| GlobalDataFlow.cs:354:22:354:35 | "taint source" : String | GlobalDataFlow.cs:162:22:162:31 | call to method OutYield [[]] : String | +| GlobalDataFlow.cs:354:22:354:35 | "taint source" : String | GlobalDataFlow.cs:162:22:162:31 | call to method OutYield [element] : String | | GlobalDataFlow.cs:379:41:379:41 | x : String | GlobalDataFlow.cs:381:11:381:11 | access to parameter x : String | | GlobalDataFlow.cs:379:41:379:41 | x : String | GlobalDataFlow.cs:381:11:381:11 | access to parameter x : String | | GlobalDataFlow.cs:381:11:381:11 | access to parameter x : String | GlobalDataFlow.cs:54:15:54:15 | x : String | @@ -221,13 +221,13 @@ edges | GlobalDataFlow.cs:402:16:402:21 | access to local variable sink11 : String | GlobalDataFlow.cs:164:22:164:43 | call to method TaintedParam : String | | GlobalDataFlow.cs:424:9:424:11 | value : String | GlobalDataFlow.cs:424:41:424:46 | access to local variable sink20 | | GlobalDataFlow.cs:435:22:435:35 | "taint source" : String | GlobalDataFlow.cs:198:22:198:32 | access to property OutProperty : String | -| GlobalDataFlow.cs:471:20:471:49 | call to method Run [Result] : String | GlobalDataFlow.cs:472:25:472:28 | access to local variable task [Result] : String | -| GlobalDataFlow.cs:471:35:471:48 | "taint source" : String | GlobalDataFlow.cs:471:20:471:49 | call to method Run [Result] : String | -| GlobalDataFlow.cs:472:25:472:28 | access to local variable task [Result] : String | GlobalDataFlow.cs:472:25:472:50 | call to method ConfigureAwait [m_configuredTaskAwaiter, m_task, Result] : String | -| GlobalDataFlow.cs:472:25:472:50 | call to method ConfigureAwait [m_configuredTaskAwaiter, m_task, Result] : String | GlobalDataFlow.cs:473:23:473:31 | access to local variable awaitable [m_configuredTaskAwaiter, m_task, Result] : String | -| GlobalDataFlow.cs:473:23:473:31 | access to local variable awaitable [m_configuredTaskAwaiter, m_task, Result] : String | GlobalDataFlow.cs:473:23:473:44 | call to method GetAwaiter [m_task, Result] : String | -| GlobalDataFlow.cs:473:23:473:44 | call to method GetAwaiter [m_task, Result] : String | GlobalDataFlow.cs:474:22:474:28 | access to local variable awaiter [m_task, Result] : String | -| GlobalDataFlow.cs:474:22:474:28 | access to local variable awaiter [m_task, Result] : String | GlobalDataFlow.cs:474:22:474:40 | call to method GetResult : String | +| GlobalDataFlow.cs:471:20:471:49 | call to method Run [property Result] : String | GlobalDataFlow.cs:472:25:472:28 | access to local variable task [property Result] : String | +| GlobalDataFlow.cs:471:35:471:48 | "taint source" : String | GlobalDataFlow.cs:471:20:471:49 | call to method Run [property Result] : String | +| GlobalDataFlow.cs:472:25:472:28 | access to local variable task [property Result] : String | GlobalDataFlow.cs:472:25:472:50 | call to method ConfigureAwait [field m_configuredTaskAwaiter, field m_task, property Result] : String | +| GlobalDataFlow.cs:472:25:472:50 | call to method ConfigureAwait [field m_configuredTaskAwaiter, field m_task, property Result] : String | GlobalDataFlow.cs:473:23:473:31 | access to local variable awaitable [field m_configuredTaskAwaiter, field m_task, property Result] : String | +| GlobalDataFlow.cs:473:23:473:31 | access to local variable awaitable [field m_configuredTaskAwaiter, field m_task, property Result] : String | GlobalDataFlow.cs:473:23:473:44 | call to method GetAwaiter [field m_task, property Result] : String | +| GlobalDataFlow.cs:473:23:473:44 | call to method GetAwaiter [field m_task, property Result] : String | GlobalDataFlow.cs:474:22:474:28 | access to local variable awaiter [field m_task, property Result] : String | +| GlobalDataFlow.cs:474:22:474:28 | access to local variable awaiter [field m_task, property Result] : String | GlobalDataFlow.cs:474:22:474:40 | call to method GetResult : String | | GlobalDataFlow.cs:474:22:474:40 | call to method GetResult : String | GlobalDataFlow.cs:475:15:475:20 | access to local variable sink45 | | GlobalDataFlow.cs:480:53:480:55 | arg : String | GlobalDataFlow.cs:484:15:484:17 | access to parameter arg : String | | GlobalDataFlow.cs:483:21:483:21 | s : String | GlobalDataFlow.cs:483:32:483:32 | access to parameter s | @@ -319,28 +319,28 @@ nodes | GlobalDataFlow.cs:79:19:79:23 | access to local variable sink2 : String | semmle.label | access to local variable sink2 : String | | GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) : String | semmle.label | SSA def(sink3) : String | | GlobalDataFlow.cs:80:15:80:19 | access to local variable sink3 | semmle.label | access to local variable sink3 | -| GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven [[]] : String | semmle.label | call to method SelectEven [[]] : String | +| GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven [element] : String | semmle.label | call to method SelectEven [element] : String | | GlobalDataFlow.cs:81:22:81:93 | call to method First : String | semmle.label | call to method First : String | -| GlobalDataFlow.cs:81:23:81:65 | (...) ... [[]] : String | semmle.label | (...) ... [[]] : String | -| GlobalDataFlow.cs:81:57:81:65 | { ..., ... } [[]] : String | semmle.label | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:81:23:81:65 | (...) ... [element] : String | semmle.label | (...) ... [element] : String | +| GlobalDataFlow.cs:81:57:81:65 | { ..., ... } [element] : String | semmle.label | { ..., ... } [element] : String | | GlobalDataFlow.cs:81:59:81:63 | access to local variable sink3 : String | semmle.label | access to local variable sink3 : String | | GlobalDataFlow.cs:82:15:82:20 | access to local variable sink13 | semmle.label | access to local variable sink13 | -| GlobalDataFlow.cs:83:22:83:87 | call to method Select [[]] : String | semmle.label | call to method Select [[]] : String | +| GlobalDataFlow.cs:83:22:83:87 | call to method Select [element] : String | semmle.label | call to method Select [element] : String | | GlobalDataFlow.cs:83:22:83:95 | call to method First : String | semmle.label | call to method First : String | -| GlobalDataFlow.cs:83:23:83:66 | (...) ... [[]] : String | semmle.label | (...) ... [[]] : String | -| GlobalDataFlow.cs:83:57:83:66 | { ..., ... } [[]] : String | semmle.label | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:83:23:83:66 | (...) ... [element] : String | semmle.label | (...) ... [element] : String | +| GlobalDataFlow.cs:83:57:83:66 | { ..., ... } [element] : String | semmle.label | { ..., ... } [element] : String | | GlobalDataFlow.cs:83:59:83:64 | access to local variable sink13 : String | semmle.label | access to local variable sink13 : String | | GlobalDataFlow.cs:84:15:84:20 | access to local variable sink14 | semmle.label | access to local variable sink14 | -| GlobalDataFlow.cs:85:22:85:128 | call to method Zip [[]] : String | semmle.label | call to method Zip [[]] : String | +| GlobalDataFlow.cs:85:22:85:128 | call to method Zip [element] : String | semmle.label | call to method Zip [element] : String | | GlobalDataFlow.cs:85:22:85:136 | call to method First : String | semmle.label | call to method First : String | -| GlobalDataFlow.cs:85:23:85:66 | (...) ... [[]] : String | semmle.label | (...) ... [[]] : String | -| GlobalDataFlow.cs:85:57:85:66 | { ..., ... } [[]] : String | semmle.label | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:85:23:85:66 | (...) ... [element] : String | semmle.label | (...) ... [element] : String | +| GlobalDataFlow.cs:85:57:85:66 | { ..., ... } [element] : String | semmle.label | { ..., ... } [element] : String | | GlobalDataFlow.cs:85:59:85:64 | access to local variable sink14 : String | semmle.label | access to local variable sink14 : String | | GlobalDataFlow.cs:86:15:86:20 | access to local variable sink15 | semmle.label | access to local variable sink15 | -| GlobalDataFlow.cs:87:22:87:128 | call to method Zip [[]] : String | semmle.label | call to method Zip [[]] : String | +| GlobalDataFlow.cs:87:22:87:128 | call to method Zip [element] : String | semmle.label | call to method Zip [element] : String | | GlobalDataFlow.cs:87:22:87:136 | call to method First : String | semmle.label | call to method First : String | -| GlobalDataFlow.cs:87:70:87:113 | (...) ... [[]] : String | semmle.label | (...) ... [[]] : String | -| GlobalDataFlow.cs:87:104:87:113 | { ..., ... } [[]] : String | semmle.label | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:87:70:87:113 | (...) ... [element] : String | semmle.label | (...) ... [element] : String | +| GlobalDataFlow.cs:87:104:87:113 | { ..., ... } [element] : String | semmle.label | { ..., ... } [element] : String | | GlobalDataFlow.cs:87:106:87:111 | access to local variable sink15 : String | semmle.label | access to local variable sink15 : String | | GlobalDataFlow.cs:88:15:88:20 | access to local variable sink16 | semmle.label | access to local variable sink16 | | GlobalDataFlow.cs:136:21:136:34 | delegate call : String | semmle.label | delegate call : String | @@ -355,7 +355,7 @@ nodes | GlobalDataFlow.cs:158:15:158:19 | access to local variable sink7 | semmle.label | access to local variable sink7 | | GlobalDataFlow.cs:160:20:160:24 | SSA def(sink8) : String | semmle.label | SSA def(sink8) : String | | GlobalDataFlow.cs:161:15:161:19 | access to local variable sink8 | semmle.label | access to local variable sink8 | -| GlobalDataFlow.cs:162:22:162:31 | call to method OutYield [[]] : String | semmle.label | call to method OutYield [[]] : String | +| GlobalDataFlow.cs:162:22:162:31 | call to method OutYield [element] : String | semmle.label | call to method OutYield [element] : String | | GlobalDataFlow.cs:162:22:162:39 | call to method First : String | semmle.label | call to method First : String | | GlobalDataFlow.cs:163:15:163:20 | access to local variable sink12 | semmle.label | access to local variable sink12 | | GlobalDataFlow.cs:164:22:164:43 | call to method TaintedParam : String | semmle.label | call to method TaintedParam : String | @@ -363,38 +363,38 @@ nodes | GlobalDataFlow.cs:180:35:180:48 | "taint source" : String | semmle.label | "taint source" : String | | GlobalDataFlow.cs:181:21:181:26 | delegate call : String | semmle.label | delegate call : String | | GlobalDataFlow.cs:182:15:182:19 | access to local variable sink9 | semmle.label | access to local variable sink9 | -| GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy [Value] : String | semmle.label | object creation of type Lazy [Value] : String | +| GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy [property Value] : String | semmle.label | object creation of type Lazy [property Value] : String | | GlobalDataFlow.cs:190:22:190:48 | access to property Value : String | semmle.label | access to property Value : String | | GlobalDataFlow.cs:191:15:191:20 | access to local variable sink10 | semmle.label | access to local variable sink10 | | GlobalDataFlow.cs:198:22:198:32 | access to property OutProperty : String | semmle.label | access to property OutProperty : String | | GlobalDataFlow.cs:199:15:199:20 | access to local variable sink19 | semmle.label | access to local variable sink19 | -| GlobalDataFlow.cs:208:38:208:61 | array creation of type String[] [[]] : String | semmle.label | array creation of type String[] [[]] : String | -| GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [[]] : String | semmle.label | call to method AsQueryable [[]] : String | -| GlobalDataFlow.cs:208:44:208:61 | { ..., ... } [[]] : String | semmle.label | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:208:38:208:61 | array creation of type String[] [element] : String | semmle.label | array creation of type String[] [element] : String | +| GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [element] : String | semmle.label | call to method AsQueryable [element] : String | +| GlobalDataFlow.cs:208:44:208:61 | { ..., ... } [element] : String | semmle.label | { ..., ... } [element] : String | | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | semmle.label | "taint source" : String | | GlobalDataFlow.cs:211:35:211:45 | sinkParam10 : String | semmle.label | sinkParam10 : String | | GlobalDataFlow.cs:211:58:211:68 | access to parameter sinkParam10 | semmle.label | access to parameter sinkParam10 | | GlobalDataFlow.cs:212:71:212:71 | x : String | semmle.label | x : String | | GlobalDataFlow.cs:212:89:212:89 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:213:22:213:28 | access to local variable tainted [[]] : String | semmle.label | access to local variable tainted [[]] : String | -| GlobalDataFlow.cs:213:22:213:39 | call to method Select [[]] : String | semmle.label | call to method Select [[]] : String | +| GlobalDataFlow.cs:213:22:213:28 | access to local variable tainted [element] : String | semmle.label | access to local variable tainted [element] : String | +| GlobalDataFlow.cs:213:22:213:39 | call to method Select [element] : String | semmle.label | call to method Select [element] : String | | GlobalDataFlow.cs:213:22:213:47 | call to method First : String | semmle.label | call to method First : String | | GlobalDataFlow.cs:214:15:214:20 | access to local variable sink24 | semmle.label | access to local variable sink24 | -| GlobalDataFlow.cs:215:22:215:28 | access to local variable tainted [[]] : String | semmle.label | access to local variable tainted [[]] : String | -| GlobalDataFlow.cs:215:22:215:39 | call to method Select [[]] : String | semmle.label | call to method Select [[]] : String | +| GlobalDataFlow.cs:215:22:215:28 | access to local variable tainted [element] : String | semmle.label | access to local variable tainted [element] : String | +| GlobalDataFlow.cs:215:22:215:39 | call to method Select [element] : String | semmle.label | call to method Select [element] : String | | GlobalDataFlow.cs:215:22:215:47 | call to method First : String | semmle.label | call to method First : String | | GlobalDataFlow.cs:216:15:216:20 | access to local variable sink25 | semmle.label | access to local variable sink25 | -| GlobalDataFlow.cs:217:22:217:28 | access to local variable tainted [[]] : String | semmle.label | access to local variable tainted [[]] : String | -| GlobalDataFlow.cs:217:22:217:49 | call to method Select [[]] : String | semmle.label | call to method Select [[]] : String | +| GlobalDataFlow.cs:217:22:217:28 | access to local variable tainted [element] : String | semmle.label | access to local variable tainted [element] : String | +| GlobalDataFlow.cs:217:22:217:49 | call to method Select [element] : String | semmle.label | call to method Select [element] : String | | GlobalDataFlow.cs:217:22:217:57 | call to method First : String | semmle.label | call to method First : String | | GlobalDataFlow.cs:218:15:218:20 | access to local variable sink26 | semmle.label | access to local variable sink26 | -| GlobalDataFlow.cs:238:20:238:49 | call to method Run [Result] : String | semmle.label | call to method Run [Result] : String | +| GlobalDataFlow.cs:238:20:238:49 | call to method Run [property Result] : String | semmle.label | call to method Run [property Result] : String | | GlobalDataFlow.cs:238:35:238:48 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:239:22:239:25 | access to local variable task [Result] : String | semmle.label | access to local variable task [Result] : String | +| GlobalDataFlow.cs:239:22:239:25 | access to local variable task [property Result] : String | semmle.label | access to local variable task [property Result] : String | | GlobalDataFlow.cs:239:22:239:32 | access to property Result : String | semmle.label | access to property Result : String | | GlobalDataFlow.cs:240:15:240:20 | access to local variable sink41 | semmle.label | access to local variable sink41 | | GlobalDataFlow.cs:241:22:241:31 | await ... : String | semmle.label | await ... : String | -| GlobalDataFlow.cs:241:28:241:31 | access to local variable task [Result] : String | semmle.label | access to local variable task [Result] : String | +| GlobalDataFlow.cs:241:28:241:31 | access to local variable task [property Result] : String | semmle.label | access to local variable task [property Result] : String | | GlobalDataFlow.cs:242:15:242:20 | access to local variable sink42 | semmle.label | access to local variable sink42 | | GlobalDataFlow.cs:254:26:254:35 | sinkParam0 : String | semmle.label | sinkParam0 : String | | GlobalDataFlow.cs:256:16:256:25 | access to parameter sinkParam0 : String | semmle.label | access to parameter sinkParam0 : String | @@ -439,13 +439,13 @@ nodes | GlobalDataFlow.cs:424:9:424:11 | value : String | semmle.label | value : String | | GlobalDataFlow.cs:424:41:424:46 | access to local variable sink20 | semmle.label | access to local variable sink20 | | GlobalDataFlow.cs:435:22:435:35 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:471:20:471:49 | call to method Run [Result] : String | semmle.label | call to method Run [Result] : String | +| GlobalDataFlow.cs:471:20:471:49 | call to method Run [property Result] : String | semmle.label | call to method Run [property Result] : String | | GlobalDataFlow.cs:471:35:471:48 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:472:25:472:28 | access to local variable task [Result] : String | semmle.label | access to local variable task [Result] : String | -| GlobalDataFlow.cs:472:25:472:50 | call to method ConfigureAwait [m_configuredTaskAwaiter, m_task, Result] : String | semmle.label | call to method ConfigureAwait [m_configuredTaskAwaiter, m_task, Result] : String | -| GlobalDataFlow.cs:473:23:473:31 | access to local variable awaitable [m_configuredTaskAwaiter, m_task, Result] : String | semmle.label | access to local variable awaitable [m_configuredTaskAwaiter, m_task, Result] : String | -| GlobalDataFlow.cs:473:23:473:44 | call to method GetAwaiter [m_task, Result] : String | semmle.label | call to method GetAwaiter [m_task, Result] : String | -| GlobalDataFlow.cs:474:22:474:28 | access to local variable awaiter [m_task, Result] : String | semmle.label | access to local variable awaiter [m_task, Result] : String | +| GlobalDataFlow.cs:472:25:472:28 | access to local variable task [property Result] : String | semmle.label | access to local variable task [property Result] : String | +| GlobalDataFlow.cs:472:25:472:50 | call to method ConfigureAwait [field m_configuredTaskAwaiter, field m_task, property Result] : String | semmle.label | call to method ConfigureAwait [field m_configuredTaskAwaiter, field m_task, property Result] : String | +| GlobalDataFlow.cs:473:23:473:31 | access to local variable awaitable [field m_configuredTaskAwaiter, field m_task, property Result] : String | semmle.label | access to local variable awaitable [field m_configuredTaskAwaiter, field m_task, property Result] : String | +| GlobalDataFlow.cs:473:23:473:44 | call to method GetAwaiter [field m_task, property Result] : String | semmle.label | call to method GetAwaiter [field m_task, property Result] : String | +| GlobalDataFlow.cs:474:22:474:28 | access to local variable awaiter [field m_task, property Result] : String | semmle.label | access to local variable awaiter [field m_task, property Result] : String | | GlobalDataFlow.cs:474:22:474:40 | call to method GetResult : String | semmle.label | call to method GetResult : String | | GlobalDataFlow.cs:475:15:475:20 | access to local variable sink45 | semmle.label | access to local variable sink45 | | GlobalDataFlow.cs:480:53:480:55 | arg : String | semmle.label | arg : String | diff --git a/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected b/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected index fe2a3987088..2a5f828159f 100644 --- a/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected +++ b/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected @@ -1,346 +1,346 @@ -| Capture.cs:33:9:33:40 | call to method Select | return | Capture.cs:33:9:33:40 | call to method Select | -| Capture.cs:33:9:33:50 | call to method ToArray | return | Capture.cs:33:9:33:50 | call to method ToArray | +| Capture.cs:33:9:33:40 | call to method Select | normal | Capture.cs:33:9:33:40 | call to method Select | +| Capture.cs:33:9:33:50 | call to method ToArray | normal | Capture.cs:33:9:33:50 | call to method ToArray | | Capture.cs:71:9:71:21 | call to local function CaptureOut1 | captured sink30 | Capture.cs:71:9:71:21 | SSA call def(sink30) | | Capture.cs:83:9:83:21 | [transitive] call to local function CaptureOut2 | captured sink31 | Capture.cs:83:9:83:21 | SSA call def(sink31) | | Capture.cs:92:9:92:41 | [transitive] call to method Select | captured sink32 | Capture.cs:92:9:92:41 | SSA call def(sink32) | -| Capture.cs:92:9:92:41 | call to method Select | return | Capture.cs:92:9:92:41 | call to method Select | -| Capture.cs:92:9:92:51 | call to method ToArray | return | Capture.cs:92:9:92:51 | call to method ToArray | +| Capture.cs:92:9:92:41 | call to method Select | normal | Capture.cs:92:9:92:41 | call to method Select | +| Capture.cs:92:9:92:51 | call to method ToArray | normal | Capture.cs:92:9:92:51 | call to method ToArray | | Capture.cs:121:9:121:35 | [transitive] call to local function CaptureOutMultipleLambdas | captured nonSink0 | Capture.cs:121:9:121:35 | SSA call def(nonSink0) | | Capture.cs:121:9:121:35 | [transitive] call to local function CaptureOutMultipleLambdas | captured sink40 | Capture.cs:121:9:121:35 | SSA call def(sink40) | | Capture.cs:132:9:132:25 | call to local function CaptureThrough1 | captured sink33 | Capture.cs:132:9:132:25 | SSA call def(sink33) | | Capture.cs:144:9:144:25 | [transitive] call to local function CaptureThrough2 | captured sink34 | Capture.cs:144:9:144:25 | SSA call def(sink34) | | Capture.cs:153:9:153:45 | [transitive] call to method Select | captured sink35 | Capture.cs:153:9:153:45 | SSA call def(sink35) | -| Capture.cs:153:9:153:45 | call to method Select | return | Capture.cs:153:9:153:45 | call to method Select | -| Capture.cs:153:9:153:55 | call to method ToArray | return | Capture.cs:153:9:153:55 | call to method ToArray | -| Capture.cs:160:22:160:38 | call to local function CaptureThrough4 | return | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 | +| Capture.cs:153:9:153:45 | call to method Select | normal | Capture.cs:153:9:153:45 | call to method Select | +| Capture.cs:153:9:153:55 | call to method ToArray | normal | Capture.cs:153:9:153:55 | call to method ToArray | +| Capture.cs:160:22:160:38 | call to local function CaptureThrough4 | normal | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 | | Capture.cs:168:9:168:32 | call to local function CaptureThrough5 | captured sink37 | Capture.cs:168:9:168:32 | SSA call def(sink37) | -| Capture.cs:191:20:191:22 | call to local function M | return | Capture.cs:191:20:191:22 | call to local function M | -| Capture.cs:194:22:194:32 | call to local function Id | return | Capture.cs:194:22:194:32 | call to local function Id | -| Capture.cs:196:20:196:25 | call to local function Id | return | Capture.cs:196:20:196:25 | call to local function Id | -| GlobalDataFlow.cs:26:9:26:26 | access to property SinkProperty0 | return | GlobalDataFlow.cs:26:9:26:26 | access to property SinkProperty0 | -| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | return | GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | -| GlobalDataFlow.cs:30:9:30:29 | access to property NonSinkProperty0 | return | GlobalDataFlow.cs:30:9:30:29 | access to property NonSinkProperty0 | -| GlobalDataFlow.cs:31:15:31:35 | access to property NonSinkProperty0 | return | GlobalDataFlow.cs:31:15:31:35 | access to property NonSinkProperty0 | -| GlobalDataFlow.cs:32:9:32:29 | access to property NonSinkProperty1 | return | GlobalDataFlow.cs:32:9:32:29 | access to property NonSinkProperty1 | -| GlobalDataFlow.cs:33:15:33:35 | access to property NonSinkProperty1 | return | GlobalDataFlow.cs:33:15:33:35 | access to property NonSinkProperty1 | -| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 | return | GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 | +| Capture.cs:191:20:191:22 | call to local function M | normal | Capture.cs:191:20:191:22 | call to local function M | +| Capture.cs:194:22:194:32 | call to local function Id | normal | Capture.cs:194:22:194:32 | call to local function Id | +| Capture.cs:196:20:196:25 | call to local function Id | normal | Capture.cs:196:20:196:25 | call to local function Id | +| GlobalDataFlow.cs:26:9:26:26 | access to property SinkProperty0 | normal | GlobalDataFlow.cs:26:9:26:26 | access to property SinkProperty0 | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | normal | GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | +| GlobalDataFlow.cs:30:9:30:29 | access to property NonSinkProperty0 | normal | GlobalDataFlow.cs:30:9:30:29 | access to property NonSinkProperty0 | +| GlobalDataFlow.cs:31:15:31:35 | access to property NonSinkProperty0 | normal | GlobalDataFlow.cs:31:15:31:35 | access to property NonSinkProperty0 | +| GlobalDataFlow.cs:32:9:32:29 | access to property NonSinkProperty1 | normal | GlobalDataFlow.cs:32:9:32:29 | access to property NonSinkProperty1 | +| GlobalDataFlow.cs:33:15:33:35 | access to property NonSinkProperty1 | normal | GlobalDataFlow.cs:33:15:33:35 | access to property NonSinkProperty1 | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 | normal | GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 | +| GlobalDataFlow.cs:37:26:37:58 | call to method GetMethod | normal | GlobalDataFlow.cs:37:26:37:58 | call to method GetMethod | | GlobalDataFlow.cs:37:26:37:58 | call to method GetMethod | qualifier | GlobalDataFlow.cs:37:26:37:41 | [post] typeof(...) | -| GlobalDataFlow.cs:37:26:37:58 | call to method GetMethod | return | GlobalDataFlow.cs:37:26:37:58 | call to method GetMethod | -| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 | return | GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 | -| GlobalDataFlow.cs:39:9:39:37 | call to method Invoke | return | GlobalDataFlow.cs:39:9:39:37 | call to method Invoke | -| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 | return | GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 | -| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 | return | GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 | -| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 | return | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 | return | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 | -| GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 | return | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 | return | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 | normal | GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 | +| GlobalDataFlow.cs:39:9:39:37 | call to method Invoke | normal | GlobalDataFlow.cs:39:9:39:37 | call to method Invoke | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 | normal | GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 | normal | GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 | normal | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 | normal | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 | +| GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 | normal | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 | +| GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 | normal | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 | +| GlobalDataFlow.cs:65:9:65:18 | access to property InProperty | normal | GlobalDataFlow.cs:65:9:65:18 | access to property InProperty | | GlobalDataFlow.cs:65:9:65:18 | access to property InProperty | qualifier | GlobalDataFlow.cs:65:9:65:18 | [post] this access | -| GlobalDataFlow.cs:65:9:65:18 | access to property InProperty | return | GlobalDataFlow.cs:65:9:65:18 | access to property InProperty | -| GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 | return | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 | +| GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 | normal | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 | +| GlobalDataFlow.cs:68:9:68:21 | access to property NonInProperty | normal | GlobalDataFlow.cs:68:9:68:21 | access to property NonInProperty | | GlobalDataFlow.cs:68:9:68:21 | access to property NonInProperty | qualifier | GlobalDataFlow.cs:68:9:68:21 | [post] this access | -| GlobalDataFlow.cs:68:9:68:21 | access to property NonInProperty | return | GlobalDataFlow.cs:68:9:68:21 | access to property NonInProperty | -| GlobalDataFlow.cs:71:21:71:46 | call to method Return | return | GlobalDataFlow.cs:71:21:71:46 | call to method Return | -| GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 | return | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 | +| GlobalDataFlow.cs:71:21:71:46 | call to method Return | normal | GlobalDataFlow.cs:71:21:71:46 | call to method Return | +| GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 | normal | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 | +| GlobalDataFlow.cs:73:29:73:64 | call to method GetMethod | normal | GlobalDataFlow.cs:73:29:73:64 | call to method GetMethod | | GlobalDataFlow.cs:73:29:73:64 | call to method GetMethod | qualifier | GlobalDataFlow.cs:73:29:73:44 | [post] typeof(...) | -| GlobalDataFlow.cs:73:29:73:64 | call to method GetMethod | return | GlobalDataFlow.cs:73:29:73:64 | call to method GetMethod | -| GlobalDataFlow.cs:73:29:73:101 | call to method Invoke | return | GlobalDataFlow.cs:73:29:73:101 | call to method Invoke | -| GlobalDataFlow.cs:76:9:76:46 | call to method ReturnOut | out | GlobalDataFlow.cs:76:30:76:34 | SSA def(sink2) | -| GlobalDataFlow.cs:76:9:76:46 | call to method ReturnOut | ref | GlobalDataFlow.cs:76:30:76:34 | SSA def(sink2) | -| GlobalDataFlow.cs:79:9:79:46 | call to method ReturnRef | out | GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) | -| GlobalDataFlow.cs:79:9:79:46 | call to method ReturnRef | ref | GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) | -| GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven | return | GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven | -| GlobalDataFlow.cs:81:22:81:93 | call to method First | return | GlobalDataFlow.cs:81:22:81:93 | call to method First | -| GlobalDataFlow.cs:83:22:83:87 | call to method Select | return | GlobalDataFlow.cs:83:22:83:87 | call to method Select | -| GlobalDataFlow.cs:83:22:83:95 | call to method First | return | GlobalDataFlow.cs:83:22:83:95 | call to method First | -| GlobalDataFlow.cs:85:22:85:128 | call to method Zip | return | GlobalDataFlow.cs:85:22:85:128 | call to method Zip | -| GlobalDataFlow.cs:85:22:85:136 | call to method First | return | GlobalDataFlow.cs:85:22:85:136 | call to method First | -| GlobalDataFlow.cs:87:22:87:128 | call to method Zip | return | GlobalDataFlow.cs:87:22:87:128 | call to method Zip | -| GlobalDataFlow.cs:87:22:87:136 | call to method First | return | GlobalDataFlow.cs:87:22:87:136 | call to method First | -| GlobalDataFlow.cs:89:22:89:110 | call to method Aggregate | return | GlobalDataFlow.cs:89:22:89:110 | call to method Aggregate | -| GlobalDataFlow.cs:91:22:91:110 | call to method Aggregate | return | GlobalDataFlow.cs:91:22:91:110 | call to method Aggregate | -| GlobalDataFlow.cs:94:9:94:42 | call to method TryParse | out | GlobalDataFlow.cs:94:36:94:41 | SSA def(sink21) | -| GlobalDataFlow.cs:94:9:94:42 | call to method TryParse | ref | GlobalDataFlow.cs:94:36:94:41 | SSA def(sink21) | -| GlobalDataFlow.cs:94:9:94:42 | call to method TryParse | return | GlobalDataFlow.cs:94:9:94:42 | call to method TryParse | -| GlobalDataFlow.cs:97:9:97:41 | call to method TryParse | out | GlobalDataFlow.cs:97:35:97:40 | SSA def(sink22) | -| GlobalDataFlow.cs:97:9:97:41 | call to method TryParse | ref | GlobalDataFlow.cs:97:35:97:40 | SSA def(sink22) | -| GlobalDataFlow.cs:97:9:97:41 | call to method TryParse | return | GlobalDataFlow.cs:97:9:97:41 | call to method TryParse | -| GlobalDataFlow.cs:101:24:101:33 | call to method Return | return | GlobalDataFlow.cs:101:24:101:33 | call to method Return | +| GlobalDataFlow.cs:73:29:73:101 | call to method Invoke | normal | GlobalDataFlow.cs:73:29:73:101 | call to method Invoke | +| GlobalDataFlow.cs:76:9:76:46 | call to method ReturnOut | out parameter 1 | GlobalDataFlow.cs:76:30:76:34 | SSA def(sink2) | +| GlobalDataFlow.cs:76:9:76:46 | call to method ReturnOut | ref parameter 1 | GlobalDataFlow.cs:76:30:76:34 | SSA def(sink2) | +| GlobalDataFlow.cs:79:9:79:46 | call to method ReturnRef | out parameter 1 | GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) | +| GlobalDataFlow.cs:79:9:79:46 | call to method ReturnRef | ref parameter 1 | GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) | +| GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven | normal | GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven | +| GlobalDataFlow.cs:81:22:81:93 | call to method First | normal | GlobalDataFlow.cs:81:22:81:93 | call to method First | +| GlobalDataFlow.cs:83:22:83:87 | call to method Select | normal | GlobalDataFlow.cs:83:22:83:87 | call to method Select | +| GlobalDataFlow.cs:83:22:83:95 | call to method First | normal | GlobalDataFlow.cs:83:22:83:95 | call to method First | +| GlobalDataFlow.cs:85:22:85:128 | call to method Zip | normal | GlobalDataFlow.cs:85:22:85:128 | call to method Zip | +| GlobalDataFlow.cs:85:22:85:136 | call to method First | normal | GlobalDataFlow.cs:85:22:85:136 | call to method First | +| GlobalDataFlow.cs:87:22:87:128 | call to method Zip | normal | GlobalDataFlow.cs:87:22:87:128 | call to method Zip | +| GlobalDataFlow.cs:87:22:87:136 | call to method First | normal | GlobalDataFlow.cs:87:22:87:136 | call to method First | +| GlobalDataFlow.cs:89:22:89:110 | call to method Aggregate | normal | GlobalDataFlow.cs:89:22:89:110 | call to method Aggregate | +| GlobalDataFlow.cs:91:22:91:110 | call to method Aggregate | normal | GlobalDataFlow.cs:91:22:91:110 | call to method Aggregate | +| GlobalDataFlow.cs:94:9:94:42 | call to method TryParse | normal | GlobalDataFlow.cs:94:9:94:42 | call to method TryParse | +| GlobalDataFlow.cs:94:9:94:42 | call to method TryParse | out parameter 1 | GlobalDataFlow.cs:94:36:94:41 | SSA def(sink21) | +| GlobalDataFlow.cs:94:9:94:42 | call to method TryParse | ref parameter 1 | GlobalDataFlow.cs:94:36:94:41 | SSA def(sink21) | +| GlobalDataFlow.cs:97:9:97:41 | call to method TryParse | normal | GlobalDataFlow.cs:97:9:97:41 | call to method TryParse | +| GlobalDataFlow.cs:97:9:97:41 | call to method TryParse | out parameter 1 | GlobalDataFlow.cs:97:35:97:40 | SSA def(sink22) | +| GlobalDataFlow.cs:97:9:97:41 | call to method TryParse | ref parameter 1 | GlobalDataFlow.cs:97:35:97:40 | SSA def(sink22) | +| GlobalDataFlow.cs:101:24:101:33 | call to method Return | normal | GlobalDataFlow.cs:101:24:101:33 | call to method Return | +| GlobalDataFlow.cs:103:28:103:63 | call to method GetMethod | normal | GlobalDataFlow.cs:103:28:103:63 | call to method GetMethod | | GlobalDataFlow.cs:103:28:103:63 | call to method GetMethod | qualifier | GlobalDataFlow.cs:103:28:103:43 | [post] typeof(...) | -| GlobalDataFlow.cs:103:28:103:63 | call to method GetMethod | return | GlobalDataFlow.cs:103:28:103:63 | call to method GetMethod | -| GlobalDataFlow.cs:103:28:103:103 | call to method Invoke | return | GlobalDataFlow.cs:103:28:103:103 | call to method Invoke | -| GlobalDataFlow.cs:105:9:105:49 | call to method ReturnOut | out | GlobalDataFlow.cs:105:27:105:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:105:9:105:49 | call to method ReturnOut | ref | GlobalDataFlow.cs:105:27:105:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:107:9:107:49 | call to method ReturnOut | out | GlobalDataFlow.cs:107:41:107:48 | SSA def(nonSink0) | -| GlobalDataFlow.cs:109:9:109:49 | call to method ReturnRef | out | GlobalDataFlow.cs:109:27:109:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:109:9:109:49 | call to method ReturnRef | ref | GlobalDataFlow.cs:109:27:109:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:111:9:111:49 | call to method ReturnRef | out | GlobalDataFlow.cs:111:30:111:34 | SSA def(sink1) | -| GlobalDataFlow.cs:111:9:111:49 | call to method ReturnRef | ref | GlobalDataFlow.cs:111:30:111:34 | SSA def(sink1) | -| GlobalDataFlow.cs:113:20:113:86 | call to method SelectEven | return | GlobalDataFlow.cs:113:20:113:86 | call to method SelectEven | -| GlobalDataFlow.cs:113:20:113:94 | call to method First | return | GlobalDataFlow.cs:113:20:113:94 | call to method First | -| GlobalDataFlow.cs:115:20:115:82 | call to method Select | return | GlobalDataFlow.cs:115:20:115:82 | call to method Select | -| GlobalDataFlow.cs:115:20:115:90 | call to method First | return | GlobalDataFlow.cs:115:20:115:90 | call to method First | -| GlobalDataFlow.cs:117:20:117:126 | call to method Zip | return | GlobalDataFlow.cs:117:20:117:126 | call to method Zip | -| GlobalDataFlow.cs:117:20:117:134 | call to method First | return | GlobalDataFlow.cs:117:20:117:134 | call to method First | -| GlobalDataFlow.cs:119:20:119:126 | call to method Zip | return | GlobalDataFlow.cs:119:20:119:126 | call to method Zip | -| GlobalDataFlow.cs:119:20:119:134 | call to method First | return | GlobalDataFlow.cs:119:20:119:134 | call to method First | -| GlobalDataFlow.cs:121:20:121:104 | call to method Aggregate | return | GlobalDataFlow.cs:121:20:121:104 | call to method Aggregate | -| GlobalDataFlow.cs:123:20:123:109 | call to method Aggregate | return | GlobalDataFlow.cs:123:20:123:109 | call to method Aggregate | -| GlobalDataFlow.cs:125:20:125:107 | call to method Aggregate | return | GlobalDataFlow.cs:125:20:125:107 | call to method Aggregate | -| GlobalDataFlow.cs:128:9:128:46 | call to method TryParse | out | GlobalDataFlow.cs:128:38:128:45 | SSA def(nonSink2) | -| GlobalDataFlow.cs:128:9:128:46 | call to method TryParse | ref | GlobalDataFlow.cs:128:38:128:45 | SSA def(nonSink2) | -| GlobalDataFlow.cs:128:9:128:46 | call to method TryParse | return | GlobalDataFlow.cs:128:9:128:46 | call to method TryParse | -| GlobalDataFlow.cs:131:9:131:45 | call to method TryParse | out | GlobalDataFlow.cs:131:37:131:44 | SSA def(nonSink3) | -| GlobalDataFlow.cs:131:9:131:45 | call to method TryParse | ref | GlobalDataFlow.cs:131:37:131:44 | SSA def(nonSink3) | -| GlobalDataFlow.cs:131:9:131:45 | call to method TryParse | return | GlobalDataFlow.cs:131:9:131:45 | call to method TryParse | -| GlobalDataFlow.cs:135:45:135:64 | call to method ApplyFunc | return | GlobalDataFlow.cs:135:45:135:64 | call to method ApplyFunc | -| GlobalDataFlow.cs:136:21:136:34 | delegate call | return | GlobalDataFlow.cs:136:21:136:34 | delegate call | -| GlobalDataFlow.cs:140:20:140:36 | delegate call | return | GlobalDataFlow.cs:140:20:140:36 | delegate call | -| GlobalDataFlow.cs:144:21:144:44 | call to method ApplyFunc | return | GlobalDataFlow.cs:144:21:144:44 | call to method ApplyFunc | -| GlobalDataFlow.cs:148:20:148:40 | call to method ApplyFunc | return | GlobalDataFlow.cs:148:20:148:40 | call to method ApplyFunc | -| GlobalDataFlow.cs:150:20:150:44 | call to method ApplyFunc | return | GlobalDataFlow.cs:150:20:150:44 | call to method ApplyFunc | +| GlobalDataFlow.cs:103:28:103:103 | call to method Invoke | normal | GlobalDataFlow.cs:103:28:103:103 | call to method Invoke | +| GlobalDataFlow.cs:105:9:105:49 | call to method ReturnOut | out parameter 1 | GlobalDataFlow.cs:105:27:105:34 | SSA def(nonSink0) | +| GlobalDataFlow.cs:105:9:105:49 | call to method ReturnOut | ref parameter 1 | GlobalDataFlow.cs:105:27:105:34 | SSA def(nonSink0) | +| GlobalDataFlow.cs:107:9:107:49 | call to method ReturnOut | out parameter 2 | GlobalDataFlow.cs:107:41:107:48 | SSA def(nonSink0) | +| GlobalDataFlow.cs:109:9:109:49 | call to method ReturnRef | out parameter 1 | GlobalDataFlow.cs:109:27:109:34 | SSA def(nonSink0) | +| GlobalDataFlow.cs:109:9:109:49 | call to method ReturnRef | ref parameter 1 | GlobalDataFlow.cs:109:27:109:34 | SSA def(nonSink0) | +| GlobalDataFlow.cs:111:9:111:49 | call to method ReturnRef | out parameter 1 | GlobalDataFlow.cs:111:30:111:34 | SSA def(sink1) | +| GlobalDataFlow.cs:111:9:111:49 | call to method ReturnRef | ref parameter 1 | GlobalDataFlow.cs:111:30:111:34 | SSA def(sink1) | +| GlobalDataFlow.cs:113:20:113:86 | call to method SelectEven | normal | GlobalDataFlow.cs:113:20:113:86 | call to method SelectEven | +| GlobalDataFlow.cs:113:20:113:94 | call to method First | normal | GlobalDataFlow.cs:113:20:113:94 | call to method First | +| GlobalDataFlow.cs:115:20:115:82 | call to method Select | normal | GlobalDataFlow.cs:115:20:115:82 | call to method Select | +| GlobalDataFlow.cs:115:20:115:90 | call to method First | normal | GlobalDataFlow.cs:115:20:115:90 | call to method First | +| GlobalDataFlow.cs:117:20:117:126 | call to method Zip | normal | GlobalDataFlow.cs:117:20:117:126 | call to method Zip | +| GlobalDataFlow.cs:117:20:117:134 | call to method First | normal | GlobalDataFlow.cs:117:20:117:134 | call to method First | +| GlobalDataFlow.cs:119:20:119:126 | call to method Zip | normal | GlobalDataFlow.cs:119:20:119:126 | call to method Zip | +| GlobalDataFlow.cs:119:20:119:134 | call to method First | normal | GlobalDataFlow.cs:119:20:119:134 | call to method First | +| GlobalDataFlow.cs:121:20:121:104 | call to method Aggregate | normal | GlobalDataFlow.cs:121:20:121:104 | call to method Aggregate | +| GlobalDataFlow.cs:123:20:123:109 | call to method Aggregate | normal | GlobalDataFlow.cs:123:20:123:109 | call to method Aggregate | +| GlobalDataFlow.cs:125:20:125:107 | call to method Aggregate | normal | GlobalDataFlow.cs:125:20:125:107 | call to method Aggregate | +| GlobalDataFlow.cs:128:9:128:46 | call to method TryParse | normal | GlobalDataFlow.cs:128:9:128:46 | call to method TryParse | +| GlobalDataFlow.cs:128:9:128:46 | call to method TryParse | out parameter 1 | GlobalDataFlow.cs:128:38:128:45 | SSA def(nonSink2) | +| GlobalDataFlow.cs:128:9:128:46 | call to method TryParse | ref parameter 1 | GlobalDataFlow.cs:128:38:128:45 | SSA def(nonSink2) | +| GlobalDataFlow.cs:131:9:131:45 | call to method TryParse | normal | GlobalDataFlow.cs:131:9:131:45 | call to method TryParse | +| GlobalDataFlow.cs:131:9:131:45 | call to method TryParse | out parameter 1 | GlobalDataFlow.cs:131:37:131:44 | SSA def(nonSink3) | +| GlobalDataFlow.cs:131:9:131:45 | call to method TryParse | ref parameter 1 | GlobalDataFlow.cs:131:37:131:44 | SSA def(nonSink3) | +| GlobalDataFlow.cs:135:45:135:64 | call to method ApplyFunc | normal | GlobalDataFlow.cs:135:45:135:64 | call to method ApplyFunc | +| GlobalDataFlow.cs:136:21:136:34 | delegate call | normal | GlobalDataFlow.cs:136:21:136:34 | delegate call | +| GlobalDataFlow.cs:140:20:140:36 | delegate call | normal | GlobalDataFlow.cs:140:20:140:36 | delegate call | +| GlobalDataFlow.cs:144:21:144:44 | call to method ApplyFunc | normal | GlobalDataFlow.cs:144:21:144:44 | call to method ApplyFunc | +| GlobalDataFlow.cs:148:20:148:40 | call to method ApplyFunc | normal | GlobalDataFlow.cs:148:20:148:40 | call to method ApplyFunc | +| GlobalDataFlow.cs:150:20:150:44 | call to method ApplyFunc | normal | GlobalDataFlow.cs:150:20:150:44 | call to method ApplyFunc | +| GlobalDataFlow.cs:154:21:154:25 | call to method Out | normal | GlobalDataFlow.cs:154:21:154:25 | call to method Out | | GlobalDataFlow.cs:154:21:154:25 | call to method Out | qualifier | GlobalDataFlow.cs:154:21:154:25 | [post] this access | -| GlobalDataFlow.cs:154:21:154:25 | call to method Out | return | GlobalDataFlow.cs:154:21:154:25 | call to method Out | -| GlobalDataFlow.cs:157:9:157:25 | call to method OutOut | out | GlobalDataFlow.cs:157:20:157:24 | SSA def(sink7) | +| GlobalDataFlow.cs:157:9:157:25 | call to method OutOut | out parameter 0 | GlobalDataFlow.cs:157:20:157:24 | SSA def(sink7) | | GlobalDataFlow.cs:157:9:157:25 | call to method OutOut | qualifier | GlobalDataFlow.cs:157:9:157:25 | [post] this access | -| GlobalDataFlow.cs:157:9:157:25 | call to method OutOut | ref | GlobalDataFlow.cs:157:20:157:24 | SSA def(sink7) | -| GlobalDataFlow.cs:160:9:160:25 | call to method OutRef | out | GlobalDataFlow.cs:160:20:160:24 | SSA def(sink8) | +| GlobalDataFlow.cs:157:9:157:25 | call to method OutOut | ref parameter 0 | GlobalDataFlow.cs:157:20:157:24 | SSA def(sink7) | +| GlobalDataFlow.cs:160:9:160:25 | call to method OutRef | out parameter 0 | GlobalDataFlow.cs:160:20:160:24 | SSA def(sink8) | | GlobalDataFlow.cs:160:9:160:25 | call to method OutRef | qualifier | GlobalDataFlow.cs:160:9:160:25 | [post] this access | -| GlobalDataFlow.cs:160:9:160:25 | call to method OutRef | ref | GlobalDataFlow.cs:160:20:160:24 | SSA def(sink8) | +| GlobalDataFlow.cs:160:9:160:25 | call to method OutRef | ref parameter 0 | GlobalDataFlow.cs:160:20:160:24 | SSA def(sink8) | +| GlobalDataFlow.cs:162:22:162:31 | call to method OutYield | normal | GlobalDataFlow.cs:162:22:162:31 | call to method OutYield | | GlobalDataFlow.cs:162:22:162:31 | call to method OutYield | qualifier | GlobalDataFlow.cs:162:22:162:31 | [post] this access | -| GlobalDataFlow.cs:162:22:162:31 | call to method OutYield | return | GlobalDataFlow.cs:162:22:162:31 | call to method OutYield | -| GlobalDataFlow.cs:162:22:162:39 | call to method First | return | GlobalDataFlow.cs:162:22:162:39 | call to method First | -| GlobalDataFlow.cs:164:22:164:43 | call to method TaintedParam | return | GlobalDataFlow.cs:164:22:164:43 | call to method TaintedParam | +| GlobalDataFlow.cs:162:22:162:39 | call to method First | normal | GlobalDataFlow.cs:162:22:162:39 | call to method First | +| GlobalDataFlow.cs:164:22:164:43 | call to method TaintedParam | normal | GlobalDataFlow.cs:164:22:164:43 | call to method TaintedParam | +| GlobalDataFlow.cs:168:20:168:27 | call to method NonOut | normal | GlobalDataFlow.cs:168:20:168:27 | call to method NonOut | | GlobalDataFlow.cs:168:20:168:27 | call to method NonOut | qualifier | GlobalDataFlow.cs:168:20:168:27 | [post] this access | -| GlobalDataFlow.cs:168:20:168:27 | call to method NonOut | return | GlobalDataFlow.cs:168:20:168:27 | call to method NonOut | -| GlobalDataFlow.cs:170:9:170:31 | call to method NonOutOut | out | GlobalDataFlow.cs:170:23:170:30 | SSA def(nonSink0) | +| GlobalDataFlow.cs:170:9:170:31 | call to method NonOutOut | out parameter 0 | GlobalDataFlow.cs:170:23:170:30 | SSA def(nonSink0) | | GlobalDataFlow.cs:170:9:170:31 | call to method NonOutOut | qualifier | GlobalDataFlow.cs:170:9:170:31 | [post] this access | -| GlobalDataFlow.cs:170:9:170:31 | call to method NonOutOut | ref | GlobalDataFlow.cs:170:23:170:30 | SSA def(nonSink0) | -| GlobalDataFlow.cs:172:9:172:31 | call to method NonOutRef | out | GlobalDataFlow.cs:172:23:172:30 | SSA def(nonSink0) | +| GlobalDataFlow.cs:170:9:170:31 | call to method NonOutOut | ref parameter 0 | GlobalDataFlow.cs:170:23:170:30 | SSA def(nonSink0) | +| GlobalDataFlow.cs:172:9:172:31 | call to method NonOutRef | out parameter 0 | GlobalDataFlow.cs:172:23:172:30 | SSA def(nonSink0) | | GlobalDataFlow.cs:172:9:172:31 | call to method NonOutRef | qualifier | GlobalDataFlow.cs:172:9:172:31 | [post] this access | -| GlobalDataFlow.cs:172:9:172:31 | call to method NonOutRef | ref | GlobalDataFlow.cs:172:23:172:30 | SSA def(nonSink0) | +| GlobalDataFlow.cs:172:9:172:31 | call to method NonOutRef | ref parameter 0 | GlobalDataFlow.cs:172:23:172:30 | SSA def(nonSink0) | +| GlobalDataFlow.cs:174:20:174:32 | call to method NonOutYield | normal | GlobalDataFlow.cs:174:20:174:32 | call to method NonOutYield | | GlobalDataFlow.cs:174:20:174:32 | call to method NonOutYield | qualifier | GlobalDataFlow.cs:174:20:174:32 | [post] this access | -| GlobalDataFlow.cs:174:20:174:32 | call to method NonOutYield | return | GlobalDataFlow.cs:174:20:174:32 | call to method NonOutYield | -| GlobalDataFlow.cs:174:20:174:40 | call to method First | return | GlobalDataFlow.cs:174:20:174:40 | call to method First | -| GlobalDataFlow.cs:176:20:176:44 | call to method NonTaintedParam | return | GlobalDataFlow.cs:176:20:176:44 | call to method NonTaintedParam | -| GlobalDataFlow.cs:181:21:181:26 | delegate call | return | GlobalDataFlow.cs:181:21:181:26 | delegate call | -| GlobalDataFlow.cs:186:20:186:27 | delegate call | return | GlobalDataFlow.cs:186:20:186:27 | delegate call | -| GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy | return | GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy | +| GlobalDataFlow.cs:174:20:174:40 | call to method First | normal | GlobalDataFlow.cs:174:20:174:40 | call to method First | +| GlobalDataFlow.cs:176:20:176:44 | call to method NonTaintedParam | normal | GlobalDataFlow.cs:176:20:176:44 | call to method NonTaintedParam | +| GlobalDataFlow.cs:181:21:181:26 | delegate call | normal | GlobalDataFlow.cs:181:21:181:26 | delegate call | +| GlobalDataFlow.cs:186:20:186:27 | delegate call | normal | GlobalDataFlow.cs:186:20:186:27 | delegate call | +| GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy | normal | GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy | +| GlobalDataFlow.cs:190:22:190:48 | access to property Value | normal | GlobalDataFlow.cs:190:22:190:48 | access to property Value | | GlobalDataFlow.cs:190:22:190:48 | access to property Value | qualifier | GlobalDataFlow.cs:190:22:190:42 | [post] object creation of type Lazy | -| GlobalDataFlow.cs:190:22:190:48 | access to property Value | return | GlobalDataFlow.cs:190:22:190:48 | access to property Value | -| GlobalDataFlow.cs:194:20:194:43 | object creation of type Lazy | return | GlobalDataFlow.cs:194:20:194:43 | object creation of type Lazy | +| GlobalDataFlow.cs:194:20:194:43 | object creation of type Lazy | normal | GlobalDataFlow.cs:194:20:194:43 | object creation of type Lazy | +| GlobalDataFlow.cs:194:20:194:49 | access to property Value | normal | GlobalDataFlow.cs:194:20:194:49 | access to property Value | | GlobalDataFlow.cs:194:20:194:49 | access to property Value | qualifier | GlobalDataFlow.cs:194:20:194:43 | [post] object creation of type Lazy | -| GlobalDataFlow.cs:194:20:194:49 | access to property Value | return | GlobalDataFlow.cs:194:20:194:49 | access to property Value | +| GlobalDataFlow.cs:198:22:198:32 | access to property OutProperty | normal | GlobalDataFlow.cs:198:22:198:32 | access to property OutProperty | | GlobalDataFlow.cs:198:22:198:32 | access to property OutProperty | qualifier | GlobalDataFlow.cs:198:22:198:32 | [post] this access | -| GlobalDataFlow.cs:198:22:198:32 | access to property OutProperty | return | GlobalDataFlow.cs:198:22:198:32 | access to property OutProperty | +| GlobalDataFlow.cs:202:20:202:33 | access to property NonOutProperty | normal | GlobalDataFlow.cs:202:20:202:33 | access to property NonOutProperty | | GlobalDataFlow.cs:202:20:202:33 | access to property NonOutProperty | qualifier | GlobalDataFlow.cs:202:20:202:33 | [post] this access | -| GlobalDataFlow.cs:202:20:202:33 | access to property NonOutProperty | return | GlobalDataFlow.cs:202:20:202:33 | access to property NonOutProperty | -| GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable | return | GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable | -| GlobalDataFlow.cs:209:41:209:77 | call to method AsQueryable | return | GlobalDataFlow.cs:209:41:209:77 | call to method AsQueryable | -| GlobalDataFlow.cs:212:76:212:90 | call to method ReturnCheck2 | return | GlobalDataFlow.cs:212:76:212:90 | call to method ReturnCheck2 | -| GlobalDataFlow.cs:213:22:213:39 | call to method Select | return | GlobalDataFlow.cs:213:22:213:39 | call to method Select | -| GlobalDataFlow.cs:213:22:213:47 | call to method First | return | GlobalDataFlow.cs:213:22:213:47 | call to method First | -| GlobalDataFlow.cs:215:22:215:39 | call to method Select | return | GlobalDataFlow.cs:215:22:215:39 | call to method Select | -| GlobalDataFlow.cs:215:22:215:47 | call to method First | return | GlobalDataFlow.cs:215:22:215:47 | call to method First | -| GlobalDataFlow.cs:217:22:217:49 | call to method Select | return | GlobalDataFlow.cs:217:22:217:49 | call to method Select | -| GlobalDataFlow.cs:217:22:217:57 | call to method First | return | GlobalDataFlow.cs:217:22:217:57 | call to method First | -| GlobalDataFlow.cs:222:76:222:92 | call to method NonReturnCheck | return | GlobalDataFlow.cs:222:76:222:92 | call to method NonReturnCheck | -| GlobalDataFlow.cs:223:23:223:43 | call to method Select | return | GlobalDataFlow.cs:223:23:223:43 | call to method Select | -| GlobalDataFlow.cs:223:23:223:51 | call to method First | return | GlobalDataFlow.cs:223:23:223:51 | call to method First | -| GlobalDataFlow.cs:225:19:225:39 | call to method Select | return | GlobalDataFlow.cs:225:19:225:39 | call to method Select | -| GlobalDataFlow.cs:225:19:225:47 | call to method First | return | GlobalDataFlow.cs:225:19:225:47 | call to method First | -| GlobalDataFlow.cs:227:19:227:39 | call to method Select | return | GlobalDataFlow.cs:227:19:227:39 | call to method Select | -| GlobalDataFlow.cs:227:19:227:47 | call to method First | return | GlobalDataFlow.cs:227:19:227:47 | call to method First | -| GlobalDataFlow.cs:229:19:229:39 | call to method Select | return | GlobalDataFlow.cs:229:19:229:39 | call to method Select | -| GlobalDataFlow.cs:229:19:229:47 | call to method First | return | GlobalDataFlow.cs:229:19:229:47 | call to method First | -| GlobalDataFlow.cs:231:19:231:49 | call to method Select | return | GlobalDataFlow.cs:231:19:231:49 | call to method Select | -| GlobalDataFlow.cs:231:19:231:57 | call to method First | return | GlobalDataFlow.cs:231:19:231:57 | call to method First | -| GlobalDataFlow.cs:238:20:238:49 | call to method Run | return | GlobalDataFlow.cs:238:20:238:49 | call to method Run | +| GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable | normal | GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable | +| GlobalDataFlow.cs:209:41:209:77 | call to method AsQueryable | normal | GlobalDataFlow.cs:209:41:209:77 | call to method AsQueryable | +| GlobalDataFlow.cs:212:76:212:90 | call to method ReturnCheck2 | normal | GlobalDataFlow.cs:212:76:212:90 | call to method ReturnCheck2 | +| GlobalDataFlow.cs:213:22:213:39 | call to method Select | normal | GlobalDataFlow.cs:213:22:213:39 | call to method Select | +| GlobalDataFlow.cs:213:22:213:47 | call to method First | normal | GlobalDataFlow.cs:213:22:213:47 | call to method First | +| GlobalDataFlow.cs:215:22:215:39 | call to method Select | normal | GlobalDataFlow.cs:215:22:215:39 | call to method Select | +| GlobalDataFlow.cs:215:22:215:47 | call to method First | normal | GlobalDataFlow.cs:215:22:215:47 | call to method First | +| GlobalDataFlow.cs:217:22:217:49 | call to method Select | normal | GlobalDataFlow.cs:217:22:217:49 | call to method Select | +| GlobalDataFlow.cs:217:22:217:57 | call to method First | normal | GlobalDataFlow.cs:217:22:217:57 | call to method First | +| GlobalDataFlow.cs:222:76:222:92 | call to method NonReturnCheck | normal | GlobalDataFlow.cs:222:76:222:92 | call to method NonReturnCheck | +| GlobalDataFlow.cs:223:23:223:43 | call to method Select | normal | GlobalDataFlow.cs:223:23:223:43 | call to method Select | +| GlobalDataFlow.cs:223:23:223:51 | call to method First | normal | GlobalDataFlow.cs:223:23:223:51 | call to method First | +| GlobalDataFlow.cs:225:19:225:39 | call to method Select | normal | GlobalDataFlow.cs:225:19:225:39 | call to method Select | +| GlobalDataFlow.cs:225:19:225:47 | call to method First | normal | GlobalDataFlow.cs:225:19:225:47 | call to method First | +| GlobalDataFlow.cs:227:19:227:39 | call to method Select | normal | GlobalDataFlow.cs:227:19:227:39 | call to method Select | +| GlobalDataFlow.cs:227:19:227:47 | call to method First | normal | GlobalDataFlow.cs:227:19:227:47 | call to method First | +| GlobalDataFlow.cs:229:19:229:39 | call to method Select | normal | GlobalDataFlow.cs:229:19:229:39 | call to method Select | +| GlobalDataFlow.cs:229:19:229:47 | call to method First | normal | GlobalDataFlow.cs:229:19:229:47 | call to method First | +| GlobalDataFlow.cs:231:19:231:49 | call to method Select | normal | GlobalDataFlow.cs:231:19:231:49 | call to method Select | +| GlobalDataFlow.cs:231:19:231:57 | call to method First | normal | GlobalDataFlow.cs:231:19:231:57 | call to method First | +| GlobalDataFlow.cs:238:20:238:49 | call to method Run | normal | GlobalDataFlow.cs:238:20:238:49 | call to method Run | +| GlobalDataFlow.cs:239:22:239:32 | access to property Result | normal | GlobalDataFlow.cs:239:22:239:32 | access to property Result | | GlobalDataFlow.cs:239:22:239:32 | access to property Result | qualifier | GlobalDataFlow.cs:239:22:239:25 | [post] access to local variable task | -| GlobalDataFlow.cs:239:22:239:32 | access to property Result | return | GlobalDataFlow.cs:239:22:239:32 | access to property Result | -| GlobalDataFlow.cs:245:16:245:33 | call to method Run | return | GlobalDataFlow.cs:245:16:245:33 | call to method Run | +| GlobalDataFlow.cs:245:16:245:33 | call to method Run | normal | GlobalDataFlow.cs:245:16:245:33 | call to method Run | +| GlobalDataFlow.cs:246:24:246:34 | access to property Result | normal | GlobalDataFlow.cs:246:24:246:34 | access to property Result | | GlobalDataFlow.cs:246:24:246:34 | access to property Result | qualifier | GlobalDataFlow.cs:246:24:246:27 | [post] access to local variable task | -| GlobalDataFlow.cs:246:24:246:34 | access to property Result | return | GlobalDataFlow.cs:246:24:246:34 | access to property Result | -| GlobalDataFlow.cs:297:17:297:38 | call to method ApplyFunc | return | GlobalDataFlow.cs:297:17:297:38 | call to method ApplyFunc | -| GlobalDataFlow.cs:386:16:386:19 | delegate call | return | GlobalDataFlow.cs:386:16:386:19 | delegate call | +| GlobalDataFlow.cs:297:17:297:38 | call to method ApplyFunc | normal | GlobalDataFlow.cs:297:17:297:38 | call to method ApplyFunc | +| GlobalDataFlow.cs:386:16:386:19 | delegate call | normal | GlobalDataFlow.cs:386:16:386:19 | delegate call | +| GlobalDataFlow.cs:445:9:445:20 | call to method Append | normal | GlobalDataFlow.cs:445:9:445:20 | call to method Append | | GlobalDataFlow.cs:445:9:445:20 | call to method Append | qualifier | GlobalDataFlow.cs:445:9:445:10 | [post] access to parameter sb | -| GlobalDataFlow.cs:445:9:445:20 | call to method Append | return | GlobalDataFlow.cs:445:9:445:20 | call to method Append | -| GlobalDataFlow.cs:450:18:450:36 | object creation of type StringBuilder | return | GlobalDataFlow.cs:450:18:450:36 | object creation of type StringBuilder | +| GlobalDataFlow.cs:450:18:450:36 | object creation of type StringBuilder | normal | GlobalDataFlow.cs:450:18:450:36 | object creation of type StringBuilder | +| GlobalDataFlow.cs:452:22:452:34 | call to method ToString | normal | GlobalDataFlow.cs:452:22:452:34 | call to method ToString | | GlobalDataFlow.cs:452:22:452:34 | call to method ToString | qualifier | GlobalDataFlow.cs:452:22:452:23 | [post] access to local variable sb | -| GlobalDataFlow.cs:452:22:452:34 | call to method ToString | return | GlobalDataFlow.cs:452:22:452:34 | call to method ToString | +| GlobalDataFlow.cs:455:9:455:18 | call to method Clear | normal | GlobalDataFlow.cs:455:9:455:18 | call to method Clear | | GlobalDataFlow.cs:455:9:455:18 | call to method Clear | qualifier | GlobalDataFlow.cs:455:9:455:10 | [post] access to local variable sb | -| GlobalDataFlow.cs:455:9:455:18 | call to method Clear | return | GlobalDataFlow.cs:455:9:455:18 | call to method Clear | +| GlobalDataFlow.cs:456:23:456:35 | call to method ToString | normal | GlobalDataFlow.cs:456:23:456:35 | call to method ToString | | GlobalDataFlow.cs:456:23:456:35 | call to method ToString | qualifier | GlobalDataFlow.cs:456:23:456:24 | [post] access to local variable sb | -| GlobalDataFlow.cs:456:23:456:35 | call to method ToString | return | GlobalDataFlow.cs:456:23:456:35 | call to method ToString | -| GlobalDataFlow.cs:462:22:462:65 | call to method Join | return | GlobalDataFlow.cs:462:22:462:65 | call to method Join | -| GlobalDataFlow.cs:465:23:465:65 | call to method Join | return | GlobalDataFlow.cs:465:23:465:65 | call to method Join | -| GlobalDataFlow.cs:471:20:471:49 | call to method Run | return | GlobalDataFlow.cs:471:20:471:49 | call to method Run | +| GlobalDataFlow.cs:462:22:462:65 | call to method Join | normal | GlobalDataFlow.cs:462:22:462:65 | call to method Join | +| GlobalDataFlow.cs:465:23:465:65 | call to method Join | normal | GlobalDataFlow.cs:465:23:465:65 | call to method Join | +| GlobalDataFlow.cs:471:20:471:49 | call to method Run | normal | GlobalDataFlow.cs:471:20:471:49 | call to method Run | +| GlobalDataFlow.cs:472:25:472:50 | call to method ConfigureAwait | normal | GlobalDataFlow.cs:472:25:472:50 | call to method ConfigureAwait | | GlobalDataFlow.cs:472:25:472:50 | call to method ConfigureAwait | qualifier | GlobalDataFlow.cs:472:25:472:28 | [post] access to local variable task | -| GlobalDataFlow.cs:472:25:472:50 | call to method ConfigureAwait | return | GlobalDataFlow.cs:472:25:472:50 | call to method ConfigureAwait | -| GlobalDataFlow.cs:473:23:473:44 | call to method GetAwaiter | return | GlobalDataFlow.cs:473:23:473:44 | call to method GetAwaiter | -| GlobalDataFlow.cs:474:22:474:40 | call to method GetResult | return | GlobalDataFlow.cs:474:22:474:40 | call to method GetResult | -| GlobalDataFlow.cs:498:44:498:47 | delegate call | return | GlobalDataFlow.cs:498:44:498:47 | delegate call | -| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | return | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | return | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | -| Splitting.cs:20:22:20:30 | call to method Return | return | Splitting.cs:20:22:20:30 | call to method Return | -| Splitting.cs:21:21:21:33 | call to method Return | return | Splitting.cs:21:21:21:33 | call to method Return | +| GlobalDataFlow.cs:473:23:473:44 | call to method GetAwaiter | normal | GlobalDataFlow.cs:473:23:473:44 | call to method GetAwaiter | +| GlobalDataFlow.cs:474:22:474:40 | call to method GetResult | normal | GlobalDataFlow.cs:474:22:474:40 | call to method GetResult | +| GlobalDataFlow.cs:498:44:498:47 | delegate call | normal | GlobalDataFlow.cs:498:44:498:47 | delegate call | +| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | normal | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | +| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | normal | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | +| Splitting.cs:20:22:20:30 | call to method Return | normal | Splitting.cs:20:22:20:30 | call to method Return | +| Splitting.cs:21:21:21:33 | call to method Return | normal | Splitting.cs:21:21:21:33 | call to method Return | +| Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element | normal | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element | | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element | qualifier | Splitting.cs:30:9:30:9 | [post] [b (line 24): false] access to local variable d | -| Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element | return | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element | +| Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element | normal | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element | | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element | qualifier | Splitting.cs:30:9:30:9 | [post] [b (line 24): true] access to local variable d | -| Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element | return | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element | +| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | normal | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | qualifier | Splitting.cs:31:17:31:17 | [post] [b (line 24): false] access to local variable d | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | return | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | +| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | normal | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | qualifier | Splitting.cs:31:17:31:17 | [post] [b (line 24): true] access to local variable d | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | return | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | -| Splitting.cs:32:9:32:16 | [b (line 24): false] dynamic call to method Check | return | Splitting.cs:32:9:32:16 | [b (line 24): false] dynamic call to method Check | -| Splitting.cs:32:9:32:16 | [b (line 24): true] dynamic call to method Check | return | Splitting.cs:32:9:32:16 | [b (line 24): true] dynamic call to method Check | -| Splitting.cs:34:13:34:20 | dynamic call to method Check | return | Splitting.cs:34:13:34:20 | dynamic call to method Check | +| Splitting.cs:32:9:32:16 | [b (line 24): false] dynamic call to method Check | normal | Splitting.cs:32:9:32:16 | [b (line 24): false] dynamic call to method Check | +| Splitting.cs:32:9:32:16 | [b (line 24): true] dynamic call to method Check | normal | Splitting.cs:32:9:32:16 | [b (line 24): true] dynamic call to method Check | +| Splitting.cs:34:13:34:20 | dynamic call to method Check | normal | Splitting.cs:34:13:34:20 | dynamic call to method Check | | This.cs:12:9:12:20 | call to method M | qualifier | This.cs:12:9:12:12 | [post] this access | | This.cs:13:9:13:15 | call to method M | qualifier | This.cs:13:9:13:15 | [post] this access | | This.cs:15:9:15:21 | call to method M | qualifier | This.cs:15:9:15:12 | [post] this access | | This.cs:16:9:16:16 | call to method M | qualifier | This.cs:16:9:16:16 | [post] this access | -| This.cs:17:9:17:18 | object creation of type This | return | This.cs:17:9:17:18 | object creation of type This | +| This.cs:17:9:17:18 | object creation of type This | normal | This.cs:17:9:17:18 | object creation of type This | | This.cs:26:13:26:24 | call to method M | qualifier | This.cs:26:13:26:16 | [post] this access | | This.cs:27:13:27:24 | call to method M | qualifier | This.cs:27:13:27:16 | [post] base access | -| This.cs:28:13:28:21 | object creation of type Sub | return | This.cs:28:13:28:21 | object creation of type Sub | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Lazy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Lazy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Lazy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Lazy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Lazy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Lazy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Run | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Run] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Run | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Run] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Run | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Run] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Run | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Run] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of Aggregate | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of Aggregate] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of Aggregate | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of Aggregate] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of Select | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of Select] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of Select | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of Select] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of Select | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of Select] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of Select | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of Select] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of Aggregate | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of Aggregate] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of Aggregate | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of Aggregate] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of Aggregate | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of Aggregate] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of Aggregate | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of Aggregate] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of SelectMany | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of SelectMany] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of SelectMany | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of SelectMany] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of SelectMany | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of SelectMany] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of SelectMany | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of SelectMany] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of ToDictionary | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of ToDictionary] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of ToDictionary | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of ToDictionary] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of ToLookup | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of ToLookup] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of ToLookup | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of ToLookup] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of Zip | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of Zip] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of Zip | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of Zip] | -| file://:0:0:0:0 | [summary] delegate call, parameter 3 of Aggregate | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 3 of Aggregate] | -| file://:0:0:0:0 | [summary] delegate call, parameter 3 of Aggregate | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 3 of Aggregate] | -| file://:0:0:0:0 | [summary] delegate call, parameter 3 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 3 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 3 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 3 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 3 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 3 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 3 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 3 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 4 of GroupJoin | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of GroupJoin] | -| file://:0:0:0:0 | [summary] delegate call, parameter 4 of GroupJoin | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of GroupJoin] | -| file://:0:0:0:0 | [summary] delegate call, parameter 4 of GroupJoin | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of GroupJoin] | -| file://:0:0:0:0 | [summary] delegate call, parameter 4 of GroupJoin | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of GroupJoin] | -| file://:0:0:0:0 | [summary] delegate call, parameter 4 of Join | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of Join] | -| file://:0:0:0:0 | [summary] delegate call, parameter 4 of Join | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of Join] | -| file://:0:0:0:0 | [summary] delegate call, parameter 4 of Join | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of Join] | -| file://:0:0:0:0 | [summary] delegate call, parameter 4 of Join | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of Join] | +| This.cs:28:13:28:21 | object creation of type Sub | normal | This.cs:28:13:28:21 | object creation of type Sub | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Lazy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Lazy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Lazy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Lazy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Lazy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Lazy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Run | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Run] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Run | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Run] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Run | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Run] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Run | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Run] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of Aggregate | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of Aggregate] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of Aggregate | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of Aggregate] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of Select | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of Select] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of Select | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of Select] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of Select | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of Select] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of Select | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of Select] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of Aggregate | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of Aggregate] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of Aggregate | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of Aggregate] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of Aggregate | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of Aggregate] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of Aggregate | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of Aggregate] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of SelectMany | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of SelectMany] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of SelectMany | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of SelectMany] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of SelectMany | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of SelectMany] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of SelectMany | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of SelectMany] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of ToDictionary | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of ToDictionary] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of ToDictionary | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of ToDictionary] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of ToLookup | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of ToLookup] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of ToLookup | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of ToLookup] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of Zip | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of Zip] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of Zip | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of Zip] | +| file://:0:0:0:0 | [summary] delegate call, parameter 3 of Aggregate | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 3 of Aggregate] | +| file://:0:0:0:0 | [summary] delegate call, parameter 3 of Aggregate | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 3 of Aggregate] | +| file://:0:0:0:0 | [summary] delegate call, parameter 3 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 3 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 3 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 3 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 3 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 3 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 3 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 3 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 4 of GroupJoin | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of GroupJoin] | +| file://:0:0:0:0 | [summary] delegate call, parameter 4 of GroupJoin | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of GroupJoin] | +| file://:0:0:0:0 | [summary] delegate call, parameter 4 of GroupJoin | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of GroupJoin] | +| file://:0:0:0:0 | [summary] delegate call, parameter 4 of GroupJoin | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of GroupJoin] | +| file://:0:0:0:0 | [summary] delegate call, parameter 4 of Join | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of Join] | +| file://:0:0:0:0 | [summary] delegate call, parameter 4 of Join | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of Join] | +| file://:0:0:0:0 | [summary] delegate call, parameter 4 of Join | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of Join] | +| file://:0:0:0:0 | [summary] delegate call, parameter 4 of Join | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of Join] | diff --git a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected index e9ba5973f50..2bd27156b17 100644 --- a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected +++ b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected @@ -119,36 +119,36 @@ edges | GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:15:80:19 | access to local variable sink3 | | GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) : String | GlobalDataFlow.cs:81:59:81:63 | access to local variable sink3 : String | | GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) : String | GlobalDataFlow.cs:136:29:136:33 | access to local variable sink3 : String | -| GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven [[]] : String | GlobalDataFlow.cs:81:22:81:93 | call to method First : String | +| GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven [element] : String | GlobalDataFlow.cs:81:22:81:93 | call to method First : String | | GlobalDataFlow.cs:81:22:81:93 | call to method First : String | GlobalDataFlow.cs:82:15:82:20 | access to local variable sink13 | | GlobalDataFlow.cs:81:22:81:93 | call to method First : String | GlobalDataFlow.cs:83:59:83:64 | access to local variable sink13 : String | -| GlobalDataFlow.cs:81:23:81:65 | (...) ... [[]] : String | GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven [[]] : String | -| GlobalDataFlow.cs:81:57:81:65 | { ..., ... } [[]] : String | GlobalDataFlow.cs:81:23:81:65 | (...) ... [[]] : String | -| GlobalDataFlow.cs:81:59:81:63 | access to local variable sink3 : String | GlobalDataFlow.cs:81:57:81:65 | { ..., ... } [[]] : String | -| GlobalDataFlow.cs:83:22:83:87 | call to method Select [[]] : String | GlobalDataFlow.cs:83:22:83:95 | call to method First : String | +| GlobalDataFlow.cs:81:23:81:65 | (...) ... [element] : String | GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven [element] : String | +| GlobalDataFlow.cs:81:57:81:65 | { ..., ... } [element] : String | GlobalDataFlow.cs:81:23:81:65 | (...) ... [element] : String | +| GlobalDataFlow.cs:81:59:81:63 | access to local variable sink3 : String | GlobalDataFlow.cs:81:57:81:65 | { ..., ... } [element] : String | +| GlobalDataFlow.cs:83:22:83:87 | call to method Select [element] : String | GlobalDataFlow.cs:83:22:83:95 | call to method First : String | | GlobalDataFlow.cs:83:22:83:95 | call to method First : String | GlobalDataFlow.cs:84:15:84:20 | access to local variable sink14 | | GlobalDataFlow.cs:83:22:83:95 | call to method First : String | GlobalDataFlow.cs:85:59:85:64 | access to local variable sink14 : String | | GlobalDataFlow.cs:83:22:83:95 | call to method First : String | GlobalDataFlow.cs:89:59:89:64 | access to local variable sink14 : String | | GlobalDataFlow.cs:83:22:83:95 | call to method First : String | GlobalDataFlow.cs:91:75:91:80 | access to local variable sink14 : String | -| GlobalDataFlow.cs:83:23:83:66 | (...) ... [[]] : String | GlobalDataFlow.cs:83:22:83:87 | call to method Select [[]] : String | -| GlobalDataFlow.cs:83:23:83:66 | (...) ... [[]] : String | GlobalDataFlow.cs:312:31:312:40 | sinkParam8 : String | -| GlobalDataFlow.cs:83:57:83:66 | { ..., ... } [[]] : String | GlobalDataFlow.cs:83:23:83:66 | (...) ... [[]] : String | -| GlobalDataFlow.cs:83:59:83:64 | access to local variable sink13 : String | GlobalDataFlow.cs:83:57:83:66 | { ..., ... } [[]] : String | -| GlobalDataFlow.cs:85:22:85:128 | call to method Zip [[]] : String | GlobalDataFlow.cs:85:22:85:136 | call to method First : String | +| GlobalDataFlow.cs:83:23:83:66 | (...) ... [element] : String | GlobalDataFlow.cs:83:22:83:87 | call to method Select [element] : String | +| GlobalDataFlow.cs:83:23:83:66 | (...) ... [element] : String | GlobalDataFlow.cs:312:31:312:40 | sinkParam8 : String | +| GlobalDataFlow.cs:83:57:83:66 | { ..., ... } [element] : String | GlobalDataFlow.cs:83:23:83:66 | (...) ... [element] : String | +| GlobalDataFlow.cs:83:59:83:64 | access to local variable sink13 : String | GlobalDataFlow.cs:83:57:83:66 | { ..., ... } [element] : String | +| GlobalDataFlow.cs:85:22:85:128 | call to method Zip [element] : String | GlobalDataFlow.cs:85:22:85:136 | call to method First : String | | GlobalDataFlow.cs:85:22:85:136 | call to method First : String | GlobalDataFlow.cs:86:15:86:20 | access to local variable sink15 | | GlobalDataFlow.cs:85:22:85:136 | call to method First : String | GlobalDataFlow.cs:87:106:87:111 | access to local variable sink15 : String | -| GlobalDataFlow.cs:85:23:85:66 | (...) ... [[]] : String | GlobalDataFlow.cs:85:22:85:128 | call to method Zip [[]] : String | -| GlobalDataFlow.cs:85:57:85:66 | { ..., ... } [[]] : String | GlobalDataFlow.cs:85:23:85:66 | (...) ... [[]] : String | -| GlobalDataFlow.cs:85:59:85:64 | access to local variable sink14 : String | GlobalDataFlow.cs:85:57:85:66 | { ..., ... } [[]] : String | -| GlobalDataFlow.cs:87:22:87:128 | call to method Zip [[]] : String | GlobalDataFlow.cs:87:22:87:136 | call to method First : String | +| GlobalDataFlow.cs:85:23:85:66 | (...) ... [element] : String | GlobalDataFlow.cs:85:22:85:128 | call to method Zip [element] : String | +| GlobalDataFlow.cs:85:57:85:66 | { ..., ... } [element] : String | GlobalDataFlow.cs:85:23:85:66 | (...) ... [element] : String | +| GlobalDataFlow.cs:85:59:85:64 | access to local variable sink14 : String | GlobalDataFlow.cs:85:57:85:66 | { ..., ... } [element] : String | +| GlobalDataFlow.cs:87:22:87:128 | call to method Zip [element] : String | GlobalDataFlow.cs:87:22:87:136 | call to method First : String | | GlobalDataFlow.cs:87:22:87:136 | call to method First : String | GlobalDataFlow.cs:88:15:88:20 | access to local variable sink16 | -| GlobalDataFlow.cs:87:70:87:113 | (...) ... [[]] : String | GlobalDataFlow.cs:87:22:87:128 | call to method Zip [[]] : String | -| GlobalDataFlow.cs:87:104:87:113 | { ..., ... } [[]] : String | GlobalDataFlow.cs:87:70:87:113 | (...) ... [[]] : String | -| GlobalDataFlow.cs:87:106:87:111 | access to local variable sink15 : String | GlobalDataFlow.cs:87:104:87:113 | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:87:70:87:113 | (...) ... [element] : String | GlobalDataFlow.cs:87:22:87:128 | call to method Zip [element] : String | +| GlobalDataFlow.cs:87:104:87:113 | { ..., ... } [element] : String | GlobalDataFlow.cs:87:70:87:113 | (...) ... [element] : String | +| GlobalDataFlow.cs:87:106:87:111 | access to local variable sink15 : String | GlobalDataFlow.cs:87:104:87:113 | { ..., ... } [element] : String | | GlobalDataFlow.cs:89:22:89:110 | call to method Aggregate : String | GlobalDataFlow.cs:90:15:90:20 | access to local variable sink17 | -| GlobalDataFlow.cs:89:23:89:66 | (...) ... [[]] : String | GlobalDataFlow.cs:89:22:89:110 | call to method Aggregate : String | -| GlobalDataFlow.cs:89:57:89:66 | { ..., ... } [[]] : String | GlobalDataFlow.cs:89:23:89:66 | (...) ... [[]] : String | -| GlobalDataFlow.cs:89:59:89:64 | access to local variable sink14 : String | GlobalDataFlow.cs:89:57:89:66 | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:89:23:89:66 | (...) ... [element] : String | GlobalDataFlow.cs:89:22:89:110 | call to method Aggregate : String | +| GlobalDataFlow.cs:89:57:89:66 | { ..., ... } [element] : String | GlobalDataFlow.cs:89:23:89:66 | (...) ... [element] : String | +| GlobalDataFlow.cs:89:59:89:64 | access to local variable sink14 : String | GlobalDataFlow.cs:89:57:89:66 | { ..., ... } [element] : String | | GlobalDataFlow.cs:91:22:91:110 | call to method Aggregate : String | GlobalDataFlow.cs:92:15:92:20 | access to local variable sink18 | | GlobalDataFlow.cs:91:22:91:110 | call to method Aggregate : String | GlobalDataFlow.cs:94:24:94:29 | access to local variable sink18 : String | | GlobalDataFlow.cs:91:22:91:110 | call to method Aggregate : String | GlobalDataFlow.cs:97:23:97:28 | access to local variable sink18 : String | @@ -165,42 +165,42 @@ edges | GlobalDataFlow.cs:154:21:154:25 | call to method Out : String | GlobalDataFlow.cs:155:15:155:19 | access to local variable sink6 | | GlobalDataFlow.cs:157:20:157:24 | SSA def(sink7) : String | GlobalDataFlow.cs:158:15:158:19 | access to local variable sink7 | | GlobalDataFlow.cs:160:20:160:24 | SSA def(sink8) : String | GlobalDataFlow.cs:161:15:161:19 | access to local variable sink8 | -| GlobalDataFlow.cs:162:22:162:31 | call to method OutYield [[]] : String | GlobalDataFlow.cs:162:22:162:39 | call to method First : String | +| GlobalDataFlow.cs:162:22:162:31 | call to method OutYield [element] : String | GlobalDataFlow.cs:162:22:162:39 | call to method First : String | | GlobalDataFlow.cs:162:22:162:39 | call to method First : String | GlobalDataFlow.cs:163:15:163:20 | access to local variable sink12 | | GlobalDataFlow.cs:164:22:164:43 | call to method TaintedParam : String | GlobalDataFlow.cs:165:15:165:20 | access to local variable sink23 | | GlobalDataFlow.cs:180:35:180:48 | "taint source" : String | GlobalDataFlow.cs:181:21:181:26 | delegate call : String | | GlobalDataFlow.cs:181:21:181:26 | delegate call : String | GlobalDataFlow.cs:182:15:182:19 | access to local variable sink9 | -| GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy [Value] : String | GlobalDataFlow.cs:190:22:190:48 | access to property Value : String | +| GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy [property Value] : String | GlobalDataFlow.cs:190:22:190:48 | access to property Value : String | | GlobalDataFlow.cs:190:22:190:48 | access to property Value : String | GlobalDataFlow.cs:191:15:191:20 | access to local variable sink10 | | GlobalDataFlow.cs:198:22:198:32 | access to property OutProperty : String | GlobalDataFlow.cs:199:15:199:20 | access to local variable sink19 | -| GlobalDataFlow.cs:208:38:208:61 | array creation of type String[] [[]] : String | GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [[]] : String | -| GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [[]] : String | GlobalDataFlow.cs:213:22:213:28 | access to local variable tainted [[]] : String | -| GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [[]] : String | GlobalDataFlow.cs:215:22:215:28 | access to local variable tainted [[]] : String | -| GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [[]] : String | GlobalDataFlow.cs:217:22:217:28 | access to local variable tainted [[]] : String | -| GlobalDataFlow.cs:208:44:208:61 | { ..., ... } [[]] : String | GlobalDataFlow.cs:208:38:208:61 | array creation of type String[] [[]] : String | -| GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:208:44:208:61 | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:208:38:208:61 | array creation of type String[] [element] : String | GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [element] : String | +| GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [element] : String | GlobalDataFlow.cs:213:22:213:28 | access to local variable tainted [element] : String | +| GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [element] : String | GlobalDataFlow.cs:215:22:215:28 | access to local variable tainted [element] : String | +| GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [element] : String | GlobalDataFlow.cs:217:22:217:28 | access to local variable tainted [element] : String | +| GlobalDataFlow.cs:208:44:208:61 | { ..., ... } [element] : String | GlobalDataFlow.cs:208:38:208:61 | array creation of type String[] [element] : String | +| GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:208:44:208:61 | { ..., ... } [element] : String | | GlobalDataFlow.cs:211:35:211:45 | sinkParam10 : String | GlobalDataFlow.cs:211:58:211:68 | access to parameter sinkParam10 | | GlobalDataFlow.cs:212:71:212:71 | x : String | GlobalDataFlow.cs:212:89:212:89 | access to parameter x : String | | GlobalDataFlow.cs:212:89:212:89 | access to parameter x : String | GlobalDataFlow.cs:318:32:318:41 | sinkParam9 : String | -| GlobalDataFlow.cs:213:22:213:28 | access to local variable tainted [[]] : String | GlobalDataFlow.cs:211:35:211:45 | sinkParam10 : String | -| GlobalDataFlow.cs:213:22:213:28 | access to local variable tainted [[]] : String | GlobalDataFlow.cs:213:22:213:39 | call to method Select [[]] : String | -| GlobalDataFlow.cs:213:22:213:39 | call to method Select [[]] : String | GlobalDataFlow.cs:213:22:213:47 | call to method First : String | +| GlobalDataFlow.cs:213:22:213:28 | access to local variable tainted [element] : String | GlobalDataFlow.cs:211:35:211:45 | sinkParam10 : String | +| GlobalDataFlow.cs:213:22:213:28 | access to local variable tainted [element] : String | GlobalDataFlow.cs:213:22:213:39 | call to method Select [element] : String | +| GlobalDataFlow.cs:213:22:213:39 | call to method Select [element] : String | GlobalDataFlow.cs:213:22:213:47 | call to method First : String | | GlobalDataFlow.cs:213:22:213:47 | call to method First : String | GlobalDataFlow.cs:214:15:214:20 | access to local variable sink24 | -| GlobalDataFlow.cs:215:22:215:28 | access to local variable tainted [[]] : String | GlobalDataFlow.cs:212:71:212:71 | x : String | -| GlobalDataFlow.cs:215:22:215:28 | access to local variable tainted [[]] : String | GlobalDataFlow.cs:215:22:215:39 | call to method Select [[]] : String | -| GlobalDataFlow.cs:215:22:215:39 | call to method Select [[]] : String | GlobalDataFlow.cs:215:22:215:47 | call to method First : String | +| GlobalDataFlow.cs:215:22:215:28 | access to local variable tainted [element] : String | GlobalDataFlow.cs:212:71:212:71 | x : String | +| GlobalDataFlow.cs:215:22:215:28 | access to local variable tainted [element] : String | GlobalDataFlow.cs:215:22:215:39 | call to method Select [element] : String | +| GlobalDataFlow.cs:215:22:215:39 | call to method Select [element] : String | GlobalDataFlow.cs:215:22:215:47 | call to method First : String | | GlobalDataFlow.cs:215:22:215:47 | call to method First : String | GlobalDataFlow.cs:216:15:216:20 | access to local variable sink25 | -| GlobalDataFlow.cs:217:22:217:28 | access to local variable tainted [[]] : String | GlobalDataFlow.cs:217:22:217:49 | call to method Select [[]] : String | -| GlobalDataFlow.cs:217:22:217:28 | access to local variable tainted [[]] : String | GlobalDataFlow.cs:324:32:324:42 | sinkParam11 : String | -| GlobalDataFlow.cs:217:22:217:49 | call to method Select [[]] : String | GlobalDataFlow.cs:217:22:217:57 | call to method First : String | +| GlobalDataFlow.cs:217:22:217:28 | access to local variable tainted [element] : String | GlobalDataFlow.cs:217:22:217:49 | call to method Select [element] : String | +| GlobalDataFlow.cs:217:22:217:28 | access to local variable tainted [element] : String | GlobalDataFlow.cs:324:32:324:42 | sinkParam11 : String | +| GlobalDataFlow.cs:217:22:217:49 | call to method Select [element] : String | GlobalDataFlow.cs:217:22:217:57 | call to method First : String | | GlobalDataFlow.cs:217:22:217:57 | call to method First : String | GlobalDataFlow.cs:218:15:218:20 | access to local variable sink26 | -| GlobalDataFlow.cs:238:20:238:49 | call to method Run [Result] : String | GlobalDataFlow.cs:239:22:239:25 | access to local variable task [Result] : String | -| GlobalDataFlow.cs:238:20:238:49 | call to method Run [Result] : String | GlobalDataFlow.cs:241:28:241:31 | access to local variable task [Result] : String | -| GlobalDataFlow.cs:238:35:238:48 | "taint source" : String | GlobalDataFlow.cs:238:20:238:49 | call to method Run [Result] : String | -| GlobalDataFlow.cs:239:22:239:25 | access to local variable task [Result] : String | GlobalDataFlow.cs:239:22:239:32 | access to property Result : String | +| GlobalDataFlow.cs:238:20:238:49 | call to method Run [property Result] : String | GlobalDataFlow.cs:239:22:239:25 | access to local variable task [property Result] : String | +| GlobalDataFlow.cs:238:20:238:49 | call to method Run [property Result] : String | GlobalDataFlow.cs:241:28:241:31 | access to local variable task [property Result] : String | +| GlobalDataFlow.cs:238:35:238:48 | "taint source" : String | GlobalDataFlow.cs:238:20:238:49 | call to method Run [property Result] : String | +| GlobalDataFlow.cs:239:22:239:25 | access to local variable task [property Result] : String | GlobalDataFlow.cs:239:22:239:32 | access to property Result : String | | GlobalDataFlow.cs:239:22:239:32 | access to property Result : String | GlobalDataFlow.cs:240:15:240:20 | access to local variable sink41 | | GlobalDataFlow.cs:241:22:241:31 | await ... : String | GlobalDataFlow.cs:242:15:242:20 | access to local variable sink42 | -| GlobalDataFlow.cs:241:28:241:31 | access to local variable task [Result] : String | GlobalDataFlow.cs:241:22:241:31 | await ... : String | +| GlobalDataFlow.cs:241:28:241:31 | access to local variable task [property Result] : String | GlobalDataFlow.cs:241:22:241:31 | await ... : String | | GlobalDataFlow.cs:254:26:254:35 | sinkParam0 : String | GlobalDataFlow.cs:256:16:256:25 | access to parameter sinkParam0 : String | | GlobalDataFlow.cs:254:26:254:35 | sinkParam0 : String | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam0 | | GlobalDataFlow.cs:256:16:256:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:254:26:254:35 | sinkParam0 : String | @@ -214,12 +214,12 @@ edges | GlobalDataFlow.cs:318:32:318:41 | sinkParam9 : String | GlobalDataFlow.cs:320:15:320:24 | access to parameter sinkParam9 | | GlobalDataFlow.cs:324:32:324:42 | sinkParam11 : String | GlobalDataFlow.cs:326:15:326:25 | access to parameter sinkParam11 | | GlobalDataFlow.cs:338:16:338:29 | "taint source" : String | GlobalDataFlow.cs:154:21:154:25 | call to method Out : String | -| GlobalDataFlow.cs:338:16:338:29 | "taint source" : String | GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy [Value] : String | +| GlobalDataFlow.cs:338:16:338:29 | "taint source" : String | GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy [property Value] : String | | GlobalDataFlow.cs:343:9:343:26 | SSA def(x) : String | GlobalDataFlow.cs:157:20:157:24 | SSA def(sink7) : String | | GlobalDataFlow.cs:343:13:343:26 | "taint source" : String | GlobalDataFlow.cs:343:9:343:26 | SSA def(x) : String | | GlobalDataFlow.cs:348:9:348:26 | SSA def(x) : String | GlobalDataFlow.cs:160:20:160:24 | SSA def(sink8) : String | | GlobalDataFlow.cs:348:13:348:26 | "taint source" : String | GlobalDataFlow.cs:348:9:348:26 | SSA def(x) : String | -| GlobalDataFlow.cs:354:22:354:35 | "taint source" : String | GlobalDataFlow.cs:162:22:162:31 | call to method OutYield [[]] : String | +| GlobalDataFlow.cs:354:22:354:35 | "taint source" : String | GlobalDataFlow.cs:162:22:162:31 | call to method OutYield [element] : String | | GlobalDataFlow.cs:379:41:379:41 | x : String | GlobalDataFlow.cs:381:11:381:11 | access to parameter x : String | | GlobalDataFlow.cs:379:41:379:41 | x : String | GlobalDataFlow.cs:381:11:381:11 | access to parameter x : String | | GlobalDataFlow.cs:381:11:381:11 | access to parameter x : String | GlobalDataFlow.cs:54:15:54:15 | x : String | @@ -235,19 +235,19 @@ edges | GlobalDataFlow.cs:402:16:402:21 | access to local variable sink11 : String | GlobalDataFlow.cs:164:22:164:43 | call to method TaintedParam : String | | GlobalDataFlow.cs:424:9:424:11 | value : String | GlobalDataFlow.cs:424:41:424:46 | access to local variable sink20 | | GlobalDataFlow.cs:435:22:435:35 | "taint source" : String | GlobalDataFlow.cs:198:22:198:32 | access to property OutProperty : String | -| GlobalDataFlow.cs:451:31:451:32 | [post] access to local variable sb [[]] : String | GlobalDataFlow.cs:452:22:452:23 | access to local variable sb [[]] : String | -| GlobalDataFlow.cs:451:35:451:48 | "taint source" : String | GlobalDataFlow.cs:451:31:451:32 | [post] access to local variable sb [[]] : String | -| GlobalDataFlow.cs:452:22:452:23 | access to local variable sb [[]] : String | GlobalDataFlow.cs:452:22:452:34 | call to method ToString : String | +| GlobalDataFlow.cs:451:31:451:32 | [post] access to local variable sb [element] : String | GlobalDataFlow.cs:452:22:452:23 | access to local variable sb [element] : String | +| GlobalDataFlow.cs:451:35:451:48 | "taint source" : String | GlobalDataFlow.cs:451:31:451:32 | [post] access to local variable sb [element] : String | +| GlobalDataFlow.cs:452:22:452:23 | access to local variable sb [element] : String | GlobalDataFlow.cs:452:22:452:34 | call to method ToString : String | | GlobalDataFlow.cs:452:22:452:34 | call to method ToString : String | GlobalDataFlow.cs:453:15:453:20 | access to local variable sink43 | | GlobalDataFlow.cs:462:22:462:65 | call to method Join : String | GlobalDataFlow.cs:463:15:463:20 | access to local variable sink44 | | GlobalDataFlow.cs:462:51:462:64 | "taint source" : String | GlobalDataFlow.cs:462:22:462:65 | call to method Join : String | -| GlobalDataFlow.cs:471:20:471:49 | call to method Run [Result] : String | GlobalDataFlow.cs:472:25:472:28 | access to local variable task [Result] : String | -| GlobalDataFlow.cs:471:35:471:48 | "taint source" : String | GlobalDataFlow.cs:471:20:471:49 | call to method Run [Result] : String | -| GlobalDataFlow.cs:472:25:472:28 | access to local variable task [Result] : String | GlobalDataFlow.cs:472:25:472:50 | call to method ConfigureAwait [m_configuredTaskAwaiter, m_task, Result] : String | -| GlobalDataFlow.cs:472:25:472:50 | call to method ConfigureAwait [m_configuredTaskAwaiter, m_task, Result] : String | GlobalDataFlow.cs:473:23:473:31 | access to local variable awaitable [m_configuredTaskAwaiter, m_task, Result] : String | -| GlobalDataFlow.cs:473:23:473:31 | access to local variable awaitable [m_configuredTaskAwaiter, m_task, Result] : String | GlobalDataFlow.cs:473:23:473:44 | call to method GetAwaiter [m_task, Result] : String | -| GlobalDataFlow.cs:473:23:473:44 | call to method GetAwaiter [m_task, Result] : String | GlobalDataFlow.cs:474:22:474:28 | access to local variable awaiter [m_task, Result] : String | -| GlobalDataFlow.cs:474:22:474:28 | access to local variable awaiter [m_task, Result] : String | GlobalDataFlow.cs:474:22:474:40 | call to method GetResult : String | +| GlobalDataFlow.cs:471:20:471:49 | call to method Run [property Result] : String | GlobalDataFlow.cs:472:25:472:28 | access to local variable task [property Result] : String | +| GlobalDataFlow.cs:471:35:471:48 | "taint source" : String | GlobalDataFlow.cs:471:20:471:49 | call to method Run [property Result] : String | +| GlobalDataFlow.cs:472:25:472:28 | access to local variable task [property Result] : String | GlobalDataFlow.cs:472:25:472:50 | call to method ConfigureAwait [field m_configuredTaskAwaiter, field m_task, property Result] : String | +| GlobalDataFlow.cs:472:25:472:50 | call to method ConfigureAwait [field m_configuredTaskAwaiter, field m_task, property Result] : String | GlobalDataFlow.cs:473:23:473:31 | access to local variable awaitable [field m_configuredTaskAwaiter, field m_task, property Result] : String | +| GlobalDataFlow.cs:473:23:473:31 | access to local variable awaitable [field m_configuredTaskAwaiter, field m_task, property Result] : String | GlobalDataFlow.cs:473:23:473:44 | call to method GetAwaiter [field m_task, property Result] : String | +| GlobalDataFlow.cs:473:23:473:44 | call to method GetAwaiter [field m_task, property Result] : String | GlobalDataFlow.cs:474:22:474:28 | access to local variable awaiter [field m_task, property Result] : String | +| GlobalDataFlow.cs:474:22:474:28 | access to local variable awaiter [field m_task, property Result] : String | GlobalDataFlow.cs:474:22:474:40 | call to method GetResult : String | | GlobalDataFlow.cs:474:22:474:40 | call to method GetResult : String | GlobalDataFlow.cs:475:15:475:20 | access to local variable sink45 | | GlobalDataFlow.cs:480:53:480:55 | arg : String | GlobalDataFlow.cs:484:15:484:17 | access to parameter arg : String | | GlobalDataFlow.cs:483:21:483:21 | s : String | GlobalDataFlow.cs:483:32:483:32 | access to parameter s | @@ -339,33 +339,33 @@ nodes | GlobalDataFlow.cs:79:19:79:23 | access to local variable sink2 : String | semmle.label | access to local variable sink2 : String | | GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) : String | semmle.label | SSA def(sink3) : String | | GlobalDataFlow.cs:80:15:80:19 | access to local variable sink3 | semmle.label | access to local variable sink3 | -| GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven [[]] : String | semmle.label | call to method SelectEven [[]] : String | +| GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven [element] : String | semmle.label | call to method SelectEven [element] : String | | GlobalDataFlow.cs:81:22:81:93 | call to method First : String | semmle.label | call to method First : String | -| GlobalDataFlow.cs:81:23:81:65 | (...) ... [[]] : String | semmle.label | (...) ... [[]] : String | -| GlobalDataFlow.cs:81:57:81:65 | { ..., ... } [[]] : String | semmle.label | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:81:23:81:65 | (...) ... [element] : String | semmle.label | (...) ... [element] : String | +| GlobalDataFlow.cs:81:57:81:65 | { ..., ... } [element] : String | semmle.label | { ..., ... } [element] : String | | GlobalDataFlow.cs:81:59:81:63 | access to local variable sink3 : String | semmle.label | access to local variable sink3 : String | | GlobalDataFlow.cs:82:15:82:20 | access to local variable sink13 | semmle.label | access to local variable sink13 | -| GlobalDataFlow.cs:83:22:83:87 | call to method Select [[]] : String | semmle.label | call to method Select [[]] : String | +| GlobalDataFlow.cs:83:22:83:87 | call to method Select [element] : String | semmle.label | call to method Select [element] : String | | GlobalDataFlow.cs:83:22:83:95 | call to method First : String | semmle.label | call to method First : String | -| GlobalDataFlow.cs:83:23:83:66 | (...) ... [[]] : String | semmle.label | (...) ... [[]] : String | -| GlobalDataFlow.cs:83:57:83:66 | { ..., ... } [[]] : String | semmle.label | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:83:23:83:66 | (...) ... [element] : String | semmle.label | (...) ... [element] : String | +| GlobalDataFlow.cs:83:57:83:66 | { ..., ... } [element] : String | semmle.label | { ..., ... } [element] : String | | GlobalDataFlow.cs:83:59:83:64 | access to local variable sink13 : String | semmle.label | access to local variable sink13 : String | | GlobalDataFlow.cs:84:15:84:20 | access to local variable sink14 | semmle.label | access to local variable sink14 | -| GlobalDataFlow.cs:85:22:85:128 | call to method Zip [[]] : String | semmle.label | call to method Zip [[]] : String | +| GlobalDataFlow.cs:85:22:85:128 | call to method Zip [element] : String | semmle.label | call to method Zip [element] : String | | GlobalDataFlow.cs:85:22:85:136 | call to method First : String | semmle.label | call to method First : String | -| GlobalDataFlow.cs:85:23:85:66 | (...) ... [[]] : String | semmle.label | (...) ... [[]] : String | -| GlobalDataFlow.cs:85:57:85:66 | { ..., ... } [[]] : String | semmle.label | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:85:23:85:66 | (...) ... [element] : String | semmle.label | (...) ... [element] : String | +| GlobalDataFlow.cs:85:57:85:66 | { ..., ... } [element] : String | semmle.label | { ..., ... } [element] : String | | GlobalDataFlow.cs:85:59:85:64 | access to local variable sink14 : String | semmle.label | access to local variable sink14 : String | | GlobalDataFlow.cs:86:15:86:20 | access to local variable sink15 | semmle.label | access to local variable sink15 | -| GlobalDataFlow.cs:87:22:87:128 | call to method Zip [[]] : String | semmle.label | call to method Zip [[]] : String | +| GlobalDataFlow.cs:87:22:87:128 | call to method Zip [element] : String | semmle.label | call to method Zip [element] : String | | GlobalDataFlow.cs:87:22:87:136 | call to method First : String | semmle.label | call to method First : String | -| GlobalDataFlow.cs:87:70:87:113 | (...) ... [[]] : String | semmle.label | (...) ... [[]] : String | -| GlobalDataFlow.cs:87:104:87:113 | { ..., ... } [[]] : String | semmle.label | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:87:70:87:113 | (...) ... [element] : String | semmle.label | (...) ... [element] : String | +| GlobalDataFlow.cs:87:104:87:113 | { ..., ... } [element] : String | semmle.label | { ..., ... } [element] : String | | GlobalDataFlow.cs:87:106:87:111 | access to local variable sink15 : String | semmle.label | access to local variable sink15 : String | | GlobalDataFlow.cs:88:15:88:20 | access to local variable sink16 | semmle.label | access to local variable sink16 | | GlobalDataFlow.cs:89:22:89:110 | call to method Aggregate : String | semmle.label | call to method Aggregate : String | -| GlobalDataFlow.cs:89:23:89:66 | (...) ... [[]] : String | semmle.label | (...) ... [[]] : String | -| GlobalDataFlow.cs:89:57:89:66 | { ..., ... } [[]] : String | semmle.label | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:89:23:89:66 | (...) ... [element] : String | semmle.label | (...) ... [element] : String | +| GlobalDataFlow.cs:89:57:89:66 | { ..., ... } [element] : String | semmle.label | { ..., ... } [element] : String | | GlobalDataFlow.cs:89:59:89:64 | access to local variable sink14 : String | semmle.label | access to local variable sink14 : String | | GlobalDataFlow.cs:90:15:90:20 | access to local variable sink17 | semmle.label | access to local variable sink17 | | GlobalDataFlow.cs:91:22:91:110 | call to method Aggregate : String | semmle.label | call to method Aggregate : String | @@ -389,7 +389,7 @@ nodes | GlobalDataFlow.cs:158:15:158:19 | access to local variable sink7 | semmle.label | access to local variable sink7 | | GlobalDataFlow.cs:160:20:160:24 | SSA def(sink8) : String | semmle.label | SSA def(sink8) : String | | GlobalDataFlow.cs:161:15:161:19 | access to local variable sink8 | semmle.label | access to local variable sink8 | -| GlobalDataFlow.cs:162:22:162:31 | call to method OutYield [[]] : String | semmle.label | call to method OutYield [[]] : String | +| GlobalDataFlow.cs:162:22:162:31 | call to method OutYield [element] : String | semmle.label | call to method OutYield [element] : String | | GlobalDataFlow.cs:162:22:162:39 | call to method First : String | semmle.label | call to method First : String | | GlobalDataFlow.cs:163:15:163:20 | access to local variable sink12 | semmle.label | access to local variable sink12 | | GlobalDataFlow.cs:164:22:164:43 | call to method TaintedParam : String | semmle.label | call to method TaintedParam : String | @@ -397,38 +397,38 @@ nodes | GlobalDataFlow.cs:180:35:180:48 | "taint source" : String | semmle.label | "taint source" : String | | GlobalDataFlow.cs:181:21:181:26 | delegate call : String | semmle.label | delegate call : String | | GlobalDataFlow.cs:182:15:182:19 | access to local variable sink9 | semmle.label | access to local variable sink9 | -| GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy [Value] : String | semmle.label | object creation of type Lazy [Value] : String | +| GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy [property Value] : String | semmle.label | object creation of type Lazy [property Value] : String | | GlobalDataFlow.cs:190:22:190:48 | access to property Value : String | semmle.label | access to property Value : String | | GlobalDataFlow.cs:191:15:191:20 | access to local variable sink10 | semmle.label | access to local variable sink10 | | GlobalDataFlow.cs:198:22:198:32 | access to property OutProperty : String | semmle.label | access to property OutProperty : String | | GlobalDataFlow.cs:199:15:199:20 | access to local variable sink19 | semmle.label | access to local variable sink19 | -| GlobalDataFlow.cs:208:38:208:61 | array creation of type String[] [[]] : String | semmle.label | array creation of type String[] [[]] : String | -| GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [[]] : String | semmle.label | call to method AsQueryable [[]] : String | -| GlobalDataFlow.cs:208:44:208:61 | { ..., ... } [[]] : String | semmle.label | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:208:38:208:61 | array creation of type String[] [element] : String | semmle.label | array creation of type String[] [element] : String | +| GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable [element] : String | semmle.label | call to method AsQueryable [element] : String | +| GlobalDataFlow.cs:208:44:208:61 | { ..., ... } [element] : String | semmle.label | { ..., ... } [element] : String | | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | semmle.label | "taint source" : String | | GlobalDataFlow.cs:211:35:211:45 | sinkParam10 : String | semmle.label | sinkParam10 : String | | GlobalDataFlow.cs:211:58:211:68 | access to parameter sinkParam10 | semmle.label | access to parameter sinkParam10 | | GlobalDataFlow.cs:212:71:212:71 | x : String | semmle.label | x : String | | GlobalDataFlow.cs:212:89:212:89 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:213:22:213:28 | access to local variable tainted [[]] : String | semmle.label | access to local variable tainted [[]] : String | -| GlobalDataFlow.cs:213:22:213:39 | call to method Select [[]] : String | semmle.label | call to method Select [[]] : String | +| GlobalDataFlow.cs:213:22:213:28 | access to local variable tainted [element] : String | semmle.label | access to local variable tainted [element] : String | +| GlobalDataFlow.cs:213:22:213:39 | call to method Select [element] : String | semmle.label | call to method Select [element] : String | | GlobalDataFlow.cs:213:22:213:47 | call to method First : String | semmle.label | call to method First : String | | GlobalDataFlow.cs:214:15:214:20 | access to local variable sink24 | semmle.label | access to local variable sink24 | -| GlobalDataFlow.cs:215:22:215:28 | access to local variable tainted [[]] : String | semmle.label | access to local variable tainted [[]] : String | -| GlobalDataFlow.cs:215:22:215:39 | call to method Select [[]] : String | semmle.label | call to method Select [[]] : String | +| GlobalDataFlow.cs:215:22:215:28 | access to local variable tainted [element] : String | semmle.label | access to local variable tainted [element] : String | +| GlobalDataFlow.cs:215:22:215:39 | call to method Select [element] : String | semmle.label | call to method Select [element] : String | | GlobalDataFlow.cs:215:22:215:47 | call to method First : String | semmle.label | call to method First : String | | GlobalDataFlow.cs:216:15:216:20 | access to local variable sink25 | semmle.label | access to local variable sink25 | -| GlobalDataFlow.cs:217:22:217:28 | access to local variable tainted [[]] : String | semmle.label | access to local variable tainted [[]] : String | -| GlobalDataFlow.cs:217:22:217:49 | call to method Select [[]] : String | semmle.label | call to method Select [[]] : String | +| GlobalDataFlow.cs:217:22:217:28 | access to local variable tainted [element] : String | semmle.label | access to local variable tainted [element] : String | +| GlobalDataFlow.cs:217:22:217:49 | call to method Select [element] : String | semmle.label | call to method Select [element] : String | | GlobalDataFlow.cs:217:22:217:57 | call to method First : String | semmle.label | call to method First : String | | GlobalDataFlow.cs:218:15:218:20 | access to local variable sink26 | semmle.label | access to local variable sink26 | -| GlobalDataFlow.cs:238:20:238:49 | call to method Run [Result] : String | semmle.label | call to method Run [Result] : String | +| GlobalDataFlow.cs:238:20:238:49 | call to method Run [property Result] : String | semmle.label | call to method Run [property Result] : String | | GlobalDataFlow.cs:238:35:238:48 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:239:22:239:25 | access to local variable task [Result] : String | semmle.label | access to local variable task [Result] : String | +| GlobalDataFlow.cs:239:22:239:25 | access to local variable task [property Result] : String | semmle.label | access to local variable task [property Result] : String | | GlobalDataFlow.cs:239:22:239:32 | access to property Result : String | semmle.label | access to property Result : String | | GlobalDataFlow.cs:240:15:240:20 | access to local variable sink41 | semmle.label | access to local variable sink41 | | GlobalDataFlow.cs:241:22:241:31 | await ... : String | semmle.label | await ... : String | -| GlobalDataFlow.cs:241:28:241:31 | access to local variable task [Result] : String | semmle.label | access to local variable task [Result] : String | +| GlobalDataFlow.cs:241:28:241:31 | access to local variable task [property Result] : String | semmle.label | access to local variable task [property Result] : String | | GlobalDataFlow.cs:242:15:242:20 | access to local variable sink42 | semmle.label | access to local variable sink42 | | GlobalDataFlow.cs:254:26:254:35 | sinkParam0 : String | semmle.label | sinkParam0 : String | | GlobalDataFlow.cs:256:16:256:25 | access to parameter sinkParam0 : String | semmle.label | access to parameter sinkParam0 : String | @@ -473,21 +473,21 @@ nodes | GlobalDataFlow.cs:424:9:424:11 | value : String | semmle.label | value : String | | GlobalDataFlow.cs:424:41:424:46 | access to local variable sink20 | semmle.label | access to local variable sink20 | | GlobalDataFlow.cs:435:22:435:35 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:451:31:451:32 | [post] access to local variable sb [[]] : String | semmle.label | [post] access to local variable sb [[]] : String | +| GlobalDataFlow.cs:451:31:451:32 | [post] access to local variable sb [element] : String | semmle.label | [post] access to local variable sb [element] : String | | GlobalDataFlow.cs:451:35:451:48 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:452:22:452:23 | access to local variable sb [[]] : String | semmle.label | access to local variable sb [[]] : String | +| GlobalDataFlow.cs:452:22:452:23 | access to local variable sb [element] : String | semmle.label | access to local variable sb [element] : String | | GlobalDataFlow.cs:452:22:452:34 | call to method ToString : String | semmle.label | call to method ToString : String | | GlobalDataFlow.cs:453:15:453:20 | access to local variable sink43 | semmle.label | access to local variable sink43 | | GlobalDataFlow.cs:462:22:462:65 | call to method Join : String | semmle.label | call to method Join : String | | GlobalDataFlow.cs:462:51:462:64 | "taint source" : String | semmle.label | "taint source" : String | | GlobalDataFlow.cs:463:15:463:20 | access to local variable sink44 | semmle.label | access to local variable sink44 | -| GlobalDataFlow.cs:471:20:471:49 | call to method Run [Result] : String | semmle.label | call to method Run [Result] : String | +| GlobalDataFlow.cs:471:20:471:49 | call to method Run [property Result] : String | semmle.label | call to method Run [property Result] : String | | GlobalDataFlow.cs:471:35:471:48 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:472:25:472:28 | access to local variable task [Result] : String | semmle.label | access to local variable task [Result] : String | -| GlobalDataFlow.cs:472:25:472:50 | call to method ConfigureAwait [m_configuredTaskAwaiter, m_task, Result] : String | semmle.label | call to method ConfigureAwait [m_configuredTaskAwaiter, m_task, Result] : String | -| GlobalDataFlow.cs:473:23:473:31 | access to local variable awaitable [m_configuredTaskAwaiter, m_task, Result] : String | semmle.label | access to local variable awaitable [m_configuredTaskAwaiter, m_task, Result] : String | -| GlobalDataFlow.cs:473:23:473:44 | call to method GetAwaiter [m_task, Result] : String | semmle.label | call to method GetAwaiter [m_task, Result] : String | -| GlobalDataFlow.cs:474:22:474:28 | access to local variable awaiter [m_task, Result] : String | semmle.label | access to local variable awaiter [m_task, Result] : String | +| GlobalDataFlow.cs:472:25:472:28 | access to local variable task [property Result] : String | semmle.label | access to local variable task [property Result] : String | +| GlobalDataFlow.cs:472:25:472:50 | call to method ConfigureAwait [field m_configuredTaskAwaiter, field m_task, property Result] : String | semmle.label | call to method ConfigureAwait [field m_configuredTaskAwaiter, field m_task, property Result] : String | +| GlobalDataFlow.cs:473:23:473:31 | access to local variable awaitable [field m_configuredTaskAwaiter, field m_task, property Result] : String | semmle.label | access to local variable awaitable [field m_configuredTaskAwaiter, field m_task, property Result] : String | +| GlobalDataFlow.cs:473:23:473:44 | call to method GetAwaiter [field m_task, property Result] : String | semmle.label | call to method GetAwaiter [field m_task, property Result] : String | +| GlobalDataFlow.cs:474:22:474:28 | access to local variable awaiter [field m_task, property Result] : String | semmle.label | access to local variable awaiter [field m_task, property Result] : String | | GlobalDataFlow.cs:474:22:474:40 | call to method GetResult : String | semmle.label | call to method GetResult : String | | GlobalDataFlow.cs:475:15:475:20 | access to local variable sink45 | semmle.label | access to local variable sink45 | | GlobalDataFlow.cs:480:53:480:55 | arg : String | semmle.label | arg : String | diff --git a/csharp/ql/test/library-tests/dataflow/library/FlowSummaries.expected b/csharp/ql/test/library-tests/dataflow/library/FlowSummaries.expected index 8ea7f7d9875..5a0c76baed0 100644 --- a/csharp/ql/test/library-tests/dataflow/library/FlowSummaries.expected +++ b/csharp/ql/test/library-tests/dataflow/library/FlowSummaries.expected @@ -1,746 +1,746 @@ -| MS.Internal.Xml.Linq.ComponentModel.XDeferredAxis<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.().Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 0 -> return [Item1] | true | -| System.().Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 1 -> return [Item2] | true | -| System.().Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 2 -> return [Item3] | true | -| System.().Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 3 -> return [Item4] | true | -| System.().Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 4 -> return [Item5] | true | -| System.().Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 5 -> return [Item6] | true | -| System.().Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 6 -> return [Item7] | true | -| System.().Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 7 -> return [Item8] | true | -| System.().Create(T1, T2, T3, T4, T5, T6, T7) | parameter 0 -> return [Item1] | true | -| System.().Create(T1, T2, T3, T4, T5, T6, T7) | parameter 1 -> return [Item2] | true | -| System.().Create(T1, T2, T3, T4, T5, T6, T7) | parameter 2 -> return [Item3] | true | -| System.().Create(T1, T2, T3, T4, T5, T6, T7) | parameter 3 -> return [Item4] | true | -| System.().Create(T1, T2, T3, T4, T5, T6, T7) | parameter 4 -> return [Item5] | true | -| System.().Create(T1, T2, T3, T4, T5, T6, T7) | parameter 5 -> return [Item6] | true | -| System.().Create(T1, T2, T3, T4, T5, T6, T7) | parameter 6 -> return [Item7] | true | -| System.().Create(T1, T2, T3, T4, T5, T6) | parameter 0 -> return [Item1] | true | -| System.().Create(T1, T2, T3, T4, T5, T6) | parameter 1 -> return [Item2] | true | -| System.().Create(T1, T2, T3, T4, T5, T6) | parameter 2 -> return [Item3] | true | -| System.().Create(T1, T2, T3, T4, T5, T6) | parameter 3 -> return [Item4] | true | -| System.().Create(T1, T2, T3, T4, T5, T6) | parameter 4 -> return [Item5] | true | -| System.().Create(T1, T2, T3, T4, T5, T6) | parameter 5 -> return [Item6] | true | -| System.().Create(T1, T2, T3, T4, T5) | parameter 0 -> return [Item1] | true | -| System.().Create(T1, T2, T3, T4, T5) | parameter 1 -> return [Item2] | true | -| System.().Create(T1, T2, T3, T4, T5) | parameter 2 -> return [Item3] | true | -| System.().Create(T1, T2, T3, T4, T5) | parameter 3 -> return [Item4] | true | -| System.().Create(T1, T2, T3, T4, T5) | parameter 4 -> return [Item5] | true | -| System.().Create(T1, T2, T3, T4) | parameter 0 -> return [Item1] | true | -| System.().Create(T1, T2, T3, T4) | parameter 1 -> return [Item2] | true | -| System.().Create(T1, T2, T3, T4) | parameter 2 -> return [Item3] | true | -| System.().Create(T1, T2, T3, T4) | parameter 3 -> return [Item4] | true | -| System.().Create(T1, T2, T3) | parameter 0 -> return [Item1] | true | -| System.().Create(T1, T2, T3) | parameter 1 -> return [Item2] | true | -| System.().Create(T1, T2, T3) | parameter 2 -> return [Item3] | true | -| System.().Create(T1, T2) | parameter 0 -> return [Item1] | true | -| System.().Create(T1, T2) | parameter 1 -> return [Item2] | true | -| System.().Create(T1) | parameter 0 -> return [Item1] | true | -| System.(T1).ValueTuple(T1) | parameter 0 -> return [Item1] | true | -| System.(T1).get_Item(int) | this parameter [Item1] -> return | true | -| System.(T1,T2).ValueTuple(T1, T2) | parameter 0 -> return [Item1] | true | -| System.(T1,T2).ValueTuple(T1, T2) | parameter 1 -> return [Item2] | true | -| System.(T1,T2).get_Item(int) | this parameter [Item1] -> return | true | -| System.(T1,T2).get_Item(int) | this parameter [Item2] -> return | true | -| System.(T1,T2,T3).ValueTuple(T1, T2, T3) | parameter 0 -> return [Item1] | true | -| System.(T1,T2,T3).ValueTuple(T1, T2, T3) | parameter 1 -> return [Item2] | true | -| System.(T1,T2,T3).ValueTuple(T1, T2, T3) | parameter 2 -> return [Item3] | true | -| System.(T1,T2,T3).get_Item(int) | this parameter [Item1] -> return | true | -| System.(T1,T2,T3).get_Item(int) | this parameter [Item2] -> return | true | -| System.(T1,T2,T3).get_Item(int) | this parameter [Item3] -> return | true | -| System.(T1,T2,T3,T4).ValueTuple(T1, T2, T3, T4) | parameter 0 -> return [Item1] | true | -| System.(T1,T2,T3,T4).ValueTuple(T1, T2, T3, T4) | parameter 1 -> return [Item2] | true | -| System.(T1,T2,T3,T4).ValueTuple(T1, T2, T3, T4) | parameter 2 -> return [Item3] | true | -| System.(T1,T2,T3,T4).ValueTuple(T1, T2, T3, T4) | parameter 3 -> return [Item4] | true | -| System.(T1,T2,T3,T4).get_Item(int) | this parameter [Item1] -> return | true | -| System.(T1,T2,T3,T4).get_Item(int) | this parameter [Item2] -> return | true | -| System.(T1,T2,T3,T4).get_Item(int) | this parameter [Item3] -> return | true | -| System.(T1,T2,T3,T4).get_Item(int) | this parameter [Item4] -> return | true | -| System.(T1,T2,T3,T4,T5).ValueTuple(T1, T2, T3, T4, T5) | parameter 0 -> return [Item1] | true | -| System.(T1,T2,T3,T4,T5).ValueTuple(T1, T2, T3, T4, T5) | parameter 1 -> return [Item2] | true | -| System.(T1,T2,T3,T4,T5).ValueTuple(T1, T2, T3, T4, T5) | parameter 2 -> return [Item3] | true | -| System.(T1,T2,T3,T4,T5).ValueTuple(T1, T2, T3, T4, T5) | parameter 3 -> return [Item4] | true | -| System.(T1,T2,T3,T4,T5).ValueTuple(T1, T2, T3, T4, T5) | parameter 4 -> return [Item5] | true | -| System.(T1,T2,T3,T4,T5).get_Item(int) | this parameter [Item1] -> return | true | -| System.(T1,T2,T3,T4,T5).get_Item(int) | this parameter [Item2] -> return | true | -| System.(T1,T2,T3,T4,T5).get_Item(int) | this parameter [Item3] -> return | true | -| System.(T1,T2,T3,T4,T5).get_Item(int) | this parameter [Item4] -> return | true | -| System.(T1,T2,T3,T4,T5).get_Item(int) | this parameter [Item5] -> return | true | -| System.(T1,T2,T3,T4,T5,T6).ValueTuple(T1, T2, T3, T4, T5, T6) | parameter 0 -> return [Item1] | true | -| System.(T1,T2,T3,T4,T5,T6).ValueTuple(T1, T2, T3, T4, T5, T6) | parameter 1 -> return [Item2] | true | -| System.(T1,T2,T3,T4,T5,T6).ValueTuple(T1, T2, T3, T4, T5, T6) | parameter 2 -> return [Item3] | true | -| System.(T1,T2,T3,T4,T5,T6).ValueTuple(T1, T2, T3, T4, T5, T6) | parameter 3 -> return [Item4] | true | -| System.(T1,T2,T3,T4,T5,T6).ValueTuple(T1, T2, T3, T4, T5, T6) | parameter 4 -> return [Item5] | true | -| System.(T1,T2,T3,T4,T5,T6).ValueTuple(T1, T2, T3, T4, T5, T6) | parameter 5 -> return [Item6] | true | -| System.(T1,T2,T3,T4,T5,T6).get_Item(int) | this parameter [Item1] -> return | true | -| System.(T1,T2,T3,T4,T5,T6).get_Item(int) | this parameter [Item2] -> return | true | -| System.(T1,T2,T3,T4,T5,T6).get_Item(int) | this parameter [Item3] -> return | true | -| System.(T1,T2,T3,T4,T5,T6).get_Item(int) | this parameter [Item4] -> return | true | -| System.(T1,T2,T3,T4,T5,T6).get_Item(int) | this parameter [Item5] -> return | true | -| System.(T1,T2,T3,T4,T5,T6).get_Item(int) | this parameter [Item6] -> return | true | -| System.(T1,T2,T3,T4,T5,T6,T7).ValueTuple(T1, T2, T3, T4, T5, T6, T7) | parameter 0 -> return [Item1] | true | -| System.(T1,T2,T3,T4,T5,T6,T7).ValueTuple(T1, T2, T3, T4, T5, T6, T7) | parameter 1 -> return [Item2] | true | -| System.(T1,T2,T3,T4,T5,T6,T7).ValueTuple(T1, T2, T3, T4, T5, T6, T7) | parameter 2 -> return [Item3] | true | -| System.(T1,T2,T3,T4,T5,T6,T7).ValueTuple(T1, T2, T3, T4, T5, T6, T7) | parameter 3 -> return [Item4] | true | -| System.(T1,T2,T3,T4,T5,T6,T7).ValueTuple(T1, T2, T3, T4, T5, T6, T7) | parameter 4 -> return [Item5] | true | -| System.(T1,T2,T3,T4,T5,T6,T7).ValueTuple(T1, T2, T3, T4, T5, T6, T7) | parameter 5 -> return [Item6] | true | -| System.(T1,T2,T3,T4,T5,T6,T7).ValueTuple(T1, T2, T3, T4, T5, T6, T7) | parameter 6 -> return [Item7] | true | -| System.(T1,T2,T3,T4,T5,T6,T7).get_Item(int) | this parameter [Item1] -> return | true | -| System.(T1,T2,T3,T4,T5,T6,T7).get_Item(int) | this parameter [Item2] -> return | true | -| System.(T1,T2,T3,T4,T5,T6,T7).get_Item(int) | this parameter [Item3] -> return | true | -| System.(T1,T2,T3,T4,T5,T6,T7).get_Item(int) | this parameter [Item4] -> return | true | -| System.(T1,T2,T3,T4,T5,T6,T7).get_Item(int) | this parameter [Item5] -> return | true | -| System.(T1,T2,T3,T4,T5,T6,T7).get_Item(int) | this parameter [Item6] -> return | true | -| System.(T1,T2,T3,T4,T5,T6,T7).get_Item(int) | this parameter [Item7] -> return | true | -| System.Array.Add(object) | parameter 0 -> this parameter [[]] | true | -| System.Array.AsReadOnly(T[]) | parameter 0 [[]] -> return [[]] | true | -| System.Array.Clone() | parameter 0 [[]] -> return [[]] | true | -| System.Array.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Array.CopyTo(Array, long) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Array.Find(T[], Predicate) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Array.Find(T[], Predicate) | parameter 0 [[]] -> return | true | -| System.Array.FindAll(T[], Predicate) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Array.FindAll(T[], Predicate) | parameter 0 [[]] -> return | true | -| System.Array.FindLast(T[], Predicate) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Array.FindLast(T[], Predicate) | parameter 0 [[]] -> return | true | -| System.Array.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Array.Insert(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Array.Reverse(Array) | parameter 0 [[]] -> return [[]] | true | -| System.Array.Reverse(Array, int, int) | parameter 0 [[]] -> return [[]] | true | -| System.Array.Reverse(T[]) | parameter 0 [[]] -> return [[]] | true | -| System.Array.Reverse(T[], int, int) | parameter 0 [[]] -> return [[]] | true | -| System.Array.get_Item(int) | this parameter [[]] -> return | true | -| System.Array.set_Item(int, object) | parameter 1 -> this parameter [[]] | true | +| MS.Internal.Xml.Linq.ComponentModel.XDeferredAxis<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.().Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 0 -> return [field Item1] | true | +| System.().Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 1 -> return [field Item2] | true | +| System.().Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 2 -> return [field Item3] | true | +| System.().Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 3 -> return [field Item4] | true | +| System.().Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 4 -> return [field Item5] | true | +| System.().Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 5 -> return [field Item6] | true | +| System.().Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 6 -> return [field Item7] | true | +| System.().Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 7 -> return [field Item8] | true | +| System.().Create(T1, T2, T3, T4, T5, T6, T7) | parameter 0 -> return [field Item1] | true | +| System.().Create(T1, T2, T3, T4, T5, T6, T7) | parameter 1 -> return [field Item2] | true | +| System.().Create(T1, T2, T3, T4, T5, T6, T7) | parameter 2 -> return [field Item3] | true | +| System.().Create(T1, T2, T3, T4, T5, T6, T7) | parameter 3 -> return [field Item4] | true | +| System.().Create(T1, T2, T3, T4, T5, T6, T7) | parameter 4 -> return [field Item5] | true | +| System.().Create(T1, T2, T3, T4, T5, T6, T7) | parameter 5 -> return [field Item6] | true | +| System.().Create(T1, T2, T3, T4, T5, T6, T7) | parameter 6 -> return [field Item7] | true | +| System.().Create(T1, T2, T3, T4, T5, T6) | parameter 0 -> return [field Item1] | true | +| System.().Create(T1, T2, T3, T4, T5, T6) | parameter 1 -> return [field Item2] | true | +| System.().Create(T1, T2, T3, T4, T5, T6) | parameter 2 -> return [field Item3] | true | +| System.().Create(T1, T2, T3, T4, T5, T6) | parameter 3 -> return [field Item4] | true | +| System.().Create(T1, T2, T3, T4, T5, T6) | parameter 4 -> return [field Item5] | true | +| System.().Create(T1, T2, T3, T4, T5, T6) | parameter 5 -> return [field Item6] | true | +| System.().Create(T1, T2, T3, T4, T5) | parameter 0 -> return [field Item1] | true | +| System.().Create(T1, T2, T3, T4, T5) | parameter 1 -> return [field Item2] | true | +| System.().Create(T1, T2, T3, T4, T5) | parameter 2 -> return [field Item3] | true | +| System.().Create(T1, T2, T3, T4, T5) | parameter 3 -> return [field Item4] | true | +| System.().Create(T1, T2, T3, T4, T5) | parameter 4 -> return [field Item5] | true | +| System.().Create(T1, T2, T3, T4) | parameter 0 -> return [field Item1] | true | +| System.().Create(T1, T2, T3, T4) | parameter 1 -> return [field Item2] | true | +| System.().Create(T1, T2, T3, T4) | parameter 2 -> return [field Item3] | true | +| System.().Create(T1, T2, T3, T4) | parameter 3 -> return [field Item4] | true | +| System.().Create(T1, T2, T3) | parameter 0 -> return [field Item1] | true | +| System.().Create(T1, T2, T3) | parameter 1 -> return [field Item2] | true | +| System.().Create(T1, T2, T3) | parameter 2 -> return [field Item3] | true | +| System.().Create(T1, T2) | parameter 0 -> return [field Item1] | true | +| System.().Create(T1, T2) | parameter 1 -> return [field Item2] | true | +| System.().Create(T1) | parameter 0 -> return [field Item1] | true | +| System.(T1).ValueTuple(T1) | parameter 0 -> return [field Item1] | true | +| System.(T1).get_Item(int) | this parameter [field Item1] -> return | true | +| System.(T1,T2).ValueTuple(T1, T2) | parameter 0 -> return [field Item1] | true | +| System.(T1,T2).ValueTuple(T1, T2) | parameter 1 -> return [field Item2] | true | +| System.(T1,T2).get_Item(int) | this parameter [field Item1] -> return | true | +| System.(T1,T2).get_Item(int) | this parameter [field Item2] -> return | true | +| System.(T1,T2,T3).ValueTuple(T1, T2, T3) | parameter 0 -> return [field Item1] | true | +| System.(T1,T2,T3).ValueTuple(T1, T2, T3) | parameter 1 -> return [field Item2] | true | +| System.(T1,T2,T3).ValueTuple(T1, T2, T3) | parameter 2 -> return [field Item3] | true | +| System.(T1,T2,T3).get_Item(int) | this parameter [field Item1] -> return | true | +| System.(T1,T2,T3).get_Item(int) | this parameter [field Item2] -> return | true | +| System.(T1,T2,T3).get_Item(int) | this parameter [field Item3] -> return | true | +| System.(T1,T2,T3,T4).ValueTuple(T1, T2, T3, T4) | parameter 0 -> return [field Item1] | true | +| System.(T1,T2,T3,T4).ValueTuple(T1, T2, T3, T4) | parameter 1 -> return [field Item2] | true | +| System.(T1,T2,T3,T4).ValueTuple(T1, T2, T3, T4) | parameter 2 -> return [field Item3] | true | +| System.(T1,T2,T3,T4).ValueTuple(T1, T2, T3, T4) | parameter 3 -> return [field Item4] | true | +| System.(T1,T2,T3,T4).get_Item(int) | this parameter [field Item1] -> return | true | +| System.(T1,T2,T3,T4).get_Item(int) | this parameter [field Item2] -> return | true | +| System.(T1,T2,T3,T4).get_Item(int) | this parameter [field Item3] -> return | true | +| System.(T1,T2,T3,T4).get_Item(int) | this parameter [field Item4] -> return | true | +| System.(T1,T2,T3,T4,T5).ValueTuple(T1, T2, T3, T4, T5) | parameter 0 -> return [field Item1] | true | +| System.(T1,T2,T3,T4,T5).ValueTuple(T1, T2, T3, T4, T5) | parameter 1 -> return [field Item2] | true | +| System.(T1,T2,T3,T4,T5).ValueTuple(T1, T2, T3, T4, T5) | parameter 2 -> return [field Item3] | true | +| System.(T1,T2,T3,T4,T5).ValueTuple(T1, T2, T3, T4, T5) | parameter 3 -> return [field Item4] | true | +| System.(T1,T2,T3,T4,T5).ValueTuple(T1, T2, T3, T4, T5) | parameter 4 -> return [field Item5] | true | +| System.(T1,T2,T3,T4,T5).get_Item(int) | this parameter [field Item1] -> return | true | +| System.(T1,T2,T3,T4,T5).get_Item(int) | this parameter [field Item2] -> return | true | +| System.(T1,T2,T3,T4,T5).get_Item(int) | this parameter [field Item3] -> return | true | +| System.(T1,T2,T3,T4,T5).get_Item(int) | this parameter [field Item4] -> return | true | +| System.(T1,T2,T3,T4,T5).get_Item(int) | this parameter [field Item5] -> return | true | +| System.(T1,T2,T3,T4,T5,T6).ValueTuple(T1, T2, T3, T4, T5, T6) | parameter 0 -> return [field Item1] | true | +| System.(T1,T2,T3,T4,T5,T6).ValueTuple(T1, T2, T3, T4, T5, T6) | parameter 1 -> return [field Item2] | true | +| System.(T1,T2,T3,T4,T5,T6).ValueTuple(T1, T2, T3, T4, T5, T6) | parameter 2 -> return [field Item3] | true | +| System.(T1,T2,T3,T4,T5,T6).ValueTuple(T1, T2, T3, T4, T5, T6) | parameter 3 -> return [field Item4] | true | +| System.(T1,T2,T3,T4,T5,T6).ValueTuple(T1, T2, T3, T4, T5, T6) | parameter 4 -> return [field Item5] | true | +| System.(T1,T2,T3,T4,T5,T6).ValueTuple(T1, T2, T3, T4, T5, T6) | parameter 5 -> return [field Item6] | true | +| System.(T1,T2,T3,T4,T5,T6).get_Item(int) | this parameter [field Item1] -> return | true | +| System.(T1,T2,T3,T4,T5,T6).get_Item(int) | this parameter [field Item2] -> return | true | +| System.(T1,T2,T3,T4,T5,T6).get_Item(int) | this parameter [field Item3] -> return | true | +| System.(T1,T2,T3,T4,T5,T6).get_Item(int) | this parameter [field Item4] -> return | true | +| System.(T1,T2,T3,T4,T5,T6).get_Item(int) | this parameter [field Item5] -> return | true | +| System.(T1,T2,T3,T4,T5,T6).get_Item(int) | this parameter [field Item6] -> return | true | +| System.(T1,T2,T3,T4,T5,T6,T7).ValueTuple(T1, T2, T3, T4, T5, T6, T7) | parameter 0 -> return [field Item1] | true | +| System.(T1,T2,T3,T4,T5,T6,T7).ValueTuple(T1, T2, T3, T4, T5, T6, T7) | parameter 1 -> return [field Item2] | true | +| System.(T1,T2,T3,T4,T5,T6,T7).ValueTuple(T1, T2, T3, T4, T5, T6, T7) | parameter 2 -> return [field Item3] | true | +| System.(T1,T2,T3,T4,T5,T6,T7).ValueTuple(T1, T2, T3, T4, T5, T6, T7) | parameter 3 -> return [field Item4] | true | +| System.(T1,T2,T3,T4,T5,T6,T7).ValueTuple(T1, T2, T3, T4, T5, T6, T7) | parameter 4 -> return [field Item5] | true | +| System.(T1,T2,T3,T4,T5,T6,T7).ValueTuple(T1, T2, T3, T4, T5, T6, T7) | parameter 5 -> return [field Item6] | true | +| System.(T1,T2,T3,T4,T5,T6,T7).ValueTuple(T1, T2, T3, T4, T5, T6, T7) | parameter 6 -> return [field Item7] | true | +| System.(T1,T2,T3,T4,T5,T6,T7).get_Item(int) | this parameter [field Item1] -> return | true | +| System.(T1,T2,T3,T4,T5,T6,T7).get_Item(int) | this parameter [field Item2] -> return | true | +| System.(T1,T2,T3,T4,T5,T6,T7).get_Item(int) | this parameter [field Item3] -> return | true | +| System.(T1,T2,T3,T4,T5,T6,T7).get_Item(int) | this parameter [field Item4] -> return | true | +| System.(T1,T2,T3,T4,T5,T6,T7).get_Item(int) | this parameter [field Item5] -> return | true | +| System.(T1,T2,T3,T4,T5,T6,T7).get_Item(int) | this parameter [field Item6] -> return | true | +| System.(T1,T2,T3,T4,T5,T6,T7).get_Item(int) | this parameter [field Item7] -> return | true | +| System.Array.Add(object) | parameter 0 -> this parameter [element] | true | +| System.Array.AsReadOnly(T[]) | parameter 0 [element] -> return [element] | true | +| System.Array.Clone() | parameter 0 [element] -> return [element] | true | +| System.Array.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Array.CopyTo(Array, long) | this parameter [element] -> parameter 0 [element] | true | +| System.Array.Find(T[], Predicate) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Array.Find(T[], Predicate) | parameter 0 [element] -> return | true | +| System.Array.FindAll(T[], Predicate) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Array.FindAll(T[], Predicate) | parameter 0 [element] -> return | true | +| System.Array.FindLast(T[], Predicate) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Array.FindLast(T[], Predicate) | parameter 0 [element] -> return | true | +| System.Array.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Array.Insert(int, object) | parameter 1 -> this parameter [element] | true | +| System.Array.Reverse(Array) | parameter 0 [element] -> return [element] | true | +| System.Array.Reverse(Array, int, int) | parameter 0 [element] -> return [element] | true | +| System.Array.Reverse(T[]) | parameter 0 [element] -> return [element] | true | +| System.Array.Reverse(T[], int, int) | parameter 0 [element] -> return [element] | true | +| System.Array.get_Item(int) | this parameter [element] -> return | true | +| System.Array.set_Item(int, object) | parameter 1 -> this parameter [element] | true | | System.Boolean.Parse(string) | parameter 0 -> return | false | | System.Boolean.TryParse(string, out bool) | parameter 0 -> parameter 1 | false | | System.Boolean.TryParse(string, out bool) | parameter 0 -> return | false | -| System.Collections.ArrayList.Add(object) | parameter 0 -> this parameter [[]] | true | -| System.Collections.ArrayList.AddRange(ICollection) | parameter 0 [[]] -> this parameter [[]] | true | -| System.Collections.ArrayList.Clone() | parameter 0 [[]] -> return [[]] | true | -| System.Collections.ArrayList.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.ArrayList.FixedSize(ArrayList) | parameter 0 [[]] -> return [[]] | true | -| System.Collections.ArrayList.FixedSize(IList) | parameter 0 [[]] -> return [[]] | true | -| System.Collections.ArrayList.FixedSizeArrayList.Add(object) | parameter 0 -> this parameter [[]] | true | -| System.Collections.ArrayList.FixedSizeArrayList.AddRange(ICollection) | parameter 0 [[]] -> this parameter [[]] | true | -| System.Collections.ArrayList.FixedSizeArrayList.Clone() | parameter 0 [[]] -> return [[]] | true | -| System.Collections.ArrayList.FixedSizeArrayList.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.ArrayList.FixedSizeArrayList.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.ArrayList.FixedSizeArrayList.GetEnumerator(int, int) | this parameter [[]] -> return [Current] | true | -| System.Collections.ArrayList.FixedSizeArrayList.GetRange(int, int) | parameter 0 [[]] -> return [[]] | true | -| System.Collections.ArrayList.FixedSizeArrayList.Insert(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Collections.ArrayList.FixedSizeArrayList.InsertRange(int, ICollection) | parameter 1 [[]] -> this parameter [[]] | true | -| System.Collections.ArrayList.FixedSizeArrayList.Reverse(int, int) | parameter 0 [[]] -> return [[]] | true | -| System.Collections.ArrayList.FixedSizeArrayList.get_Item(int) | this parameter [[]] -> return | true | -| System.Collections.ArrayList.FixedSizeArrayList.set_Item(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Collections.ArrayList.FixedSizeList.Add(object) | parameter 0 -> this parameter [[]] | true | -| System.Collections.ArrayList.FixedSizeList.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.ArrayList.FixedSizeList.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.ArrayList.FixedSizeList.Insert(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Collections.ArrayList.FixedSizeList.get_Item(int) | this parameter [[]] -> return | true | -| System.Collections.ArrayList.FixedSizeList.set_Item(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Collections.ArrayList.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.ArrayList.GetEnumerator(int, int) | this parameter [[]] -> return [Current] | true | -| System.Collections.ArrayList.GetRange(int, int) | parameter 0 [[]] -> return [[]] | true | -| System.Collections.ArrayList.IListWrapper.Add(object) | parameter 0 -> this parameter [[]] | true | -| System.Collections.ArrayList.IListWrapper.AddRange(ICollection) | parameter 0 [[]] -> this parameter [[]] | true | -| System.Collections.ArrayList.IListWrapper.Clone() | parameter 0 [[]] -> return [[]] | true | -| System.Collections.ArrayList.IListWrapper.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.ArrayList.IListWrapper.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.ArrayList.IListWrapper.GetEnumerator(int, int) | this parameter [[]] -> return [Current] | true | -| System.Collections.ArrayList.IListWrapper.GetRange(int, int) | parameter 0 [[]] -> return [[]] | true | -| System.Collections.ArrayList.IListWrapper.Insert(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Collections.ArrayList.IListWrapper.InsertRange(int, ICollection) | parameter 1 [[]] -> this parameter [[]] | true | -| System.Collections.ArrayList.IListWrapper.Reverse(int, int) | parameter 0 [[]] -> return [[]] | true | -| System.Collections.ArrayList.IListWrapper.get_Item(int) | this parameter [[]] -> return | true | -| System.Collections.ArrayList.IListWrapper.set_Item(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Collections.ArrayList.Insert(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Collections.ArrayList.InsertRange(int, ICollection) | parameter 1 [[]] -> this parameter [[]] | true | -| System.Collections.ArrayList.Range.Add(object) | parameter 0 -> this parameter [[]] | true | -| System.Collections.ArrayList.Range.AddRange(ICollection) | parameter 0 [[]] -> this parameter [[]] | true | -| System.Collections.ArrayList.Range.Clone() | parameter 0 [[]] -> return [[]] | true | -| System.Collections.ArrayList.Range.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.ArrayList.Range.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.ArrayList.Range.GetEnumerator(int, int) | this parameter [[]] -> return [Current] | true | -| System.Collections.ArrayList.Range.GetRange(int, int) | parameter 0 [[]] -> return [[]] | true | -| System.Collections.ArrayList.Range.Insert(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Collections.ArrayList.Range.InsertRange(int, ICollection) | parameter 1 [[]] -> this parameter [[]] | true | -| System.Collections.ArrayList.Range.Reverse(int, int) | parameter 0 [[]] -> return [[]] | true | -| System.Collections.ArrayList.Range.get_Item(int) | this parameter [[]] -> return | true | -| System.Collections.ArrayList.Range.set_Item(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Collections.ArrayList.ReadOnlyArrayList.Add(object) | parameter 0 -> this parameter [[]] | true | -| System.Collections.ArrayList.ReadOnlyArrayList.AddRange(ICollection) | parameter 0 [[]] -> this parameter [[]] | true | -| System.Collections.ArrayList.ReadOnlyArrayList.Clone() | parameter 0 [[]] -> return [[]] | true | -| System.Collections.ArrayList.ReadOnlyArrayList.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.ArrayList.ReadOnlyArrayList.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.ArrayList.ReadOnlyArrayList.GetEnumerator(int, int) | this parameter [[]] -> return [Current] | true | -| System.Collections.ArrayList.ReadOnlyArrayList.GetRange(int, int) | parameter 0 [[]] -> return [[]] | true | -| System.Collections.ArrayList.ReadOnlyArrayList.Insert(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Collections.ArrayList.ReadOnlyArrayList.InsertRange(int, ICollection) | parameter 1 [[]] -> this parameter [[]] | true | -| System.Collections.ArrayList.ReadOnlyArrayList.Reverse(int, int) | parameter 0 [[]] -> return [[]] | true | -| System.Collections.ArrayList.ReadOnlyArrayList.get_Item(int) | this parameter [[]] -> return | true | -| System.Collections.ArrayList.ReadOnlyArrayList.set_Item(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Collections.ArrayList.ReadOnlyList.Add(object) | parameter 0 -> this parameter [[]] | true | -| System.Collections.ArrayList.ReadOnlyList.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.ArrayList.ReadOnlyList.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.ArrayList.ReadOnlyList.Insert(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Collections.ArrayList.ReadOnlyList.get_Item(int) | this parameter [[]] -> return | true | -| System.Collections.ArrayList.ReadOnlyList.set_Item(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Collections.ArrayList.Repeat(object, int) | parameter 0 -> return [[]] | true | -| System.Collections.ArrayList.Reverse() | parameter 0 [[]] -> return [[]] | true | -| System.Collections.ArrayList.Reverse(int, int) | parameter 0 [[]] -> return [[]] | true | -| System.Collections.ArrayList.SyncArrayList.Add(object) | parameter 0 -> this parameter [[]] | true | -| System.Collections.ArrayList.SyncArrayList.AddRange(ICollection) | parameter 0 [[]] -> this parameter [[]] | true | -| System.Collections.ArrayList.SyncArrayList.Clone() | parameter 0 [[]] -> return [[]] | true | -| System.Collections.ArrayList.SyncArrayList.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.ArrayList.SyncArrayList.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.ArrayList.SyncArrayList.GetEnumerator(int, int) | this parameter [[]] -> return [Current] | true | -| System.Collections.ArrayList.SyncArrayList.GetRange(int, int) | parameter 0 [[]] -> return [[]] | true | -| System.Collections.ArrayList.SyncArrayList.Insert(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Collections.ArrayList.SyncArrayList.InsertRange(int, ICollection) | parameter 1 [[]] -> this parameter [[]] | true | -| System.Collections.ArrayList.SyncArrayList.Reverse(int, int) | parameter 0 [[]] -> return [[]] | true | -| System.Collections.ArrayList.SyncArrayList.get_Item(int) | this parameter [[]] -> return | true | -| System.Collections.ArrayList.SyncArrayList.set_Item(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Collections.ArrayList.SyncIList.Add(object) | parameter 0 -> this parameter [[]] | true | -| System.Collections.ArrayList.SyncIList.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.ArrayList.SyncIList.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.ArrayList.SyncIList.Insert(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Collections.ArrayList.SyncIList.get_Item(int) | this parameter [[]] -> return | true | -| System.Collections.ArrayList.SyncIList.set_Item(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Collections.ArrayList.get_Item(int) | this parameter [[]] -> return | true | -| System.Collections.ArrayList.set_Item(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Collections.BitArray.Clone() | parameter 0 [[]] -> return [[]] | true | -| System.Collections.BitArray.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.BitArray.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.CollectionBase.Add(object) | parameter 0 -> this parameter [[]] | true | -| System.Collections.CollectionBase.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.CollectionBase.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.CollectionBase.Insert(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Collections.CollectionBase.get_Item(int) | this parameter [[]] -> return | true | -| System.Collections.CollectionBase.set_Item(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Collections.Concurrent.BlockingCollection<>.d__68.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Concurrent.BlockingCollection<>.Add(T) | parameter 0 -> this parameter [[]] | true | -| System.Collections.Concurrent.BlockingCollection<>.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Concurrent.BlockingCollection<>.CopyTo(T[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Concurrent.BlockingCollection<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Concurrent.ConcurrentBag<>.Add(T) | parameter 0 -> this parameter [[]] | true | -| System.Collections.Concurrent.ConcurrentBag<>.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Concurrent.ConcurrentBag<>.CopyTo(T[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Concurrent.ConcurrentBag<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(KeyValuePair) | parameter 0 -> this parameter [[]] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(KeyValuePair) | parameter 0 [Key] -> this parameter [[], Key] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(KeyValuePair) | parameter 0 [Value] -> this parameter [[], Value] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(TKey, TValue) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(TKey, TValue) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(object, object) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(object, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(IEnumerable>) | parameter 0 [[], Key] -> return [[], Key] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(IEnumerable>) | parameter 0 [[], Value] -> return [[], Value] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(IEnumerable>, IEqualityComparer) | parameter 0 [[], Key] -> return [[], Key] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(IEnumerable>, IEqualityComparer) | parameter 0 [[], Value] -> return [[], Value] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(int, IEnumerable>, IEqualityComparer) | parameter 1 [[], Key] -> return [[], Key] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(int, IEnumerable>, IEqualityComparer) | parameter 1 [[], Value] -> return [[], Value] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.CopyTo(KeyValuePair[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.get_Item(TKey) | this parameter [[], Value] -> return | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.get_Item(object) | this parameter [[], Value] -> return | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.get_Keys() | this parameter [[], Key] -> return [[]] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.get_Values() | this parameter [[], Value] -> return [[]] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.set_Item(TKey, TValue) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.set_Item(TKey, TValue) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.set_Item(object, object) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.set_Item(object, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.Concurrent.ConcurrentQueue<>.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Concurrent.ConcurrentQueue<>.CopyTo(T[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Concurrent.ConcurrentQueue<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Concurrent.ConcurrentStack<>.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Concurrent.ConcurrentStack<>.CopyTo(T[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Concurrent.ConcurrentStack<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Concurrent.IProducerConsumerCollection<>.CopyTo(T[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Concurrent.OrderablePartitioner<>.EnumerableDropIndices.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Concurrent.Partitioner.d__7.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Concurrent.Partitioner.d__10.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Concurrent.Partitioner.DynamicPartitionerForArray<>.InternalPartitionEnumerable.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Concurrent.Partitioner.DynamicPartitionerForIEnumerable<>.InternalPartitionEnumerable.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Concurrent.Partitioner.DynamicPartitionerForIList<>.InternalPartitionEnumerable.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.DictionaryBase.Add(object, object) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.DictionaryBase.Add(object, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.DictionaryBase.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.DictionaryBase.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.DictionaryBase.get_Item(object) | this parameter [[], Value] -> return | true | -| System.Collections.DictionaryBase.get_Keys() | this parameter [[], Key] -> return [[]] | true | -| System.Collections.DictionaryBase.get_Values() | this parameter [[], Value] -> return [[]] | true | -| System.Collections.DictionaryBase.set_Item(object, object) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.DictionaryBase.set_Item(object, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.EmptyReadOnlyDictionaryInternal.Add(object, object) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.EmptyReadOnlyDictionaryInternal.Add(object, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.EmptyReadOnlyDictionaryInternal.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.EmptyReadOnlyDictionaryInternal.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.EmptyReadOnlyDictionaryInternal.get_Item(object) | this parameter [[], Value] -> return | true | -| System.Collections.EmptyReadOnlyDictionaryInternal.get_Keys() | this parameter [[], Key] -> return [[]] | true | -| System.Collections.EmptyReadOnlyDictionaryInternal.get_Values() | this parameter [[], Value] -> return [[]] | true | -| System.Collections.EmptyReadOnlyDictionaryInternal.set_Item(object, object) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.EmptyReadOnlyDictionaryInternal.set_Item(object, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.Generic.Dictionary<,>.Add(KeyValuePair) | parameter 0 -> this parameter [[]] | true | -| System.Collections.Generic.Dictionary<,>.Add(KeyValuePair) | parameter 0 [Key] -> this parameter [[], Key] | true | -| System.Collections.Generic.Dictionary<,>.Add(KeyValuePair) | parameter 0 [Value] -> this parameter [[], Value] | true | -| System.Collections.Generic.Dictionary<,>.Add(TKey, TValue) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.Generic.Dictionary<,>.Add(TKey, TValue) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.Generic.Dictionary<,>.Add(object, object) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.Generic.Dictionary<,>.Add(object, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.Generic.Dictionary<,>.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Generic.Dictionary<,>.CopyTo(KeyValuePair[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Generic.Dictionary<,>.Dictionary(IDictionary) | parameter 0 [[], Key] -> return [[], Key] | true | -| System.Collections.Generic.Dictionary<,>.Dictionary(IDictionary) | parameter 0 [[], Value] -> return [[], Value] | true | -| System.Collections.Generic.Dictionary<,>.Dictionary(IDictionary, IEqualityComparer) | parameter 0 [[], Key] -> return [[], Key] | true | -| System.Collections.Generic.Dictionary<,>.Dictionary(IDictionary, IEqualityComparer) | parameter 0 [[], Value] -> return [[], Value] | true | -| System.Collections.Generic.Dictionary<,>.Dictionary(IEnumerable>) | parameter 0 [[], Key] -> return [[], Key] | true | -| System.Collections.Generic.Dictionary<,>.Dictionary(IEnumerable>) | parameter 0 [[], Value] -> return [[], Value] | true | -| System.Collections.Generic.Dictionary<,>.Dictionary(IEnumerable>, IEqualityComparer) | parameter 0 [[], Key] -> return [[], Key] | true | -| System.Collections.Generic.Dictionary<,>.Dictionary(IEnumerable>, IEqualityComparer) | parameter 0 [[], Value] -> return [[], Value] | true | -| System.Collections.Generic.Dictionary<,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Generic.Dictionary<,>.KeyCollection.Add(TKey) | parameter 0 -> this parameter [[]] | true | -| System.Collections.Generic.Dictionary<,>.KeyCollection.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Generic.Dictionary<,>.KeyCollection.CopyTo(TKey[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Generic.Dictionary<,>.KeyCollection.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Generic.Dictionary<,>.ValueCollection.Add(TValue) | parameter 0 -> this parameter [[]] | true | -| System.Collections.Generic.Dictionary<,>.ValueCollection.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Generic.Dictionary<,>.ValueCollection.CopyTo(TValue[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Generic.Dictionary<,>.ValueCollection.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Generic.Dictionary<,>.get_Item(TKey) | this parameter [[], Value] -> return | true | -| System.Collections.Generic.Dictionary<,>.get_Item(object) | this parameter [[], Value] -> return | true | -| System.Collections.Generic.Dictionary<,>.get_Keys() | this parameter [[], Key] -> return [[]] | true | -| System.Collections.Generic.Dictionary<,>.get_Values() | this parameter [[], Value] -> return [[]] | true | -| System.Collections.Generic.Dictionary<,>.set_Item(TKey, TValue) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.Generic.Dictionary<,>.set_Item(TKey, TValue) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.Generic.Dictionary<,>.set_Item(object, object) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.Generic.Dictionary<,>.set_Item(object, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.Generic.HashSet<>.Add(T) | parameter 0 -> this parameter [[]] | true | -| System.Collections.Generic.HashSet<>.CopyTo(T[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Generic.HashSet<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Generic.ICollection<>.Add(T) | parameter 0 -> this parameter [[]] | true | -| System.Collections.Generic.ICollection<>.CopyTo(T[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Generic.IDictionary<,>.Add(TKey, TValue) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.Generic.IDictionary<,>.Add(TKey, TValue) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.Generic.IDictionary<,>.get_Item(TKey) | this parameter [[], Value] -> return | true | -| System.Collections.Generic.IDictionary<,>.get_Keys() | this parameter [[], Key] -> return [[]] | true | -| System.Collections.Generic.IDictionary<,>.get_Values() | this parameter [[], Value] -> return [[]] | true | -| System.Collections.Generic.IDictionary<,>.set_Item(TKey, TValue) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.Generic.IDictionary<,>.set_Item(TKey, TValue) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.Generic.IList<>.Insert(int, T) | parameter 1 -> this parameter [[]] | true | -| System.Collections.Generic.IList<>.get_Item(int) | this parameter [[]] -> return | true | -| System.Collections.Generic.IList<>.set_Item(int, T) | parameter 1 -> this parameter [[]] | true | -| System.Collections.Generic.ISet<>.Add(T) | parameter 0 -> this parameter [[]] | true | -| System.Collections.Generic.KeyValuePair<,>.KeyValuePair() | parameter 0 -> return [Key] | true | -| System.Collections.Generic.KeyValuePair<,>.KeyValuePair() | parameter 1 -> return [Value] | true | -| System.Collections.Generic.KeyValuePair<,>.KeyValuePair(TKey, TValue) | parameter 0 -> return [Key] | true | -| System.Collections.Generic.KeyValuePair<,>.KeyValuePair(TKey, TValue) | parameter 1 -> return [Value] | true | -| System.Collections.Generic.LinkedList<>.Add(T) | parameter 0 -> this parameter [[]] | true | -| System.Collections.Generic.LinkedList<>.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Generic.LinkedList<>.CopyTo(T[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Generic.LinkedList<>.Find(T) | this parameter [[]] -> return | true | -| System.Collections.Generic.LinkedList<>.FindLast(T) | this parameter [[]] -> return | true | -| System.Collections.Generic.LinkedList<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Generic.List<>.Add(T) | parameter 0 -> this parameter [[]] | true | -| System.Collections.Generic.List<>.Add(object) | parameter 0 -> this parameter [[]] | true | -| System.Collections.Generic.List<>.AddRange(IEnumerable) | parameter 0 [[]] -> this parameter [[]] | true | -| System.Collections.Generic.List<>.AsReadOnly() | parameter 0 [[]] -> return [[]] | true | -| System.Collections.Generic.List<>.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Generic.List<>.CopyTo(T[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Generic.List<>.Find(Predicate) | this parameter [[]] -> parameter 0 of delegate parameter 0 | true | -| System.Collections.Generic.List<>.Find(Predicate) | this parameter [[]] -> return | true | -| System.Collections.Generic.List<>.FindAll(Predicate) | this parameter [[]] -> parameter 0 of delegate parameter 0 | true | -| System.Collections.Generic.List<>.FindAll(Predicate) | this parameter [[]] -> return | true | -| System.Collections.Generic.List<>.FindLast(Predicate) | this parameter [[]] -> parameter 0 of delegate parameter 0 | true | -| System.Collections.Generic.List<>.FindLast(Predicate) | this parameter [[]] -> return | true | -| System.Collections.Generic.List<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Generic.List<>.GetRange(int, int) | parameter 0 [[]] -> return [[]] | true | -| System.Collections.Generic.List<>.Insert(int, T) | parameter 1 -> this parameter [[]] | true | -| System.Collections.Generic.List<>.Insert(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Collections.Generic.List<>.InsertRange(int, IEnumerable) | parameter 1 [[]] -> this parameter [[]] | true | -| System.Collections.Generic.List<>.Reverse() | parameter 0 [[]] -> return [[]] | true | -| System.Collections.Generic.List<>.Reverse(int, int) | parameter 0 [[]] -> return [[]] | true | -| System.Collections.Generic.List<>.get_Item(int) | this parameter [[]] -> return | true | -| System.Collections.Generic.List<>.set_Item(int, T) | parameter 1 -> this parameter [[]] | true | -| System.Collections.Generic.List<>.set_Item(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Collections.Generic.Queue<>.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Generic.Queue<>.CopyTo(T[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Generic.Queue<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Generic.Queue<>.Peek() | this parameter [[]] -> return | true | -| System.Collections.Generic.SortedDictionary<,>.Add(KeyValuePair) | parameter 0 -> this parameter [[]] | true | -| System.Collections.Generic.SortedDictionary<,>.Add(KeyValuePair) | parameter 0 [Key] -> this parameter [[], Key] | true | -| System.Collections.Generic.SortedDictionary<,>.Add(KeyValuePair) | parameter 0 [Value] -> this parameter [[], Value] | true | -| System.Collections.Generic.SortedDictionary<,>.Add(TKey, TValue) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.Generic.SortedDictionary<,>.Add(TKey, TValue) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.Generic.SortedDictionary<,>.Add(object, object) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.Generic.SortedDictionary<,>.Add(object, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.Generic.SortedDictionary<,>.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Generic.SortedDictionary<,>.CopyTo(KeyValuePair[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Generic.SortedDictionary<,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Generic.SortedDictionary<,>.KeyCollection.Add(TKey) | parameter 0 -> this parameter [[]] | true | -| System.Collections.Generic.SortedDictionary<,>.KeyCollection.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Generic.SortedDictionary<,>.KeyCollection.CopyTo(TKey[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Generic.SortedDictionary<,>.KeyCollection.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Generic.SortedDictionary<,>.SortedDictionary(IDictionary) | parameter 0 [[], Key] -> return [[], Key] | true | -| System.Collections.Generic.SortedDictionary<,>.SortedDictionary(IDictionary) | parameter 0 [[], Value] -> return [[], Value] | true | -| System.Collections.Generic.SortedDictionary<,>.SortedDictionary(IDictionary, IComparer) | parameter 0 [[], Key] -> return [[], Key] | true | -| System.Collections.Generic.SortedDictionary<,>.SortedDictionary(IDictionary, IComparer) | parameter 0 [[], Value] -> return [[], Value] | true | -| System.Collections.Generic.SortedDictionary<,>.ValueCollection.Add(TValue) | parameter 0 -> this parameter [[]] | true | -| System.Collections.Generic.SortedDictionary<,>.ValueCollection.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Generic.SortedDictionary<,>.ValueCollection.CopyTo(TValue[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Generic.SortedDictionary<,>.ValueCollection.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Generic.SortedDictionary<,>.get_Item(TKey) | this parameter [[], Value] -> return | true | -| System.Collections.Generic.SortedDictionary<,>.get_Item(object) | this parameter [[], Value] -> return | true | -| System.Collections.Generic.SortedDictionary<,>.get_Keys() | this parameter [[], Key] -> return [[]] | true | -| System.Collections.Generic.SortedDictionary<,>.get_Values() | this parameter [[], Value] -> return [[]] | true | -| System.Collections.Generic.SortedDictionary<,>.set_Item(TKey, TValue) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.Generic.SortedDictionary<,>.set_Item(TKey, TValue) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.Generic.SortedDictionary<,>.set_Item(object, object) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.Generic.SortedDictionary<,>.set_Item(object, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.Generic.SortedList<,>.Add(KeyValuePair) | parameter 0 -> this parameter [[]] | true | -| System.Collections.Generic.SortedList<,>.Add(KeyValuePair) | parameter 0 [Key] -> this parameter [[], Key] | true | -| System.Collections.Generic.SortedList<,>.Add(KeyValuePair) | parameter 0 [Value] -> this parameter [[], Value] | true | -| System.Collections.Generic.SortedList<,>.Add(TKey, TValue) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.Generic.SortedList<,>.Add(TKey, TValue) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.Generic.SortedList<,>.Add(object, object) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.Generic.SortedList<,>.Add(object, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.Generic.SortedList<,>.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Generic.SortedList<,>.CopyTo(KeyValuePair[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Generic.SortedList<,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Generic.SortedList<,>.KeyList.Add(TKey) | parameter 0 -> this parameter [[]] | true | -| System.Collections.Generic.SortedList<,>.KeyList.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Generic.SortedList<,>.KeyList.CopyTo(TKey[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Generic.SortedList<,>.KeyList.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Generic.SortedList<,>.KeyList.Insert(int, TKey) | parameter 1 -> this parameter [[]] | true | -| System.Collections.Generic.SortedList<,>.KeyList.get_Item(int) | this parameter [[]] -> return | true | -| System.Collections.Generic.SortedList<,>.KeyList.set_Item(int, TKey) | parameter 1 -> this parameter [[]] | true | -| System.Collections.Generic.SortedList<,>.SortedList(IDictionary) | parameter 0 [[], Key] -> return [[], Key] | true | -| System.Collections.Generic.SortedList<,>.SortedList(IDictionary) | parameter 0 [[], Value] -> return [[], Value] | true | -| System.Collections.Generic.SortedList<,>.SortedList(IDictionary, IComparer) | parameter 0 [[], Key] -> return [[], Key] | true | -| System.Collections.Generic.SortedList<,>.SortedList(IDictionary, IComparer) | parameter 0 [[], Value] -> return [[], Value] | true | -| System.Collections.Generic.SortedList<,>.ValueList.Add(TValue) | parameter 0 -> this parameter [[]] | true | -| System.Collections.Generic.SortedList<,>.ValueList.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Generic.SortedList<,>.ValueList.CopyTo(TValue[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Generic.SortedList<,>.ValueList.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Generic.SortedList<,>.ValueList.Insert(int, TValue) | parameter 1 -> this parameter [[]] | true | -| System.Collections.Generic.SortedList<,>.ValueList.get_Item(int) | this parameter [[]] -> return | true | -| System.Collections.Generic.SortedList<,>.ValueList.set_Item(int, TValue) | parameter 1 -> this parameter [[]] | true | -| System.Collections.Generic.SortedList<,>.get_Item(TKey) | this parameter [[], Value] -> return | true | -| System.Collections.Generic.SortedList<,>.get_Item(object) | this parameter [[], Value] -> return | true | -| System.Collections.Generic.SortedList<,>.get_Keys() | this parameter [[], Key] -> return [[]] | true | -| System.Collections.Generic.SortedList<,>.get_Values() | this parameter [[], Value] -> return [[]] | true | -| System.Collections.Generic.SortedList<,>.set_Item(TKey, TValue) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.Generic.SortedList<,>.set_Item(TKey, TValue) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.Generic.SortedList<,>.set_Item(object, object) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.Generic.SortedList<,>.set_Item(object, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.Generic.SortedSet<>.d__84.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Generic.SortedSet<>.Add(T) | parameter 0 -> this parameter [[]] | true | -| System.Collections.Generic.SortedSet<>.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Generic.SortedSet<>.CopyTo(T[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Generic.SortedSet<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Generic.SortedSet<>.Reverse() | parameter 0 [[]] -> return [[]] | true | -| System.Collections.Generic.Stack<>.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Generic.Stack<>.CopyTo(T[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Generic.Stack<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Generic.Stack<>.Peek() | this parameter [[]] -> return | true | -| System.Collections.Generic.Stack<>.Pop() | this parameter [[]] -> return | true | -| System.Collections.Hashtable.Add(object, object) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.Hashtable.Add(object, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.Hashtable.Clone() | parameter 0 [[]] -> return [[]] | true | -| System.Collections.Hashtable.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Hashtable.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Hashtable.Hashtable(IDictionary) | parameter 0 [[], Key] -> return [[], Key] | true | -| System.Collections.Hashtable.Hashtable(IDictionary) | parameter 0 [[], Value] -> return [[], Value] | true | -| System.Collections.Hashtable.Hashtable(IDictionary, IEqualityComparer) | parameter 0 [[], Key] -> return [[], Key] | true | -| System.Collections.Hashtable.Hashtable(IDictionary, IEqualityComparer) | parameter 0 [[], Value] -> return [[], Value] | true | -| System.Collections.Hashtable.Hashtable(IDictionary, IHashCodeProvider, IComparer) | parameter 0 [[], Key] -> return [[], Key] | true | -| System.Collections.Hashtable.Hashtable(IDictionary, IHashCodeProvider, IComparer) | parameter 0 [[], Value] -> return [[], Value] | true | -| System.Collections.Hashtable.Hashtable(IDictionary, float) | parameter 0 [[], Key] -> return [[], Key] | true | -| System.Collections.Hashtable.Hashtable(IDictionary, float) | parameter 0 [[], Value] -> return [[], Value] | true | -| System.Collections.Hashtable.Hashtable(IDictionary, float, IEqualityComparer) | parameter 0 [[], Key] -> return [[], Key] | true | -| System.Collections.Hashtable.Hashtable(IDictionary, float, IEqualityComparer) | parameter 0 [[], Value] -> return [[], Value] | true | -| System.Collections.Hashtable.Hashtable(IDictionary, float, IHashCodeProvider, IComparer) | parameter 0 [[], Key] -> return [[], Key] | true | -| System.Collections.Hashtable.Hashtable(IDictionary, float, IHashCodeProvider, IComparer) | parameter 0 [[], Value] -> return [[], Value] | true | -| System.Collections.Hashtable.KeyCollection.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Hashtable.KeyCollection.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Hashtable.SyncHashtable.Add(object, object) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.Hashtable.SyncHashtable.Add(object, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.Hashtable.SyncHashtable.Clone() | parameter 0 [[]] -> return [[]] | true | -| System.Collections.Hashtable.SyncHashtable.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Hashtable.SyncHashtable.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Hashtable.SyncHashtable.get_Item(object) | this parameter [[], Value] -> return | true | -| System.Collections.Hashtable.SyncHashtable.get_Keys() | this parameter [[], Key] -> return [[]] | true | -| System.Collections.Hashtable.SyncHashtable.get_Values() | this parameter [[], Value] -> return [[]] | true | -| System.Collections.Hashtable.SyncHashtable.set_Item(object, object) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.Hashtable.SyncHashtable.set_Item(object, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.Hashtable.ValueCollection.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Hashtable.ValueCollection.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Hashtable.get_Item(object) | this parameter [[], Value] -> return | true | -| System.Collections.Hashtable.get_Keys() | this parameter [[], Key] -> return [[]] | true | -| System.Collections.Hashtable.get_Values() | this parameter [[], Value] -> return [[]] | true | -| System.Collections.Hashtable.set_Item(object, object) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.Hashtable.set_Item(object, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.ICollection.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.IDictionary.Add(object, object) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.IDictionary.Add(object, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.IDictionary.get_Item(object) | this parameter [[], Value] -> return | true | -| System.Collections.IDictionary.get_Keys() | this parameter [[], Key] -> return [[]] | true | -| System.Collections.IDictionary.get_Values() | this parameter [[], Value] -> return [[]] | true | -| System.Collections.IDictionary.set_Item(object, object) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.IDictionary.set_Item(object, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.IEnumerable.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.IList.Add(object) | parameter 0 -> this parameter [[]] | true | -| System.Collections.IList.Insert(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Collections.IList.get_Item(int) | this parameter [[]] -> return | true | -| System.Collections.IList.set_Item(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Collections.ListDictionaryInternal.Add(object, object) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.ListDictionaryInternal.Add(object, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.ListDictionaryInternal.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.ListDictionaryInternal.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.ListDictionaryInternal.NodeKeyValueCollection.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.ListDictionaryInternal.NodeKeyValueCollection.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.ListDictionaryInternal.get_Item(object) | this parameter [[], Value] -> return | true | -| System.Collections.ListDictionaryInternal.get_Keys() | this parameter [[], Key] -> return [[]] | true | -| System.Collections.ListDictionaryInternal.get_Values() | this parameter [[], Value] -> return [[]] | true | -| System.Collections.ListDictionaryInternal.set_Item(object, object) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.ListDictionaryInternal.set_Item(object, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.ObjectModel.Collection<>.Add(T) | parameter 0 -> this parameter [[]] | true | -| System.Collections.ObjectModel.Collection<>.Add(object) | parameter 0 -> this parameter [[]] | true | -| System.Collections.ObjectModel.Collection<>.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.ObjectModel.Collection<>.CopyTo(T[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.ObjectModel.Collection<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.ObjectModel.Collection<>.Insert(int, T) | parameter 1 -> this parameter [[]] | true | -| System.Collections.ObjectModel.Collection<>.Insert(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Collections.ObjectModel.Collection<>.get_Item(int) | this parameter [[]] -> return | true | -| System.Collections.ObjectModel.Collection<>.set_Item(int, T) | parameter 1 -> this parameter [[]] | true | -| System.Collections.ObjectModel.Collection<>.set_Item(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Collections.ObjectModel.KeyedCollection<,>.get_Item(TKey) | this parameter [[]] -> return | true | -| System.Collections.ObjectModel.ReadOnlyCollection<>.Add(T) | parameter 0 -> this parameter [[]] | true | -| System.Collections.ObjectModel.ReadOnlyCollection<>.Add(object) | parameter 0 -> this parameter [[]] | true | -| System.Collections.ObjectModel.ReadOnlyCollection<>.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.ObjectModel.ReadOnlyCollection<>.CopyTo(T[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.ObjectModel.ReadOnlyCollection<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.ObjectModel.ReadOnlyCollection<>.Insert(int, T) | parameter 1 -> this parameter [[]] | true | -| System.Collections.ObjectModel.ReadOnlyCollection<>.Insert(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Collections.ObjectModel.ReadOnlyCollection<>.get_Item(int) | this parameter [[]] -> return | true | -| System.Collections.ObjectModel.ReadOnlyCollection<>.set_Item(int, T) | parameter 1 -> this parameter [[]] | true | -| System.Collections.ObjectModel.ReadOnlyCollection<>.set_Item(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(KeyValuePair) | parameter 0 -> this parameter [[]] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(KeyValuePair) | parameter 0 [Key] -> this parameter [[], Key] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(KeyValuePair) | parameter 0 [Value] -> this parameter [[], Value] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(TKey, TValue) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(TKey, TValue) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(object, object) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(object, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.CopyTo(KeyValuePair[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.KeyCollection.Add(TKey) | parameter 0 -> this parameter [[]] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.KeyCollection.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.KeyCollection.CopyTo(TKey[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.KeyCollection.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ReadOnlyDictionary(IDictionary) | parameter 0 [[], Key] -> return [[], Key] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ReadOnlyDictionary(IDictionary) | parameter 0 [[], Value] -> return [[], Value] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ValueCollection.Add(TValue) | parameter 0 -> this parameter [[]] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ValueCollection.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ValueCollection.CopyTo(TValue[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ValueCollection.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.get_Item(TKey) | this parameter [[], Value] -> return | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.get_Item(object) | this parameter [[], Value] -> return | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.get_Keys() | this parameter [[], Key] -> return [[]] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.get_Values() | this parameter [[], Value] -> return [[]] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.set_Item(TKey, TValue) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.set_Item(TKey, TValue) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.set_Item(object, object) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.set_Item(object, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.Queue.Clone() | parameter 0 [[]] -> return [[]] | true | -| System.Collections.Queue.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Queue.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Queue.Peek() | this parameter [[]] -> return | true | -| System.Collections.Queue.SynchronizedQueue.Clone() | parameter 0 [[]] -> return [[]] | true | -| System.Collections.Queue.SynchronizedQueue.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Queue.SynchronizedQueue.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Queue.SynchronizedQueue.Peek() | this parameter [[]] -> return | true | -| System.Collections.ReadOnlyCollectionBase.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.ReadOnlyCollectionBase.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.SortedList.Add(object, object) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.SortedList.Add(object, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.SortedList.Clone() | parameter 0 [[]] -> return [[]] | true | -| System.Collections.SortedList.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.SortedList.GetByIndex(int) | this parameter [[], Value] -> return | true | -| System.Collections.SortedList.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.SortedList.GetValueList() | this parameter [[], Value] -> return [[]] | true | -| System.Collections.SortedList.KeyList.Add(object) | parameter 0 -> this parameter [[]] | true | -| System.Collections.SortedList.KeyList.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.SortedList.KeyList.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.SortedList.KeyList.Insert(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Collections.SortedList.KeyList.get_Item(int) | this parameter [[]] -> return | true | -| System.Collections.SortedList.KeyList.set_Item(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Collections.SortedList.SortedList(IDictionary) | parameter 0 [[], Key] -> return [[], Key] | true | -| System.Collections.SortedList.SortedList(IDictionary) | parameter 0 [[], Value] -> return [[], Value] | true | -| System.Collections.SortedList.SortedList(IDictionary, IComparer) | parameter 0 [[], Key] -> return [[], Key] | true | -| System.Collections.SortedList.SortedList(IDictionary, IComparer) | parameter 0 [[], Value] -> return [[], Value] | true | -| System.Collections.SortedList.SyncSortedList.Add(object, object) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.SortedList.SyncSortedList.Add(object, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.SortedList.SyncSortedList.Clone() | parameter 0 [[]] -> return [[]] | true | -| System.Collections.SortedList.SyncSortedList.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.SortedList.SyncSortedList.GetByIndex(int) | this parameter [[], Value] -> return | true | -| System.Collections.SortedList.SyncSortedList.GetValueList() | this parameter [[], Value] -> return [[]] | true | -| System.Collections.SortedList.SyncSortedList.get_Item(object) | this parameter [[], Value] -> return | true | -| System.Collections.SortedList.SyncSortedList.set_Item(object, object) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.SortedList.SyncSortedList.set_Item(object, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.SortedList.ValueList.Add(object) | parameter 0 -> this parameter [[]] | true | -| System.Collections.SortedList.ValueList.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.SortedList.ValueList.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.SortedList.ValueList.Insert(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Collections.SortedList.ValueList.get_Item(int) | this parameter [[]] -> return | true | -| System.Collections.SortedList.ValueList.set_Item(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Collections.SortedList.get_Item(object) | this parameter [[], Value] -> return | true | -| System.Collections.SortedList.get_Keys() | this parameter [[], Key] -> return [[]] | true | -| System.Collections.SortedList.get_Values() | this parameter [[], Value] -> return [[]] | true | -| System.Collections.SortedList.set_Item(object, object) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.SortedList.set_Item(object, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.Specialized.HybridDictionary.Add(object, object) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.Specialized.HybridDictionary.Add(object, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.Specialized.HybridDictionary.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Specialized.HybridDictionary.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Specialized.HybridDictionary.get_Item(object) | this parameter [[], Value] -> return | true | -| System.Collections.Specialized.HybridDictionary.get_Keys() | this parameter [[], Key] -> return [[]] | true | -| System.Collections.Specialized.HybridDictionary.get_Values() | this parameter [[], Value] -> return [[]] | true | -| System.Collections.Specialized.HybridDictionary.set_Item(object, object) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.Specialized.HybridDictionary.set_Item(object, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.Specialized.IOrderedDictionary.get_Item(int) | this parameter [[], Value] -> return | true | -| System.Collections.Specialized.IOrderedDictionary.set_Item(int, object) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.Specialized.IOrderedDictionary.set_Item(int, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.Specialized.ListDictionary.Add(object, object) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.Specialized.ListDictionary.Add(object, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.Specialized.ListDictionary.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Specialized.ListDictionary.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Specialized.ListDictionary.NodeKeyValueCollection.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Specialized.ListDictionary.NodeKeyValueCollection.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Specialized.ListDictionary.get_Item(object) | this parameter [[], Value] -> return | true | -| System.Collections.Specialized.ListDictionary.get_Keys() | this parameter [[], Key] -> return [[]] | true | -| System.Collections.Specialized.ListDictionary.get_Values() | this parameter [[], Value] -> return [[]] | true | -| System.Collections.Specialized.ListDictionary.set_Item(object, object) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.Specialized.ListDictionary.set_Item(object, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.Specialized.NameObjectCollectionBase.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Specialized.NameObjectCollectionBase.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Specialized.NameObjectCollectionBase.KeysCollection.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Specialized.NameObjectCollectionBase.KeysCollection.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Specialized.NameValueCollection.Add(NameValueCollection) | parameter 0 -> this parameter [[]] | true | -| System.Collections.Specialized.NameValueCollection.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Specialized.OrderedDictionary.Add(object, object) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.Specialized.OrderedDictionary.Add(object, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.Specialized.OrderedDictionary.AsReadOnly() | parameter 0 [[]] -> return [[]] | true | -| System.Collections.Specialized.OrderedDictionary.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Specialized.OrderedDictionary.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Specialized.OrderedDictionary.OrderedDictionaryKeyValueCollection.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Specialized.OrderedDictionary.OrderedDictionaryKeyValueCollection.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Specialized.OrderedDictionary.get_Item(int) | this parameter [[], Value] -> return | true | -| System.Collections.Specialized.OrderedDictionary.get_Item(object) | this parameter [[], Value] -> return | true | -| System.Collections.Specialized.OrderedDictionary.get_Keys() | this parameter [[], Key] -> return [[]] | true | -| System.Collections.Specialized.OrderedDictionary.get_Values() | this parameter [[], Value] -> return [[]] | true | -| System.Collections.Specialized.OrderedDictionary.set_Item(int, object) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.Specialized.OrderedDictionary.set_Item(int, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.Specialized.OrderedDictionary.set_Item(object, object) | parameter 0 -> this parameter [[], Key] | true | -| System.Collections.Specialized.OrderedDictionary.set_Item(object, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.Specialized.ReadOnlyList.Add(object) | parameter 0 -> this parameter [[]] | true | -| System.Collections.Specialized.ReadOnlyList.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Specialized.ReadOnlyList.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Specialized.ReadOnlyList.Insert(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Collections.Specialized.ReadOnlyList.get_Item(int) | this parameter [[]] -> return | true | -| System.Collections.Specialized.ReadOnlyList.set_Item(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Collections.Specialized.StringCollection.Add(object) | parameter 0 -> this parameter [[]] | true | -| System.Collections.Specialized.StringCollection.Add(string) | parameter 0 -> this parameter [[]] | true | -| System.Collections.Specialized.StringCollection.AddRange(String[]) | parameter 0 [[]] -> this parameter [[]] | true | -| System.Collections.Specialized.StringCollection.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Specialized.StringCollection.CopyTo(String[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Specialized.StringCollection.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Specialized.StringCollection.Insert(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Collections.Specialized.StringCollection.Insert(int, string) | parameter 1 -> this parameter [[]] | true | -| System.Collections.Specialized.StringCollection.get_Item(int) | this parameter [[]] -> return | true | -| System.Collections.Specialized.StringCollection.set_Item(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Collections.Specialized.StringCollection.set_Item(int, string) | parameter 1 -> this parameter [[]] | true | -| System.Collections.Specialized.StringDictionary.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Stack.Clone() | parameter 0 [[]] -> return [[]] | true | -| System.Collections.Stack.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Stack.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Stack.Peek() | this parameter [[]] -> return | true | -| System.Collections.Stack.Pop() | this parameter [[]] -> return | true | -| System.Collections.Stack.SyncStack.Clone() | parameter 0 [[]] -> return [[]] | true | -| System.Collections.Stack.SyncStack.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Collections.Stack.SyncStack.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Stack.SyncStack.Peek() | this parameter [[]] -> return | true | -| System.Collections.Stack.SyncStack.Pop() | this parameter [[]] -> return | true | -| System.ComponentModel.AttributeCollection.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.ComponentModel.AttributeCollection.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.ComponentModel.BindingList<>.Find(PropertyDescriptor, object) | this parameter [[]] -> return | true | -| System.ComponentModel.Design.DesignerCollection.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.ComponentModel.Design.DesignerCollection.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.Add(object) | parameter 0 -> this parameter [[]] | true | -| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.Insert(int, object) | parameter 1 -> this parameter [[]] | true | -| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.get_Item(int) | this parameter [[]] -> return | true | -| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.get_Item(string) | this parameter [[]] -> return | true | -| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.set_Item(int, object) | parameter 1 -> this parameter [[]] | true | -| System.ComponentModel.Design.DesignerVerbCollection.Add(DesignerVerb) | parameter 0 -> this parameter [[]] | true | -| System.ComponentModel.Design.DesignerVerbCollection.AddRange(DesignerVerbCollection) | parameter 0 [[]] -> this parameter [[]] | true | -| System.ComponentModel.Design.DesignerVerbCollection.AddRange(DesignerVerb[]) | parameter 0 [[]] -> this parameter [[]] | true | -| System.ComponentModel.Design.DesignerVerbCollection.CopyTo(DesignerVerb[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.ComponentModel.Design.DesignerVerbCollection.Insert(int, DesignerVerb) | parameter 1 -> this parameter [[]] | true | -| System.ComponentModel.Design.DesignerVerbCollection.get_Item(int) | this parameter [[]] -> return | true | -| System.ComponentModel.Design.DesignerVerbCollection.set_Item(int, DesignerVerb) | parameter 1 -> this parameter [[]] | true | -| System.ComponentModel.EventDescriptorCollection.Add(EventDescriptor) | parameter 0 -> this parameter [[]] | true | -| System.ComponentModel.EventDescriptorCollection.Add(object) | parameter 0 -> this parameter [[]] | true | -| System.ComponentModel.EventDescriptorCollection.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.ComponentModel.EventDescriptorCollection.Find(string, bool) | this parameter [[]] -> return | true | -| System.ComponentModel.EventDescriptorCollection.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.ComponentModel.EventDescriptorCollection.Insert(int, EventDescriptor) | parameter 1 -> this parameter [[]] | true | -| System.ComponentModel.EventDescriptorCollection.Insert(int, object) | parameter 1 -> this parameter [[]] | true | -| System.ComponentModel.EventDescriptorCollection.get_Item(int) | this parameter [[]] -> return | true | -| System.ComponentModel.EventDescriptorCollection.get_Item(string) | this parameter [[]] -> return | true | -| System.ComponentModel.EventDescriptorCollection.set_Item(int, object) | parameter 1 -> this parameter [[]] | true | -| System.ComponentModel.IBindingList.Find(PropertyDescriptor, object) | this parameter [[]] -> return | true | -| System.ComponentModel.ListSortDescriptionCollection.Add(object) | parameter 0 -> this parameter [[]] | true | -| System.ComponentModel.ListSortDescriptionCollection.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.ComponentModel.ListSortDescriptionCollection.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.ComponentModel.ListSortDescriptionCollection.Insert(int, object) | parameter 1 -> this parameter [[]] | true | -| System.ComponentModel.ListSortDescriptionCollection.get_Item(int) | this parameter [[]] -> return | true | -| System.ComponentModel.ListSortDescriptionCollection.set_Item(int, ListSortDescription) | parameter 1 -> this parameter [[]] | true | -| System.ComponentModel.ListSortDescriptionCollection.set_Item(int, object) | parameter 1 -> this parameter [[]] | true | -| System.ComponentModel.PropertyDescriptorCollection.Add(PropertyDescriptor) | parameter 0 -> this parameter [[]] | true | -| System.ComponentModel.PropertyDescriptorCollection.Add(PropertyDescriptor) | parameter 0 [Key] -> this parameter [[], Key] | true | -| System.ComponentModel.PropertyDescriptorCollection.Add(PropertyDescriptor) | parameter 0 [Value] -> this parameter [[], Value] | true | -| System.ComponentModel.PropertyDescriptorCollection.Add(object) | parameter 0 -> this parameter [[]] | true | -| System.ComponentModel.PropertyDescriptorCollection.Add(object) | parameter 0 [Key] -> this parameter [[], Key] | true | -| System.ComponentModel.PropertyDescriptorCollection.Add(object) | parameter 0 [Value] -> this parameter [[], Value] | true | -| System.ComponentModel.PropertyDescriptorCollection.Add(object, object) | parameter 0 -> this parameter [[], Key] | true | -| System.ComponentModel.PropertyDescriptorCollection.Add(object, object) | parameter 1 -> this parameter [[], Value] | true | -| System.ComponentModel.PropertyDescriptorCollection.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.ComponentModel.PropertyDescriptorCollection.Find(string, bool) | this parameter [[]] -> return | true | -| System.ComponentModel.PropertyDescriptorCollection.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.ComponentModel.PropertyDescriptorCollection.Insert(int, PropertyDescriptor) | parameter 1 -> this parameter [[]] | true | -| System.ComponentModel.PropertyDescriptorCollection.Insert(int, object) | parameter 1 -> this parameter [[]] | true | -| System.ComponentModel.PropertyDescriptorCollection.PropertyDescriptorCollection(PropertyDescriptor[]) | parameter 0 [[], Key] -> return [[], Key] | true | -| System.ComponentModel.PropertyDescriptorCollection.PropertyDescriptorCollection(PropertyDescriptor[]) | parameter 0 [[], Value] -> return [[], Value] | true | -| System.ComponentModel.PropertyDescriptorCollection.PropertyDescriptorCollection(PropertyDescriptor[], bool) | parameter 0 [[], Key] -> return [[], Key] | true | -| System.ComponentModel.PropertyDescriptorCollection.PropertyDescriptorCollection(PropertyDescriptor[], bool) | parameter 0 [[], Value] -> return [[], Value] | true | -| System.ComponentModel.PropertyDescriptorCollection.get_Item(int) | this parameter [[], Value] -> return | true | -| System.ComponentModel.PropertyDescriptorCollection.get_Item(int) | this parameter [[]] -> return | true | -| System.ComponentModel.PropertyDescriptorCollection.get_Item(object) | this parameter [[], Value] -> return | true | -| System.ComponentModel.PropertyDescriptorCollection.get_Item(object) | this parameter [[]] -> return | true | -| System.ComponentModel.PropertyDescriptorCollection.get_Item(string) | this parameter [[], Value] -> return | true | -| System.ComponentModel.PropertyDescriptorCollection.get_Item(string) | this parameter [[]] -> return | true | -| System.ComponentModel.PropertyDescriptorCollection.get_Keys() | this parameter [[], Key] -> return [[]] | true | -| System.ComponentModel.PropertyDescriptorCollection.get_Values() | this parameter [[], Value] -> return [[]] | true | -| System.ComponentModel.PropertyDescriptorCollection.set_Item(int, object) | parameter 0 -> this parameter [[], Key] | true | -| System.ComponentModel.PropertyDescriptorCollection.set_Item(int, object) | parameter 1 -> this parameter [[], Value] | true | -| System.ComponentModel.PropertyDescriptorCollection.set_Item(int, object) | parameter 1 -> this parameter [[]] | true | -| System.ComponentModel.PropertyDescriptorCollection.set_Item(object, object) | parameter 0 -> this parameter [[], Key] | true | -| System.ComponentModel.PropertyDescriptorCollection.set_Item(object, object) | parameter 1 -> this parameter [[], Value] | true | -| System.ComponentModel.PropertyDescriptorCollection.set_Item(object, object) | parameter 1 -> this parameter [[]] | true | -| System.ComponentModel.TypeConverter.StandardValuesCollection.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.ComponentModel.TypeConverter.StandardValuesCollection.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.Collections.ArrayList.Add(object) | parameter 0 -> this parameter [element] | true | +| System.Collections.ArrayList.AddRange(ICollection) | parameter 0 [element] -> this parameter [element] | true | +| System.Collections.ArrayList.Clone() | parameter 0 [element] -> return [element] | true | +| System.Collections.ArrayList.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.ArrayList.FixedSize(ArrayList) | parameter 0 [element] -> return [element] | true | +| System.Collections.ArrayList.FixedSize(IList) | parameter 0 [element] -> return [element] | true | +| System.Collections.ArrayList.FixedSizeArrayList.Add(object) | parameter 0 -> this parameter [element] | true | +| System.Collections.ArrayList.FixedSizeArrayList.AddRange(ICollection) | parameter 0 [element] -> this parameter [element] | true | +| System.Collections.ArrayList.FixedSizeArrayList.Clone() | parameter 0 [element] -> return [element] | true | +| System.Collections.ArrayList.FixedSizeArrayList.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.ArrayList.FixedSizeArrayList.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.ArrayList.FixedSizeArrayList.GetEnumerator(int, int) | this parameter [element] -> return [property Current] | true | +| System.Collections.ArrayList.FixedSizeArrayList.GetRange(int, int) | parameter 0 [element] -> return [element] | true | +| System.Collections.ArrayList.FixedSizeArrayList.Insert(int, object) | parameter 1 -> this parameter [element] | true | +| System.Collections.ArrayList.FixedSizeArrayList.InsertRange(int, ICollection) | parameter 1 [element] -> this parameter [element] | true | +| System.Collections.ArrayList.FixedSizeArrayList.Reverse(int, int) | parameter 0 [element] -> return [element] | true | +| System.Collections.ArrayList.FixedSizeArrayList.get_Item(int) | this parameter [element] -> return | true | +| System.Collections.ArrayList.FixedSizeArrayList.set_Item(int, object) | parameter 1 -> this parameter [element] | true | +| System.Collections.ArrayList.FixedSizeList.Add(object) | parameter 0 -> this parameter [element] | true | +| System.Collections.ArrayList.FixedSizeList.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.ArrayList.FixedSizeList.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.ArrayList.FixedSizeList.Insert(int, object) | parameter 1 -> this parameter [element] | true | +| System.Collections.ArrayList.FixedSizeList.get_Item(int) | this parameter [element] -> return | true | +| System.Collections.ArrayList.FixedSizeList.set_Item(int, object) | parameter 1 -> this parameter [element] | true | +| System.Collections.ArrayList.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.ArrayList.GetEnumerator(int, int) | this parameter [element] -> return [property Current] | true | +| System.Collections.ArrayList.GetRange(int, int) | parameter 0 [element] -> return [element] | true | +| System.Collections.ArrayList.IListWrapper.Add(object) | parameter 0 -> this parameter [element] | true | +| System.Collections.ArrayList.IListWrapper.AddRange(ICollection) | parameter 0 [element] -> this parameter [element] | true | +| System.Collections.ArrayList.IListWrapper.Clone() | parameter 0 [element] -> return [element] | true | +| System.Collections.ArrayList.IListWrapper.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.ArrayList.IListWrapper.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.ArrayList.IListWrapper.GetEnumerator(int, int) | this parameter [element] -> return [property Current] | true | +| System.Collections.ArrayList.IListWrapper.GetRange(int, int) | parameter 0 [element] -> return [element] | true | +| System.Collections.ArrayList.IListWrapper.Insert(int, object) | parameter 1 -> this parameter [element] | true | +| System.Collections.ArrayList.IListWrapper.InsertRange(int, ICollection) | parameter 1 [element] -> this parameter [element] | true | +| System.Collections.ArrayList.IListWrapper.Reverse(int, int) | parameter 0 [element] -> return [element] | true | +| System.Collections.ArrayList.IListWrapper.get_Item(int) | this parameter [element] -> return | true | +| System.Collections.ArrayList.IListWrapper.set_Item(int, object) | parameter 1 -> this parameter [element] | true | +| System.Collections.ArrayList.Insert(int, object) | parameter 1 -> this parameter [element] | true | +| System.Collections.ArrayList.InsertRange(int, ICollection) | parameter 1 [element] -> this parameter [element] | true | +| System.Collections.ArrayList.Range.Add(object) | parameter 0 -> this parameter [element] | true | +| System.Collections.ArrayList.Range.AddRange(ICollection) | parameter 0 [element] -> this parameter [element] | true | +| System.Collections.ArrayList.Range.Clone() | parameter 0 [element] -> return [element] | true | +| System.Collections.ArrayList.Range.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.ArrayList.Range.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.ArrayList.Range.GetEnumerator(int, int) | this parameter [element] -> return [property Current] | true | +| System.Collections.ArrayList.Range.GetRange(int, int) | parameter 0 [element] -> return [element] | true | +| System.Collections.ArrayList.Range.Insert(int, object) | parameter 1 -> this parameter [element] | true | +| System.Collections.ArrayList.Range.InsertRange(int, ICollection) | parameter 1 [element] -> this parameter [element] | true | +| System.Collections.ArrayList.Range.Reverse(int, int) | parameter 0 [element] -> return [element] | true | +| System.Collections.ArrayList.Range.get_Item(int) | this parameter [element] -> return | true | +| System.Collections.ArrayList.Range.set_Item(int, object) | parameter 1 -> this parameter [element] | true | +| System.Collections.ArrayList.ReadOnlyArrayList.Add(object) | parameter 0 -> this parameter [element] | true | +| System.Collections.ArrayList.ReadOnlyArrayList.AddRange(ICollection) | parameter 0 [element] -> this parameter [element] | true | +| System.Collections.ArrayList.ReadOnlyArrayList.Clone() | parameter 0 [element] -> return [element] | true | +| System.Collections.ArrayList.ReadOnlyArrayList.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.ArrayList.ReadOnlyArrayList.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.ArrayList.ReadOnlyArrayList.GetEnumerator(int, int) | this parameter [element] -> return [property Current] | true | +| System.Collections.ArrayList.ReadOnlyArrayList.GetRange(int, int) | parameter 0 [element] -> return [element] | true | +| System.Collections.ArrayList.ReadOnlyArrayList.Insert(int, object) | parameter 1 -> this parameter [element] | true | +| System.Collections.ArrayList.ReadOnlyArrayList.InsertRange(int, ICollection) | parameter 1 [element] -> this parameter [element] | true | +| System.Collections.ArrayList.ReadOnlyArrayList.Reverse(int, int) | parameter 0 [element] -> return [element] | true | +| System.Collections.ArrayList.ReadOnlyArrayList.get_Item(int) | this parameter [element] -> return | true | +| System.Collections.ArrayList.ReadOnlyArrayList.set_Item(int, object) | parameter 1 -> this parameter [element] | true | +| System.Collections.ArrayList.ReadOnlyList.Add(object) | parameter 0 -> this parameter [element] | true | +| System.Collections.ArrayList.ReadOnlyList.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.ArrayList.ReadOnlyList.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.ArrayList.ReadOnlyList.Insert(int, object) | parameter 1 -> this parameter [element] | true | +| System.Collections.ArrayList.ReadOnlyList.get_Item(int) | this parameter [element] -> return | true | +| System.Collections.ArrayList.ReadOnlyList.set_Item(int, object) | parameter 1 -> this parameter [element] | true | +| System.Collections.ArrayList.Repeat(object, int) | parameter 0 -> return [element] | true | +| System.Collections.ArrayList.Reverse() | parameter 0 [element] -> return [element] | true | +| System.Collections.ArrayList.Reverse(int, int) | parameter 0 [element] -> return [element] | true | +| System.Collections.ArrayList.SyncArrayList.Add(object) | parameter 0 -> this parameter [element] | true | +| System.Collections.ArrayList.SyncArrayList.AddRange(ICollection) | parameter 0 [element] -> this parameter [element] | true | +| System.Collections.ArrayList.SyncArrayList.Clone() | parameter 0 [element] -> return [element] | true | +| System.Collections.ArrayList.SyncArrayList.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.ArrayList.SyncArrayList.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.ArrayList.SyncArrayList.GetEnumerator(int, int) | this parameter [element] -> return [property Current] | true | +| System.Collections.ArrayList.SyncArrayList.GetRange(int, int) | parameter 0 [element] -> return [element] | true | +| System.Collections.ArrayList.SyncArrayList.Insert(int, object) | parameter 1 -> this parameter [element] | true | +| System.Collections.ArrayList.SyncArrayList.InsertRange(int, ICollection) | parameter 1 [element] -> this parameter [element] | true | +| System.Collections.ArrayList.SyncArrayList.Reverse(int, int) | parameter 0 [element] -> return [element] | true | +| System.Collections.ArrayList.SyncArrayList.get_Item(int) | this parameter [element] -> return | true | +| System.Collections.ArrayList.SyncArrayList.set_Item(int, object) | parameter 1 -> this parameter [element] | true | +| System.Collections.ArrayList.SyncIList.Add(object) | parameter 0 -> this parameter [element] | true | +| System.Collections.ArrayList.SyncIList.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.ArrayList.SyncIList.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.ArrayList.SyncIList.Insert(int, object) | parameter 1 -> this parameter [element] | true | +| System.Collections.ArrayList.SyncIList.get_Item(int) | this parameter [element] -> return | true | +| System.Collections.ArrayList.SyncIList.set_Item(int, object) | parameter 1 -> this parameter [element] | true | +| System.Collections.ArrayList.get_Item(int) | this parameter [element] -> return | true | +| System.Collections.ArrayList.set_Item(int, object) | parameter 1 -> this parameter [element] | true | +| System.Collections.BitArray.Clone() | parameter 0 [element] -> return [element] | true | +| System.Collections.BitArray.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.BitArray.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.CollectionBase.Add(object) | parameter 0 -> this parameter [element] | true | +| System.Collections.CollectionBase.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.CollectionBase.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.CollectionBase.Insert(int, object) | parameter 1 -> this parameter [element] | true | +| System.Collections.CollectionBase.get_Item(int) | this parameter [element] -> return | true | +| System.Collections.CollectionBase.set_Item(int, object) | parameter 1 -> this parameter [element] | true | +| System.Collections.Concurrent.BlockingCollection<>.d__68.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Concurrent.BlockingCollection<>.Add(T) | parameter 0 -> this parameter [element] | true | +| System.Collections.Concurrent.BlockingCollection<>.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Concurrent.BlockingCollection<>.CopyTo(T[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Concurrent.BlockingCollection<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Concurrent.ConcurrentBag<>.Add(T) | parameter 0 -> this parameter [element] | true | +| System.Collections.Concurrent.ConcurrentBag<>.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Concurrent.ConcurrentBag<>.CopyTo(T[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Concurrent.ConcurrentBag<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(KeyValuePair) | parameter 0 -> this parameter [element] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(KeyValuePair) | parameter 0 [property Key] -> this parameter [element, property Key] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(KeyValuePair) | parameter 0 [property Value] -> this parameter [element, property Value] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(TKey, TValue) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(TKey, TValue) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(object, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(object, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(IEnumerable>) | parameter 0 [element, property Key] -> return [element, property Key] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(IEnumerable>) | parameter 0 [element, property Value] -> return [element, property Value] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(IEnumerable>, IEqualityComparer) | parameter 0 [element, property Key] -> return [element, property Key] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(IEnumerable>, IEqualityComparer) | parameter 0 [element, property Value] -> return [element, property Value] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(int, IEnumerable>, IEqualityComparer) | parameter 1 [element, property Key] -> return [element, property Key] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(int, IEnumerable>, IEqualityComparer) | parameter 1 [element, property Value] -> return [element, property Value] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.CopyTo(KeyValuePair[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.get_Item(TKey) | this parameter [element, property Value] -> return | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.get_Item(object) | this parameter [element, property Value] -> return | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.get_Keys() | this parameter [element, property Key] -> return [element] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.get_Values() | this parameter [element, property Value] -> return [element] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.set_Item(TKey, TValue) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.set_Item(TKey, TValue) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.set_Item(object, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.set_Item(object, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.Concurrent.ConcurrentQueue<>.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Concurrent.ConcurrentQueue<>.CopyTo(T[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Concurrent.ConcurrentQueue<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Concurrent.ConcurrentStack<>.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Concurrent.ConcurrentStack<>.CopyTo(T[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Concurrent.ConcurrentStack<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Concurrent.IProducerConsumerCollection<>.CopyTo(T[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Concurrent.OrderablePartitioner<>.EnumerableDropIndices.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Concurrent.Partitioner.d__7.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Concurrent.Partitioner.d__10.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Concurrent.Partitioner.DynamicPartitionerForArray<>.InternalPartitionEnumerable.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Concurrent.Partitioner.DynamicPartitionerForIEnumerable<>.InternalPartitionEnumerable.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Concurrent.Partitioner.DynamicPartitionerForIList<>.InternalPartitionEnumerable.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.DictionaryBase.Add(object, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.DictionaryBase.Add(object, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.DictionaryBase.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.DictionaryBase.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.DictionaryBase.get_Item(object) | this parameter [element, property Value] -> return | true | +| System.Collections.DictionaryBase.get_Keys() | this parameter [element, property Key] -> return [element] | true | +| System.Collections.DictionaryBase.get_Values() | this parameter [element, property Value] -> return [element] | true | +| System.Collections.DictionaryBase.set_Item(object, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.DictionaryBase.set_Item(object, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.EmptyReadOnlyDictionaryInternal.Add(object, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.EmptyReadOnlyDictionaryInternal.Add(object, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.EmptyReadOnlyDictionaryInternal.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.EmptyReadOnlyDictionaryInternal.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.EmptyReadOnlyDictionaryInternal.get_Item(object) | this parameter [element, property Value] -> return | true | +| System.Collections.EmptyReadOnlyDictionaryInternal.get_Keys() | this parameter [element, property Key] -> return [element] | true | +| System.Collections.EmptyReadOnlyDictionaryInternal.get_Values() | this parameter [element, property Value] -> return [element] | true | +| System.Collections.EmptyReadOnlyDictionaryInternal.set_Item(object, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.EmptyReadOnlyDictionaryInternal.set_Item(object, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.Generic.Dictionary<,>.Add(KeyValuePair) | parameter 0 -> this parameter [element] | true | +| System.Collections.Generic.Dictionary<,>.Add(KeyValuePair) | parameter 0 [property Key] -> this parameter [element, property Key] | true | +| System.Collections.Generic.Dictionary<,>.Add(KeyValuePair) | parameter 0 [property Value] -> this parameter [element, property Value] | true | +| System.Collections.Generic.Dictionary<,>.Add(TKey, TValue) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.Generic.Dictionary<,>.Add(TKey, TValue) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.Generic.Dictionary<,>.Add(object, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.Generic.Dictionary<,>.Add(object, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.Generic.Dictionary<,>.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Generic.Dictionary<,>.CopyTo(KeyValuePair[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IDictionary) | parameter 0 [element, property Key] -> return [element, property Key] | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IDictionary) | parameter 0 [element, property Value] -> return [element, property Value] | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IDictionary, IEqualityComparer) | parameter 0 [element, property Key] -> return [element, property Key] | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IDictionary, IEqualityComparer) | parameter 0 [element, property Value] -> return [element, property Value] | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IEnumerable>) | parameter 0 [element, property Key] -> return [element, property Key] | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IEnumerable>) | parameter 0 [element, property Value] -> return [element, property Value] | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IEnumerable>, IEqualityComparer) | parameter 0 [element, property Key] -> return [element, property Key] | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IEnumerable>, IEqualityComparer) | parameter 0 [element, property Value] -> return [element, property Value] | true | +| System.Collections.Generic.Dictionary<,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Generic.Dictionary<,>.KeyCollection.Add(TKey) | parameter 0 -> this parameter [element] | true | +| System.Collections.Generic.Dictionary<,>.KeyCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Generic.Dictionary<,>.KeyCollection.CopyTo(TKey[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Generic.Dictionary<,>.KeyCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Generic.Dictionary<,>.ValueCollection.Add(TValue) | parameter 0 -> this parameter [element] | true | +| System.Collections.Generic.Dictionary<,>.ValueCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Generic.Dictionary<,>.ValueCollection.CopyTo(TValue[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Generic.Dictionary<,>.ValueCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Generic.Dictionary<,>.get_Item(TKey) | this parameter [element, property Value] -> return | true | +| System.Collections.Generic.Dictionary<,>.get_Item(object) | this parameter [element, property Value] -> return | true | +| System.Collections.Generic.Dictionary<,>.get_Keys() | this parameter [element, property Key] -> return [element] | true | +| System.Collections.Generic.Dictionary<,>.get_Values() | this parameter [element, property Value] -> return [element] | true | +| System.Collections.Generic.Dictionary<,>.set_Item(TKey, TValue) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.Generic.Dictionary<,>.set_Item(TKey, TValue) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.Generic.Dictionary<,>.set_Item(object, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.Generic.Dictionary<,>.set_Item(object, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.Generic.HashSet<>.Add(T) | parameter 0 -> this parameter [element] | true | +| System.Collections.Generic.HashSet<>.CopyTo(T[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Generic.HashSet<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Generic.ICollection<>.Add(T) | parameter 0 -> this parameter [element] | true | +| System.Collections.Generic.ICollection<>.CopyTo(T[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Generic.IDictionary<,>.Add(TKey, TValue) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.Generic.IDictionary<,>.Add(TKey, TValue) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.Generic.IDictionary<,>.get_Item(TKey) | this parameter [element, property Value] -> return | true | +| System.Collections.Generic.IDictionary<,>.get_Keys() | this parameter [element, property Key] -> return [element] | true | +| System.Collections.Generic.IDictionary<,>.get_Values() | this parameter [element, property Value] -> return [element] | true | +| System.Collections.Generic.IDictionary<,>.set_Item(TKey, TValue) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.Generic.IDictionary<,>.set_Item(TKey, TValue) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.Generic.IList<>.Insert(int, T) | parameter 1 -> this parameter [element] | true | +| System.Collections.Generic.IList<>.get_Item(int) | this parameter [element] -> return | true | +| System.Collections.Generic.IList<>.set_Item(int, T) | parameter 1 -> this parameter [element] | true | +| System.Collections.Generic.ISet<>.Add(T) | parameter 0 -> this parameter [element] | true | +| System.Collections.Generic.KeyValuePair<,>.KeyValuePair() | parameter 0 -> return [property Key] | true | +| System.Collections.Generic.KeyValuePair<,>.KeyValuePair() | parameter 1 -> return [property Value] | true | +| System.Collections.Generic.KeyValuePair<,>.KeyValuePair(TKey, TValue) | parameter 0 -> return [property Key] | true | +| System.Collections.Generic.KeyValuePair<,>.KeyValuePair(TKey, TValue) | parameter 1 -> return [property Value] | true | +| System.Collections.Generic.LinkedList<>.Add(T) | parameter 0 -> this parameter [element] | true | +| System.Collections.Generic.LinkedList<>.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Generic.LinkedList<>.CopyTo(T[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Generic.LinkedList<>.Find(T) | this parameter [element] -> return | true | +| System.Collections.Generic.LinkedList<>.FindLast(T) | this parameter [element] -> return | true | +| System.Collections.Generic.LinkedList<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Generic.List<>.Add(T) | parameter 0 -> this parameter [element] | true | +| System.Collections.Generic.List<>.Add(object) | parameter 0 -> this parameter [element] | true | +| System.Collections.Generic.List<>.AddRange(IEnumerable) | parameter 0 [element] -> this parameter [element] | true | +| System.Collections.Generic.List<>.AsReadOnly() | parameter 0 [element] -> return [element] | true | +| System.Collections.Generic.List<>.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Generic.List<>.CopyTo(T[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Generic.List<>.Find(Predicate) | this parameter [element] -> parameter 0 of delegate parameter 0 | true | +| System.Collections.Generic.List<>.Find(Predicate) | this parameter [element] -> return | true | +| System.Collections.Generic.List<>.FindAll(Predicate) | this parameter [element] -> parameter 0 of delegate parameter 0 | true | +| System.Collections.Generic.List<>.FindAll(Predicate) | this parameter [element] -> return | true | +| System.Collections.Generic.List<>.FindLast(Predicate) | this parameter [element] -> parameter 0 of delegate parameter 0 | true | +| System.Collections.Generic.List<>.FindLast(Predicate) | this parameter [element] -> return | true | +| System.Collections.Generic.List<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Generic.List<>.GetRange(int, int) | parameter 0 [element] -> return [element] | true | +| System.Collections.Generic.List<>.Insert(int, T) | parameter 1 -> this parameter [element] | true | +| System.Collections.Generic.List<>.Insert(int, object) | parameter 1 -> this parameter [element] | true | +| System.Collections.Generic.List<>.InsertRange(int, IEnumerable) | parameter 1 [element] -> this parameter [element] | true | +| System.Collections.Generic.List<>.Reverse() | parameter 0 [element] -> return [element] | true | +| System.Collections.Generic.List<>.Reverse(int, int) | parameter 0 [element] -> return [element] | true | +| System.Collections.Generic.List<>.get_Item(int) | this parameter [element] -> return | true | +| System.Collections.Generic.List<>.set_Item(int, T) | parameter 1 -> this parameter [element] | true | +| System.Collections.Generic.List<>.set_Item(int, object) | parameter 1 -> this parameter [element] | true | +| System.Collections.Generic.Queue<>.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Generic.Queue<>.CopyTo(T[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Generic.Queue<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Generic.Queue<>.Peek() | this parameter [element] -> return | true | +| System.Collections.Generic.SortedDictionary<,>.Add(KeyValuePair) | parameter 0 -> this parameter [element] | true | +| System.Collections.Generic.SortedDictionary<,>.Add(KeyValuePair) | parameter 0 [property Key] -> this parameter [element, property Key] | true | +| System.Collections.Generic.SortedDictionary<,>.Add(KeyValuePair) | parameter 0 [property Value] -> this parameter [element, property Value] | true | +| System.Collections.Generic.SortedDictionary<,>.Add(TKey, TValue) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.Generic.SortedDictionary<,>.Add(TKey, TValue) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.Generic.SortedDictionary<,>.Add(object, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.Generic.SortedDictionary<,>.Add(object, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.Generic.SortedDictionary<,>.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Generic.SortedDictionary<,>.CopyTo(KeyValuePair[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Generic.SortedDictionary<,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Generic.SortedDictionary<,>.KeyCollection.Add(TKey) | parameter 0 -> this parameter [element] | true | +| System.Collections.Generic.SortedDictionary<,>.KeyCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Generic.SortedDictionary<,>.KeyCollection.CopyTo(TKey[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Generic.SortedDictionary<,>.KeyCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Generic.SortedDictionary<,>.SortedDictionary(IDictionary) | parameter 0 [element, property Key] -> return [element, property Key] | true | +| System.Collections.Generic.SortedDictionary<,>.SortedDictionary(IDictionary) | parameter 0 [element, property Value] -> return [element, property Value] | true | +| System.Collections.Generic.SortedDictionary<,>.SortedDictionary(IDictionary, IComparer) | parameter 0 [element, property Key] -> return [element, property Key] | true | +| System.Collections.Generic.SortedDictionary<,>.SortedDictionary(IDictionary, IComparer) | parameter 0 [element, property Value] -> return [element, property Value] | true | +| System.Collections.Generic.SortedDictionary<,>.ValueCollection.Add(TValue) | parameter 0 -> this parameter [element] | true | +| System.Collections.Generic.SortedDictionary<,>.ValueCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Generic.SortedDictionary<,>.ValueCollection.CopyTo(TValue[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Generic.SortedDictionary<,>.ValueCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Generic.SortedDictionary<,>.get_Item(TKey) | this parameter [element, property Value] -> return | true | +| System.Collections.Generic.SortedDictionary<,>.get_Item(object) | this parameter [element, property Value] -> return | true | +| System.Collections.Generic.SortedDictionary<,>.get_Keys() | this parameter [element, property Key] -> return [element] | true | +| System.Collections.Generic.SortedDictionary<,>.get_Values() | this parameter [element, property Value] -> return [element] | true | +| System.Collections.Generic.SortedDictionary<,>.set_Item(TKey, TValue) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.Generic.SortedDictionary<,>.set_Item(TKey, TValue) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.Generic.SortedDictionary<,>.set_Item(object, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.Generic.SortedDictionary<,>.set_Item(object, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.Generic.SortedList<,>.Add(KeyValuePair) | parameter 0 -> this parameter [element] | true | +| System.Collections.Generic.SortedList<,>.Add(KeyValuePair) | parameter 0 [property Key] -> this parameter [element, property Key] | true | +| System.Collections.Generic.SortedList<,>.Add(KeyValuePair) | parameter 0 [property Value] -> this parameter [element, property Value] | true | +| System.Collections.Generic.SortedList<,>.Add(TKey, TValue) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.Generic.SortedList<,>.Add(TKey, TValue) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.Generic.SortedList<,>.Add(object, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.Generic.SortedList<,>.Add(object, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.Generic.SortedList<,>.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Generic.SortedList<,>.CopyTo(KeyValuePair[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Generic.SortedList<,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Generic.SortedList<,>.KeyList.Add(TKey) | parameter 0 -> this parameter [element] | true | +| System.Collections.Generic.SortedList<,>.KeyList.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Generic.SortedList<,>.KeyList.CopyTo(TKey[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Generic.SortedList<,>.KeyList.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Generic.SortedList<,>.KeyList.Insert(int, TKey) | parameter 1 -> this parameter [element] | true | +| System.Collections.Generic.SortedList<,>.KeyList.get_Item(int) | this parameter [element] -> return | true | +| System.Collections.Generic.SortedList<,>.KeyList.set_Item(int, TKey) | parameter 1 -> this parameter [element] | true | +| System.Collections.Generic.SortedList<,>.SortedList(IDictionary) | parameter 0 [element, property Key] -> return [element, property Key] | true | +| System.Collections.Generic.SortedList<,>.SortedList(IDictionary) | parameter 0 [element, property Value] -> return [element, property Value] | true | +| System.Collections.Generic.SortedList<,>.SortedList(IDictionary, IComparer) | parameter 0 [element, property Key] -> return [element, property Key] | true | +| System.Collections.Generic.SortedList<,>.SortedList(IDictionary, IComparer) | parameter 0 [element, property Value] -> return [element, property Value] | true | +| System.Collections.Generic.SortedList<,>.ValueList.Add(TValue) | parameter 0 -> this parameter [element] | true | +| System.Collections.Generic.SortedList<,>.ValueList.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Generic.SortedList<,>.ValueList.CopyTo(TValue[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Generic.SortedList<,>.ValueList.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Generic.SortedList<,>.ValueList.Insert(int, TValue) | parameter 1 -> this parameter [element] | true | +| System.Collections.Generic.SortedList<,>.ValueList.get_Item(int) | this parameter [element] -> return | true | +| System.Collections.Generic.SortedList<,>.ValueList.set_Item(int, TValue) | parameter 1 -> this parameter [element] | true | +| System.Collections.Generic.SortedList<,>.get_Item(TKey) | this parameter [element, property Value] -> return | true | +| System.Collections.Generic.SortedList<,>.get_Item(object) | this parameter [element, property Value] -> return | true | +| System.Collections.Generic.SortedList<,>.get_Keys() | this parameter [element, property Key] -> return [element] | true | +| System.Collections.Generic.SortedList<,>.get_Values() | this parameter [element, property Value] -> return [element] | true | +| System.Collections.Generic.SortedList<,>.set_Item(TKey, TValue) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.Generic.SortedList<,>.set_Item(TKey, TValue) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.Generic.SortedList<,>.set_Item(object, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.Generic.SortedList<,>.set_Item(object, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.Generic.SortedSet<>.d__84.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Generic.SortedSet<>.Add(T) | parameter 0 -> this parameter [element] | true | +| System.Collections.Generic.SortedSet<>.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Generic.SortedSet<>.CopyTo(T[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Generic.SortedSet<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Generic.SortedSet<>.Reverse() | parameter 0 [element] -> return [element] | true | +| System.Collections.Generic.Stack<>.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Generic.Stack<>.CopyTo(T[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Generic.Stack<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Generic.Stack<>.Peek() | this parameter [element] -> return | true | +| System.Collections.Generic.Stack<>.Pop() | this parameter [element] -> return | true | +| System.Collections.Hashtable.Add(object, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.Hashtable.Add(object, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.Hashtable.Clone() | parameter 0 [element] -> return [element] | true | +| System.Collections.Hashtable.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Hashtable.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Hashtable.Hashtable(IDictionary) | parameter 0 [element, property Key] -> return [element, property Key] | true | +| System.Collections.Hashtable.Hashtable(IDictionary) | parameter 0 [element, property Value] -> return [element, property Value] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, IEqualityComparer) | parameter 0 [element, property Key] -> return [element, property Key] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, IEqualityComparer) | parameter 0 [element, property Value] -> return [element, property Value] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, IHashCodeProvider, IComparer) | parameter 0 [element, property Key] -> return [element, property Key] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, IHashCodeProvider, IComparer) | parameter 0 [element, property Value] -> return [element, property Value] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, float) | parameter 0 [element, property Key] -> return [element, property Key] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, float) | parameter 0 [element, property Value] -> return [element, property Value] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, float, IEqualityComparer) | parameter 0 [element, property Key] -> return [element, property Key] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, float, IEqualityComparer) | parameter 0 [element, property Value] -> return [element, property Value] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, float, IHashCodeProvider, IComparer) | parameter 0 [element, property Key] -> return [element, property Key] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, float, IHashCodeProvider, IComparer) | parameter 0 [element, property Value] -> return [element, property Value] | true | +| System.Collections.Hashtable.KeyCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Hashtable.KeyCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Hashtable.SyncHashtable.Add(object, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.Hashtable.SyncHashtable.Add(object, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.Hashtable.SyncHashtable.Clone() | parameter 0 [element] -> return [element] | true | +| System.Collections.Hashtable.SyncHashtable.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Hashtable.SyncHashtable.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Hashtable.SyncHashtable.get_Item(object) | this parameter [element, property Value] -> return | true | +| System.Collections.Hashtable.SyncHashtable.get_Keys() | this parameter [element, property Key] -> return [element] | true | +| System.Collections.Hashtable.SyncHashtable.get_Values() | this parameter [element, property Value] -> return [element] | true | +| System.Collections.Hashtable.SyncHashtable.set_Item(object, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.Hashtable.SyncHashtable.set_Item(object, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.Hashtable.ValueCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Hashtable.ValueCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Hashtable.get_Item(object) | this parameter [element, property Value] -> return | true | +| System.Collections.Hashtable.get_Keys() | this parameter [element, property Key] -> return [element] | true | +| System.Collections.Hashtable.get_Values() | this parameter [element, property Value] -> return [element] | true | +| System.Collections.Hashtable.set_Item(object, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.Hashtable.set_Item(object, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.ICollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.IDictionary.Add(object, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.IDictionary.Add(object, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.IDictionary.get_Item(object) | this parameter [element, property Value] -> return | true | +| System.Collections.IDictionary.get_Keys() | this parameter [element, property Key] -> return [element] | true | +| System.Collections.IDictionary.get_Values() | this parameter [element, property Value] -> return [element] | true | +| System.Collections.IDictionary.set_Item(object, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.IDictionary.set_Item(object, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.IEnumerable.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.IList.Add(object) | parameter 0 -> this parameter [element] | true | +| System.Collections.IList.Insert(int, object) | parameter 1 -> this parameter [element] | true | +| System.Collections.IList.get_Item(int) | this parameter [element] -> return | true | +| System.Collections.IList.set_Item(int, object) | parameter 1 -> this parameter [element] | true | +| System.Collections.ListDictionaryInternal.Add(object, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.ListDictionaryInternal.Add(object, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.ListDictionaryInternal.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.ListDictionaryInternal.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.ListDictionaryInternal.NodeKeyValueCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.ListDictionaryInternal.NodeKeyValueCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.ListDictionaryInternal.get_Item(object) | this parameter [element, property Value] -> return | true | +| System.Collections.ListDictionaryInternal.get_Keys() | this parameter [element, property Key] -> return [element] | true | +| System.Collections.ListDictionaryInternal.get_Values() | this parameter [element, property Value] -> return [element] | true | +| System.Collections.ListDictionaryInternal.set_Item(object, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.ListDictionaryInternal.set_Item(object, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.ObjectModel.Collection<>.Add(T) | parameter 0 -> this parameter [element] | true | +| System.Collections.ObjectModel.Collection<>.Add(object) | parameter 0 -> this parameter [element] | true | +| System.Collections.ObjectModel.Collection<>.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.ObjectModel.Collection<>.CopyTo(T[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.ObjectModel.Collection<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.ObjectModel.Collection<>.Insert(int, T) | parameter 1 -> this parameter [element] | true | +| System.Collections.ObjectModel.Collection<>.Insert(int, object) | parameter 1 -> this parameter [element] | true | +| System.Collections.ObjectModel.Collection<>.get_Item(int) | this parameter [element] -> return | true | +| System.Collections.ObjectModel.Collection<>.set_Item(int, T) | parameter 1 -> this parameter [element] | true | +| System.Collections.ObjectModel.Collection<>.set_Item(int, object) | parameter 1 -> this parameter [element] | true | +| System.Collections.ObjectModel.KeyedCollection<,>.get_Item(TKey) | this parameter [element] -> return | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.Add(T) | parameter 0 -> this parameter [element] | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.Add(object) | parameter 0 -> this parameter [element] | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.CopyTo(T[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.Insert(int, T) | parameter 1 -> this parameter [element] | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.Insert(int, object) | parameter 1 -> this parameter [element] | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.get_Item(int) | this parameter [element] -> return | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.set_Item(int, T) | parameter 1 -> this parameter [element] | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.set_Item(int, object) | parameter 1 -> this parameter [element] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(KeyValuePair) | parameter 0 -> this parameter [element] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(KeyValuePair) | parameter 0 [property Key] -> this parameter [element, property Key] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(KeyValuePair) | parameter 0 [property Value] -> this parameter [element, property Value] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(TKey, TValue) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(TKey, TValue) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(object, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(object, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.CopyTo(KeyValuePair[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.KeyCollection.Add(TKey) | parameter 0 -> this parameter [element] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.KeyCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.KeyCollection.CopyTo(TKey[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.KeyCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ReadOnlyDictionary(IDictionary) | parameter 0 [element, property Key] -> return [element, property Key] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ReadOnlyDictionary(IDictionary) | parameter 0 [element, property Value] -> return [element, property Value] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ValueCollection.Add(TValue) | parameter 0 -> this parameter [element] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ValueCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ValueCollection.CopyTo(TValue[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ValueCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.get_Item(TKey) | this parameter [element, property Value] -> return | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.get_Item(object) | this parameter [element, property Value] -> return | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.get_Keys() | this parameter [element, property Key] -> return [element] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.get_Values() | this parameter [element, property Value] -> return [element] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.set_Item(TKey, TValue) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.set_Item(TKey, TValue) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.set_Item(object, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.set_Item(object, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.Queue.Clone() | parameter 0 [element] -> return [element] | true | +| System.Collections.Queue.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Queue.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Queue.Peek() | this parameter [element] -> return | true | +| System.Collections.Queue.SynchronizedQueue.Clone() | parameter 0 [element] -> return [element] | true | +| System.Collections.Queue.SynchronizedQueue.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Queue.SynchronizedQueue.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Queue.SynchronizedQueue.Peek() | this parameter [element] -> return | true | +| System.Collections.ReadOnlyCollectionBase.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.ReadOnlyCollectionBase.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.SortedList.Add(object, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.SortedList.Add(object, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.SortedList.Clone() | parameter 0 [element] -> return [element] | true | +| System.Collections.SortedList.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.SortedList.GetByIndex(int) | this parameter [element, property Value] -> return | true | +| System.Collections.SortedList.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.SortedList.GetValueList() | this parameter [element, property Value] -> return [element] | true | +| System.Collections.SortedList.KeyList.Add(object) | parameter 0 -> this parameter [element] | true | +| System.Collections.SortedList.KeyList.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.SortedList.KeyList.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.SortedList.KeyList.Insert(int, object) | parameter 1 -> this parameter [element] | true | +| System.Collections.SortedList.KeyList.get_Item(int) | this parameter [element] -> return | true | +| System.Collections.SortedList.KeyList.set_Item(int, object) | parameter 1 -> this parameter [element] | true | +| System.Collections.SortedList.SortedList(IDictionary) | parameter 0 [element, property Key] -> return [element, property Key] | true | +| System.Collections.SortedList.SortedList(IDictionary) | parameter 0 [element, property Value] -> return [element, property Value] | true | +| System.Collections.SortedList.SortedList(IDictionary, IComparer) | parameter 0 [element, property Key] -> return [element, property Key] | true | +| System.Collections.SortedList.SortedList(IDictionary, IComparer) | parameter 0 [element, property Value] -> return [element, property Value] | true | +| System.Collections.SortedList.SyncSortedList.Add(object, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.SortedList.SyncSortedList.Add(object, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.SortedList.SyncSortedList.Clone() | parameter 0 [element] -> return [element] | true | +| System.Collections.SortedList.SyncSortedList.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.SortedList.SyncSortedList.GetByIndex(int) | this parameter [element, property Value] -> return | true | +| System.Collections.SortedList.SyncSortedList.GetValueList() | this parameter [element, property Value] -> return [element] | true | +| System.Collections.SortedList.SyncSortedList.get_Item(object) | this parameter [element, property Value] -> return | true | +| System.Collections.SortedList.SyncSortedList.set_Item(object, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.SortedList.SyncSortedList.set_Item(object, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.SortedList.ValueList.Add(object) | parameter 0 -> this parameter [element] | true | +| System.Collections.SortedList.ValueList.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.SortedList.ValueList.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.SortedList.ValueList.Insert(int, object) | parameter 1 -> this parameter [element] | true | +| System.Collections.SortedList.ValueList.get_Item(int) | this parameter [element] -> return | true | +| System.Collections.SortedList.ValueList.set_Item(int, object) | parameter 1 -> this parameter [element] | true | +| System.Collections.SortedList.get_Item(object) | this parameter [element, property Value] -> return | true | +| System.Collections.SortedList.get_Keys() | this parameter [element, property Key] -> return [element] | true | +| System.Collections.SortedList.get_Values() | this parameter [element, property Value] -> return [element] | true | +| System.Collections.SortedList.set_Item(object, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.SortedList.set_Item(object, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.Specialized.HybridDictionary.Add(object, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.Specialized.HybridDictionary.Add(object, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.Specialized.HybridDictionary.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Specialized.HybridDictionary.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Specialized.HybridDictionary.get_Item(object) | this parameter [element, property Value] -> return | true | +| System.Collections.Specialized.HybridDictionary.get_Keys() | this parameter [element, property Key] -> return [element] | true | +| System.Collections.Specialized.HybridDictionary.get_Values() | this parameter [element, property Value] -> return [element] | true | +| System.Collections.Specialized.HybridDictionary.set_Item(object, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.Specialized.HybridDictionary.set_Item(object, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.Specialized.IOrderedDictionary.get_Item(int) | this parameter [element, property Value] -> return | true | +| System.Collections.Specialized.IOrderedDictionary.set_Item(int, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.Specialized.IOrderedDictionary.set_Item(int, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.Specialized.ListDictionary.Add(object, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.Specialized.ListDictionary.Add(object, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.Specialized.ListDictionary.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Specialized.ListDictionary.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Specialized.ListDictionary.NodeKeyValueCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Specialized.ListDictionary.NodeKeyValueCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Specialized.ListDictionary.get_Item(object) | this parameter [element, property Value] -> return | true | +| System.Collections.Specialized.ListDictionary.get_Keys() | this parameter [element, property Key] -> return [element] | true | +| System.Collections.Specialized.ListDictionary.get_Values() | this parameter [element, property Value] -> return [element] | true | +| System.Collections.Specialized.ListDictionary.set_Item(object, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.Specialized.ListDictionary.set_Item(object, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.Specialized.NameObjectCollectionBase.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Specialized.NameObjectCollectionBase.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Specialized.NameObjectCollectionBase.KeysCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Specialized.NameObjectCollectionBase.KeysCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Specialized.NameValueCollection.Add(NameValueCollection) | parameter 0 -> this parameter [element] | true | +| System.Collections.Specialized.NameValueCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Specialized.OrderedDictionary.Add(object, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.Specialized.OrderedDictionary.Add(object, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.Specialized.OrderedDictionary.AsReadOnly() | parameter 0 [element] -> return [element] | true | +| System.Collections.Specialized.OrderedDictionary.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Specialized.OrderedDictionary.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Specialized.OrderedDictionary.OrderedDictionaryKeyValueCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Specialized.OrderedDictionary.OrderedDictionaryKeyValueCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Specialized.OrderedDictionary.get_Item(int) | this parameter [element, property Value] -> return | true | +| System.Collections.Specialized.OrderedDictionary.get_Item(object) | this parameter [element, property Value] -> return | true | +| System.Collections.Specialized.OrderedDictionary.get_Keys() | this parameter [element, property Key] -> return [element] | true | +| System.Collections.Specialized.OrderedDictionary.get_Values() | this parameter [element, property Value] -> return [element] | true | +| System.Collections.Specialized.OrderedDictionary.set_Item(int, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.Specialized.OrderedDictionary.set_Item(int, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.Specialized.OrderedDictionary.set_Item(object, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.Collections.Specialized.OrderedDictionary.set_Item(object, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.Collections.Specialized.ReadOnlyList.Add(object) | parameter 0 -> this parameter [element] | true | +| System.Collections.Specialized.ReadOnlyList.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Specialized.ReadOnlyList.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Specialized.ReadOnlyList.Insert(int, object) | parameter 1 -> this parameter [element] | true | +| System.Collections.Specialized.ReadOnlyList.get_Item(int) | this parameter [element] -> return | true | +| System.Collections.Specialized.ReadOnlyList.set_Item(int, object) | parameter 1 -> this parameter [element] | true | +| System.Collections.Specialized.StringCollection.Add(object) | parameter 0 -> this parameter [element] | true | +| System.Collections.Specialized.StringCollection.Add(string) | parameter 0 -> this parameter [element] | true | +| System.Collections.Specialized.StringCollection.AddRange(String[]) | parameter 0 [element] -> this parameter [element] | true | +| System.Collections.Specialized.StringCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Specialized.StringCollection.CopyTo(String[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Specialized.StringCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Specialized.StringCollection.Insert(int, object) | parameter 1 -> this parameter [element] | true | +| System.Collections.Specialized.StringCollection.Insert(int, string) | parameter 1 -> this parameter [element] | true | +| System.Collections.Specialized.StringCollection.get_Item(int) | this parameter [element] -> return | true | +| System.Collections.Specialized.StringCollection.set_Item(int, object) | parameter 1 -> this parameter [element] | true | +| System.Collections.Specialized.StringCollection.set_Item(int, string) | parameter 1 -> this parameter [element] | true | +| System.Collections.Specialized.StringDictionary.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Stack.Clone() | parameter 0 [element] -> return [element] | true | +| System.Collections.Stack.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Stack.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Stack.Peek() | this parameter [element] -> return | true | +| System.Collections.Stack.Pop() | this parameter [element] -> return | true | +| System.Collections.Stack.SyncStack.Clone() | parameter 0 [element] -> return [element] | true | +| System.Collections.Stack.SyncStack.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Collections.Stack.SyncStack.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Collections.Stack.SyncStack.Peek() | this parameter [element] -> return | true | +| System.Collections.Stack.SyncStack.Pop() | this parameter [element] -> return | true | +| System.ComponentModel.AttributeCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.ComponentModel.AttributeCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.ComponentModel.BindingList<>.Find(PropertyDescriptor, object) | this parameter [element] -> return | true | +| System.ComponentModel.Design.DesignerCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.ComponentModel.Design.DesignerCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.Add(object) | parameter 0 -> this parameter [element] | true | +| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.Insert(int, object) | parameter 1 -> this parameter [element] | true | +| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.get_Item(int) | this parameter [element] -> return | true | +| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.get_Item(string) | this parameter [element] -> return | true | +| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.set_Item(int, object) | parameter 1 -> this parameter [element] | true | +| System.ComponentModel.Design.DesignerVerbCollection.Add(DesignerVerb) | parameter 0 -> this parameter [element] | true | +| System.ComponentModel.Design.DesignerVerbCollection.AddRange(DesignerVerbCollection) | parameter 0 [element] -> this parameter [element] | true | +| System.ComponentModel.Design.DesignerVerbCollection.AddRange(DesignerVerb[]) | parameter 0 [element] -> this parameter [element] | true | +| System.ComponentModel.Design.DesignerVerbCollection.CopyTo(DesignerVerb[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.ComponentModel.Design.DesignerVerbCollection.Insert(int, DesignerVerb) | parameter 1 -> this parameter [element] | true | +| System.ComponentModel.Design.DesignerVerbCollection.get_Item(int) | this parameter [element] -> return | true | +| System.ComponentModel.Design.DesignerVerbCollection.set_Item(int, DesignerVerb) | parameter 1 -> this parameter [element] | true | +| System.ComponentModel.EventDescriptorCollection.Add(EventDescriptor) | parameter 0 -> this parameter [element] | true | +| System.ComponentModel.EventDescriptorCollection.Add(object) | parameter 0 -> this parameter [element] | true | +| System.ComponentModel.EventDescriptorCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.ComponentModel.EventDescriptorCollection.Find(string, bool) | this parameter [element] -> return | true | +| System.ComponentModel.EventDescriptorCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.ComponentModel.EventDescriptorCollection.Insert(int, EventDescriptor) | parameter 1 -> this parameter [element] | true | +| System.ComponentModel.EventDescriptorCollection.Insert(int, object) | parameter 1 -> this parameter [element] | true | +| System.ComponentModel.EventDescriptorCollection.get_Item(int) | this parameter [element] -> return | true | +| System.ComponentModel.EventDescriptorCollection.get_Item(string) | this parameter [element] -> return | true | +| System.ComponentModel.EventDescriptorCollection.set_Item(int, object) | parameter 1 -> this parameter [element] | true | +| System.ComponentModel.IBindingList.Find(PropertyDescriptor, object) | this parameter [element] -> return | true | +| System.ComponentModel.ListSortDescriptionCollection.Add(object) | parameter 0 -> this parameter [element] | true | +| System.ComponentModel.ListSortDescriptionCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.ComponentModel.ListSortDescriptionCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.ComponentModel.ListSortDescriptionCollection.Insert(int, object) | parameter 1 -> this parameter [element] | true | +| System.ComponentModel.ListSortDescriptionCollection.get_Item(int) | this parameter [element] -> return | true | +| System.ComponentModel.ListSortDescriptionCollection.set_Item(int, ListSortDescription) | parameter 1 -> this parameter [element] | true | +| System.ComponentModel.ListSortDescriptionCollection.set_Item(int, object) | parameter 1 -> this parameter [element] | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(PropertyDescriptor) | parameter 0 -> this parameter [element] | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(PropertyDescriptor) | parameter 0 [property Key] -> this parameter [element, property Key] | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(PropertyDescriptor) | parameter 0 [property Value] -> this parameter [element, property Value] | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(object) | parameter 0 -> this parameter [element] | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(object) | parameter 0 [property Key] -> this parameter [element, property Key] | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(object) | parameter 0 [property Value] -> this parameter [element, property Value] | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(object, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(object, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.ComponentModel.PropertyDescriptorCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.ComponentModel.PropertyDescriptorCollection.Find(string, bool) | this parameter [element] -> return | true | +| System.ComponentModel.PropertyDescriptorCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.ComponentModel.PropertyDescriptorCollection.Insert(int, PropertyDescriptor) | parameter 1 -> this parameter [element] | true | +| System.ComponentModel.PropertyDescriptorCollection.Insert(int, object) | parameter 1 -> this parameter [element] | true | +| System.ComponentModel.PropertyDescriptorCollection.PropertyDescriptorCollection(PropertyDescriptor[]) | parameter 0 [element, property Key] -> return [element, property Key] | true | +| System.ComponentModel.PropertyDescriptorCollection.PropertyDescriptorCollection(PropertyDescriptor[]) | parameter 0 [element, property Value] -> return [element, property Value] | true | +| System.ComponentModel.PropertyDescriptorCollection.PropertyDescriptorCollection(PropertyDescriptor[], bool) | parameter 0 [element, property Key] -> return [element, property Key] | true | +| System.ComponentModel.PropertyDescriptorCollection.PropertyDescriptorCollection(PropertyDescriptor[], bool) | parameter 0 [element, property Value] -> return [element, property Value] | true | +| System.ComponentModel.PropertyDescriptorCollection.get_Item(int) | this parameter [element, property Value] -> return | true | +| System.ComponentModel.PropertyDescriptorCollection.get_Item(int) | this parameter [element] -> return | true | +| System.ComponentModel.PropertyDescriptorCollection.get_Item(object) | this parameter [element, property Value] -> return | true | +| System.ComponentModel.PropertyDescriptorCollection.get_Item(object) | this parameter [element] -> return | true | +| System.ComponentModel.PropertyDescriptorCollection.get_Item(string) | this parameter [element, property Value] -> return | true | +| System.ComponentModel.PropertyDescriptorCollection.get_Item(string) | this parameter [element] -> return | true | +| System.ComponentModel.PropertyDescriptorCollection.get_Keys() | this parameter [element, property Key] -> return [element] | true | +| System.ComponentModel.PropertyDescriptorCollection.get_Values() | this parameter [element, property Value] -> return [element] | true | +| System.ComponentModel.PropertyDescriptorCollection.set_Item(int, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.ComponentModel.PropertyDescriptorCollection.set_Item(int, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.ComponentModel.PropertyDescriptorCollection.set_Item(int, object) | parameter 1 -> this parameter [element] | true | +| System.ComponentModel.PropertyDescriptorCollection.set_Item(object, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.ComponentModel.PropertyDescriptorCollection.set_Item(object, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.ComponentModel.PropertyDescriptorCollection.set_Item(object, object) | parameter 1 -> this parameter [element] | true | +| System.ComponentModel.TypeConverter.StandardValuesCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.ComponentModel.TypeConverter.StandardValuesCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | | System.ConsolePal.UnixConsoleStream.Read(Byte[], int, int) | this parameter -> parameter 0 | false | | System.ConsolePal.UnixConsoleStream.Write(Byte[], int, int) | parameter 0 -> this parameter | false | | System.Convert.ChangeType(object, Type) | parameter 0 -> return | false | @@ -1062,47 +1062,47 @@ | System.Convert.TryFromBase64Chars(ReadOnlySpan, Span, out int) | parameter 0 -> return | false | | System.Convert.TryFromBase64String(string, Span, out int) | parameter 0 -> return | false | | System.Convert.TryToBase64Chars(ReadOnlySpan, Span, out int, Base64FormattingOptions) | parameter 0 -> return | false | -| System.Diagnostics.Tracing.CounterPayload.d__51.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Diagnostics.Tracing.CounterPayload.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Diagnostics.Tracing.EventPayload.Add(KeyValuePair) | parameter 0 -> this parameter [[]] | true | -| System.Diagnostics.Tracing.EventPayload.Add(KeyValuePair) | parameter 0 [Key] -> this parameter [[], Key] | true | -| System.Diagnostics.Tracing.EventPayload.Add(KeyValuePair) | parameter 0 [Value] -> this parameter [[], Value] | true | -| System.Diagnostics.Tracing.EventPayload.Add(string, object) | parameter 0 -> this parameter [[], Key] | true | -| System.Diagnostics.Tracing.EventPayload.Add(string, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Diagnostics.Tracing.EventPayload.CopyTo(KeyValuePair[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Diagnostics.Tracing.EventPayload.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Diagnostics.Tracing.EventPayload.get_Item(string) | this parameter [[], Value] -> return | true | -| System.Diagnostics.Tracing.EventPayload.get_Keys() | this parameter [[], Key] -> return [[]] | true | -| System.Diagnostics.Tracing.EventPayload.get_Values() | this parameter [[], Value] -> return [[]] | true | -| System.Diagnostics.Tracing.EventPayload.set_Item(string, object) | parameter 0 -> this parameter [[], Key] | true | -| System.Diagnostics.Tracing.EventPayload.set_Item(string, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Diagnostics.Tracing.IncrementingCounterPayload.d__39.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Diagnostics.Tracing.IncrementingCounterPayload.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Dynamic.ExpandoObject.Add(KeyValuePair) | parameter 0 -> this parameter [[]] | true | -| System.Dynamic.ExpandoObject.Add(KeyValuePair) | parameter 0 [Key] -> this parameter [[], Key] | true | -| System.Dynamic.ExpandoObject.Add(KeyValuePair) | parameter 0 [Value] -> this parameter [[], Value] | true | -| System.Dynamic.ExpandoObject.Add(string, object) | parameter 0 -> this parameter [[], Key] | true | -| System.Dynamic.ExpandoObject.Add(string, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Dynamic.ExpandoObject.CopyTo(KeyValuePair[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Dynamic.ExpandoObject.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Dynamic.ExpandoObject.KeyCollection.Add(string) | parameter 0 -> this parameter [[]] | true | -| System.Dynamic.ExpandoObject.KeyCollection.CopyTo(String[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Dynamic.ExpandoObject.KeyCollection.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Dynamic.ExpandoObject.MetaExpando.d__6.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Dynamic.ExpandoObject.ValueCollection.Add(object) | parameter 0 -> this parameter [[]] | true | -| System.Dynamic.ExpandoObject.ValueCollection.CopyTo(Object[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Dynamic.ExpandoObject.ValueCollection.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Dynamic.ExpandoObject.get_Item(string) | this parameter [[], Value] -> return | true | -| System.Dynamic.ExpandoObject.get_Keys() | this parameter [[], Key] -> return [[]] | true | -| System.Dynamic.ExpandoObject.get_Values() | this parameter [[], Value] -> return [[]] | true | -| System.Dynamic.ExpandoObject.set_Item(string, object) | parameter 0 -> this parameter [[], Key] | true | -| System.Dynamic.ExpandoObject.set_Item(string, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Dynamic.Utils.ListProvider<>.Add(T) | parameter 0 -> this parameter [[]] | true | -| System.Dynamic.Utils.ListProvider<>.CopyTo(T[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Dynamic.Utils.ListProvider<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Dynamic.Utils.ListProvider<>.Insert(int, T) | parameter 1 -> this parameter [[]] | true | -| System.Dynamic.Utils.ListProvider<>.get_Item(int) | this parameter [[]] -> return | true | -| System.Dynamic.Utils.ListProvider<>.set_Item(int, T) | parameter 1 -> this parameter [[]] | true | +| System.Diagnostics.Tracing.CounterPayload.d__51.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Diagnostics.Tracing.CounterPayload.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Diagnostics.Tracing.EventPayload.Add(KeyValuePair) | parameter 0 -> this parameter [element] | true | +| System.Diagnostics.Tracing.EventPayload.Add(KeyValuePair) | parameter 0 [property Key] -> this parameter [element, property Key] | true | +| System.Diagnostics.Tracing.EventPayload.Add(KeyValuePair) | parameter 0 [property Value] -> this parameter [element, property Value] | true | +| System.Diagnostics.Tracing.EventPayload.Add(string, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.Diagnostics.Tracing.EventPayload.Add(string, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.Diagnostics.Tracing.EventPayload.CopyTo(KeyValuePair[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Diagnostics.Tracing.EventPayload.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Diagnostics.Tracing.EventPayload.get_Item(string) | this parameter [element, property Value] -> return | true | +| System.Diagnostics.Tracing.EventPayload.get_Keys() | this parameter [element, property Key] -> return [element] | true | +| System.Diagnostics.Tracing.EventPayload.get_Values() | this parameter [element, property Value] -> return [element] | true | +| System.Diagnostics.Tracing.EventPayload.set_Item(string, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.Diagnostics.Tracing.EventPayload.set_Item(string, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.Diagnostics.Tracing.IncrementingCounterPayload.d__39.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Diagnostics.Tracing.IncrementingCounterPayload.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Dynamic.ExpandoObject.Add(KeyValuePair) | parameter 0 -> this parameter [element] | true | +| System.Dynamic.ExpandoObject.Add(KeyValuePair) | parameter 0 [property Key] -> this parameter [element, property Key] | true | +| System.Dynamic.ExpandoObject.Add(KeyValuePair) | parameter 0 [property Value] -> this parameter [element, property Value] | true | +| System.Dynamic.ExpandoObject.Add(string, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.Dynamic.ExpandoObject.Add(string, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.Dynamic.ExpandoObject.CopyTo(KeyValuePair[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Dynamic.ExpandoObject.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Dynamic.ExpandoObject.KeyCollection.Add(string) | parameter 0 -> this parameter [element] | true | +| System.Dynamic.ExpandoObject.KeyCollection.CopyTo(String[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Dynamic.ExpandoObject.KeyCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Dynamic.ExpandoObject.MetaExpando.d__6.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Dynamic.ExpandoObject.ValueCollection.Add(object) | parameter 0 -> this parameter [element] | true | +| System.Dynamic.ExpandoObject.ValueCollection.CopyTo(Object[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Dynamic.ExpandoObject.ValueCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Dynamic.ExpandoObject.get_Item(string) | this parameter [element, property Value] -> return | true | +| System.Dynamic.ExpandoObject.get_Keys() | this parameter [element, property Key] -> return [element] | true | +| System.Dynamic.ExpandoObject.get_Values() | this parameter [element, property Value] -> return [element] | true | +| System.Dynamic.ExpandoObject.set_Item(string, object) | parameter 0 -> this parameter [element, property Key] | true | +| System.Dynamic.ExpandoObject.set_Item(string, object) | parameter 1 -> this parameter [element, property Value] | true | +| System.Dynamic.Utils.ListProvider<>.Add(T) | parameter 0 -> this parameter [element] | true | +| System.Dynamic.Utils.ListProvider<>.CopyTo(T[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Dynamic.Utils.ListProvider<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Dynamic.Utils.ListProvider<>.Insert(int, T) | parameter 1 -> this parameter [element] | true | +| System.Dynamic.Utils.ListProvider<>.get_Item(int) | this parameter [element] -> return | true | +| System.Dynamic.Utils.ListProvider<>.set_Item(int, T) | parameter 1 -> this parameter [element] | true | | System.IO.BufferedStream.BeginRead(Byte[], int, int, AsyncCallback, object) | this parameter -> parameter 0 | false | | System.IO.BufferedStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | parameter 0 -> this parameter | false | | System.IO.BufferedStream.CopyTo(Stream, int) | this parameter -> parameter 0 | false | @@ -1169,7 +1169,7 @@ | System.IO.MemoryStream.ToArray() | this parameter -> return | false | | System.IO.MemoryStream.Write(Byte[], int, int) | parameter 0 -> this parameter | false | | System.IO.MemoryStream.WriteAsync(Byte[], int, int, CancellationToken) | parameter 0 -> this parameter | false | -| System.IO.Path.Combine(params String[]) | parameter 0 [[]] -> return | false | +| System.IO.Path.Combine(params String[]) | parameter 0 [element] -> return | false | | System.IO.Path.Combine(string, string) | parameter 0 -> return | false | | System.IO.Path.Combine(string, string) | parameter 1 -> return | false | | System.IO.Path.Combine(string, string, string) | parameter 0 -> return | false | @@ -1269,713 +1269,713 @@ | System.Int32.TryParse(string, NumberStyles, IFormatProvider, out int) | parameter 0 -> return | false | | System.Int32.TryParse(string, out int) | parameter 0 -> parameter 1 | false | | System.Int32.TryParse(string, out int) | parameter 0 -> return | false | -| System.Lazy<>.Lazy(Func) | deleget output from parameter 0 -> return [Value] | true | -| System.Lazy<>.Lazy(Func, LazyThreadSafetyMode) | deleget output from parameter 0 -> return [Value] | true | -| System.Lazy<>.Lazy(Func, bool) | deleget output from parameter 0 -> return [Value] | true | +| System.Lazy<>.Lazy(Func) | deleget output from parameter 0 -> return [property Value] | true | +| System.Lazy<>.Lazy(Func, LazyThreadSafetyMode) | deleget output from parameter 0 -> return [property Value] | true | +| System.Lazy<>.Lazy(Func, bool) | deleget output from parameter 0 -> return [property Value] | true | | System.Lazy<>.get_Value() | this parameter -> return | false | -| System.Linq.EmptyPartition<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.d__64<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.d__81<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.d__98<,,,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.d__101<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.d__105<,,,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.d__62<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.d__174<,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.d__177<,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.d__179<,,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.d__181<,,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.d__194<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.d__190<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.d__192<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.d__221<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.d__217<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.d__219<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.d__240<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.d__243<,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.d__244<,,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.Linq.EmptyPartition<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Enumerable.d__64<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Enumerable.d__81<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Enumerable.d__98<,,,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Enumerable.d__101<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Enumerable.d__105<,,,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Enumerable.d__62<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Enumerable.d__174<,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Enumerable.d__177<,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Enumerable.d__179<,,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Enumerable.d__181<,,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Enumerable.d__194<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Enumerable.d__190<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Enumerable.d__192<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Enumerable.d__221<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Enumerable.d__217<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Enumerable.d__219<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Enumerable.d__240<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Enumerable.d__243<,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Enumerable.d__244<,,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | | System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func, Func) | deleget output from parameter 2 -> parameter 0 of delegate parameter 3 | true | | System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func, Func) | deleget output from parameter 3 -> return | true | -| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func, Func) | parameter 0 [[]] -> parameter 1 of delegate parameter 2 | true | +| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func, Func) | parameter 0 [element] -> parameter 1 of delegate parameter 2 | true | | System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func, Func) | parameter 1 -> parameter 0 of delegate parameter 2 | true | | System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func) | deleget output from parameter 2 -> return | true | -| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func) | parameter 0 [[]] -> parameter 1 of delegate parameter 2 | true | +| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func) | parameter 0 [element] -> parameter 1 of delegate parameter 2 | true | | System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func) | parameter 1 -> parameter 0 of delegate parameter 2 | true | | System.Linq.Enumerable.Aggregate(IEnumerable, Func) | deleget output from parameter 1 -> return | true | -| System.Linq.Enumerable.Aggregate(IEnumerable, Func) | parameter 0 [[]] -> parameter 1 of delegate parameter 1 | true | -| System.Linq.Enumerable.All(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Any(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.AsEnumerable(IEnumerable) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Enumerable.Average(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Average(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Average(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Average(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Average(IEnumerable, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Average(IEnumerable, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Average(IEnumerable, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Average(IEnumerable, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Average(IEnumerable, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Average(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Cast(IEnumerable) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Enumerable.Concat(IEnumerable, IEnumerable) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Enumerable.Concat(IEnumerable, IEnumerable) | parameter 1 [[]] -> return [[]] | true | -| System.Linq.Enumerable.Count(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.DefaultIfEmpty(IEnumerable) | parameter 0 [[]] -> return | true | -| System.Linq.Enumerable.DefaultIfEmpty(IEnumerable, TSource) | parameter 0 [[]] -> return | true | +| System.Linq.Enumerable.Aggregate(IEnumerable, Func) | parameter 0 [element] -> parameter 1 of delegate parameter 1 | true | +| System.Linq.Enumerable.All(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Any(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.AsEnumerable(IEnumerable) | parameter 0 [element] -> return [element] | true | +| System.Linq.Enumerable.Average(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Average(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Average(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Average(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Average(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Average(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Average(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Average(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Average(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Average(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Cast(IEnumerable) | parameter 0 [element] -> return [element] | true | +| System.Linq.Enumerable.Concat(IEnumerable, IEnumerable) | parameter 0 [element] -> return [element] | true | +| System.Linq.Enumerable.Concat(IEnumerable, IEnumerable) | parameter 1 [element] -> return [element] | true | +| System.Linq.Enumerable.Count(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.DefaultIfEmpty(IEnumerable) | parameter 0 [element] -> return | true | +| System.Linq.Enumerable.DefaultIfEmpty(IEnumerable, TSource) | parameter 0 [element] -> return | true | | System.Linq.Enumerable.DefaultIfEmpty(IEnumerable, TSource) | parameter 1 -> return | true | -| System.Linq.Enumerable.Distinct(IEnumerable) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Enumerable.Distinct(IEnumerable, IEqualityComparer) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Enumerable.ElementAt(IEnumerable, int) | parameter 0 [[]] -> return | true | -| System.Linq.Enumerable.ElementAtOrDefault(IEnumerable, int) | parameter 0 [[]] -> return | true | -| System.Linq.Enumerable.Except(IEnumerable, IEnumerable) | parameter 0 [[]] -> return | true | -| System.Linq.Enumerable.Except(IEnumerable, IEnumerable, IEqualityComparer) | parameter 0 [[]] -> return | true | -| System.Linq.Enumerable.First(IEnumerable) | parameter 0 [[]] -> return | true | -| System.Linq.Enumerable.First(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.First(IEnumerable, Func) | parameter 0 [[]] -> return | true | -| System.Linq.Enumerable.FirstOrDefault(IEnumerable) | parameter 0 [[]] -> return | true | -| System.Linq.Enumerable.FirstOrDefault(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.FirstOrDefault(IEnumerable, Func) | parameter 0 [[]] -> return | true | +| System.Linq.Enumerable.Distinct(IEnumerable) | parameter 0 [element] -> return [element] | true | +| System.Linq.Enumerable.Distinct(IEnumerable, IEqualityComparer) | parameter 0 [element] -> return [element] | true | +| System.Linq.Enumerable.ElementAt(IEnumerable, int) | parameter 0 [element] -> return | true | +| System.Linq.Enumerable.ElementAtOrDefault(IEnumerable, int) | parameter 0 [element] -> return | true | +| System.Linq.Enumerable.Except(IEnumerable, IEnumerable) | parameter 0 [element] -> return | true | +| System.Linq.Enumerable.Except(IEnumerable, IEnumerable, IEqualityComparer) | parameter 0 [element] -> return | true | +| System.Linq.Enumerable.First(IEnumerable) | parameter 0 [element] -> return | true | +| System.Linq.Enumerable.First(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.First(IEnumerable, Func) | parameter 0 [element] -> return | true | +| System.Linq.Enumerable.FirstOrDefault(IEnumerable) | parameter 0 [element] -> return | true | +| System.Linq.Enumerable.FirstOrDefault(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.FirstOrDefault(IEnumerable, Func) | parameter 0 [element] -> return | true | | System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | deleget output from parameter 1 -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | deleget output from parameter 2 -> parameter 1 of delegate parameter 3 [[]] | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | deleget output from parameter 3 -> return [[]] | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | deleget output from parameter 2 -> parameter 1 of delegate parameter 3 [element] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | deleget output from parameter 3 -> return [element] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | | System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | deleget output from parameter 1 -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | deleget output from parameter 2 -> parameter 1 of delegate parameter 3 [[]] | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | deleget output from parameter 3 -> return [[]] | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func) | deleget output from parameter 2 -> return [[]] | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | deleget output from parameter 2 -> parameter 1 of delegate parameter 3 [element] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | deleget output from parameter 3 -> return [element] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func) | deleget output from parameter 2 -> return [element] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | | System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, IEqualityComparer) | deleget output from parameter 1 -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | | System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>) | deleget output from parameter 1 -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>) | deleget output from parameter 2 -> return [[]] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>) | deleget output from parameter 2 -> return [element] | true | | System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>) | parameter 0 -> parameter 1 of delegate parameter 2 | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | | System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>, IEqualityComparer) | deleget output from parameter 1 -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | deleget output from parameter 4 -> return [[]] | true | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | parameter 0 [[]] -> parameter 0 of delegate parameter 4 | true | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | parameter 1 [[]] -> parameter 0 of delegate parameter 3 | true | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | parameter 1 [[]] -> parameter 1 of delegate parameter 4 | true | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | deleget output from parameter 4 -> return [[]] | true | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 4 | true | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | parameter 1 [[]] -> parameter 0 of delegate parameter 3 | true | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | parameter 1 [[]] -> parameter 1 of delegate parameter 4 | true | -| System.Linq.Enumerable.Intersect(IEnumerable, IEnumerable) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Enumerable.Intersect(IEnumerable, IEnumerable) | parameter 1 [[]] -> return [[]] | true | -| System.Linq.Enumerable.Intersect(IEnumerable, IEnumerable, IEqualityComparer) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Enumerable.Intersect(IEnumerable, IEnumerable, IEqualityComparer) | parameter 1 [[]] -> return [[]] | true | -| System.Linq.Enumerable.Iterator<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | deleget output from parameter 4 -> return [[]] | true | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 4 | true | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | parameter 1 [[]] -> parameter 0 of delegate parameter 3 | true | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | parameter 1 [[]] -> parameter 1 of delegate parameter 4 | true | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | deleget output from parameter 4 -> return [[]] | true | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 4 | true | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | parameter 1 [[]] -> parameter 0 of delegate parameter 3 | true | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | parameter 1 [[]] -> parameter 1 of delegate parameter 4 | true | -| System.Linq.Enumerable.Last(IEnumerable) | parameter 0 [[]] -> return | true | -| System.Linq.Enumerable.Last(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Last(IEnumerable, Func) | parameter 0 [[]] -> return | true | -| System.Linq.Enumerable.LastOrDefault(IEnumerable) | parameter 0 [[]] -> return | true | -| System.Linq.Enumerable.LastOrDefault(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.LastOrDefault(IEnumerable, Func) | parameter 0 [[]] -> return | true | -| System.Linq.Enumerable.LongCount(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Max(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Max(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Max(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Max(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Max(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Max(IEnumerable, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Max(IEnumerable, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Max(IEnumerable, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Max(IEnumerable, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Max(IEnumerable, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Max(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Min(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Min(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Min(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Min(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Min(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Min(IEnumerable, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Min(IEnumerable, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Min(IEnumerable, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Min(IEnumerable, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Min(IEnumerable, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Min(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.OfType(IEnumerable) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Enumerable.OrderBy(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.OrderBy(IEnumerable, Func) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Enumerable.OrderBy(IEnumerable, Func, IComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.OrderBy(IEnumerable, Func, IComparer) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Enumerable.OrderByDescending(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.OrderByDescending(IEnumerable, Func) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Enumerable.OrderByDescending(IEnumerable, Func, IComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.OrderByDescending(IEnumerable, Func, IComparer) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Enumerable.Reverse(IEnumerable) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Enumerable.Select(IEnumerable, Func) | deleget output from parameter 1 -> return [[]] | true | -| System.Linq.Enumerable.Select(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Select(IEnumerable, Func) | deleget output from parameter 1 -> return [[]] | true | -| System.Linq.Enumerable.Select(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | deleget output from parameter 1 [[]] -> parameter 1 of delegate parameter 2 | true | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | deleget output from parameter 2 -> return [[]] | true | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | deleget output from parameter 1 [[]] -> parameter 1 of delegate parameter 2 | true | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | deleget output from parameter 2 -> return [[]] | true | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>) | deleget output from parameter 1 -> return [[]] | true | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>) | deleget output from parameter 1 -> return [[]] | true | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Single(IEnumerable) | parameter 0 [[]] -> return | true | -| System.Linq.Enumerable.Single(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Single(IEnumerable, Func) | parameter 0 [[]] -> return | true | -| System.Linq.Enumerable.SingleOrDefault(IEnumerable) | parameter 0 [[]] -> return | true | -| System.Linq.Enumerable.SingleOrDefault(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.SingleOrDefault(IEnumerable, Func) | parameter 0 [[]] -> return | true | -| System.Linq.Enumerable.Skip(IEnumerable, int) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Enumerable.Sum(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Sum(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Sum(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Sum(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Sum(IEnumerable, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Sum(IEnumerable, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Sum(IEnumerable, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Sum(IEnumerable, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Sum(IEnumerable, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Sum(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Take(IEnumerable, int) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Enumerable.ThenBy(IOrderedEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.ThenBy(IOrderedEnumerable, Func) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Enumerable.ThenBy(IOrderedEnumerable, Func, IComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.ThenBy(IOrderedEnumerable, Func, IComparer) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Enumerable.ThenByDescending(IOrderedEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.ThenByDescending(IOrderedEnumerable, Func) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Enumerable.ThenByDescending(IOrderedEnumerable, Func, IComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.ThenByDescending(IOrderedEnumerable, Func, IComparer) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Enumerable.ToArray(IEnumerable) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func) | deleget output from parameter 2 -> return [[]] | true | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func, IEqualityComparer) | deleget output from parameter 2 -> return [[]] | true | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, IEqualityComparer) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Enumerable.ToList(IEnumerable) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func) | deleget output from parameter 2 -> return [[]] | true | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func, IEqualityComparer) | deleget output from parameter 2 -> return [[]] | true | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func, IEqualityComparer) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Enumerable.Union(IEnumerable, IEnumerable) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Enumerable.Union(IEnumerable, IEnumerable) | parameter 1 [[]] -> return [[]] | true | -| System.Linq.Enumerable.Union(IEnumerable, IEnumerable, IEqualityComparer) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Enumerable.Union(IEnumerable, IEnumerable, IEqualityComparer) | parameter 1 [[]] -> return [[]] | true | -| System.Linq.Enumerable.Where(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Where(IEnumerable, Func) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Enumerable.Where(IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Where(IEnumerable, Func) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Enumerable.Zip(IEnumerable, IEnumerable, Func) | deleget output from parameter 2 -> return [[]] | true | -| System.Linq.Enumerable.Zip(IEnumerable, IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.Zip(IEnumerable, IEnumerable, Func) | parameter 1 [[]] -> parameter 1 of delegate parameter 2 | true | -| System.Linq.EnumerableQuery<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Expressions.BlockExpressionList.Add(Expression) | parameter 0 -> this parameter [[]] | true | -| System.Linq.Expressions.BlockExpressionList.CopyTo(Expression[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Linq.Expressions.BlockExpressionList.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Expressions.BlockExpressionList.Insert(int, Expression) | parameter 1 -> this parameter [[]] | true | -| System.Linq.Expressions.BlockExpressionList.get_Item(int) | this parameter [[]] -> return | true | -| System.Linq.Expressions.BlockExpressionList.set_Item(int, Expression) | parameter 1 -> this parameter [[]] | true | -| System.Linq.Expressions.Compiler.CompilerScope.d__32.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Expressions.Compiler.ParameterList.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Expressions.Interpreter.InterpretedFrame.d__29.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.GroupedEnumerable<,,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.GroupedEnumerable<,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.GroupedResultEnumerable<,,,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.GroupedResultEnumerable<,,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Grouping<,>.Add(TElement) | parameter 0 -> this parameter [[]] | true | -| System.Linq.Grouping<,>.CopyTo(TElement[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Linq.Grouping<,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Grouping<,>.Insert(int, TElement) | parameter 1 -> this parameter [[]] | true | -| System.Linq.Grouping<,>.get_Item(int) | this parameter [[]] -> return | true | -| System.Linq.Grouping<,>.set_Item(int, TElement) | parameter 1 -> this parameter [[]] | true | -| System.Linq.Lookup<,>.d__19<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Lookup<,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.OrderedEnumerable<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.OrderedPartition<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Parallel.CancellableEnumerable.d__0<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Parallel.EnumerableWrapperWeakToStrong.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Parallel.ExceptionAggregator.d__0<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Parallel.ExceptionAggregator.d__1<,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Parallel.GroupByGrouping<,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Parallel.ListChunk<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Parallel.Lookup<,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Parallel.MergeExecutor<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Parallel.OrderedGroupByGrouping<,,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Parallel.ParallelEnumerableWrapper.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Parallel.PartitionerQueryOperator<>.d__5.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Parallel.QueryResults<>.Add(T) | parameter 0 -> this parameter [[]] | true | -| System.Linq.Parallel.QueryResults<>.CopyTo(T[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Linq.Parallel.QueryResults<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Parallel.QueryResults<>.Insert(int, T) | parameter 1 -> this parameter [[]] | true | -| System.Linq.Parallel.QueryResults<>.get_Item(int) | this parameter [[]] -> return | true | -| System.Linq.Parallel.QueryResults<>.set_Item(int, T) | parameter 1 -> this parameter [[]] | true | -| System.Linq.Parallel.RangeEnumerable.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Parallel.ZipQueryOperator<,,>.d__9.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | deleget output from parameter 4 -> return [element] | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | parameter 0 [element] -> parameter 0 of delegate parameter 4 | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | parameter 1 [element] -> parameter 0 of delegate parameter 3 | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | parameter 1 [element] -> parameter 1 of delegate parameter 4 | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | deleget output from parameter 4 -> return [element] | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 4 | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | parameter 1 [element] -> parameter 0 of delegate parameter 3 | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | parameter 1 [element] -> parameter 1 of delegate parameter 4 | true | +| System.Linq.Enumerable.Intersect(IEnumerable, IEnumerable) | parameter 0 [element] -> return [element] | true | +| System.Linq.Enumerable.Intersect(IEnumerable, IEnumerable) | parameter 1 [element] -> return [element] | true | +| System.Linq.Enumerable.Intersect(IEnumerable, IEnumerable, IEqualityComparer) | parameter 0 [element] -> return [element] | true | +| System.Linq.Enumerable.Intersect(IEnumerable, IEnumerable, IEqualityComparer) | parameter 1 [element] -> return [element] | true | +| System.Linq.Enumerable.Iterator<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | deleget output from parameter 4 -> return [element] | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 4 | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | parameter 1 [element] -> parameter 0 of delegate parameter 3 | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | parameter 1 [element] -> parameter 1 of delegate parameter 4 | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | deleget output from parameter 4 -> return [element] | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 4 | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | parameter 1 [element] -> parameter 0 of delegate parameter 3 | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | parameter 1 [element] -> parameter 1 of delegate parameter 4 | true | +| System.Linq.Enumerable.Last(IEnumerable) | parameter 0 [element] -> return | true | +| System.Linq.Enumerable.Last(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Last(IEnumerable, Func) | parameter 0 [element] -> return | true | +| System.Linq.Enumerable.LastOrDefault(IEnumerable) | parameter 0 [element] -> return | true | +| System.Linq.Enumerable.LastOrDefault(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.LastOrDefault(IEnumerable, Func) | parameter 0 [element] -> return | true | +| System.Linq.Enumerable.LongCount(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Max(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Max(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Max(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Max(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Max(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Max(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Max(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Max(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Max(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Max(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Max(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Min(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Min(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Min(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Min(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Min(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Min(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Min(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Min(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Min(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Min(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Min(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.OfType(IEnumerable) | parameter 0 [element] -> return [element] | true | +| System.Linq.Enumerable.OrderBy(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.OrderBy(IEnumerable, Func) | parameter 0 [element] -> return [element] | true | +| System.Linq.Enumerable.OrderBy(IEnumerable, Func, IComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.OrderBy(IEnumerable, Func, IComparer) | parameter 0 [element] -> return [element] | true | +| System.Linq.Enumerable.OrderByDescending(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.OrderByDescending(IEnumerable, Func) | parameter 0 [element] -> return [element] | true | +| System.Linq.Enumerable.OrderByDescending(IEnumerable, Func, IComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.OrderByDescending(IEnumerable, Func, IComparer) | parameter 0 [element] -> return [element] | true | +| System.Linq.Enumerable.Reverse(IEnumerable) | parameter 0 [element] -> return [element] | true | +| System.Linq.Enumerable.Select(IEnumerable, Func) | deleget output from parameter 1 -> return [element] | true | +| System.Linq.Enumerable.Select(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Select(IEnumerable, Func) | deleget output from parameter 1 -> return [element] | true | +| System.Linq.Enumerable.Select(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | deleget output from parameter 1 [element] -> parameter 1 of delegate parameter 2 | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | deleget output from parameter 2 -> return [element] | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | deleget output from parameter 1 [element] -> parameter 1 of delegate parameter 2 | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | deleget output from parameter 2 -> return [element] | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>) | deleget output from parameter 1 -> return [element] | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>) | deleget output from parameter 1 -> return [element] | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Single(IEnumerable) | parameter 0 [element] -> return | true | +| System.Linq.Enumerable.Single(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Single(IEnumerable, Func) | parameter 0 [element] -> return | true | +| System.Linq.Enumerable.SingleOrDefault(IEnumerable) | parameter 0 [element] -> return | true | +| System.Linq.Enumerable.SingleOrDefault(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.SingleOrDefault(IEnumerable, Func) | parameter 0 [element] -> return | true | +| System.Linq.Enumerable.Skip(IEnumerable, int) | parameter 0 [element] -> return [element] | true | +| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | parameter 0 [element] -> return [element] | true | +| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | parameter 0 [element] -> return [element] | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Take(IEnumerable, int) | parameter 0 [element] -> return [element] | true | +| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | parameter 0 [element] -> return [element] | true | +| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | parameter 0 [element] -> return [element] | true | +| System.Linq.Enumerable.ThenBy(IOrderedEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.ThenBy(IOrderedEnumerable, Func) | parameter 0 [element] -> return [element] | true | +| System.Linq.Enumerable.ThenBy(IOrderedEnumerable, Func, IComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.ThenBy(IOrderedEnumerable, Func, IComparer) | parameter 0 [element] -> return [element] | true | +| System.Linq.Enumerable.ThenByDescending(IOrderedEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.ThenByDescending(IOrderedEnumerable, Func) | parameter 0 [element] -> return [element] | true | +| System.Linq.Enumerable.ThenByDescending(IOrderedEnumerable, Func, IComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.ThenByDescending(IOrderedEnumerable, Func, IComparer) | parameter 0 [element] -> return [element] | true | +| System.Linq.Enumerable.ToArray(IEnumerable) | parameter 0 [element] -> return [element] | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func) | deleget output from parameter 2 -> return [element] | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func, IEqualityComparer) | deleget output from parameter 2 -> return [element] | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func) | parameter 0 [element] -> return [element] | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, IEqualityComparer) | parameter 0 [element] -> return [element] | true | +| System.Linq.Enumerable.ToList(IEnumerable) | parameter 0 [element] -> return [element] | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func) | deleget output from parameter 2 -> return [element] | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func, IEqualityComparer) | deleget output from parameter 2 -> return [element] | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func) | parameter 0 [element] -> return [element] | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func, IEqualityComparer) | parameter 0 [element] -> return [element] | true | +| System.Linq.Enumerable.Union(IEnumerable, IEnumerable) | parameter 0 [element] -> return [element] | true | +| System.Linq.Enumerable.Union(IEnumerable, IEnumerable) | parameter 1 [element] -> return [element] | true | +| System.Linq.Enumerable.Union(IEnumerable, IEnumerable, IEqualityComparer) | parameter 0 [element] -> return [element] | true | +| System.Linq.Enumerable.Union(IEnumerable, IEnumerable, IEqualityComparer) | parameter 1 [element] -> return [element] | true | +| System.Linq.Enumerable.Where(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Where(IEnumerable, Func) | parameter 0 [element] -> return [element] | true | +| System.Linq.Enumerable.Where(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Enumerable.Where(IEnumerable, Func) | parameter 0 [element] -> return [element] | true | +| System.Linq.Enumerable.Zip(IEnumerable, IEnumerable, Func) | deleget output from parameter 2 -> return [element] | true | +| System.Linq.Enumerable.Zip(IEnumerable, IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.Enumerable.Zip(IEnumerable, IEnumerable, Func) | parameter 1 [element] -> parameter 1 of delegate parameter 2 | true | +| System.Linq.EnumerableQuery<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Expressions.BlockExpressionList.Add(Expression) | parameter 0 -> this parameter [element] | true | +| System.Linq.Expressions.BlockExpressionList.CopyTo(Expression[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Linq.Expressions.BlockExpressionList.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Expressions.BlockExpressionList.Insert(int, Expression) | parameter 1 -> this parameter [element] | true | +| System.Linq.Expressions.BlockExpressionList.get_Item(int) | this parameter [element] -> return | true | +| System.Linq.Expressions.BlockExpressionList.set_Item(int, Expression) | parameter 1 -> this parameter [element] | true | +| System.Linq.Expressions.Compiler.CompilerScope.d__32.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Expressions.Compiler.ParameterList.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Expressions.Interpreter.InterpretedFrame.d__29.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.GroupedEnumerable<,,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.GroupedEnumerable<,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.GroupedResultEnumerable<,,,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.GroupedResultEnumerable<,,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Grouping<,>.Add(TElement) | parameter 0 -> this parameter [element] | true | +| System.Linq.Grouping<,>.CopyTo(TElement[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Linq.Grouping<,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Grouping<,>.Insert(int, TElement) | parameter 1 -> this parameter [element] | true | +| System.Linq.Grouping<,>.get_Item(int) | this parameter [element] -> return | true | +| System.Linq.Grouping<,>.set_Item(int, TElement) | parameter 1 -> this parameter [element] | true | +| System.Linq.Lookup<,>.d__19<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Lookup<,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.OrderedEnumerable<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.OrderedPartition<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Parallel.CancellableEnumerable.d__0<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Parallel.EnumerableWrapperWeakToStrong.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Parallel.ExceptionAggregator.d__0<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Parallel.ExceptionAggregator.d__1<,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Parallel.GroupByGrouping<,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Parallel.ListChunk<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Parallel.Lookup<,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Parallel.MergeExecutor<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Parallel.OrderedGroupByGrouping<,,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Parallel.ParallelEnumerableWrapper.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Parallel.PartitionerQueryOperator<>.d__5.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Parallel.QueryResults<>.Add(T) | parameter 0 -> this parameter [element] | true | +| System.Linq.Parallel.QueryResults<>.CopyTo(T[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Linq.Parallel.QueryResults<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Parallel.QueryResults<>.Insert(int, T) | parameter 1 -> this parameter [element] | true | +| System.Linq.Parallel.QueryResults<>.get_Item(int) | this parameter [element] -> return | true | +| System.Linq.Parallel.QueryResults<>.set_Item(int, T) | parameter 1 -> this parameter [element] | true | +| System.Linq.Parallel.RangeEnumerable.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Linq.Parallel.ZipQueryOperator<,,>.d__9.GetEnumerator() | this parameter [element] -> return [property Current] | true | | System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func, Func) | deleget output from parameter 2 -> parameter 0 of delegate parameter 3 | true | | System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func, Func) | deleget output from parameter 3 -> return | true | -| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func, Func) | parameter 0 [[]] -> parameter 1 of delegate parameter 2 | true | +| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func, Func) | parameter 0 [element] -> parameter 1 of delegate parameter 2 | true | | System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func, Func) | parameter 1 -> parameter 0 of delegate parameter 2 | true | | System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func) | deleget output from parameter 2 -> return | true | -| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func) | parameter 0 [[]] -> parameter 1 of delegate parameter 2 | true | +| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func) | parameter 0 [element] -> parameter 1 of delegate parameter 2 | true | | System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func) | parameter 1 -> parameter 0 of delegate parameter 2 | true | | System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, Func) | deleget output from parameter 1 -> return | true | -| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, Func) | parameter 0 [[]] -> parameter 1 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.All(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Any(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.AsEnumerable(ParallelQuery) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Cast(ParallelQuery) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.Concat(ParallelQuery, IEnumerable) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.Concat(ParallelQuery, IEnumerable) | parameter 1 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.Concat(ParallelQuery, ParallelQuery) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.Concat(ParallelQuery, ParallelQuery) | parameter 1 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.Count(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.DefaultIfEmpty(ParallelQuery) | parameter 0 [[]] -> return | true | -| System.Linq.ParallelEnumerable.DefaultIfEmpty(ParallelQuery, TSource) | parameter 0 [[]] -> return | true | +| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, Func) | parameter 0 [element] -> parameter 1 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.All(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Any(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.AsEnumerable(ParallelQuery) | parameter 0 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Cast(ParallelQuery) | parameter 0 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.Concat(ParallelQuery, IEnumerable) | parameter 0 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.Concat(ParallelQuery, IEnumerable) | parameter 1 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.Concat(ParallelQuery, ParallelQuery) | parameter 0 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.Concat(ParallelQuery, ParallelQuery) | parameter 1 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.Count(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.DefaultIfEmpty(ParallelQuery) | parameter 0 [element] -> return | true | +| System.Linq.ParallelEnumerable.DefaultIfEmpty(ParallelQuery, TSource) | parameter 0 [element] -> return | true | | System.Linq.ParallelEnumerable.DefaultIfEmpty(ParallelQuery, TSource) | parameter 1 -> return | true | -| System.Linq.ParallelEnumerable.Distinct(ParallelQuery) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.Distinct(ParallelQuery, IEqualityComparer) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.ElementAt(ParallelQuery, int) | parameter 0 [[]] -> return | true | -| System.Linq.ParallelEnumerable.ElementAtOrDefault(ParallelQuery, int) | parameter 0 [[]] -> return | true | -| System.Linq.ParallelEnumerable.Except(ParallelQuery, IEnumerable) | parameter 0 [[]] -> return | true | -| System.Linq.ParallelEnumerable.Except(ParallelQuery, IEnumerable, IEqualityComparer) | parameter 0 [[]] -> return | true | -| System.Linq.ParallelEnumerable.Except(ParallelQuery, ParallelQuery) | parameter 0 [[]] -> return | true | -| System.Linq.ParallelEnumerable.Except(ParallelQuery, ParallelQuery, IEqualityComparer) | parameter 0 [[]] -> return | true | -| System.Linq.ParallelEnumerable.First(ParallelQuery) | parameter 0 [[]] -> return | true | -| System.Linq.ParallelEnumerable.First(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.First(ParallelQuery, Func) | parameter 0 [[]] -> return | true | -| System.Linq.ParallelEnumerable.FirstOrDefault(ParallelQuery) | parameter 0 [[]] -> return | true | -| System.Linq.ParallelEnumerable.FirstOrDefault(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.FirstOrDefault(ParallelQuery, Func) | parameter 0 [[]] -> return | true | +| System.Linq.ParallelEnumerable.Distinct(ParallelQuery) | parameter 0 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.Distinct(ParallelQuery, IEqualityComparer) | parameter 0 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.ElementAt(ParallelQuery, int) | parameter 0 [element] -> return | true | +| System.Linq.ParallelEnumerable.ElementAtOrDefault(ParallelQuery, int) | parameter 0 [element] -> return | true | +| System.Linq.ParallelEnumerable.Except(ParallelQuery, IEnumerable) | parameter 0 [element] -> return | true | +| System.Linq.ParallelEnumerable.Except(ParallelQuery, IEnumerable, IEqualityComparer) | parameter 0 [element] -> return | true | +| System.Linq.ParallelEnumerable.Except(ParallelQuery, ParallelQuery) | parameter 0 [element] -> return | true | +| System.Linq.ParallelEnumerable.Except(ParallelQuery, ParallelQuery, IEqualityComparer) | parameter 0 [element] -> return | true | +| System.Linq.ParallelEnumerable.First(ParallelQuery) | parameter 0 [element] -> return | true | +| System.Linq.ParallelEnumerable.First(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.First(ParallelQuery, Func) | parameter 0 [element] -> return | true | +| System.Linq.ParallelEnumerable.FirstOrDefault(ParallelQuery) | parameter 0 [element] -> return | true | +| System.Linq.ParallelEnumerable.FirstOrDefault(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.FirstOrDefault(ParallelQuery, Func) | parameter 0 [element] -> return | true | | System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | deleget output from parameter 1 -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | deleget output from parameter 2 -> parameter 1 of delegate parameter 3 [[]] | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | deleget output from parameter 3 -> return [[]] | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | deleget output from parameter 2 -> parameter 1 of delegate parameter 3 [element] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | deleget output from parameter 3 -> return [element] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | | System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | deleget output from parameter 1 -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | deleget output from parameter 2 -> parameter 1 of delegate parameter 3 [[]] | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | deleget output from parameter 3 -> return [[]] | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func) | deleget output from parameter 2 -> return [[]] | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | deleget output from parameter 2 -> parameter 1 of delegate parameter 3 [element] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | deleget output from parameter 3 -> return [element] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func) | deleget output from parameter 2 -> return [element] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | | System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, IEqualityComparer) | deleget output from parameter 1 -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | | System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>) | deleget output from parameter 1 -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>) | deleget output from parameter 2 -> return [[]] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>) | deleget output from parameter 2 -> return [element] | true | | System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>) | parameter 0 -> parameter 1 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | | System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>, IEqualityComparer) | deleget output from parameter 1 -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | deleget output from parameter 4 -> return [[]] | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | parameter 0 [[]] -> parameter 0 of delegate parameter 4 | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | parameter 1 [[]] -> parameter 0 of delegate parameter 3 | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | parameter 1 [[]] -> parameter 1 of delegate parameter 4 | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | deleget output from parameter 4 -> return [[]] | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 4 | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | parameter 1 [[]] -> parameter 0 of delegate parameter 3 | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | parameter 1 [[]] -> parameter 1 of delegate parameter 4 | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | deleget output from parameter 4 -> return [[]] | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | parameter 0 [[]] -> parameter 0 of delegate parameter 4 | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | parameter 1 [[]] -> parameter 0 of delegate parameter 3 | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | parameter 1 [[]] -> parameter 1 of delegate parameter 4 | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | deleget output from parameter 4 -> return [[]] | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 4 | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | parameter 1 [[]] -> parameter 0 of delegate parameter 3 | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | parameter 1 [[]] -> parameter 1 of delegate parameter 4 | true | -| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, IEnumerable) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, IEnumerable) | parameter 1 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, IEnumerable, IEqualityComparer) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, IEnumerable, IEqualityComparer) | parameter 1 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, ParallelQuery) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, ParallelQuery) | parameter 1 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, ParallelQuery, IEqualityComparer) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, ParallelQuery, IEqualityComparer) | parameter 1 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | deleget output from parameter 4 -> return [[]] | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 4 | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | parameter 1 [[]] -> parameter 0 of delegate parameter 3 | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | parameter 1 [[]] -> parameter 1 of delegate parameter 4 | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | deleget output from parameter 4 -> return [[]] | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 4 | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | parameter 1 [[]] -> parameter 0 of delegate parameter 3 | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | parameter 1 [[]] -> parameter 1 of delegate parameter 4 | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | deleget output from parameter 4 -> return [[]] | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 4 | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | parameter 1 [[]] -> parameter 0 of delegate parameter 3 | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | parameter 1 [[]] -> parameter 1 of delegate parameter 4 | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | deleget output from parameter 4 -> return [[]] | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 4 | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | parameter 1 [[]] -> parameter 0 of delegate parameter 3 | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | parameter 1 [[]] -> parameter 1 of delegate parameter 4 | true | -| System.Linq.ParallelEnumerable.Last(ParallelQuery) | parameter 0 [[]] -> return | true | -| System.Linq.ParallelEnumerable.Last(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Last(ParallelQuery, Func) | parameter 0 [[]] -> return | true | -| System.Linq.ParallelEnumerable.LastOrDefault(ParallelQuery) | parameter 0 [[]] -> return | true | -| System.Linq.ParallelEnumerable.LastOrDefault(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.LastOrDefault(ParallelQuery, Func) | parameter 0 [[]] -> return | true | -| System.Linq.ParallelEnumerable.LongCount(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.OfType(ParallelQuery) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.OrderBy(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.OrderBy(ParallelQuery, Func) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.OrderBy(ParallelQuery, Func, IComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.OrderBy(ParallelQuery, Func, IComparer) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.OrderByDescending(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.OrderByDescending(ParallelQuery, Func) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.OrderByDescending(ParallelQuery, Func, IComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.OrderByDescending(ParallelQuery, Func, IComparer) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.Reverse(ParallelQuery) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.Select(ParallelQuery, Func) | deleget output from parameter 1 -> return [[]] | true | -| System.Linq.ParallelEnumerable.Select(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Select(ParallelQuery, Func) | deleget output from parameter 1 -> return [[]] | true | -| System.Linq.ParallelEnumerable.Select(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | deleget output from parameter 1 [[]] -> parameter 1 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | deleget output from parameter 2 -> return [[]] | true | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | deleget output from parameter 1 [[]] -> parameter 1 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | deleget output from parameter 2 -> return [[]] | true | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>) | deleget output from parameter 1 -> return [[]] | true | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>) | deleget output from parameter 1 -> return [[]] | true | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Single(ParallelQuery) | parameter 0 [[]] -> return | true | -| System.Linq.ParallelEnumerable.Single(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Single(ParallelQuery, Func) | parameter 0 [[]] -> return | true | -| System.Linq.ParallelEnumerable.SingleOrDefault(ParallelQuery) | parameter 0 [[]] -> return | true | -| System.Linq.ParallelEnumerable.SingleOrDefault(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.SingleOrDefault(ParallelQuery, Func) | parameter 0 [[]] -> return | true | -| System.Linq.ParallelEnumerable.Skip(ParallelQuery, int) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Take(ParallelQuery, int) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.ThenBy(OrderedParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.ThenBy(OrderedParallelQuery, Func) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.ThenBy(OrderedParallelQuery, Func, IComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.ThenBy(OrderedParallelQuery, Func, IComparer) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.ThenByDescending(OrderedParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.ThenByDescending(OrderedParallelQuery, Func) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.ThenByDescending(OrderedParallelQuery, Func, IComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.ThenByDescending(OrderedParallelQuery, Func, IComparer) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.ToArray(ParallelQuery) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func) | deleget output from parameter 2 -> return [[]] | true | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func, IEqualityComparer) | deleget output from parameter 2 -> return [[]] | true | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, IEqualityComparer) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.ToList(ParallelQuery) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func) | deleget output from parameter 2 -> return [[]] | true | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func, IEqualityComparer) | deleget output from parameter 2 -> return [[]] | true | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, IEqualityComparer) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.Union(ParallelQuery, IEnumerable) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.Union(ParallelQuery, IEnumerable) | parameter 1 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.Union(ParallelQuery, IEnumerable, IEqualityComparer) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.Union(ParallelQuery, IEnumerable, IEqualityComparer) | parameter 1 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.Union(ParallelQuery, ParallelQuery) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.Union(ParallelQuery, ParallelQuery) | parameter 1 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.Union(ParallelQuery, ParallelQuery, IEqualityComparer) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.Union(ParallelQuery, ParallelQuery, IEqualityComparer) | parameter 1 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.ParallelEnumerable.Zip(ParallelQuery, IEnumerable, Func) | deleget output from parameter 2 -> return [[]] | true | -| System.Linq.ParallelEnumerable.Zip(ParallelQuery, IEnumerable, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.Zip(ParallelQuery, IEnumerable, Func) | parameter 1 [[]] -> parameter 1 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.Zip(ParallelQuery, ParallelQuery, Func) | deleget output from parameter 2 -> return [[]] | true | -| System.Linq.ParallelEnumerable.Zip(ParallelQuery, ParallelQuery, Func) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.Zip(ParallelQuery, ParallelQuery, Func) | parameter 1 [[]] -> parameter 1 of delegate parameter 2 | true | -| System.Linq.ParallelQuery.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | deleget output from parameter 4 -> return [element] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | parameter 0 [element] -> parameter 0 of delegate parameter 4 | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | parameter 1 [element] -> parameter 0 of delegate parameter 3 | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | parameter 1 [element] -> parameter 1 of delegate parameter 4 | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | deleget output from parameter 4 -> return [element] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 4 | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | parameter 1 [element] -> parameter 0 of delegate parameter 3 | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | parameter 1 [element] -> parameter 1 of delegate parameter 4 | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | deleget output from parameter 4 -> return [element] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | parameter 0 [element] -> parameter 0 of delegate parameter 4 | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | parameter 1 [element] -> parameter 0 of delegate parameter 3 | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | parameter 1 [element] -> parameter 1 of delegate parameter 4 | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | deleget output from parameter 4 -> return [element] | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 4 | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | parameter 1 [element] -> parameter 0 of delegate parameter 3 | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | parameter 1 [element] -> parameter 1 of delegate parameter 4 | true | +| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, IEnumerable) | parameter 0 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, IEnumerable) | parameter 1 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, IEnumerable, IEqualityComparer) | parameter 0 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, IEnumerable, IEqualityComparer) | parameter 1 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, ParallelQuery) | parameter 0 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, ParallelQuery) | parameter 1 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, ParallelQuery, IEqualityComparer) | parameter 0 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, ParallelQuery, IEqualityComparer) | parameter 1 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | deleget output from parameter 4 -> return [element] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 4 | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | parameter 1 [element] -> parameter 0 of delegate parameter 3 | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | parameter 1 [element] -> parameter 1 of delegate parameter 4 | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | deleget output from parameter 4 -> return [element] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 4 | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | parameter 1 [element] -> parameter 0 of delegate parameter 3 | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | parameter 1 [element] -> parameter 1 of delegate parameter 4 | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | deleget output from parameter 4 -> return [element] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 4 | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | parameter 1 [element] -> parameter 0 of delegate parameter 3 | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | parameter 1 [element] -> parameter 1 of delegate parameter 4 | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | deleget output from parameter 4 -> return [element] | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 4 | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | parameter 1 [element] -> parameter 0 of delegate parameter 3 | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | parameter 1 [element] -> parameter 1 of delegate parameter 4 | true | +| System.Linq.ParallelEnumerable.Last(ParallelQuery) | parameter 0 [element] -> return | true | +| System.Linq.ParallelEnumerable.Last(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Last(ParallelQuery, Func) | parameter 0 [element] -> return | true | +| System.Linq.ParallelEnumerable.LastOrDefault(ParallelQuery) | parameter 0 [element] -> return | true | +| System.Linq.ParallelEnumerable.LastOrDefault(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.LastOrDefault(ParallelQuery, Func) | parameter 0 [element] -> return | true | +| System.Linq.ParallelEnumerable.LongCount(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.OfType(ParallelQuery) | parameter 0 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.OrderBy(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.OrderBy(ParallelQuery, Func) | parameter 0 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.OrderBy(ParallelQuery, Func, IComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.OrderBy(ParallelQuery, Func, IComparer) | parameter 0 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.OrderByDescending(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.OrderByDescending(ParallelQuery, Func) | parameter 0 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.OrderByDescending(ParallelQuery, Func, IComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.OrderByDescending(ParallelQuery, Func, IComparer) | parameter 0 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.Reverse(ParallelQuery) | parameter 0 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.Select(ParallelQuery, Func) | deleget output from parameter 1 -> return [element] | true | +| System.Linq.ParallelEnumerable.Select(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Select(ParallelQuery, Func) | deleget output from parameter 1 -> return [element] | true | +| System.Linq.ParallelEnumerable.Select(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | deleget output from parameter 1 [element] -> parameter 1 of delegate parameter 2 | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | deleget output from parameter 2 -> return [element] | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | deleget output from parameter 1 [element] -> parameter 1 of delegate parameter 2 | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | deleget output from parameter 2 -> return [element] | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>) | deleget output from parameter 1 -> return [element] | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>) | deleget output from parameter 1 -> return [element] | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Single(ParallelQuery) | parameter 0 [element] -> return | true | +| System.Linq.ParallelEnumerable.Single(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Single(ParallelQuery, Func) | parameter 0 [element] -> return | true | +| System.Linq.ParallelEnumerable.SingleOrDefault(ParallelQuery) | parameter 0 [element] -> return | true | +| System.Linq.ParallelEnumerable.SingleOrDefault(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.SingleOrDefault(ParallelQuery, Func) | parameter 0 [element] -> return | true | +| System.Linq.ParallelEnumerable.Skip(ParallelQuery, int) | parameter 0 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | parameter 0 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | parameter 0 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Take(ParallelQuery, int) | parameter 0 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | parameter 0 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | parameter 0 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.ThenBy(OrderedParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.ThenBy(OrderedParallelQuery, Func) | parameter 0 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.ThenBy(OrderedParallelQuery, Func, IComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.ThenBy(OrderedParallelQuery, Func, IComparer) | parameter 0 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.ThenByDescending(OrderedParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.ThenByDescending(OrderedParallelQuery, Func) | parameter 0 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.ThenByDescending(OrderedParallelQuery, Func, IComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.ThenByDescending(OrderedParallelQuery, Func, IComparer) | parameter 0 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.ToArray(ParallelQuery) | parameter 0 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func) | deleget output from parameter 2 -> return [element] | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func, IEqualityComparer) | deleget output from parameter 2 -> return [element] | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func) | parameter 0 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, IEqualityComparer) | parameter 0 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.ToList(ParallelQuery) | parameter 0 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func) | deleget output from parameter 2 -> return [element] | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func, IEqualityComparer) | deleget output from parameter 2 -> return [element] | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func) | parameter 0 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, IEqualityComparer) | parameter 0 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.Union(ParallelQuery, IEnumerable) | parameter 0 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.Union(ParallelQuery, IEnumerable) | parameter 1 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.Union(ParallelQuery, IEnumerable, IEqualityComparer) | parameter 0 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.Union(ParallelQuery, IEnumerable, IEqualityComparer) | parameter 1 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.Union(ParallelQuery, ParallelQuery) | parameter 0 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.Union(ParallelQuery, ParallelQuery) | parameter 1 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.Union(ParallelQuery, ParallelQuery, IEqualityComparer) | parameter 0 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.Union(ParallelQuery, ParallelQuery, IEqualityComparer) | parameter 1 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | parameter 0 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | parameter 0 [element] -> return [element] | true | +| System.Linq.ParallelEnumerable.Zip(ParallelQuery, IEnumerable, Func) | deleget output from parameter 2 -> return [element] | true | +| System.Linq.ParallelEnumerable.Zip(ParallelQuery, IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.ParallelEnumerable.Zip(ParallelQuery, IEnumerable, Func) | parameter 1 [element] -> parameter 1 of delegate parameter 2 | true | +| System.Linq.ParallelEnumerable.Zip(ParallelQuery, ParallelQuery, Func) | deleget output from parameter 2 -> return [element] | true | +| System.Linq.ParallelEnumerable.Zip(ParallelQuery, ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.ParallelEnumerable.Zip(ParallelQuery, ParallelQuery, Func) | parameter 1 [element] -> parameter 1 of delegate parameter 2 | true | +| System.Linq.ParallelQuery.GetEnumerator() | this parameter [element] -> return [property Current] | true | | System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>, Expression>) | deleget output from parameter 2 -> parameter 0 of delegate parameter 3 | true | | System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>, Expression>) | deleget output from parameter 3 -> return | true | -| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>, Expression>) | parameter 0 [[]] -> parameter 1 of delegate parameter 2 | true | +| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>, Expression>) | parameter 0 [element] -> parameter 1 of delegate parameter 2 | true | | System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>, Expression>) | parameter 1 -> parameter 0 of delegate parameter 2 | true | | System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>) | deleget output from parameter 2 -> return | true | -| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>) | parameter 0 [[]] -> parameter 1 of delegate parameter 2 | true | +| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>) | parameter 0 [element] -> parameter 1 of delegate parameter 2 | true | | System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>) | parameter 1 -> parameter 0 of delegate parameter 2 | true | | System.Linq.Queryable.Aggregate(IQueryable, Expression>) | deleget output from parameter 1 -> return | true | -| System.Linq.Queryable.Aggregate(IQueryable, Expression>) | parameter 0 [[]] -> parameter 1 of delegate parameter 1 | true | -| System.Linq.Queryable.All(IQueryable, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Any(IQueryable, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.AsQueryable(IEnumerable) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Queryable.AsQueryable(IEnumerable) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Queryable.Average(IQueryable, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Average(IQueryable, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Average(IQueryable, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Average(IQueryable, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Average(IQueryable, Expression>>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Average(IQueryable, Expression>>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Average(IQueryable, Expression>>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Average(IQueryable, Expression>>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Average(IQueryable, Expression>>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Average(IQueryable, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Cast(IQueryable) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Queryable.Concat(IQueryable, IEnumerable) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Queryable.Concat(IQueryable, IEnumerable) | parameter 1 [[]] -> return [[]] | true | -| System.Linq.Queryable.Count(IQueryable, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.DefaultIfEmpty(IQueryable) | parameter 0 [[]] -> return | true | -| System.Linq.Queryable.DefaultIfEmpty(IQueryable, TSource) | parameter 0 [[]] -> return | true | +| System.Linq.Queryable.Aggregate(IQueryable, Expression>) | parameter 0 [element] -> parameter 1 of delegate parameter 1 | true | +| System.Linq.Queryable.All(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.Any(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.AsQueryable(IEnumerable) | parameter 0 [element] -> return [element] | true | +| System.Linq.Queryable.AsQueryable(IEnumerable) | parameter 0 [element] -> return [element] | true | +| System.Linq.Queryable.Average(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.Average(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.Average(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.Average(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.Average(IQueryable, Expression>>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.Average(IQueryable, Expression>>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.Average(IQueryable, Expression>>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.Average(IQueryable, Expression>>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.Average(IQueryable, Expression>>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.Average(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.Cast(IQueryable) | parameter 0 [element] -> return [element] | true | +| System.Linq.Queryable.Concat(IQueryable, IEnumerable) | parameter 0 [element] -> return [element] | true | +| System.Linq.Queryable.Concat(IQueryable, IEnumerable) | parameter 1 [element] -> return [element] | true | +| System.Linq.Queryable.Count(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.DefaultIfEmpty(IQueryable) | parameter 0 [element] -> return | true | +| System.Linq.Queryable.DefaultIfEmpty(IQueryable, TSource) | parameter 0 [element] -> return | true | | System.Linq.Queryable.DefaultIfEmpty(IQueryable, TSource) | parameter 1 -> return | true | -| System.Linq.Queryable.Distinct(IQueryable) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Queryable.Distinct(IQueryable, IEqualityComparer) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Queryable.ElementAt(IQueryable, int) | parameter 0 [[]] -> return | true | -| System.Linq.Queryable.ElementAtOrDefault(IQueryable, int) | parameter 0 [[]] -> return | true | -| System.Linq.Queryable.Except(IQueryable, IEnumerable) | parameter 0 [[]] -> return | true | -| System.Linq.Queryable.Except(IQueryable, IEnumerable, IEqualityComparer) | parameter 0 [[]] -> return | true | -| System.Linq.Queryable.First(IQueryable) | parameter 0 [[]] -> return | true | -| System.Linq.Queryable.First(IQueryable, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.First(IQueryable, Expression>) | parameter 0 [[]] -> return | true | -| System.Linq.Queryable.FirstOrDefault(IQueryable) | parameter 0 [[]] -> return | true | -| System.Linq.Queryable.FirstOrDefault(IQueryable, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.FirstOrDefault(IQueryable, Expression>) | parameter 0 [[]] -> return | true | +| System.Linq.Queryable.Distinct(IQueryable) | parameter 0 [element] -> return [element] | true | +| System.Linq.Queryable.Distinct(IQueryable, IEqualityComparer) | parameter 0 [element] -> return [element] | true | +| System.Linq.Queryable.ElementAt(IQueryable, int) | parameter 0 [element] -> return | true | +| System.Linq.Queryable.ElementAtOrDefault(IQueryable, int) | parameter 0 [element] -> return | true | +| System.Linq.Queryable.Except(IQueryable, IEnumerable) | parameter 0 [element] -> return | true | +| System.Linq.Queryable.Except(IQueryable, IEnumerable, IEqualityComparer) | parameter 0 [element] -> return | true | +| System.Linq.Queryable.First(IQueryable) | parameter 0 [element] -> return | true | +| System.Linq.Queryable.First(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.First(IQueryable, Expression>) | parameter 0 [element] -> return | true | +| System.Linq.Queryable.FirstOrDefault(IQueryable) | parameter 0 [element] -> return | true | +| System.Linq.Queryable.FirstOrDefault(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.FirstOrDefault(IQueryable, Expression>) | parameter 0 [element] -> return | true | | System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | deleget output from parameter 1 -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | deleget output from parameter 2 -> parameter 1 of delegate parameter 3 [[]] | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | deleget output from parameter 3 -> return [[]] | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | deleget output from parameter 2 -> parameter 1 of delegate parameter 3 [element] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | deleget output from parameter 3 -> return [element] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | | System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | deleget output from parameter 1 -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | deleget output from parameter 2 -> parameter 1 of delegate parameter 3 [[]] | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | deleget output from parameter 3 -> return [[]] | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>) | deleget output from parameter 2 -> return [[]] | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | deleget output from parameter 2 -> parameter 1 of delegate parameter 3 [element] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | deleget output from parameter 3 -> return [element] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>) | deleget output from parameter 2 -> return [element] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | | System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, IEqualityComparer) | deleget output from parameter 1 -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>) | deleget output from parameter 2 -> return [[]] | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>) | deleget output from parameter 2 -> return [element] | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | | System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>, IEqualityComparer) | deleget output from parameter 1 -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | deleget output from parameter 4 -> return [[]] | true | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | parameter 0 [[]] -> parameter 0 of delegate parameter 4 | true | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | parameter 1 [[]] -> parameter 0 of delegate parameter 3 | true | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | parameter 1 [[]] -> parameter 1 of delegate parameter 4 | true | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | deleget output from parameter 4 -> return [[]] | true | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 4 | true | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | parameter 1 [[]] -> parameter 0 of delegate parameter 3 | true | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | parameter 1 [[]] -> parameter 1 of delegate parameter 4 | true | -| System.Linq.Queryable.Intersect(IQueryable, IEnumerable) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Queryable.Intersect(IQueryable, IEnumerable) | parameter 1 [[]] -> return [[]] | true | -| System.Linq.Queryable.Intersect(IQueryable, IEnumerable, IEqualityComparer) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Queryable.Intersect(IQueryable, IEnumerable, IEqualityComparer) | parameter 1 [[]] -> return [[]] | true | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | deleget output from parameter 4 -> return [[]] | true | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 4 | true | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | parameter 1 [[]] -> parameter 0 of delegate parameter 3 | true | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | parameter 1 [[]] -> parameter 1 of delegate parameter 4 | true | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | deleget output from parameter 4 -> return [[]] | true | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 4 | true | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | parameter 1 [[]] -> parameter 0 of delegate parameter 3 | true | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | parameter 1 [[]] -> parameter 1 of delegate parameter 4 | true | -| System.Linq.Queryable.Last(IQueryable) | parameter 0 [[]] -> return | true | -| System.Linq.Queryable.Last(IQueryable, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Last(IQueryable, Expression>) | parameter 0 [[]] -> return | true | -| System.Linq.Queryable.LastOrDefault(IQueryable) | parameter 0 [[]] -> return | true | -| System.Linq.Queryable.LastOrDefault(IQueryable, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.LastOrDefault(IQueryable, Expression>) | parameter 0 [[]] -> return | true | -| System.Linq.Queryable.LongCount(IQueryable, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Max(IQueryable, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Min(IQueryable, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.OfType(IQueryable) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Queryable.OrderBy(IQueryable, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.OrderBy(IQueryable, Expression>) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Queryable.OrderBy(IQueryable, Expression>, IComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.OrderBy(IQueryable, Expression>, IComparer) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>, IComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>, IComparer) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Queryable.Reverse(IQueryable) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Queryable.Select(IQueryable, Expression>) | deleget output from parameter 1 -> return [[]] | true | -| System.Linq.Queryable.Select(IQueryable, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Select(IQueryable, Expression>) | deleget output from parameter 1 -> return [[]] | true | -| System.Linq.Queryable.Select(IQueryable, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | deleget output from parameter 1 [[]] -> parameter 1 of delegate parameter 2 | true | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | deleget output from parameter 2 -> return [[]] | true | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | deleget output from parameter 1 [[]] -> parameter 1 of delegate parameter 2 | true | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | deleget output from parameter 2 -> return [[]] | true | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | deleget output from parameter 1 -> return [[]] | true | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | deleget output from parameter 1 -> return [[]] | true | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Single(IQueryable) | parameter 0 [[]] -> return | true | -| System.Linq.Queryable.Single(IQueryable, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Single(IQueryable, Expression>) | parameter 0 [[]] -> return | true | -| System.Linq.Queryable.SingleOrDefault(IQueryable) | parameter 0 [[]] -> return | true | -| System.Linq.Queryable.SingleOrDefault(IQueryable, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.SingleOrDefault(IQueryable, Expression>) | parameter 0 [[]] -> return | true | -| System.Linq.Queryable.Skip(IQueryable, int) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Queryable.Sum(IQueryable, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Sum(IQueryable, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Sum(IQueryable, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Sum(IQueryable, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Sum(IQueryable, Expression>>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Sum(IQueryable, Expression>>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Sum(IQueryable, Expression>>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Sum(IQueryable, Expression>>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Sum(IQueryable, Expression>>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Sum(IQueryable, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Take(IQueryable, int) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>, IComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>, IComparer) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>, IComparer) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>, IComparer) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Queryable.Union(IQueryable, IEnumerable) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Queryable.Union(IQueryable, IEnumerable) | parameter 1 [[]] -> return [[]] | true | -| System.Linq.Queryable.Union(IQueryable, IEnumerable, IEqualityComparer) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Queryable.Union(IQueryable, IEnumerable, IEqualityComparer) | parameter 1 [[]] -> return [[]] | true | -| System.Linq.Queryable.Where(IQueryable, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Where(IQueryable, Expression>) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Queryable.Where(IQueryable, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Where(IQueryable, Expression>) | parameter 0 [[]] -> return [[]] | true | -| System.Linq.Queryable.Zip(IQueryable, IEnumerable, Expression>) | deleget output from parameter 2 -> return [[]] | true | -| System.Linq.Queryable.Zip(IQueryable, IEnumerable, Expression>) | parameter 0 [[]] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Queryable.Zip(IQueryable, IEnumerable, Expression>) | parameter 1 [[]] -> parameter 1 of delegate parameter 2 | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | deleget output from parameter 4 -> return [element] | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | parameter 0 [element] -> parameter 0 of delegate parameter 4 | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | parameter 1 [element] -> parameter 0 of delegate parameter 3 | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | parameter 1 [element] -> parameter 1 of delegate parameter 4 | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | deleget output from parameter 4 -> return [element] | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 4 | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | parameter 1 [element] -> parameter 0 of delegate parameter 3 | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | parameter 1 [element] -> parameter 1 of delegate parameter 4 | true | +| System.Linq.Queryable.Intersect(IQueryable, IEnumerable) | parameter 0 [element] -> return [element] | true | +| System.Linq.Queryable.Intersect(IQueryable, IEnumerable) | parameter 1 [element] -> return [element] | true | +| System.Linq.Queryable.Intersect(IQueryable, IEnumerable, IEqualityComparer) | parameter 0 [element] -> return [element] | true | +| System.Linq.Queryable.Intersect(IQueryable, IEnumerable, IEqualityComparer) | parameter 1 [element] -> return [element] | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | deleget output from parameter 4 -> return [element] | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 4 | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | parameter 1 [element] -> parameter 0 of delegate parameter 3 | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | parameter 1 [element] -> parameter 1 of delegate parameter 4 | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | deleget output from parameter 4 -> return [element] | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 4 | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | parameter 1 [element] -> parameter 0 of delegate parameter 3 | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | parameter 1 [element] -> parameter 1 of delegate parameter 4 | true | +| System.Linq.Queryable.Last(IQueryable) | parameter 0 [element] -> return | true | +| System.Linq.Queryable.Last(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.Last(IQueryable, Expression>) | parameter 0 [element] -> return | true | +| System.Linq.Queryable.LastOrDefault(IQueryable) | parameter 0 [element] -> return | true | +| System.Linq.Queryable.LastOrDefault(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.LastOrDefault(IQueryable, Expression>) | parameter 0 [element] -> return | true | +| System.Linq.Queryable.LongCount(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.Max(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.Min(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.OfType(IQueryable) | parameter 0 [element] -> return [element] | true | +| System.Linq.Queryable.OrderBy(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.OrderBy(IQueryable, Expression>) | parameter 0 [element] -> return [element] | true | +| System.Linq.Queryable.OrderBy(IQueryable, Expression>, IComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.OrderBy(IQueryable, Expression>, IComparer) | parameter 0 [element] -> return [element] | true | +| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>) | parameter 0 [element] -> return [element] | true | +| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>, IComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>, IComparer) | parameter 0 [element] -> return [element] | true | +| System.Linq.Queryable.Reverse(IQueryable) | parameter 0 [element] -> return [element] | true | +| System.Linq.Queryable.Select(IQueryable, Expression>) | deleget output from parameter 1 -> return [element] | true | +| System.Linq.Queryable.Select(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.Select(IQueryable, Expression>) | deleget output from parameter 1 -> return [element] | true | +| System.Linq.Queryable.Select(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | deleget output from parameter 1 [element] -> parameter 1 of delegate parameter 2 | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | deleget output from parameter 2 -> return [element] | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | deleget output from parameter 1 [element] -> parameter 1 of delegate parameter 2 | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | deleget output from parameter 2 -> return [element] | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | deleget output from parameter 1 -> return [element] | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | deleget output from parameter 1 -> return [element] | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.Single(IQueryable) | parameter 0 [element] -> return | true | +| System.Linq.Queryable.Single(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.Single(IQueryable, Expression>) | parameter 0 [element] -> return | true | +| System.Linq.Queryable.SingleOrDefault(IQueryable) | parameter 0 [element] -> return | true | +| System.Linq.Queryable.SingleOrDefault(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.SingleOrDefault(IQueryable, Expression>) | parameter 0 [element] -> return | true | +| System.Linq.Queryable.Skip(IQueryable, int) | parameter 0 [element] -> return [element] | true | +| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | parameter 0 [element] -> return [element] | true | +| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | parameter 0 [element] -> return [element] | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.Take(IQueryable, int) | parameter 0 [element] -> return [element] | true | +| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | parameter 0 [element] -> return [element] | true | +| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | parameter 0 [element] -> return [element] | true | +| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>) | parameter 0 [element] -> return [element] | true | +| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>, IComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>, IComparer) | parameter 0 [element] -> return [element] | true | +| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>) | parameter 0 [element] -> return [element] | true | +| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>, IComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>, IComparer) | parameter 0 [element] -> return [element] | true | +| System.Linq.Queryable.Union(IQueryable, IEnumerable) | parameter 0 [element] -> return [element] | true | +| System.Linq.Queryable.Union(IQueryable, IEnumerable) | parameter 1 [element] -> return [element] | true | +| System.Linq.Queryable.Union(IQueryable, IEnumerable, IEqualityComparer) | parameter 0 [element] -> return [element] | true | +| System.Linq.Queryable.Union(IQueryable, IEnumerable, IEqualityComparer) | parameter 1 [element] -> return [element] | true | +| System.Linq.Queryable.Where(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.Where(IQueryable, Expression>) | parameter 0 [element] -> return [element] | true | +| System.Linq.Queryable.Where(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | +| System.Linq.Queryable.Where(IQueryable, Expression>) | parameter 0 [element] -> return [element] | true | +| System.Linq.Queryable.Zip(IQueryable, IEnumerable, Expression>) | deleget output from parameter 2 -> return [element] | true | +| System.Linq.Queryable.Zip(IQueryable, IEnumerable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | +| System.Linq.Queryable.Zip(IQueryable, IEnumerable, Expression>) | parameter 1 [element] -> parameter 1 of delegate parameter 2 | true | | System.Net.Cookie.get_Value() | this parameter -> return | false | -| System.Net.CookieCollection.Add(Cookie) | parameter 0 -> this parameter [[]] | true | -| System.Net.CookieCollection.Add(CookieCollection) | parameter 0 -> this parameter [[]] | true | -| System.Net.CookieCollection.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Net.CookieCollection.CopyTo(Cookie[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Net.CookieCollection.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Net.CredentialCache.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Net.HttpListenerPrefixCollection.Add(string) | parameter 0 -> this parameter [[]] | true | -| System.Net.HttpListenerPrefixCollection.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Net.HttpListenerPrefixCollection.CopyTo(String[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Net.HttpListenerPrefixCollection.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.Net.CookieCollection.Add(Cookie) | parameter 0 -> this parameter [element] | true | +| System.Net.CookieCollection.Add(CookieCollection) | parameter 0 -> this parameter [element] | true | +| System.Net.CookieCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Net.CookieCollection.CopyTo(Cookie[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Net.CookieCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Net.CredentialCache.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Net.HttpListenerPrefixCollection.Add(string) | parameter 0 -> this parameter [element] | true | +| System.Net.HttpListenerPrefixCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Net.HttpListenerPrefixCollection.CopyTo(String[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Net.HttpListenerPrefixCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | | System.Net.HttpRequestStream.BeginRead(Byte[], int, int, AsyncCallback, object) | this parameter -> parameter 0 | false | | System.Net.HttpRequestStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | parameter 0 -> this parameter | false | | System.Net.HttpRequestStream.Read(Byte[], int, int) | this parameter -> parameter 0 | false | @@ -1984,10 +1984,10 @@ | System.Net.HttpResponseStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | parameter 0 -> this parameter | false | | System.Net.HttpResponseStream.Read(Byte[], int, int) | this parameter -> parameter 0 | false | | System.Net.HttpResponseStream.Write(Byte[], int, int) | parameter 0 -> this parameter | false | -| System.Net.NetworkInformation.IPAddressCollection.Add(IPAddress) | parameter 0 -> this parameter [[]] | true | -| System.Net.NetworkInformation.IPAddressCollection.CopyTo(IPAddress[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Net.NetworkInformation.IPAddressCollection.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Net.Security.CipherSuitesPolicy.d__6.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.Net.NetworkInformation.IPAddressCollection.Add(IPAddress) | parameter 0 -> this parameter [element] | true | +| System.Net.NetworkInformation.IPAddressCollection.CopyTo(IPAddress[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Net.NetworkInformation.IPAddressCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Net.Security.CipherSuitesPolicy.d__6.GetEnumerator() | this parameter [element] -> return [property Current] | true | | System.Net.Security.NegotiateStream.BeginRead(Byte[], int, int, AsyncCallback, object) | this parameter -> parameter 0 | false | | System.Net.Security.NegotiateStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | parameter 0 -> this parameter | false | | System.Net.Security.NegotiateStream.Read(Byte[], int, int) | this parameter -> parameter 0 | false | @@ -2003,48 +2003,48 @@ | System.Net.WebUtility.HtmlEncode(string) | parameter 0 -> return | false | | System.Net.WebUtility.HtmlEncode(string, TextWriter) | parameter 0 -> return | false | | System.Net.WebUtility.UrlEncode(string) | parameter 0 -> return | false | -| System.Nullable<>.GetValueOrDefault() | this parameter [Value] -> return | true | +| System.Nullable<>.GetValueOrDefault() | this parameter [property Value] -> return | true | | System.Nullable<>.GetValueOrDefault(T) | parameter 0 -> return | true | -| System.Nullable<>.GetValueOrDefault(T) | this parameter [Value] -> return | true | -| System.Nullable<>.Nullable(T) | parameter 0 -> return [Value] | true | -| System.Nullable<>.get_HasValue() | this parameter [Value] -> return | false | +| System.Nullable<>.GetValueOrDefault(T) | this parameter [property Value] -> return | true | +| System.Nullable<>.Nullable(T) | parameter 0 -> return [property Value] | true | +| System.Nullable<>.get_HasValue() | this parameter [property Value] -> return | false | | System.Nullable<>.get_Value() | this parameter -> return | false | -| System.Reflection.TypeInfo.d__10.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Reflection.TypeInfo.d__22.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Resources.ResourceFallbackManager.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Resources.ResourceReader.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Resources.ResourceSet.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Resources.RuntimeResourceSet.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Runtime.CompilerServices.ConditionalWeakTable<,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Runtime.CompilerServices.ConfiguredTaskAwaitable<>.ConfiguredTaskAwaiter.GetResult() | this parameter [m_task, Result] -> return | true | -| System.Runtime.CompilerServices.ConfiguredTaskAwaitable<>.GetAwaiter() | this parameter [m_configuredTaskAwaiter] -> return | true | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Add(T) | parameter 0 -> this parameter [[]] | true | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Add(object) | parameter 0 -> this parameter [[]] | true | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.CopyTo(T[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Insert(int, T) | parameter 1 -> this parameter [[]] | true | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Insert(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Reverse() | parameter 0 [[]] -> return [[]] | true | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Reverse(int, int) | parameter 0 [[]] -> return [[]] | true | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.get_Item(int) | this parameter [[]] -> return | true | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.set_Item(int, T) | parameter 1 -> this parameter [[]] | true | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.set_Item(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Runtime.CompilerServices.TaskAwaiter<>.GetResult() | this parameter [m_task, Result] -> return | true | -| System.Runtime.InteropServices.MemoryMarshal.d__15<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Runtime.Loader.AssemblyLoadContext.d__83.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Runtime.Loader.AssemblyLoadContext.d__53.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Runtime.Loader.LibraryNameVariation.d__5.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.Reflection.TypeInfo.d__10.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Reflection.TypeInfo.d__22.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Resources.ResourceFallbackManager.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Resources.ResourceReader.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Resources.ResourceSet.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Resources.RuntimeResourceSet.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Runtime.CompilerServices.ConditionalWeakTable<,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Runtime.CompilerServices.ConfiguredTaskAwaitable<>.ConfiguredTaskAwaiter.GetResult() | this parameter [field m_task, property Result] -> return | true | +| System.Runtime.CompilerServices.ConfiguredTaskAwaitable<>.GetAwaiter() | this parameter [field m_configuredTaskAwaiter] -> return | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Add(T) | parameter 0 -> this parameter [element] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Add(object) | parameter 0 -> this parameter [element] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.CopyTo(T[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Insert(int, T) | parameter 1 -> this parameter [element] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Insert(int, object) | parameter 1 -> this parameter [element] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Reverse() | parameter 0 [element] -> return [element] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Reverse(int, int) | parameter 0 [element] -> return [element] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.get_Item(int) | this parameter [element] -> return | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.set_Item(int, T) | parameter 1 -> this parameter [element] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.set_Item(int, object) | parameter 1 -> this parameter [element] | true | +| System.Runtime.CompilerServices.TaskAwaiter<>.GetResult() | this parameter [field m_task, property Result] -> return | true | +| System.Runtime.InteropServices.MemoryMarshal.d__15<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Runtime.Loader.AssemblyLoadContext.d__83.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Runtime.Loader.AssemblyLoadContext.d__53.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Runtime.Loader.LibraryNameVariation.d__5.GetEnumerator() | this parameter [element] -> return [property Current] | true | | System.Security.Cryptography.CryptoStream.BeginRead(Byte[], int, int, AsyncCallback, object) | this parameter -> parameter 0 | false | | System.Security.Cryptography.CryptoStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | parameter 0 -> this parameter | false | | System.Security.Cryptography.CryptoStream.Read(Byte[], int, int) | this parameter -> parameter 0 | false | | System.Security.Cryptography.CryptoStream.ReadAsync(Byte[], int, int, CancellationToken) | this parameter -> parameter 0 | false | | System.Security.Cryptography.CryptoStream.Write(Byte[], int, int) | parameter 0 -> this parameter | false | | System.Security.Cryptography.CryptoStream.WriteAsync(Byte[], int, int, CancellationToken) | parameter 0 -> this parameter | false | -| System.Security.PermissionSet.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Security.PermissionSet.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.Security.PermissionSet.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Security.PermissionSet.GetEnumerator() | this parameter [element] -> return [property Current] | true | | System.String.Clone() | this parameter -> return | true | -| System.String.Concat(IEnumerable) | parameter 0 [[]] -> return | false | +| System.String.Concat(IEnumerable) | parameter 0 [element] -> return | false | | System.String.Concat(ReadOnlySpan, ReadOnlySpan) | parameter 0 -> return | false | | System.String.Concat(ReadOnlySpan, ReadOnlySpan) | parameter 1 -> return | false | | System.String.Concat(ReadOnlySpan, ReadOnlySpan, ReadOnlySpan) | parameter 0 -> return | false | @@ -2060,8 +2060,8 @@ | System.String.Concat(object, object, object) | parameter 0 -> return | false | | System.String.Concat(object, object, object) | parameter 1 -> return | false | | System.String.Concat(object, object, object) | parameter 2 -> return | false | -| System.String.Concat(params Object[]) | parameter 0 [[]] -> return | false | -| System.String.Concat(params String[]) | parameter 0 [[]] -> return | false | +| System.String.Concat(params Object[]) | parameter 0 [element] -> return | false | +| System.String.Concat(params String[]) | parameter 0 [element] -> return | false | | System.String.Concat(string, string) | parameter 0 -> return | false | | System.String.Concat(string, string) | parameter 1 -> return | false | | System.String.Concat(string, string, string) | parameter 0 -> return | false | @@ -2071,7 +2071,7 @@ | System.String.Concat(string, string, string, string) | parameter 1 -> return | false | | System.String.Concat(string, string, string, string) | parameter 2 -> return | false | | System.String.Concat(string, string, string, string) | parameter 3 -> return | false | -| System.String.Concat(IEnumerable) | parameter 0 [[]] -> return | false | +| System.String.Concat(IEnumerable) | parameter 0 [element] -> return | false | | System.String.Copy(string) | parameter 0 -> return | true | | System.String.Format(IFormatProvider, string, object) | parameter 1 -> return | false | | System.String.Format(IFormatProvider, string, object) | parameter 2 -> return | false | @@ -2083,7 +2083,7 @@ | System.String.Format(IFormatProvider, string, object, object, object) | parameter 3 -> return | false | | System.String.Format(IFormatProvider, string, object, object, object) | parameter 4 -> return | false | | System.String.Format(IFormatProvider, string, params Object[]) | parameter 1 -> return | false | -| System.String.Format(IFormatProvider, string, params Object[]) | parameter 2 [[]] -> return | false | +| System.String.Format(IFormatProvider, string, params Object[]) | parameter 2 [element] -> return | false | | System.String.Format(string, object) | parameter 0 -> return | false | | System.String.Format(string, object) | parameter 1 -> return | false | | System.String.Format(string, object, object) | parameter 0 -> return | false | @@ -2094,28 +2094,28 @@ | System.String.Format(string, object, object, object) | parameter 2 -> return | false | | System.String.Format(string, object, object, object) | parameter 3 -> return | false | | System.String.Format(string, params Object[]) | parameter 0 -> return | false | -| System.String.Format(string, params Object[]) | parameter 1 [[]] -> return | false | -| System.String.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.String.Format(string, params Object[]) | parameter 1 [element] -> return | false | +| System.String.GetEnumerator() | this parameter [element] -> return [property Current] | true | | System.String.Insert(int, string) | parameter 1 -> return | false | | System.String.Insert(int, string) | this parameter -> return | false | | System.String.Join(char, String[], int, int) | parameter 0 -> return | false | -| System.String.Join(char, String[], int, int) | parameter 1 [[]] -> return | false | +| System.String.Join(char, String[], int, int) | parameter 1 [element] -> return | false | | System.String.Join(char, params Object[]) | parameter 0 -> return | false | -| System.String.Join(char, params Object[]) | parameter 1 [[]] -> return | false | +| System.String.Join(char, params Object[]) | parameter 1 [element] -> return | false | | System.String.Join(char, params String[]) | parameter 0 -> return | false | -| System.String.Join(char, params String[]) | parameter 1 [[]] -> return | false | +| System.String.Join(char, params String[]) | parameter 1 [element] -> return | false | | System.String.Join(string, IEnumerable) | parameter 0 -> return | false | -| System.String.Join(string, IEnumerable) | parameter 1 [[]] -> return | false | +| System.String.Join(string, IEnumerable) | parameter 1 [element] -> return | false | | System.String.Join(string, String[], int, int) | parameter 0 -> return | false | -| System.String.Join(string, String[], int, int) | parameter 1 [[]] -> return | false | +| System.String.Join(string, String[], int, int) | parameter 1 [element] -> return | false | | System.String.Join(string, params Object[]) | parameter 0 -> return | false | -| System.String.Join(string, params Object[]) | parameter 1 [[]] -> return | false | +| System.String.Join(string, params Object[]) | parameter 1 [element] -> return | false | | System.String.Join(string, params String[]) | parameter 0 -> return | false | -| System.String.Join(string, params String[]) | parameter 1 [[]] -> return | false | +| System.String.Join(string, params String[]) | parameter 1 [element] -> return | false | | System.String.Join(char, IEnumerable) | parameter 0 -> return | false | -| System.String.Join(char, IEnumerable) | parameter 1 [[]] -> return | false | +| System.String.Join(char, IEnumerable) | parameter 1 [element] -> return | false | | System.String.Join(string, IEnumerable) | parameter 0 -> return | false | -| System.String.Join(string, IEnumerable) | parameter 1 [[]] -> return | false | +| System.String.Join(string, IEnumerable) | parameter 1 [element] -> return | false | | System.String.Normalize() | this parameter -> return | false | | System.String.Normalize(NormalizationForm) | this parameter -> return | false | | System.String.PadLeft(int) | this parameter -> return | false | @@ -2128,18 +2128,18 @@ | System.String.Replace(char, char) | this parameter -> return | false | | System.String.Replace(string, string) | parameter 1 -> return | false | | System.String.Replace(string, string) | this parameter -> return | false | -| System.String.Split(Char[], StringSplitOptions) | this parameter -> return [[]] | false | -| System.String.Split(Char[], int) | this parameter -> return [[]] | false | -| System.String.Split(Char[], int, StringSplitOptions) | this parameter -> return [[]] | false | -| System.String.Split(String[], StringSplitOptions) | this parameter -> return [[]] | false | -| System.String.Split(String[], int, StringSplitOptions) | this parameter -> return [[]] | false | -| System.String.Split(char, StringSplitOptions) | this parameter -> return [[]] | false | -| System.String.Split(char, int, StringSplitOptions) | this parameter -> return [[]] | false | -| System.String.Split(params Char[]) | this parameter -> return [[]] | false | -| System.String.Split(string, StringSplitOptions) | this parameter -> return [[]] | false | -| System.String.Split(string, int, StringSplitOptions) | this parameter -> return [[]] | false | -| System.String.String(Char[]) | parameter 0 [[]] -> return | false | -| System.String.String(Char[], int, int) | parameter 0 [[]] -> return | false | +| System.String.Split(Char[], StringSplitOptions) | this parameter -> return [element] | false | +| System.String.Split(Char[], int) | this parameter -> return [element] | false | +| System.String.Split(Char[], int, StringSplitOptions) | this parameter -> return [element] | false | +| System.String.Split(String[], StringSplitOptions) | this parameter -> return [element] | false | +| System.String.Split(String[], int, StringSplitOptions) | this parameter -> return [element] | false | +| System.String.Split(char, StringSplitOptions) | this parameter -> return [element] | false | +| System.String.Split(char, int, StringSplitOptions) | this parameter -> return [element] | false | +| System.String.Split(params Char[]) | this parameter -> return [element] | false | +| System.String.Split(string, StringSplitOptions) | this parameter -> return [element] | false | +| System.String.Split(string, int, StringSplitOptions) | this parameter -> return [element] | false | +| System.String.String(Char[]) | parameter 0 [element] -> return | false | +| System.String.String(Char[], int, int) | parameter 0 [element] -> return | false | | System.String.Substring(int) | this parameter -> return | false | | System.String.Substring(int, int) | this parameter -> return | false | | System.String.ToLower() | this parameter -> return | false | @@ -2159,154 +2159,154 @@ | System.String.TrimStart() | this parameter -> return | false | | System.String.TrimStart(char) | this parameter -> return | false | | System.String.TrimStart(params Char[]) | this parameter -> return | false | -| System.Text.Encoding.GetBytes(Char[]) | parameter 0 [[]] -> return | false | -| System.Text.Encoding.GetBytes(Char[], int, int) | parameter 0 [[]] -> return | false | -| System.Text.Encoding.GetBytes(Char[], int, int, Byte[], int) | parameter 0 [[]] -> return | false | +| System.Text.Encoding.GetBytes(Char[]) | parameter 0 [element] -> return | false | +| System.Text.Encoding.GetBytes(Char[], int, int) | parameter 0 [element] -> return | false | +| System.Text.Encoding.GetBytes(Char[], int, int, Byte[], int) | parameter 0 [element] -> return | false | | System.Text.Encoding.GetBytes(ReadOnlySpan, Span) | parameter 0 -> return | false | | System.Text.Encoding.GetBytes(char*, int, byte*, int) | parameter 0 -> return | false | | System.Text.Encoding.GetBytes(char*, int, byte*, int, EncoderNLS) | parameter 0 -> return | false | | System.Text.Encoding.GetBytes(string) | parameter 0 -> return | false | | System.Text.Encoding.GetBytes(string, int, int) | parameter 0 -> return | false | | System.Text.Encoding.GetBytes(string, int, int, Byte[], int) | parameter 0 -> return | false | -| System.Text.Encoding.GetChars(Byte[]) | parameter 0 [[]] -> return | false | -| System.Text.Encoding.GetChars(Byte[], int, int) | parameter 0 [[]] -> return | false | -| System.Text.Encoding.GetChars(Byte[], int, int, Char[], int) | parameter 0 [[]] -> return | false | -| System.Text.Encoding.GetChars(ReadOnlySpan, Span) | parameter 0 [[]] -> return | false | -| System.Text.Encoding.GetChars(byte*, int, char*, int) | parameter 0 [[]] -> return | false | -| System.Text.Encoding.GetChars(byte*, int, char*, int, DecoderNLS) | parameter 0 [[]] -> return | false | -| System.Text.Encoding.GetString(Byte[]) | parameter 0 [[]] -> return | false | -| System.Text.Encoding.GetString(Byte[], int, int) | parameter 0 [[]] -> return | false | -| System.Text.Encoding.GetString(ReadOnlySpan) | parameter 0 [[]] -> return | false | -| System.Text.Encoding.GetString(byte*, int) | parameter 0 [[]] -> return | false | -| System.Text.RegularExpressions.CaptureCollection.Add(Capture) | parameter 0 -> this parameter [[]] | true | -| System.Text.RegularExpressions.CaptureCollection.Add(object) | parameter 0 -> this parameter [[]] | true | -| System.Text.RegularExpressions.CaptureCollection.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Text.RegularExpressions.CaptureCollection.CopyTo(Capture[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Text.RegularExpressions.CaptureCollection.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Text.RegularExpressions.CaptureCollection.Insert(int, Capture) | parameter 1 -> this parameter [[]] | true | -| System.Text.RegularExpressions.CaptureCollection.Insert(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Text.RegularExpressions.CaptureCollection.get_Item(int) | this parameter [[]] -> return | true | -| System.Text.RegularExpressions.CaptureCollection.set_Item(int, Capture) | parameter 1 -> this parameter [[]] | true | -| System.Text.RegularExpressions.CaptureCollection.set_Item(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Text.RegularExpressions.GroupCollection.d__49.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Text.RegularExpressions.GroupCollection.d__51.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Text.RegularExpressions.GroupCollection.Add(Group) | parameter 0 -> this parameter [[]] | true | -| System.Text.RegularExpressions.GroupCollection.Add(object) | parameter 0 -> this parameter [[]] | true | -| System.Text.RegularExpressions.GroupCollection.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Text.RegularExpressions.GroupCollection.CopyTo(Group[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Text.RegularExpressions.GroupCollection.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Text.RegularExpressions.GroupCollection.Insert(int, Group) | parameter 1 -> this parameter [[]] | true | -| System.Text.RegularExpressions.GroupCollection.Insert(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Text.RegularExpressions.GroupCollection.get_Item(int) | this parameter [[]] -> return | true | -| System.Text.RegularExpressions.GroupCollection.get_Item(string) | this parameter [[]] -> return | true | -| System.Text.RegularExpressions.GroupCollection.set_Item(int, Group) | parameter 1 -> this parameter [[]] | true | -| System.Text.RegularExpressions.GroupCollection.set_Item(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Text.RegularExpressions.MatchCollection.Add(Match) | parameter 0 -> this parameter [[]] | true | -| System.Text.RegularExpressions.MatchCollection.Add(object) | parameter 0 -> this parameter [[]] | true | -| System.Text.RegularExpressions.MatchCollection.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Text.RegularExpressions.MatchCollection.CopyTo(Match[], int) | this parameter [[]] -> parameter 0 [[]] | true | -| System.Text.RegularExpressions.MatchCollection.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Text.RegularExpressions.MatchCollection.Insert(int, Match) | parameter 1 -> this parameter [[]] | true | -| System.Text.RegularExpressions.MatchCollection.Insert(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Text.RegularExpressions.MatchCollection.get_Item(int) | this parameter [[]] -> return | true | -| System.Text.RegularExpressions.MatchCollection.set_Item(int, Match) | parameter 1 -> this parameter [[]] | true | -| System.Text.RegularExpressions.MatchCollection.set_Item(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Text.StringBuilder.Append(object) | parameter 0 -> return [[]] | true | -| System.Text.StringBuilder.Append(object) | parameter 0 -> this parameter [[]] | true | -| System.Text.StringBuilder.Append(string) | parameter 0 -> return [[]] | true | -| System.Text.StringBuilder.Append(string) | parameter 0 -> this parameter [[]] | true | -| System.Text.StringBuilder.Append(string, int, int) | parameter 0 -> return [[]] | true | -| System.Text.StringBuilder.Append(string, int, int) | parameter 0 -> this parameter [[]] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object) | parameter 1 -> return [[]] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object) | parameter 1 -> this parameter [[]] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object) | parameter 2 -> return [[]] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object) | parameter 2 -> this parameter [[]] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | parameter 1 -> return [[]] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | parameter 1 -> this parameter [[]] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | parameter 2 -> return [[]] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | parameter 2 -> this parameter [[]] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | parameter 3 -> return [[]] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | parameter 3 -> this parameter [[]] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | parameter 1 -> return [[]] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | parameter 1 -> this parameter [[]] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | parameter 2 -> return [[]] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | parameter 2 -> this parameter [[]] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | parameter 3 -> return [[]] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | parameter 3 -> this parameter [[]] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | parameter 4 -> return [[]] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | parameter 4 -> this parameter [[]] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, params Object[]) | parameter 1 -> return [[]] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, params Object[]) | parameter 1 -> this parameter [[]] | true | -| System.Text.StringBuilder.AppendFormat(string, object) | parameter 0 -> return [[]] | true | -| System.Text.StringBuilder.AppendFormat(string, object) | parameter 0 -> this parameter [[]] | true | -| System.Text.StringBuilder.AppendFormat(string, object) | parameter 1 -> return [[]] | true | -| System.Text.StringBuilder.AppendFormat(string, object) | parameter 1 -> this parameter [[]] | true | -| System.Text.StringBuilder.AppendFormat(string, object, object) | parameter 0 -> return [[]] | true | -| System.Text.StringBuilder.AppendFormat(string, object, object) | parameter 0 -> this parameter [[]] | true | -| System.Text.StringBuilder.AppendFormat(string, object, object) | parameter 1 -> return [[]] | true | -| System.Text.StringBuilder.AppendFormat(string, object, object) | parameter 1 -> this parameter [[]] | true | -| System.Text.StringBuilder.AppendFormat(string, object, object) | parameter 2 -> return [[]] | true | -| System.Text.StringBuilder.AppendFormat(string, object, object) | parameter 2 -> this parameter [[]] | true | -| System.Text.StringBuilder.AppendFormat(string, object, object, object) | parameter 0 -> return [[]] | true | -| System.Text.StringBuilder.AppendFormat(string, object, object, object) | parameter 0 -> this parameter [[]] | true | -| System.Text.StringBuilder.AppendFormat(string, object, object, object) | parameter 1 -> return [[]] | true | -| System.Text.StringBuilder.AppendFormat(string, object, object, object) | parameter 1 -> this parameter [[]] | true | -| System.Text.StringBuilder.AppendFormat(string, object, object, object) | parameter 2 -> return [[]] | true | -| System.Text.StringBuilder.AppendFormat(string, object, object, object) | parameter 2 -> this parameter [[]] | true | -| System.Text.StringBuilder.AppendFormat(string, object, object, object) | parameter 3 -> return [[]] | true | -| System.Text.StringBuilder.AppendFormat(string, object, object, object) | parameter 3 -> this parameter [[]] | true | -| System.Text.StringBuilder.AppendFormat(string, params Object[]) | parameter 0 -> return [[]] | true | -| System.Text.StringBuilder.AppendFormat(string, params Object[]) | parameter 0 -> this parameter [[]] | true | -| System.Text.StringBuilder.AppendLine(string) | parameter 0 -> return [[]] | true | -| System.Text.StringBuilder.AppendLine(string) | parameter 0 -> this parameter [[]] | true | -| System.Text.StringBuilder.StringBuilder(string) | parameter 0 -> return [[]] | true | -| System.Text.StringBuilder.StringBuilder(string, int) | parameter 0 -> return [[]] | true | -| System.Text.StringBuilder.StringBuilder(string, int, int, int) | parameter 0 -> return [[]] | true | -| System.Text.StringBuilder.ToString() | this parameter [[]] -> return | false | -| System.Text.StringBuilder.ToString(int, int) | this parameter [[]] -> return | false | +| System.Text.Encoding.GetChars(Byte[]) | parameter 0 [element] -> return | false | +| System.Text.Encoding.GetChars(Byte[], int, int) | parameter 0 [element] -> return | false | +| System.Text.Encoding.GetChars(Byte[], int, int, Char[], int) | parameter 0 [element] -> return | false | +| System.Text.Encoding.GetChars(ReadOnlySpan, Span) | parameter 0 [element] -> return | false | +| System.Text.Encoding.GetChars(byte*, int, char*, int) | parameter 0 [element] -> return | false | +| System.Text.Encoding.GetChars(byte*, int, char*, int, DecoderNLS) | parameter 0 [element] -> return | false | +| System.Text.Encoding.GetString(Byte[]) | parameter 0 [element] -> return | false | +| System.Text.Encoding.GetString(Byte[], int, int) | parameter 0 [element] -> return | false | +| System.Text.Encoding.GetString(ReadOnlySpan) | parameter 0 [element] -> return | false | +| System.Text.Encoding.GetString(byte*, int) | parameter 0 [element] -> return | false | +| System.Text.RegularExpressions.CaptureCollection.Add(Capture) | parameter 0 -> this parameter [element] | true | +| System.Text.RegularExpressions.CaptureCollection.Add(object) | parameter 0 -> this parameter [element] | true | +| System.Text.RegularExpressions.CaptureCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Text.RegularExpressions.CaptureCollection.CopyTo(Capture[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Text.RegularExpressions.CaptureCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Text.RegularExpressions.CaptureCollection.Insert(int, Capture) | parameter 1 -> this parameter [element] | true | +| System.Text.RegularExpressions.CaptureCollection.Insert(int, object) | parameter 1 -> this parameter [element] | true | +| System.Text.RegularExpressions.CaptureCollection.get_Item(int) | this parameter [element] -> return | true | +| System.Text.RegularExpressions.CaptureCollection.set_Item(int, Capture) | parameter 1 -> this parameter [element] | true | +| System.Text.RegularExpressions.CaptureCollection.set_Item(int, object) | parameter 1 -> this parameter [element] | true | +| System.Text.RegularExpressions.GroupCollection.d__49.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Text.RegularExpressions.GroupCollection.d__51.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Text.RegularExpressions.GroupCollection.Add(Group) | parameter 0 -> this parameter [element] | true | +| System.Text.RegularExpressions.GroupCollection.Add(object) | parameter 0 -> this parameter [element] | true | +| System.Text.RegularExpressions.GroupCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Text.RegularExpressions.GroupCollection.CopyTo(Group[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Text.RegularExpressions.GroupCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Text.RegularExpressions.GroupCollection.Insert(int, Group) | parameter 1 -> this parameter [element] | true | +| System.Text.RegularExpressions.GroupCollection.Insert(int, object) | parameter 1 -> this parameter [element] | true | +| System.Text.RegularExpressions.GroupCollection.get_Item(int) | this parameter [element] -> return | true | +| System.Text.RegularExpressions.GroupCollection.get_Item(string) | this parameter [element] -> return | true | +| System.Text.RegularExpressions.GroupCollection.set_Item(int, Group) | parameter 1 -> this parameter [element] | true | +| System.Text.RegularExpressions.GroupCollection.set_Item(int, object) | parameter 1 -> this parameter [element] | true | +| System.Text.RegularExpressions.MatchCollection.Add(Match) | parameter 0 -> this parameter [element] | true | +| System.Text.RegularExpressions.MatchCollection.Add(object) | parameter 0 -> this parameter [element] | true | +| System.Text.RegularExpressions.MatchCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | +| System.Text.RegularExpressions.MatchCollection.CopyTo(Match[], int) | this parameter [element] -> parameter 0 [element] | true | +| System.Text.RegularExpressions.MatchCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Text.RegularExpressions.MatchCollection.Insert(int, Match) | parameter 1 -> this parameter [element] | true | +| System.Text.RegularExpressions.MatchCollection.Insert(int, object) | parameter 1 -> this parameter [element] | true | +| System.Text.RegularExpressions.MatchCollection.get_Item(int) | this parameter [element] -> return | true | +| System.Text.RegularExpressions.MatchCollection.set_Item(int, Match) | parameter 1 -> this parameter [element] | true | +| System.Text.RegularExpressions.MatchCollection.set_Item(int, object) | parameter 1 -> this parameter [element] | true | +| System.Text.StringBuilder.Append(object) | parameter 0 -> return [element] | true | +| System.Text.StringBuilder.Append(object) | parameter 0 -> this parameter [element] | true | +| System.Text.StringBuilder.Append(string) | parameter 0 -> return [element] | true | +| System.Text.StringBuilder.Append(string) | parameter 0 -> this parameter [element] | true | +| System.Text.StringBuilder.Append(string, int, int) | parameter 0 -> return [element] | true | +| System.Text.StringBuilder.Append(string, int, int) | parameter 0 -> this parameter [element] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object) | parameter 1 -> return [element] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object) | parameter 1 -> this parameter [element] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object) | parameter 2 -> return [element] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object) | parameter 2 -> this parameter [element] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | parameter 1 -> return [element] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | parameter 1 -> this parameter [element] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | parameter 2 -> return [element] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | parameter 2 -> this parameter [element] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | parameter 3 -> return [element] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | parameter 3 -> this parameter [element] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | parameter 1 -> return [element] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | parameter 1 -> this parameter [element] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | parameter 2 -> return [element] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | parameter 2 -> this parameter [element] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | parameter 3 -> return [element] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | parameter 3 -> this parameter [element] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | parameter 4 -> return [element] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | parameter 4 -> this parameter [element] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, params Object[]) | parameter 1 -> return [element] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, params Object[]) | parameter 1 -> this parameter [element] | true | +| System.Text.StringBuilder.AppendFormat(string, object) | parameter 0 -> return [element] | true | +| System.Text.StringBuilder.AppendFormat(string, object) | parameter 0 -> this parameter [element] | true | +| System.Text.StringBuilder.AppendFormat(string, object) | parameter 1 -> return [element] | true | +| System.Text.StringBuilder.AppendFormat(string, object) | parameter 1 -> this parameter [element] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object) | parameter 0 -> return [element] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object) | parameter 0 -> this parameter [element] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object) | parameter 1 -> return [element] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object) | parameter 1 -> this parameter [element] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object) | parameter 2 -> return [element] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object) | parameter 2 -> this parameter [element] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | parameter 0 -> return [element] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | parameter 0 -> this parameter [element] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | parameter 1 -> return [element] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | parameter 1 -> this parameter [element] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | parameter 2 -> return [element] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | parameter 2 -> this parameter [element] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | parameter 3 -> return [element] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | parameter 3 -> this parameter [element] | true | +| System.Text.StringBuilder.AppendFormat(string, params Object[]) | parameter 0 -> return [element] | true | +| System.Text.StringBuilder.AppendFormat(string, params Object[]) | parameter 0 -> this parameter [element] | true | +| System.Text.StringBuilder.AppendLine(string) | parameter 0 -> return [element] | true | +| System.Text.StringBuilder.AppendLine(string) | parameter 0 -> this parameter [element] | true | +| System.Text.StringBuilder.StringBuilder(string) | parameter 0 -> return [element] | true | +| System.Text.StringBuilder.StringBuilder(string, int) | parameter 0 -> return [element] | true | +| System.Text.StringBuilder.StringBuilder(string, int, int, int) | parameter 0 -> return [element] | true | +| System.Text.StringBuilder.ToString() | this parameter [element] -> return | false | +| System.Text.StringBuilder.ToString(int, int) | this parameter [element] -> return | false | | System.Text.TranscodingStream.BeginRead(Byte[], int, int, AsyncCallback, object) | this parameter -> parameter 0 | false | | System.Text.TranscodingStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | parameter 0 -> this parameter | false | | System.Text.TranscodingStream.Read(Byte[], int, int) | this parameter -> parameter 0 | false | | System.Text.TranscodingStream.ReadAsync(Byte[], int, int, CancellationToken) | this parameter -> parameter 0 | false | | System.Text.TranscodingStream.Write(Byte[], int, int) | parameter 0 -> this parameter | false | | System.Text.TranscodingStream.WriteAsync(Byte[], int, int, CancellationToken) | parameter 0 -> this parameter | false | -| System.Threading.Tasks.SingleProducerSingleConsumerQueue<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.Threading.Tasks.SingleProducerSingleConsumerQueue<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | | System.Threading.Tasks.Task.ContinueWith(Action, object) | parameter 1 -> parameter 1 of delegate parameter 0 | true | | System.Threading.Tasks.Task.ContinueWith(Action, object, CancellationToken) | parameter 1 -> parameter 1 of delegate parameter 0 | true | | System.Threading.Tasks.Task.ContinueWith(Action, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | parameter 1 -> parameter 1 of delegate parameter 0 | true | | System.Threading.Tasks.Task.ContinueWith(Action, object, TaskContinuationOptions) | parameter 1 -> parameter 1 of delegate parameter 0 | true | | System.Threading.Tasks.Task.ContinueWith(Action, object, TaskScheduler) | parameter 1 -> parameter 1 of delegate parameter 0 | true | -| System.Threading.Tasks.Task.ContinueWith(Func, object) | deleget output from parameter 0 -> return [Result] | true | +| System.Threading.Tasks.Task.ContinueWith(Func, object) | deleget output from parameter 0 -> return [property Result] | true | | System.Threading.Tasks.Task.ContinueWith(Func, object) | parameter 1 -> parameter 1 of delegate parameter 0 | true | -| System.Threading.Tasks.Task.ContinueWith(Func, object, CancellationToken) | deleget output from parameter 0 -> return [Result] | true | +| System.Threading.Tasks.Task.ContinueWith(Func, object, CancellationToken) | deleget output from parameter 0 -> return [property Result] | true | | System.Threading.Tasks.Task.ContinueWith(Func, object, CancellationToken) | parameter 1 -> parameter 1 of delegate parameter 0 | true | -| System.Threading.Tasks.Task.ContinueWith(Func, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | deleget output from parameter 0 -> return [Result] | true | +| System.Threading.Tasks.Task.ContinueWith(Func, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | deleget output from parameter 0 -> return [property Result] | true | | System.Threading.Tasks.Task.ContinueWith(Func, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | parameter 1 -> parameter 1 of delegate parameter 0 | true | -| System.Threading.Tasks.Task.ContinueWith(Func, object, TaskContinuationOptions) | deleget output from parameter 0 -> return [Result] | true | +| System.Threading.Tasks.Task.ContinueWith(Func, object, TaskContinuationOptions) | deleget output from parameter 0 -> return [property Result] | true | | System.Threading.Tasks.Task.ContinueWith(Func, object, TaskContinuationOptions) | parameter 1 -> parameter 1 of delegate parameter 0 | true | -| System.Threading.Tasks.Task.ContinueWith(Func, object, TaskScheduler) | deleget output from parameter 0 -> return [Result] | true | +| System.Threading.Tasks.Task.ContinueWith(Func, object, TaskScheduler) | deleget output from parameter 0 -> return [property Result] | true | | System.Threading.Tasks.Task.ContinueWith(Func, object, TaskScheduler) | parameter 1 -> parameter 1 of delegate parameter 0 | true | -| System.Threading.Tasks.Task.ContinueWith(Func) | deleget output from parameter 0 -> return [Result] | true | -| System.Threading.Tasks.Task.ContinueWith(Func, CancellationToken) | deleget output from parameter 0 -> return [Result] | true | -| System.Threading.Tasks.Task.ContinueWith(Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | deleget output from parameter 0 -> return [Result] | true | -| System.Threading.Tasks.Task.ContinueWith(Func, TaskContinuationOptions) | deleget output from parameter 0 -> return [Result] | true | -| System.Threading.Tasks.Task.ContinueWith(Func, TaskScheduler) | deleget output from parameter 0 -> return [Result] | true | -| System.Threading.Tasks.Task.FromResult(TResult) | parameter 0 -> return [Result] | true | -| System.Threading.Tasks.Task.Run(Func) | deleget output from parameter 0 -> return [Result] | true | -| System.Threading.Tasks.Task.Run(Func, CancellationToken) | deleget output from parameter 0 -> return [Result] | true | -| System.Threading.Tasks.Task.Run(Func>) | deleget output from parameter 0 -> return [Result] | true | -| System.Threading.Tasks.Task.Run(Func>, CancellationToken) | deleget output from parameter 0 -> return [Result] | true | +| System.Threading.Tasks.Task.ContinueWith(Func) | deleget output from parameter 0 -> return [property Result] | true | +| System.Threading.Tasks.Task.ContinueWith(Func, CancellationToken) | deleget output from parameter 0 -> return [property Result] | true | +| System.Threading.Tasks.Task.ContinueWith(Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | deleget output from parameter 0 -> return [property Result] | true | +| System.Threading.Tasks.Task.ContinueWith(Func, TaskContinuationOptions) | deleget output from parameter 0 -> return [property Result] | true | +| System.Threading.Tasks.Task.ContinueWith(Func, TaskScheduler) | deleget output from parameter 0 -> return [property Result] | true | +| System.Threading.Tasks.Task.FromResult(TResult) | parameter 0 -> return [property Result] | true | +| System.Threading.Tasks.Task.Run(Func) | deleget output from parameter 0 -> return [property Result] | true | +| System.Threading.Tasks.Task.Run(Func, CancellationToken) | deleget output from parameter 0 -> return [property Result] | true | +| System.Threading.Tasks.Task.Run(Func>) | deleget output from parameter 0 -> return [property Result] | true | +| System.Threading.Tasks.Task.Run(Func>, CancellationToken) | deleget output from parameter 0 -> return [property Result] | true | | System.Threading.Tasks.Task.Task(Action, object) | parameter 1 -> parameter 0 of delegate parameter 0 | true | | System.Threading.Tasks.Task.Task(Action, object, CancellationToken) | parameter 1 -> parameter 0 of delegate parameter 0 | true | | System.Threading.Tasks.Task.Task(Action, object, CancellationToken, TaskCreationOptions) | parameter 1 -> parameter 0 of delegate parameter 0 | true | | System.Threading.Tasks.Task.Task(Action, object, TaskCreationOptions) | parameter 1 -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task.WhenAll(IEnumerable>) | parameter 0 [[], Result] -> return [Result, []] | true | -| System.Threading.Tasks.Task.WhenAll(params Task[]) | parameter 0 [[], Result] -> return [Result, []] | true | -| System.Threading.Tasks.Task.WhenAny(IEnumerable>) | parameter 0 [[], Result] -> return [Result, []] | true | -| System.Threading.Tasks.Task.WhenAny(Task, Task) | parameter 0 [[], Result] -> return [Result, []] | true | -| System.Threading.Tasks.Task.WhenAny(Task, Task) | parameter 1 [[], Result] -> return [Result, []] | true | -| System.Threading.Tasks.Task.WhenAny(params Task[]) | parameter 0 [[], Result] -> return [Result, []] | true | -| System.Threading.Tasks.Task<>.ConfigureAwait(bool) | this parameter -> return [m_configuredTaskAwaiter, m_task] | true | +| System.Threading.Tasks.Task.WhenAll(IEnumerable>) | parameter 0 [element, property Result] -> return [property Result, element] | true | +| System.Threading.Tasks.Task.WhenAll(params Task[]) | parameter 0 [element, property Result] -> return [property Result, element] | true | +| System.Threading.Tasks.Task.WhenAny(IEnumerable>) | parameter 0 [element, property Result] -> return [property Result, element] | true | +| System.Threading.Tasks.Task.WhenAny(Task, Task) | parameter 0 [element, property Result] -> return [property Result, element] | true | +| System.Threading.Tasks.Task.WhenAny(Task, Task) | parameter 1 [element, property Result] -> return [property Result, element] | true | +| System.Threading.Tasks.Task.WhenAny(params Task[]) | parameter 0 [element, property Result] -> return [property Result, element] | true | +| System.Threading.Tasks.Task<>.ConfigureAwait(bool) | this parameter -> return [field m_configuredTaskAwaiter, field m_task] | true | | System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object) | parameter 1 -> parameter 1 of delegate parameter 0 | true | | System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object) | this parameter -> parameter 0 of delegate parameter 0 | true | | System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object, CancellationToken) | parameter 1 -> parameter 1 of delegate parameter 0 | true | @@ -2322,363 +2322,363 @@ | System.Threading.Tasks.Task<>.ContinueWith(Action>, CancellationToken, TaskContinuationOptions, TaskScheduler) | this parameter -> parameter 0 of delegate parameter 0 | true | | System.Threading.Tasks.Task<>.ContinueWith(Action>, TaskContinuationOptions) | this parameter -> parameter 0 of delegate parameter 0 | true | | System.Threading.Tasks.Task<>.ContinueWith(Action>, TaskScheduler) | this parameter -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object) | deleget output from parameter 0 -> return [Result] | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object) | deleget output from parameter 0 -> return [property Result] | true | | System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object) | parameter 1 -> parameter 1 of delegate parameter 0 | true | | System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object) | this parameter -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, CancellationToken) | deleget output from parameter 0 -> return [Result] | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, CancellationToken) | deleget output from parameter 0 -> return [property Result] | true | | System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, CancellationToken) | parameter 1 -> parameter 1 of delegate parameter 0 | true | | System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, CancellationToken) | this parameter -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | deleget output from parameter 0 -> return [Result] | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | deleget output from parameter 0 -> return [property Result] | true | | System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | parameter 1 -> parameter 1 of delegate parameter 0 | true | | System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | this parameter -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, TaskContinuationOptions) | deleget output from parameter 0 -> return [Result] | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, TaskContinuationOptions) | deleget output from parameter 0 -> return [property Result] | true | | System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, TaskContinuationOptions) | parameter 1 -> parameter 1 of delegate parameter 0 | true | | System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, TaskContinuationOptions) | this parameter -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, TaskScheduler) | deleget output from parameter 0 -> return [Result] | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, TaskScheduler) | deleget output from parameter 0 -> return [property Result] | true | | System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, TaskScheduler) | parameter 1 -> parameter 1 of delegate parameter 0 | true | | System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, TaskScheduler) | this parameter -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>) | deleget output from parameter 0 -> return [Result] | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>) | deleget output from parameter 0 -> return [property Result] | true | | System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>) | this parameter -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, CancellationToken) | deleget output from parameter 0 -> return [Result] | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, CancellationToken) | deleget output from parameter 0 -> return [property Result] | true | | System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, CancellationToken) | this parameter -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | deleget output from parameter 0 -> return [Result] | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | deleget output from parameter 0 -> return [property Result] | true | | System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | this parameter -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, TaskContinuationOptions) | deleget output from parameter 0 -> return [Result] | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, TaskContinuationOptions) | deleget output from parameter 0 -> return [property Result] | true | | System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, TaskContinuationOptions) | this parameter -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, TaskScheduler) | deleget output from parameter 0 -> return [Result] | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, TaskScheduler) | deleget output from parameter 0 -> return [property Result] | true | | System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, TaskScheduler) | this parameter -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.GetAwaiter() | this parameter -> return [m_task] | true | -| System.Threading.Tasks.Task<>.Task(Func, object) | deleget output from parameter 0 -> return [Result] | true | +| System.Threading.Tasks.Task<>.GetAwaiter() | this parameter -> return [field m_task] | true | +| System.Threading.Tasks.Task<>.Task(Func, object) | deleget output from parameter 0 -> return [property Result] | true | | System.Threading.Tasks.Task<>.Task(Func, object) | parameter 1 -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.Task(Func, object, CancellationToken) | deleget output from parameter 0 -> return [Result] | true | +| System.Threading.Tasks.Task<>.Task(Func, object, CancellationToken) | deleget output from parameter 0 -> return [property Result] | true | | System.Threading.Tasks.Task<>.Task(Func, object, CancellationToken) | parameter 1 -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.Task(Func, object, CancellationToken, TaskCreationOptions) | deleget output from parameter 0 -> return [Result] | true | +| System.Threading.Tasks.Task<>.Task(Func, object, CancellationToken, TaskCreationOptions) | deleget output from parameter 0 -> return [property Result] | true | | System.Threading.Tasks.Task<>.Task(Func, object, CancellationToken, TaskCreationOptions) | parameter 1 -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.Task(Func, object, TaskCreationOptions) | deleget output from parameter 0 -> return [Result] | true | +| System.Threading.Tasks.Task<>.Task(Func, object, TaskCreationOptions) | deleget output from parameter 0 -> return [property Result] | true | | System.Threading.Tasks.Task<>.Task(Func, object, TaskCreationOptions) | parameter 1 -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.Task(Func) | deleget output from parameter 0 -> return [Result] | true | -| System.Threading.Tasks.Task<>.Task(Func, CancellationToken) | deleget output from parameter 0 -> return [Result] | true | -| System.Threading.Tasks.Task<>.Task(Func, CancellationToken, TaskCreationOptions) | deleget output from parameter 0 -> return [Result] | true | -| System.Threading.Tasks.Task<>.Task(Func, TaskCreationOptions) | deleget output from parameter 0 -> return [Result] | true | +| System.Threading.Tasks.Task<>.Task(Func) | deleget output from parameter 0 -> return [property Result] | true | +| System.Threading.Tasks.Task<>.Task(Func, CancellationToken) | deleget output from parameter 0 -> return [property Result] | true | +| System.Threading.Tasks.Task<>.Task(Func, CancellationToken, TaskCreationOptions) | deleget output from parameter 0 -> return [property Result] | true | +| System.Threading.Tasks.Task<>.Task(Func, TaskCreationOptions) | deleget output from parameter 0 -> return [property Result] | true | | System.Threading.Tasks.Task<>.get_Result() | this parameter -> return | false | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func) | deleget output from parameter 1 -> return [Result] | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func) | deleget output from parameter 1 -> return [property Result] | true | | System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, CancellationToken) | deleget output from parameter 1 -> return [Result] | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, CancellationToken) | deleget output from parameter 1 -> return [property Result] | true | | System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, CancellationToken) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | deleget output from parameter 1 -> return [Result] | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | deleget output from parameter 1 -> return [property Result] | true | | System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, TaskContinuationOptions) | deleget output from parameter 1 -> return [Result] | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, TaskContinuationOptions) | deleget output from parameter 1 -> return [property Result] | true | | System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, TaskContinuationOptions) | parameter 0 -> parameter 0 of delegate parameter 1 | true | | System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Action) | parameter 0 -> parameter 0 of delegate parameter 1 | true | | System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Action, CancellationToken) | parameter 0 -> parameter 0 of delegate parameter 1 | true | | System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Action, CancellationToken, TaskContinuationOptions, TaskScheduler) | parameter 0 -> parameter 0 of delegate parameter 1 | true | | System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Action, TaskContinuationOptions) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func) | deleget output from parameter 1 -> return [Result] | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, CancellationToken) | deleget output from parameter 1 -> return [Result] | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | deleget output from parameter 1 -> return [Result] | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, TaskContinuationOptions) | deleget output from parameter 1 -> return [Result] | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>) | deleget output from parameter 1 -> return [Result] | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func) | deleget output from parameter 1 -> return [property Result] | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, CancellationToken) | deleget output from parameter 1 -> return [property Result] | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | deleget output from parameter 1 -> return [property Result] | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, TaskContinuationOptions) | deleget output from parameter 1 -> return [property Result] | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>) | deleget output from parameter 1 -> return [property Result] | true | | System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>, CancellationToken) | deleget output from parameter 1 -> return [Result] | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>, CancellationToken) | deleget output from parameter 1 -> return [property Result] | true | | System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>, CancellationToken) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | deleget output from parameter 1 -> return [Result] | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | deleget output from parameter 1 -> return [property Result] | true | | System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>, TaskContinuationOptions) | deleget output from parameter 1 -> return [Result] | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>, TaskContinuationOptions) | deleget output from parameter 1 -> return [property Result] | true | | System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>, TaskContinuationOptions) | parameter 0 -> parameter 0 of delegate parameter 1 | true | | System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Action>) | parameter 0 -> parameter 0 of delegate parameter 1 | true | | System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Action>, CancellationToken) | parameter 0 -> parameter 0 of delegate parameter 1 | true | | System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Action>, CancellationToken, TaskContinuationOptions, TaskScheduler) | parameter 0 -> parameter 0 of delegate parameter 1 | true | | System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Action>, TaskContinuationOptions) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func) | deleget output from parameter 1 -> return [Result] | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, CancellationToken) | deleget output from parameter 1 -> return [Result] | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | deleget output from parameter 1 -> return [Result] | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TaskContinuationOptions) | deleget output from parameter 1 -> return [Result] | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func) | deleget output from parameter 1 -> return [property Result] | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, CancellationToken) | deleget output from parameter 1 -> return [property Result] | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | deleget output from parameter 1 -> return [property Result] | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TaskContinuationOptions) | deleget output from parameter 1 -> return [property Result] | true | | System.Threading.Tasks.TaskFactory.StartNew(Action, object) | parameter 1 -> parameter 0 of delegate parameter 0 | true | | System.Threading.Tasks.TaskFactory.StartNew(Action, object, CancellationToken) | parameter 1 -> parameter 0 of delegate parameter 0 | true | | System.Threading.Tasks.TaskFactory.StartNew(Action, object, CancellationToken, TaskCreationOptions, TaskScheduler) | parameter 1 -> parameter 0 of delegate parameter 0 | true | | System.Threading.Tasks.TaskFactory.StartNew(Action, object, TaskCreationOptions) | parameter 1 -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.TaskFactory.StartNew(Func, object) | deleget output from parameter 0 -> return [Result] | true | +| System.Threading.Tasks.TaskFactory.StartNew(Func, object) | deleget output from parameter 0 -> return [property Result] | true | | System.Threading.Tasks.TaskFactory.StartNew(Func, object) | parameter 1 -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.TaskFactory.StartNew(Func, object, CancellationToken) | deleget output from parameter 0 -> return [Result] | true | +| System.Threading.Tasks.TaskFactory.StartNew(Func, object, CancellationToken) | deleget output from parameter 0 -> return [property Result] | true | | System.Threading.Tasks.TaskFactory.StartNew(Func, object, CancellationToken) | parameter 1 -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.TaskFactory.StartNew(Func, object, CancellationToken, TaskCreationOptions, TaskScheduler) | deleget output from parameter 0 -> return [Result] | true | +| System.Threading.Tasks.TaskFactory.StartNew(Func, object, CancellationToken, TaskCreationOptions, TaskScheduler) | deleget output from parameter 0 -> return [property Result] | true | | System.Threading.Tasks.TaskFactory.StartNew(Func, object, CancellationToken, TaskCreationOptions, TaskScheduler) | parameter 1 -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.TaskFactory.StartNew(Func, object, TaskCreationOptions) | deleget output from parameter 0 -> return [Result] | true | +| System.Threading.Tasks.TaskFactory.StartNew(Func, object, TaskCreationOptions) | deleget output from parameter 0 -> return [property Result] | true | | System.Threading.Tasks.TaskFactory.StartNew(Func, object, TaskCreationOptions) | parameter 1 -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.TaskFactory.StartNew(Func) | deleget output from parameter 0 -> return [Result] | true | -| System.Threading.Tasks.TaskFactory.StartNew(Func, CancellationToken) | deleget output from parameter 0 -> return [Result] | true | -| System.Threading.Tasks.TaskFactory.StartNew(Func, CancellationToken, TaskCreationOptions, TaskScheduler) | deleget output from parameter 0 -> return [Result] | true | -| System.Threading.Tasks.TaskFactory.StartNew(Func, TaskCreationOptions) | deleget output from parameter 0 -> return [Result] | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func) | deleget output from parameter 1 -> return [Result] | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, CancellationToken) | deleget output from parameter 1 -> return [Result] | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | deleget output from parameter 1 -> return [Result] | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, TaskContinuationOptions) | deleget output from parameter 1 -> return [Result] | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func) | deleget output from parameter 1 -> return [Result] | true | +| System.Threading.Tasks.TaskFactory.StartNew(Func) | deleget output from parameter 0 -> return [property Result] | true | +| System.Threading.Tasks.TaskFactory.StartNew(Func, CancellationToken) | deleget output from parameter 0 -> return [property Result] | true | +| System.Threading.Tasks.TaskFactory.StartNew(Func, CancellationToken, TaskCreationOptions, TaskScheduler) | deleget output from parameter 0 -> return [property Result] | true | +| System.Threading.Tasks.TaskFactory.StartNew(Func, TaskCreationOptions) | deleget output from parameter 0 -> return [property Result] | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func) | deleget output from parameter 1 -> return [property Result] | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, CancellationToken) | deleget output from parameter 1 -> return [property Result] | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | deleget output from parameter 1 -> return [property Result] | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, TaskContinuationOptions) | deleget output from parameter 1 -> return [property Result] | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func) | deleget output from parameter 1 -> return [property Result] | true | | System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, CancellationToken) | deleget output from parameter 1 -> return [Result] | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, CancellationToken) | deleget output from parameter 1 -> return [property Result] | true | | System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, CancellationToken) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | deleget output from parameter 1 -> return [Result] | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | deleget output from parameter 1 -> return [property Result] | true | | System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, TaskContinuationOptions) | deleget output from parameter 1 -> return [Result] | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, TaskContinuationOptions) | deleget output from parameter 1 -> return [property Result] | true | | System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, TaskContinuationOptions) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func) | deleget output from parameter 1 -> return [Result] | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, CancellationToken) | deleget output from parameter 1 -> return [Result] | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | deleget output from parameter 1 -> return [Result] | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TaskContinuationOptions) | deleget output from parameter 1 -> return [Result] | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>) | deleget output from parameter 1 -> return [Result] | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func) | deleget output from parameter 1 -> return [property Result] | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, CancellationToken) | deleget output from parameter 1 -> return [property Result] | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | deleget output from parameter 1 -> return [property Result] | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TaskContinuationOptions) | deleget output from parameter 1 -> return [property Result] | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>) | deleget output from parameter 1 -> return [property Result] | true | | System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>, CancellationToken) | deleget output from parameter 1 -> return [Result] | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>, CancellationToken) | deleget output from parameter 1 -> return [property Result] | true | | System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>, CancellationToken) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | deleget output from parameter 1 -> return [Result] | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | deleget output from parameter 1 -> return [property Result] | true | | System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>, TaskContinuationOptions) | deleget output from parameter 1 -> return [Result] | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>, TaskContinuationOptions) | deleget output from parameter 1 -> return [property Result] | true | | System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>, TaskContinuationOptions) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object) | deleget output from parameter 0 -> return [Result] | true | +| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object) | deleget output from parameter 0 -> return [property Result] | true | | System.Threading.Tasks.TaskFactory<>.StartNew(Func, object) | parameter 1 -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, CancellationToken) | deleget output from parameter 0 -> return [Result] | true | +| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, CancellationToken) | deleget output from parameter 0 -> return [property Result] | true | | System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, CancellationToken) | parameter 1 -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, CancellationToken, TaskCreationOptions, TaskScheduler) | deleget output from parameter 0 -> return [Result] | true | +| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, CancellationToken, TaskCreationOptions, TaskScheduler) | deleget output from parameter 0 -> return [property Result] | true | | System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, CancellationToken, TaskCreationOptions, TaskScheduler) | parameter 1 -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, TaskCreationOptions) | deleget output from parameter 0 -> return [Result] | true | +| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, TaskCreationOptions) | deleget output from parameter 0 -> return [property Result] | true | | System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, TaskCreationOptions) | parameter 1 -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.TaskFactory<>.StartNew(Func) | deleget output from parameter 0 -> return [Result] | true | -| System.Threading.Tasks.TaskFactory<>.StartNew(Func, CancellationToken) | deleget output from parameter 0 -> return [Result] | true | -| System.Threading.Tasks.TaskFactory<>.StartNew(Func, CancellationToken, TaskCreationOptions, TaskScheduler) | deleget output from parameter 0 -> return [Result] | true | -| System.Threading.Tasks.TaskFactory<>.StartNew(Func, TaskCreationOptions) | deleget output from parameter 0 -> return [Result] | true | -| System.Threading.Tasks.ThreadPoolTaskScheduler.d__6.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Threading.ThreadPool.d__52.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Threading.ThreadPool.d__51.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 0 -> return [Item1] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 1 -> return [Item2] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 2 -> return [Item3] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 3 -> return [Item4] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 4 -> return [Item5] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 5 -> return [Item6] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 6 -> return [Item7] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7) | parameter 0 -> return [Item1] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7) | parameter 1 -> return [Item2] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7) | parameter 2 -> return [Item3] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7) | parameter 3 -> return [Item4] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7) | parameter 4 -> return [Item5] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7) | parameter 5 -> return [Item6] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7) | parameter 6 -> return [Item7] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6) | parameter 0 -> return [Item1] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6) | parameter 1 -> return [Item2] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6) | parameter 2 -> return [Item3] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6) | parameter 3 -> return [Item4] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6) | parameter 4 -> return [Item5] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6) | parameter 5 -> return [Item6] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5) | parameter 0 -> return [Item1] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5) | parameter 1 -> return [Item2] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5) | parameter 2 -> return [Item3] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5) | parameter 3 -> return [Item4] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5) | parameter 4 -> return [Item5] | true | -| System.Tuple.Create(T1, T2, T3, T4) | parameter 0 -> return [Item1] | true | -| System.Tuple.Create(T1, T2, T3, T4) | parameter 1 -> return [Item2] | true | -| System.Tuple.Create(T1, T2, T3, T4) | parameter 2 -> return [Item3] | true | -| System.Tuple.Create(T1, T2, T3, T4) | parameter 3 -> return [Item4] | true | -| System.Tuple.Create(T1, T2, T3) | parameter 0 -> return [Item1] | true | -| System.Tuple.Create(T1, T2, T3) | parameter 1 -> return [Item2] | true | -| System.Tuple.Create(T1, T2, T3) | parameter 2 -> return [Item3] | true | -| System.Tuple.Create(T1, T2) | parameter 0 -> return [Item1] | true | -| System.Tuple.Create(T1, T2) | parameter 1 -> return [Item2] | true | -| System.Tuple.Create(T1) | parameter 0 -> return [Item1] | true | -| System.Tuple<,,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 0 -> return [Item1] | true | -| System.Tuple<,,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 1 -> return [Item2] | true | -| System.Tuple<,,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 2 -> return [Item3] | true | -| System.Tuple<,,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 3 -> return [Item4] | true | -| System.Tuple<,,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 4 -> return [Item5] | true | -| System.Tuple<,,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 5 -> return [Item6] | true | -| System.Tuple<,,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 6 -> return [Item7] | true | -| System.Tuple<,,,,,,,>.get_Item(int) | this parameter [Item1] -> return | true | -| System.Tuple<,,,,,,,>.get_Item(int) | this parameter [Item2] -> return | true | -| System.Tuple<,,,,,,,>.get_Item(int) | this parameter [Item3] -> return | true | -| System.Tuple<,,,,,,,>.get_Item(int) | this parameter [Item4] -> return | true | -| System.Tuple<,,,,,,,>.get_Item(int) | this parameter [Item5] -> return | true | -| System.Tuple<,,,,,,,>.get_Item(int) | this parameter [Item6] -> return | true | -| System.Tuple<,,,,,,,>.get_Item(int) | this parameter [Item7] -> return | true | -| System.Tuple<,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7) | parameter 0 -> return [Item1] | true | -| System.Tuple<,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7) | parameter 1 -> return [Item2] | true | -| System.Tuple<,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7) | parameter 2 -> return [Item3] | true | -| System.Tuple<,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7) | parameter 3 -> return [Item4] | true | -| System.Tuple<,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7) | parameter 4 -> return [Item5] | true | -| System.Tuple<,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7) | parameter 5 -> return [Item6] | true | -| System.Tuple<,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7) | parameter 6 -> return [Item7] | true | -| System.Tuple<,,,,,,>.get_Item(int) | this parameter [Item1] -> return | true | -| System.Tuple<,,,,,,>.get_Item(int) | this parameter [Item2] -> return | true | -| System.Tuple<,,,,,,>.get_Item(int) | this parameter [Item3] -> return | true | -| System.Tuple<,,,,,,>.get_Item(int) | this parameter [Item4] -> return | true | -| System.Tuple<,,,,,,>.get_Item(int) | this parameter [Item5] -> return | true | -| System.Tuple<,,,,,,>.get_Item(int) | this parameter [Item6] -> return | true | -| System.Tuple<,,,,,,>.get_Item(int) | this parameter [Item7] -> return | true | -| System.Tuple<,,,,,>.Tuple(T1, T2, T3, T4, T5, T6) | parameter 0 -> return [Item1] | true | -| System.Tuple<,,,,,>.Tuple(T1, T2, T3, T4, T5, T6) | parameter 1 -> return [Item2] | true | -| System.Tuple<,,,,,>.Tuple(T1, T2, T3, T4, T5, T6) | parameter 2 -> return [Item3] | true | -| System.Tuple<,,,,,>.Tuple(T1, T2, T3, T4, T5, T6) | parameter 3 -> return [Item4] | true | -| System.Tuple<,,,,,>.Tuple(T1, T2, T3, T4, T5, T6) | parameter 4 -> return [Item5] | true | -| System.Tuple<,,,,,>.Tuple(T1, T2, T3, T4, T5, T6) | parameter 5 -> return [Item6] | true | -| System.Tuple<,,,,,>.get_Item(int) | this parameter [Item1] -> return | true | -| System.Tuple<,,,,,>.get_Item(int) | this parameter [Item2] -> return | true | -| System.Tuple<,,,,,>.get_Item(int) | this parameter [Item3] -> return | true | -| System.Tuple<,,,,,>.get_Item(int) | this parameter [Item4] -> return | true | -| System.Tuple<,,,,,>.get_Item(int) | this parameter [Item5] -> return | true | -| System.Tuple<,,,,,>.get_Item(int) | this parameter [Item6] -> return | true | -| System.Tuple<,,,,>.Tuple(T1, T2, T3, T4, T5) | parameter 0 -> return [Item1] | true | -| System.Tuple<,,,,>.Tuple(T1, T2, T3, T4, T5) | parameter 1 -> return [Item2] | true | -| System.Tuple<,,,,>.Tuple(T1, T2, T3, T4, T5) | parameter 2 -> return [Item3] | true | -| System.Tuple<,,,,>.Tuple(T1, T2, T3, T4, T5) | parameter 3 -> return [Item4] | true | -| System.Tuple<,,,,>.Tuple(T1, T2, T3, T4, T5) | parameter 4 -> return [Item5] | true | -| System.Tuple<,,,,>.get_Item(int) | this parameter [Item1] -> return | true | -| System.Tuple<,,,,>.get_Item(int) | this parameter [Item2] -> return | true | -| System.Tuple<,,,,>.get_Item(int) | this parameter [Item3] -> return | true | -| System.Tuple<,,,,>.get_Item(int) | this parameter [Item4] -> return | true | -| System.Tuple<,,,,>.get_Item(int) | this parameter [Item5] -> return | true | -| System.Tuple<,,,>.Tuple(T1, T2, T3, T4) | parameter 0 -> return [Item1] | true | -| System.Tuple<,,,>.Tuple(T1, T2, T3, T4) | parameter 1 -> return [Item2] | true | -| System.Tuple<,,,>.Tuple(T1, T2, T3, T4) | parameter 2 -> return [Item3] | true | -| System.Tuple<,,,>.Tuple(T1, T2, T3, T4) | parameter 3 -> return [Item4] | true | -| System.Tuple<,,,>.get_Item(int) | this parameter [Item1] -> return | true | -| System.Tuple<,,,>.get_Item(int) | this parameter [Item2] -> return | true | -| System.Tuple<,,,>.get_Item(int) | this parameter [Item3] -> return | true | -| System.Tuple<,,,>.get_Item(int) | this parameter [Item4] -> return | true | -| System.Tuple<,,>.Tuple(T1, T2, T3) | parameter 0 -> return [Item1] | true | -| System.Tuple<,,>.Tuple(T1, T2, T3) | parameter 1 -> return [Item2] | true | -| System.Tuple<,,>.Tuple(T1, T2, T3) | parameter 2 -> return [Item3] | true | -| System.Tuple<,,>.get_Item(int) | this parameter [Item1] -> return | true | -| System.Tuple<,,>.get_Item(int) | this parameter [Item2] -> return | true | -| System.Tuple<,,>.get_Item(int) | this parameter [Item3] -> return | true | -| System.Tuple<,>.Tuple(T1, T2) | parameter 0 -> return [Item1] | true | -| System.Tuple<,>.Tuple(T1, T2) | parameter 1 -> return [Item2] | true | -| System.Tuple<,>.get_Item(int) | this parameter [Item1] -> return | true | -| System.Tuple<,>.get_Item(int) | this parameter [Item2] -> return | true | -| System.Tuple<>.Tuple(T1) | parameter 0 -> return [Item1] | true | -| System.Tuple<>.get_Item(int) | this parameter [Item1] -> return | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20, out T21) | parameter 0 [Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20, out T21) | parameter 0 [Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20, out T21) | parameter 0 [Item3] -> parameter 3 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20, out T21) | parameter 0 [Item4] -> parameter 4 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20, out T21) | parameter 0 [Item5] -> parameter 5 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20, out T21) | parameter 0 [Item6] -> parameter 6 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20, out T21) | parameter 0 [Item7] -> parameter 7 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20) | parameter 0 [Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20) | parameter 0 [Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20) | parameter 0 [Item3] -> parameter 3 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20) | parameter 0 [Item4] -> parameter 4 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20) | parameter 0 [Item5] -> parameter 5 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20) | parameter 0 [Item6] -> parameter 6 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20) | parameter 0 [Item7] -> parameter 7 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19) | parameter 0 [Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19) | parameter 0 [Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19) | parameter 0 [Item3] -> parameter 3 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19) | parameter 0 [Item4] -> parameter 4 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19) | parameter 0 [Item5] -> parameter 5 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19) | parameter 0 [Item6] -> parameter 6 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19) | parameter 0 [Item7] -> parameter 7 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18) | parameter 0 [Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18) | parameter 0 [Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18) | parameter 0 [Item3] -> parameter 3 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18) | parameter 0 [Item4] -> parameter 4 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18) | parameter 0 [Item5] -> parameter 5 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18) | parameter 0 [Item6] -> parameter 6 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18) | parameter 0 [Item7] -> parameter 7 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17) | parameter 0 [Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17) | parameter 0 [Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17) | parameter 0 [Item3] -> parameter 3 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17) | parameter 0 [Item4] -> parameter 4 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17) | parameter 0 [Item5] -> parameter 5 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17) | parameter 0 [Item6] -> parameter 6 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17) | parameter 0 [Item7] -> parameter 7 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16) | parameter 0 [Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16) | parameter 0 [Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16) | parameter 0 [Item3] -> parameter 3 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16) | parameter 0 [Item4] -> parameter 4 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16) | parameter 0 [Item5] -> parameter 5 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16) | parameter 0 [Item6] -> parameter 6 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16) | parameter 0 [Item7] -> parameter 7 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15) | parameter 0 [Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15) | parameter 0 [Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15) | parameter 0 [Item3] -> parameter 3 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15) | parameter 0 [Item4] -> parameter 4 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15) | parameter 0 [Item5] -> parameter 5 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15) | parameter 0 [Item6] -> parameter 6 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15) | parameter 0 [Item7] -> parameter 7 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14) | parameter 0 [Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14) | parameter 0 [Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14) | parameter 0 [Item3] -> parameter 3 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14) | parameter 0 [Item4] -> parameter 4 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14) | parameter 0 [Item5] -> parameter 5 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14) | parameter 0 [Item6] -> parameter 6 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14) | parameter 0 [Item7] -> parameter 7 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13) | parameter 0 [Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13) | parameter 0 [Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13) | parameter 0 [Item3] -> parameter 3 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13) | parameter 0 [Item4] -> parameter 4 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13) | parameter 0 [Item5] -> parameter 5 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13) | parameter 0 [Item6] -> parameter 6 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13) | parameter 0 [Item7] -> parameter 7 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12) | parameter 0 [Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12) | parameter 0 [Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12) | parameter 0 [Item3] -> parameter 3 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12) | parameter 0 [Item4] -> parameter 4 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12) | parameter 0 [Item5] -> parameter 5 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12) | parameter 0 [Item6] -> parameter 6 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12) | parameter 0 [Item7] -> parameter 7 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11) | parameter 0 [Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11) | parameter 0 [Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11) | parameter 0 [Item3] -> parameter 3 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11) | parameter 0 [Item4] -> parameter 4 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11) | parameter 0 [Item5] -> parameter 5 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11) | parameter 0 [Item6] -> parameter 6 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11) | parameter 0 [Item7] -> parameter 7 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10) | parameter 0 [Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10) | parameter 0 [Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10) | parameter 0 [Item3] -> parameter 3 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10) | parameter 0 [Item4] -> parameter 4 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10) | parameter 0 [Item5] -> parameter 5 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10) | parameter 0 [Item6] -> parameter 6 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10) | parameter 0 [Item7] -> parameter 7 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9) | parameter 0 [Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9) | parameter 0 [Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9) | parameter 0 [Item3] -> parameter 3 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9) | parameter 0 [Item4] -> parameter 4 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9) | parameter 0 [Item5] -> parameter 5 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9) | parameter 0 [Item6] -> parameter 6 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9) | parameter 0 [Item7] -> parameter 7 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8) | parameter 0 [Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8) | parameter 0 [Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8) | parameter 0 [Item3] -> parameter 3 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8) | parameter 0 [Item4] -> parameter 4 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8) | parameter 0 [Item5] -> parameter 5 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8) | parameter 0 [Item6] -> parameter 6 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8) | parameter 0 [Item7] -> parameter 7 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6, out T7) | parameter 0 [Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6, out T7) | parameter 0 [Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6, out T7) | parameter 0 [Item3] -> parameter 3 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6, out T7) | parameter 0 [Item4] -> parameter 4 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6, out T7) | parameter 0 [Item5] -> parameter 5 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6, out T7) | parameter 0 [Item6] -> parameter 6 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6, out T7) | parameter 0 [Item7] -> parameter 7 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6) | parameter 0 [Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6) | parameter 0 [Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6) | parameter 0 [Item3] -> parameter 3 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6) | parameter 0 [Item4] -> parameter 4 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6) | parameter 0 [Item5] -> parameter 5 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6) | parameter 0 [Item6] -> parameter 6 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5) | parameter 0 [Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5) | parameter 0 [Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5) | parameter 0 [Item3] -> parameter 3 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5) | parameter 0 [Item4] -> parameter 4 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5) | parameter 0 [Item5] -> parameter 5 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4) | parameter 0 [Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4) | parameter 0 [Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4) | parameter 0 [Item3] -> parameter 3 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4) | parameter 0 [Item4] -> parameter 4 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3) | parameter 0 [Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3) | parameter 0 [Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3) | parameter 0 [Item3] -> parameter 3 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2) | parameter 0 [Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2) | parameter 0 [Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1) | parameter 0 [Item1] -> parameter 1 | true | +| System.Threading.Tasks.TaskFactory<>.StartNew(Func) | deleget output from parameter 0 -> return [property Result] | true | +| System.Threading.Tasks.TaskFactory<>.StartNew(Func, CancellationToken) | deleget output from parameter 0 -> return [property Result] | true | +| System.Threading.Tasks.TaskFactory<>.StartNew(Func, CancellationToken, TaskCreationOptions, TaskScheduler) | deleget output from parameter 0 -> return [property Result] | true | +| System.Threading.Tasks.TaskFactory<>.StartNew(Func, TaskCreationOptions) | deleget output from parameter 0 -> return [property Result] | true | +| System.Threading.Tasks.ThreadPoolTaskScheduler.d__6.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Threading.ThreadPool.d__52.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Threading.ThreadPool.d__51.GetEnumerator() | this parameter [element] -> return [property Current] | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 0 -> return [property Item1] | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 1 -> return [property Item2] | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 2 -> return [property Item3] | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 3 -> return [property Item4] | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 4 -> return [property Item5] | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 5 -> return [property Item6] | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 6 -> return [property Item7] | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7) | parameter 0 -> return [property Item1] | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7) | parameter 1 -> return [property Item2] | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7) | parameter 2 -> return [property Item3] | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7) | parameter 3 -> return [property Item4] | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7) | parameter 4 -> return [property Item5] | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7) | parameter 5 -> return [property Item6] | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7) | parameter 6 -> return [property Item7] | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6) | parameter 0 -> return [property Item1] | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6) | parameter 1 -> return [property Item2] | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6) | parameter 2 -> return [property Item3] | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6) | parameter 3 -> return [property Item4] | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6) | parameter 4 -> return [property Item5] | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6) | parameter 5 -> return [property Item6] | true | +| System.Tuple.Create(T1, T2, T3, T4, T5) | parameter 0 -> return [property Item1] | true | +| System.Tuple.Create(T1, T2, T3, T4, T5) | parameter 1 -> return [property Item2] | true | +| System.Tuple.Create(T1, T2, T3, T4, T5) | parameter 2 -> return [property Item3] | true | +| System.Tuple.Create(T1, T2, T3, T4, T5) | parameter 3 -> return [property Item4] | true | +| System.Tuple.Create(T1, T2, T3, T4, T5) | parameter 4 -> return [property Item5] | true | +| System.Tuple.Create(T1, T2, T3, T4) | parameter 0 -> return [property Item1] | true | +| System.Tuple.Create(T1, T2, T3, T4) | parameter 1 -> return [property Item2] | true | +| System.Tuple.Create(T1, T2, T3, T4) | parameter 2 -> return [property Item3] | true | +| System.Tuple.Create(T1, T2, T3, T4) | parameter 3 -> return [property Item4] | true | +| System.Tuple.Create(T1, T2, T3) | parameter 0 -> return [property Item1] | true | +| System.Tuple.Create(T1, T2, T3) | parameter 1 -> return [property Item2] | true | +| System.Tuple.Create(T1, T2, T3) | parameter 2 -> return [property Item3] | true | +| System.Tuple.Create(T1, T2) | parameter 0 -> return [property Item1] | true | +| System.Tuple.Create(T1, T2) | parameter 1 -> return [property Item2] | true | +| System.Tuple.Create(T1) | parameter 0 -> return [property Item1] | true | +| System.Tuple<,,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 0 -> return [property Item1] | true | +| System.Tuple<,,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 1 -> return [property Item2] | true | +| System.Tuple<,,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 2 -> return [property Item3] | true | +| System.Tuple<,,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 3 -> return [property Item4] | true | +| System.Tuple<,,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 4 -> return [property Item5] | true | +| System.Tuple<,,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 5 -> return [property Item6] | true | +| System.Tuple<,,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 6 -> return [property Item7] | true | +| System.Tuple<,,,,,,,>.get_Item(int) | this parameter [property Item1] -> return | true | +| System.Tuple<,,,,,,,>.get_Item(int) | this parameter [property Item2] -> return | true | +| System.Tuple<,,,,,,,>.get_Item(int) | this parameter [property Item3] -> return | true | +| System.Tuple<,,,,,,,>.get_Item(int) | this parameter [property Item4] -> return | true | +| System.Tuple<,,,,,,,>.get_Item(int) | this parameter [property Item5] -> return | true | +| System.Tuple<,,,,,,,>.get_Item(int) | this parameter [property Item6] -> return | true | +| System.Tuple<,,,,,,,>.get_Item(int) | this parameter [property Item7] -> return | true | +| System.Tuple<,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7) | parameter 0 -> return [property Item1] | true | +| System.Tuple<,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7) | parameter 1 -> return [property Item2] | true | +| System.Tuple<,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7) | parameter 2 -> return [property Item3] | true | +| System.Tuple<,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7) | parameter 3 -> return [property Item4] | true | +| System.Tuple<,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7) | parameter 4 -> return [property Item5] | true | +| System.Tuple<,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7) | parameter 5 -> return [property Item6] | true | +| System.Tuple<,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7) | parameter 6 -> return [property Item7] | true | +| System.Tuple<,,,,,,>.get_Item(int) | this parameter [property Item1] -> return | true | +| System.Tuple<,,,,,,>.get_Item(int) | this parameter [property Item2] -> return | true | +| System.Tuple<,,,,,,>.get_Item(int) | this parameter [property Item3] -> return | true | +| System.Tuple<,,,,,,>.get_Item(int) | this parameter [property Item4] -> return | true | +| System.Tuple<,,,,,,>.get_Item(int) | this parameter [property Item5] -> return | true | +| System.Tuple<,,,,,,>.get_Item(int) | this parameter [property Item6] -> return | true | +| System.Tuple<,,,,,,>.get_Item(int) | this parameter [property Item7] -> return | true | +| System.Tuple<,,,,,>.Tuple(T1, T2, T3, T4, T5, T6) | parameter 0 -> return [property Item1] | true | +| System.Tuple<,,,,,>.Tuple(T1, T2, T3, T4, T5, T6) | parameter 1 -> return [property Item2] | true | +| System.Tuple<,,,,,>.Tuple(T1, T2, T3, T4, T5, T6) | parameter 2 -> return [property Item3] | true | +| System.Tuple<,,,,,>.Tuple(T1, T2, T3, T4, T5, T6) | parameter 3 -> return [property Item4] | true | +| System.Tuple<,,,,,>.Tuple(T1, T2, T3, T4, T5, T6) | parameter 4 -> return [property Item5] | true | +| System.Tuple<,,,,,>.Tuple(T1, T2, T3, T4, T5, T6) | parameter 5 -> return [property Item6] | true | +| System.Tuple<,,,,,>.get_Item(int) | this parameter [property Item1] -> return | true | +| System.Tuple<,,,,,>.get_Item(int) | this parameter [property Item2] -> return | true | +| System.Tuple<,,,,,>.get_Item(int) | this parameter [property Item3] -> return | true | +| System.Tuple<,,,,,>.get_Item(int) | this parameter [property Item4] -> return | true | +| System.Tuple<,,,,,>.get_Item(int) | this parameter [property Item5] -> return | true | +| System.Tuple<,,,,,>.get_Item(int) | this parameter [property Item6] -> return | true | +| System.Tuple<,,,,>.Tuple(T1, T2, T3, T4, T5) | parameter 0 -> return [property Item1] | true | +| System.Tuple<,,,,>.Tuple(T1, T2, T3, T4, T5) | parameter 1 -> return [property Item2] | true | +| System.Tuple<,,,,>.Tuple(T1, T2, T3, T4, T5) | parameter 2 -> return [property Item3] | true | +| System.Tuple<,,,,>.Tuple(T1, T2, T3, T4, T5) | parameter 3 -> return [property Item4] | true | +| System.Tuple<,,,,>.Tuple(T1, T2, T3, T4, T5) | parameter 4 -> return [property Item5] | true | +| System.Tuple<,,,,>.get_Item(int) | this parameter [property Item1] -> return | true | +| System.Tuple<,,,,>.get_Item(int) | this parameter [property Item2] -> return | true | +| System.Tuple<,,,,>.get_Item(int) | this parameter [property Item3] -> return | true | +| System.Tuple<,,,,>.get_Item(int) | this parameter [property Item4] -> return | true | +| System.Tuple<,,,,>.get_Item(int) | this parameter [property Item5] -> return | true | +| System.Tuple<,,,>.Tuple(T1, T2, T3, T4) | parameter 0 -> return [property Item1] | true | +| System.Tuple<,,,>.Tuple(T1, T2, T3, T4) | parameter 1 -> return [property Item2] | true | +| System.Tuple<,,,>.Tuple(T1, T2, T3, T4) | parameter 2 -> return [property Item3] | true | +| System.Tuple<,,,>.Tuple(T1, T2, T3, T4) | parameter 3 -> return [property Item4] | true | +| System.Tuple<,,,>.get_Item(int) | this parameter [property Item1] -> return | true | +| System.Tuple<,,,>.get_Item(int) | this parameter [property Item2] -> return | true | +| System.Tuple<,,,>.get_Item(int) | this parameter [property Item3] -> return | true | +| System.Tuple<,,,>.get_Item(int) | this parameter [property Item4] -> return | true | +| System.Tuple<,,>.Tuple(T1, T2, T3) | parameter 0 -> return [property Item1] | true | +| System.Tuple<,,>.Tuple(T1, T2, T3) | parameter 1 -> return [property Item2] | true | +| System.Tuple<,,>.Tuple(T1, T2, T3) | parameter 2 -> return [property Item3] | true | +| System.Tuple<,,>.get_Item(int) | this parameter [property Item1] -> return | true | +| System.Tuple<,,>.get_Item(int) | this parameter [property Item2] -> return | true | +| System.Tuple<,,>.get_Item(int) | this parameter [property Item3] -> return | true | +| System.Tuple<,>.Tuple(T1, T2) | parameter 0 -> return [property Item1] | true | +| System.Tuple<,>.Tuple(T1, T2) | parameter 1 -> return [property Item2] | true | +| System.Tuple<,>.get_Item(int) | this parameter [property Item1] -> return | true | +| System.Tuple<,>.get_Item(int) | this parameter [property Item2] -> return | true | +| System.Tuple<>.Tuple(T1) | parameter 0 -> return [property Item1] | true | +| System.Tuple<>.get_Item(int) | this parameter [property Item1] -> return | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20, out T21) | parameter 0 [property Item1] -> parameter 1 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20, out T21) | parameter 0 [property Item2] -> parameter 2 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20, out T21) | parameter 0 [property Item3] -> parameter 3 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20, out T21) | parameter 0 [property Item4] -> parameter 4 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20, out T21) | parameter 0 [property Item5] -> parameter 5 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20, out T21) | parameter 0 [property Item6] -> parameter 6 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20, out T21) | parameter 0 [property Item7] -> parameter 7 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20) | parameter 0 [property Item1] -> parameter 1 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20) | parameter 0 [property Item2] -> parameter 2 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20) | parameter 0 [property Item3] -> parameter 3 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20) | parameter 0 [property Item4] -> parameter 4 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20) | parameter 0 [property Item5] -> parameter 5 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20) | parameter 0 [property Item6] -> parameter 6 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20) | parameter 0 [property Item7] -> parameter 7 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19) | parameter 0 [property Item1] -> parameter 1 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19) | parameter 0 [property Item2] -> parameter 2 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19) | parameter 0 [property Item3] -> parameter 3 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19) | parameter 0 [property Item4] -> parameter 4 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19) | parameter 0 [property Item5] -> parameter 5 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19) | parameter 0 [property Item6] -> parameter 6 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19) | parameter 0 [property Item7] -> parameter 7 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18) | parameter 0 [property Item1] -> parameter 1 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18) | parameter 0 [property Item2] -> parameter 2 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18) | parameter 0 [property Item3] -> parameter 3 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18) | parameter 0 [property Item4] -> parameter 4 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18) | parameter 0 [property Item5] -> parameter 5 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18) | parameter 0 [property Item6] -> parameter 6 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18) | parameter 0 [property Item7] -> parameter 7 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17) | parameter 0 [property Item1] -> parameter 1 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17) | parameter 0 [property Item2] -> parameter 2 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17) | parameter 0 [property Item3] -> parameter 3 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17) | parameter 0 [property Item4] -> parameter 4 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17) | parameter 0 [property Item5] -> parameter 5 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17) | parameter 0 [property Item6] -> parameter 6 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17) | parameter 0 [property Item7] -> parameter 7 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16) | parameter 0 [property Item1] -> parameter 1 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16) | parameter 0 [property Item2] -> parameter 2 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16) | parameter 0 [property Item3] -> parameter 3 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16) | parameter 0 [property Item4] -> parameter 4 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16) | parameter 0 [property Item5] -> parameter 5 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16) | parameter 0 [property Item6] -> parameter 6 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16) | parameter 0 [property Item7] -> parameter 7 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15) | parameter 0 [property Item1] -> parameter 1 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15) | parameter 0 [property Item2] -> parameter 2 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15) | parameter 0 [property Item3] -> parameter 3 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15) | parameter 0 [property Item4] -> parameter 4 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15) | parameter 0 [property Item5] -> parameter 5 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15) | parameter 0 [property Item6] -> parameter 6 | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15) | parameter 0 [property Item7] -> parameter 7 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14) | parameter 0 [property Item1] -> parameter 1 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14) | parameter 0 [property Item2] -> parameter 2 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14) | parameter 0 [property Item3] -> parameter 3 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14) | parameter 0 [property Item4] -> parameter 4 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14) | parameter 0 [property Item5] -> parameter 5 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14) | parameter 0 [property Item6] -> parameter 6 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14) | parameter 0 [property Item7] -> parameter 7 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13) | parameter 0 [property Item1] -> parameter 1 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13) | parameter 0 [property Item2] -> parameter 2 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13) | parameter 0 [property Item3] -> parameter 3 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13) | parameter 0 [property Item4] -> parameter 4 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13) | parameter 0 [property Item5] -> parameter 5 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13) | parameter 0 [property Item6] -> parameter 6 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13) | parameter 0 [property Item7] -> parameter 7 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12) | parameter 0 [property Item1] -> parameter 1 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12) | parameter 0 [property Item2] -> parameter 2 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12) | parameter 0 [property Item3] -> parameter 3 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12) | parameter 0 [property Item4] -> parameter 4 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12) | parameter 0 [property Item5] -> parameter 5 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12) | parameter 0 [property Item6] -> parameter 6 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12) | parameter 0 [property Item7] -> parameter 7 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11) | parameter 0 [property Item1] -> parameter 1 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11) | parameter 0 [property Item2] -> parameter 2 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11) | parameter 0 [property Item3] -> parameter 3 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11) | parameter 0 [property Item4] -> parameter 4 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11) | parameter 0 [property Item5] -> parameter 5 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11) | parameter 0 [property Item6] -> parameter 6 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11) | parameter 0 [property Item7] -> parameter 7 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10) | parameter 0 [property Item1] -> parameter 1 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10) | parameter 0 [property Item2] -> parameter 2 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10) | parameter 0 [property Item3] -> parameter 3 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10) | parameter 0 [property Item4] -> parameter 4 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10) | parameter 0 [property Item5] -> parameter 5 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10) | parameter 0 [property Item6] -> parameter 6 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10) | parameter 0 [property Item7] -> parameter 7 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9) | parameter 0 [property Item1] -> parameter 1 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9) | parameter 0 [property Item2] -> parameter 2 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9) | parameter 0 [property Item3] -> parameter 3 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9) | parameter 0 [property Item4] -> parameter 4 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9) | parameter 0 [property Item5] -> parameter 5 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9) | parameter 0 [property Item6] -> parameter 6 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9) | parameter 0 [property Item7] -> parameter 7 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8) | parameter 0 [property Item1] -> parameter 1 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8) | parameter 0 [property Item2] -> parameter 2 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8) | parameter 0 [property Item3] -> parameter 3 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8) | parameter 0 [property Item4] -> parameter 4 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8) | parameter 0 [property Item5] -> parameter 5 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8) | parameter 0 [property Item6] -> parameter 6 | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8) | parameter 0 [property Item7] -> parameter 7 | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6, out T7) | parameter 0 [property Item1] -> parameter 1 | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6, out T7) | parameter 0 [property Item2] -> parameter 2 | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6, out T7) | parameter 0 [property Item3] -> parameter 3 | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6, out T7) | parameter 0 [property Item4] -> parameter 4 | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6, out T7) | parameter 0 [property Item5] -> parameter 5 | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6, out T7) | parameter 0 [property Item6] -> parameter 6 | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6, out T7) | parameter 0 [property Item7] -> parameter 7 | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6) | parameter 0 [property Item1] -> parameter 1 | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6) | parameter 0 [property Item2] -> parameter 2 | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6) | parameter 0 [property Item3] -> parameter 3 | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6) | parameter 0 [property Item4] -> parameter 4 | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6) | parameter 0 [property Item5] -> parameter 5 | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6) | parameter 0 [property Item6] -> parameter 6 | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5) | parameter 0 [property Item1] -> parameter 1 | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5) | parameter 0 [property Item2] -> parameter 2 | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5) | parameter 0 [property Item3] -> parameter 3 | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5) | parameter 0 [property Item4] -> parameter 4 | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5) | parameter 0 [property Item5] -> parameter 5 | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4) | parameter 0 [property Item1] -> parameter 1 | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4) | parameter 0 [property Item2] -> parameter 2 | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4) | parameter 0 [property Item3] -> parameter 3 | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4) | parameter 0 [property Item4] -> parameter 4 | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3) | parameter 0 [property Item1] -> parameter 1 | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3) | parameter 0 [property Item2] -> parameter 2 | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3) | parameter 0 [property Item3] -> parameter 3 | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2) | parameter 0 [property Item1] -> parameter 1 | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2) | parameter 0 [property Item2] -> parameter 2 | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1) | parameter 0 [property Item1] -> parameter 1 | true | | System.Uri.ToString() | this parameter -> return | false | | System.Uri.Uri(string) | parameter 0 -> return | false | | System.Uri.Uri(string, UriKind) | parameter 0 -> return | false | @@ -2686,20 +2686,20 @@ | System.Uri.get_OriginalString() | this parameter -> return | false | | System.Uri.get_PathAndQuery() | this parameter -> return | false | | System.Uri.get_Query() | this parameter -> return | false | -| System.ValueTuple<,,,,,,,>.ValueTuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 0 -> return [Item1] | true | -| System.ValueTuple<,,,,,,,>.ValueTuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 1 -> return [Item2] | true | -| System.ValueTuple<,,,,,,,>.ValueTuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 2 -> return [Item3] | true | -| System.ValueTuple<,,,,,,,>.ValueTuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 3 -> return [Item4] | true | -| System.ValueTuple<,,,,,,,>.ValueTuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 4 -> return [Item5] | true | -| System.ValueTuple<,,,,,,,>.ValueTuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 5 -> return [Item6] | true | -| System.ValueTuple<,,,,,,,>.ValueTuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 6 -> return [Item7] | true | -| System.ValueTuple<,,,,,,,>.get_Item(int) | this parameter [Item1] -> return | true | -| System.ValueTuple<,,,,,,,>.get_Item(int) | this parameter [Item2] -> return | true | -| System.ValueTuple<,,,,,,,>.get_Item(int) | this parameter [Item3] -> return | true | -| System.ValueTuple<,,,,,,,>.get_Item(int) | this parameter [Item4] -> return | true | -| System.ValueTuple<,,,,,,,>.get_Item(int) | this parameter [Item5] -> return | true | -| System.ValueTuple<,,,,,,,>.get_Item(int) | this parameter [Item6] -> return | true | -| System.ValueTuple<,,,,,,,>.get_Item(int) | this parameter [Item7] -> return | true | +| System.ValueTuple<,,,,,,,>.ValueTuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 0 -> return [field Item1] | true | +| System.ValueTuple<,,,,,,,>.ValueTuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 1 -> return [field Item2] | true | +| System.ValueTuple<,,,,,,,>.ValueTuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 2 -> return [field Item3] | true | +| System.ValueTuple<,,,,,,,>.ValueTuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 3 -> return [field Item4] | true | +| System.ValueTuple<,,,,,,,>.ValueTuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 4 -> return [field Item5] | true | +| System.ValueTuple<,,,,,,,>.ValueTuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 5 -> return [field Item6] | true | +| System.ValueTuple<,,,,,,,>.ValueTuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 6 -> return [field Item7] | true | +| System.ValueTuple<,,,,,,,>.get_Item(int) | this parameter [field Item1] -> return | true | +| System.ValueTuple<,,,,,,,>.get_Item(int) | this parameter [field Item2] -> return | true | +| System.ValueTuple<,,,,,,,>.get_Item(int) | this parameter [field Item3] -> return | true | +| System.ValueTuple<,,,,,,,>.get_Item(int) | this parameter [field Item4] -> return | true | +| System.ValueTuple<,,,,,,,>.get_Item(int) | this parameter [field Item5] -> return | true | +| System.ValueTuple<,,,,,,,>.get_Item(int) | this parameter [field Item6] -> return | true | +| System.ValueTuple<,,,,,,,>.get_Item(int) | this parameter [field Item7] -> return | true | | System.Web.HttpCookie.get_Value() | this parameter -> return | false | | System.Web.HttpCookie.get_Values() | this parameter -> return | false | | System.Web.HttpServerUtility.UrlEncode(string) | parameter 0 -> return | false | diff --git a/csharp/ql/test/library-tests/dataflow/tuples/Tuples.expected b/csharp/ql/test/library-tests/dataflow/tuples/Tuples.expected index 339c859a6ce..ae634781cd7 100644 --- a/csharp/ql/test/library-tests/dataflow/tuples/Tuples.expected +++ b/csharp/ql/test/library-tests/dataflow/tuples/Tuples.expected @@ -1,148 +1,148 @@ edges -| Tuples.cs:7:17:7:56 | (..., ...) [Item1] : String | Tuples.cs:8:9:8:23 | (..., ...) [Item1] : String | -| Tuples.cs:7:17:7:56 | (..., ...) [Item1] : String | Tuples.cs:13:9:13:19 | (..., ...) [Item1] : String | -| Tuples.cs:7:17:7:56 | (..., ...) [Item1] : String | Tuples.cs:18:9:18:22 | (..., ...) [Item1] : String | -| Tuples.cs:7:17:7:56 | (..., ...) [Item1] : String | Tuples.cs:23:14:23:14 | access to local variable x [Item1] : String | -| Tuples.cs:7:17:7:56 | (..., ...) [Item1] : String | Tuples.cs:24:14:24:14 | access to local variable x [Item1] : String | -| Tuples.cs:7:17:7:56 | (..., ...) [Item2, Item2] : String | Tuples.cs:8:9:8:23 | (..., ...) [Item2, Item2] : String | -| Tuples.cs:7:17:7:56 | (..., ...) [Item2, Item2] : String | Tuples.cs:13:9:13:19 | (..., ...) [Item2, Item2] : String | -| Tuples.cs:7:17:7:56 | (..., ...) [Item2, Item2] : String | Tuples.cs:18:9:18:22 | (..., ...) [Item2, Item2] : String | -| Tuples.cs:7:17:7:56 | (..., ...) [Item2, Item2] : String | Tuples.cs:26:14:26:14 | access to local variable x [Item2, Item2] : String | -| Tuples.cs:7:21:7:34 | "taint source" : String | Tuples.cs:7:17:7:56 | (..., ...) [Item1] : String | -| Tuples.cs:7:37:7:55 | (..., ...) [Item2] : String | Tuples.cs:7:17:7:56 | (..., ...) [Item2, Item2] : String | -| Tuples.cs:7:41:7:54 | "taint source" : String | Tuples.cs:7:37:7:55 | (..., ...) [Item2] : String | -| Tuples.cs:8:9:8:23 | (..., ...) [Item1] : String | Tuples.cs:8:9:8:27 | SSA def(a) : String | -| Tuples.cs:8:9:8:23 | (..., ...) [Item2, Item2] : String | Tuples.cs:8:9:8:23 | (..., ...) [Item2] : String | -| Tuples.cs:8:9:8:23 | (..., ...) [Item2] : String | Tuples.cs:8:9:8:27 | SSA def(c) : String | +| Tuples.cs:7:17:7:56 | (..., ...) [field Item1] : String | Tuples.cs:8:9:8:23 | (..., ...) [field Item1] : String | +| Tuples.cs:7:17:7:56 | (..., ...) [field Item1] : String | Tuples.cs:13:9:13:19 | (..., ...) [field Item1] : String | +| Tuples.cs:7:17:7:56 | (..., ...) [field Item1] : String | Tuples.cs:18:9:18:22 | (..., ...) [field Item1] : String | +| Tuples.cs:7:17:7:56 | (..., ...) [field Item1] : String | Tuples.cs:23:14:23:14 | access to local variable x [field Item1] : String | +| Tuples.cs:7:17:7:56 | (..., ...) [field Item1] : String | Tuples.cs:24:14:24:14 | access to local variable x [field Item1] : String | +| Tuples.cs:7:17:7:56 | (..., ...) [field Item2, field Item2] : String | Tuples.cs:8:9:8:23 | (..., ...) [field Item2, field Item2] : String | +| Tuples.cs:7:17:7:56 | (..., ...) [field Item2, field Item2] : String | Tuples.cs:13:9:13:19 | (..., ...) [field Item2, field Item2] : String | +| Tuples.cs:7:17:7:56 | (..., ...) [field Item2, field Item2] : String | Tuples.cs:18:9:18:22 | (..., ...) [field Item2, field Item2] : String | +| Tuples.cs:7:17:7:56 | (..., ...) [field Item2, field Item2] : String | Tuples.cs:26:14:26:14 | access to local variable x [field Item2, field Item2] : String | +| Tuples.cs:7:21:7:34 | "taint source" : String | Tuples.cs:7:17:7:56 | (..., ...) [field Item1] : String | +| Tuples.cs:7:37:7:55 | (..., ...) [field Item2] : String | Tuples.cs:7:17:7:56 | (..., ...) [field Item2, field Item2] : String | +| Tuples.cs:7:41:7:54 | "taint source" : String | Tuples.cs:7:37:7:55 | (..., ...) [field Item2] : String | +| Tuples.cs:8:9:8:23 | (..., ...) [field Item1] : String | Tuples.cs:8:9:8:27 | SSA def(a) : String | +| Tuples.cs:8:9:8:23 | (..., ...) [field Item2, field Item2] : String | Tuples.cs:8:9:8:23 | (..., ...) [field Item2] : String | +| Tuples.cs:8:9:8:23 | (..., ...) [field Item2] : String | Tuples.cs:8:9:8:27 | SSA def(c) : String | | Tuples.cs:8:9:8:27 | SSA def(a) : String | Tuples.cs:9:14:9:14 | access to local variable a | | Tuples.cs:8:9:8:27 | SSA def(c) : String | Tuples.cs:11:14:11:14 | access to local variable c | -| Tuples.cs:13:9:13:19 | (..., ...) [Item1] : String | Tuples.cs:13:9:13:23 | SSA def(a) : String | -| Tuples.cs:13:9:13:19 | (..., ...) [Item2, Item2] : String | Tuples.cs:13:13:13:18 | (..., ...) [Item2] : String | +| Tuples.cs:13:9:13:19 | (..., ...) [field Item1] : String | Tuples.cs:13:9:13:23 | SSA def(a) : String | +| Tuples.cs:13:9:13:19 | (..., ...) [field Item2, field Item2] : String | Tuples.cs:13:13:13:18 | (..., ...) [field Item2] : String | | Tuples.cs:13:9:13:23 | SSA def(a) : String | Tuples.cs:14:14:14:14 | access to local variable a | | Tuples.cs:13:9:13:23 | SSA def(c) : String | Tuples.cs:16:14:16:14 | access to local variable c | -| Tuples.cs:13:13:13:18 | (..., ...) [Item2] : String | Tuples.cs:13:9:13:23 | SSA def(c) : String | -| Tuples.cs:18:9:18:22 | (..., ...) [Item1] : String | Tuples.cs:18:9:18:26 | SSA def(p) : String | -| Tuples.cs:18:9:18:22 | (..., ...) [Item2, Item2] : String | Tuples.cs:18:9:18:26 | SSA def(q) [Item2] : String | +| Tuples.cs:13:13:13:18 | (..., ...) [field Item2] : String | Tuples.cs:13:9:13:23 | SSA def(c) : String | +| Tuples.cs:18:9:18:22 | (..., ...) [field Item1] : String | Tuples.cs:18:9:18:26 | SSA def(p) : String | +| Tuples.cs:18:9:18:22 | (..., ...) [field Item2, field Item2] : String | Tuples.cs:18:9:18:26 | SSA def(q) [field Item2] : String | | Tuples.cs:18:9:18:26 | SSA def(p) : String | Tuples.cs:19:14:19:14 | access to local variable p | -| Tuples.cs:18:9:18:26 | SSA def(q) [Item2] : String | Tuples.cs:21:14:21:14 | access to local variable q [Item2] : String | -| Tuples.cs:21:14:21:14 | access to local variable q [Item2] : String | Tuples.cs:21:14:21:20 | access to field Item2 | -| Tuples.cs:23:14:23:14 | access to local variable x [Item1] : String | Tuples.cs:23:14:23:20 | access to field Item1 | -| Tuples.cs:24:14:24:14 | access to local variable x [Item1] : String | Tuples.cs:24:14:24:16 | access to field Item1 | -| Tuples.cs:26:14:26:14 | access to local variable x [Item2, Item2] : String | Tuples.cs:26:14:26:20 | access to field Item2 [Item2] : String | -| Tuples.cs:26:14:26:20 | access to field Item2 [Item2] : String | Tuples.cs:26:14:26:26 | access to field Item2 | -| Tuples.cs:31:17:31:72 | (..., ...) [Item1] : String | Tuples.cs:32:14:32:14 | access to local variable x [Item1] : String | -| Tuples.cs:31:17:31:72 | (..., ...) [Item10] : String | Tuples.cs:34:14:34:14 | access to local variable x [Item10] : String | -| Tuples.cs:31:18:31:31 | "taint source" : String | Tuples.cs:31:17:31:72 | (..., ...) [Item1] : String | -| Tuples.cs:31:58:31:71 | "taint source" : String | Tuples.cs:31:17:31:72 | (..., ...) [Item10] : String | -| Tuples.cs:32:14:32:14 | access to local variable x [Item1] : String | Tuples.cs:32:14:32:20 | access to field Item1 | -| Tuples.cs:34:14:34:14 | access to local variable x [Item10] : String | Tuples.cs:34:14:34:21 | access to field Item10 | -| Tuples.cs:39:17:39:68 | (...) ... [Item1] : String | Tuples.cs:40:14:40:14 | access to local variable x [Item1] : String | -| Tuples.cs:39:47:39:68 | (..., ...) [Item1] : String | Tuples.cs:39:17:39:68 | (...) ... [Item1] : String | -| Tuples.cs:39:48:39:61 | "taint source" : String | Tuples.cs:39:47:39:68 | (..., ...) [Item1] : String | -| Tuples.cs:40:14:40:14 | access to local variable x [Item1] : String | Tuples.cs:40:14:40:20 | access to field Item1 | -| Tuples.cs:50:17:50:56 | (..., ...) [Item1] : String | Tuples.cs:53:18:53:57 | SSA def(t) [Item1] : String | -| Tuples.cs:50:17:50:56 | (..., ...) [Item1] : String | Tuples.cs:58:18:58:35 | (..., ...) [Item1] : String | -| Tuples.cs:50:17:50:56 | (..., ...) [Item1] : String | Tuples.cs:77:18:77:35 | (..., ...) [Item1] : String | -| Tuples.cs:50:17:50:56 | (..., ...) [Item2, Item2] : String | Tuples.cs:53:18:53:57 | SSA def(t) [Item2, Item2] : String | -| Tuples.cs:50:17:50:56 | (..., ...) [Item2, Item2] : String | Tuples.cs:58:18:58:35 | (..., ...) [Item2, Item2] : String | -| Tuples.cs:50:17:50:56 | (..., ...) [Item2, Item2] : String | Tuples.cs:77:18:77:35 | (..., ...) [Item2, Item2] : String | -| Tuples.cs:50:18:50:31 | "taint source" : String | Tuples.cs:50:17:50:56 | (..., ...) [Item1] : String | -| Tuples.cs:50:34:50:52 | (..., ...) [Item2] : String | Tuples.cs:50:17:50:56 | (..., ...) [Item2, Item2] : String | -| Tuples.cs:50:38:50:51 | "taint source" : String | Tuples.cs:50:34:50:52 | (..., ...) [Item2] : String | -| Tuples.cs:53:18:53:57 | SSA def(t) [Item1] : String | Tuples.cs:54:22:54:22 | access to local variable t [Item1] : String | -| Tuples.cs:53:18:53:57 | SSA def(t) [Item2, Item2] : String | Tuples.cs:55:22:55:22 | access to local variable t [Item2, Item2] : String | -| Tuples.cs:54:22:54:22 | access to local variable t [Item1] : String | Tuples.cs:54:22:54:28 | access to field Item1 | -| Tuples.cs:55:22:55:22 | access to local variable t [Item2, Item2] : String | Tuples.cs:55:22:55:28 | access to field Item2 [Item2] : String | -| Tuples.cs:55:22:55:28 | access to field Item2 [Item2] : String | Tuples.cs:55:22:55:34 | access to field Item2 | -| Tuples.cs:58:18:58:35 | (..., ...) [Item1] : String | Tuples.cs:58:23:58:23 | SSA def(a) : String | -| Tuples.cs:58:18:58:35 | (..., ...) [Item2, Item2] : String | Tuples.cs:58:18:58:35 | (..., ...) [Item2] : String | -| Tuples.cs:58:18:58:35 | (..., ...) [Item2] : String | Tuples.cs:58:30:58:30 | SSA def(c) : String | +| Tuples.cs:18:9:18:26 | SSA def(q) [field Item2] : String | Tuples.cs:21:14:21:14 | access to local variable q [field Item2] : String | +| Tuples.cs:21:14:21:14 | access to local variable q [field Item2] : String | Tuples.cs:21:14:21:20 | access to field Item2 | +| Tuples.cs:23:14:23:14 | access to local variable x [field Item1] : String | Tuples.cs:23:14:23:20 | access to field Item1 | +| Tuples.cs:24:14:24:14 | access to local variable x [field Item1] : String | Tuples.cs:24:14:24:16 | access to field Item1 | +| Tuples.cs:26:14:26:14 | access to local variable x [field Item2, field Item2] : String | Tuples.cs:26:14:26:20 | access to field Item2 [field Item2] : String | +| Tuples.cs:26:14:26:20 | access to field Item2 [field Item2] : String | Tuples.cs:26:14:26:26 | access to field Item2 | +| Tuples.cs:31:17:31:72 | (..., ...) [field Item1] : String | Tuples.cs:32:14:32:14 | access to local variable x [field Item1] : String | +| Tuples.cs:31:17:31:72 | (..., ...) [field Item10] : String | Tuples.cs:34:14:34:14 | access to local variable x [field Item10] : String | +| Tuples.cs:31:18:31:31 | "taint source" : String | Tuples.cs:31:17:31:72 | (..., ...) [field Item1] : String | +| Tuples.cs:31:58:31:71 | "taint source" : String | Tuples.cs:31:17:31:72 | (..., ...) [field Item10] : String | +| Tuples.cs:32:14:32:14 | access to local variable x [field Item1] : String | Tuples.cs:32:14:32:20 | access to field Item1 | +| Tuples.cs:34:14:34:14 | access to local variable x [field Item10] : String | Tuples.cs:34:14:34:21 | access to field Item10 | +| Tuples.cs:39:17:39:68 | (...) ... [field Item1] : String | Tuples.cs:40:14:40:14 | access to local variable x [field Item1] : String | +| Tuples.cs:39:47:39:68 | (..., ...) [field Item1] : String | Tuples.cs:39:17:39:68 | (...) ... [field Item1] : String | +| Tuples.cs:39:48:39:61 | "taint source" : String | Tuples.cs:39:47:39:68 | (..., ...) [field Item1] : String | +| Tuples.cs:40:14:40:14 | access to local variable x [field Item1] : String | Tuples.cs:40:14:40:20 | access to field Item1 | +| Tuples.cs:50:17:50:56 | (..., ...) [field Item1] : String | Tuples.cs:53:18:53:57 | SSA def(t) [field Item1] : String | +| Tuples.cs:50:17:50:56 | (..., ...) [field Item1] : String | Tuples.cs:58:18:58:35 | (..., ...) [field Item1] : String | +| Tuples.cs:50:17:50:56 | (..., ...) [field Item1] : String | Tuples.cs:77:18:77:35 | (..., ...) [field Item1] : String | +| Tuples.cs:50:17:50:56 | (..., ...) [field Item2, field Item2] : String | Tuples.cs:53:18:53:57 | SSA def(t) [field Item2, field Item2] : String | +| Tuples.cs:50:17:50:56 | (..., ...) [field Item2, field Item2] : String | Tuples.cs:58:18:58:35 | (..., ...) [field Item2, field Item2] : String | +| Tuples.cs:50:17:50:56 | (..., ...) [field Item2, field Item2] : String | Tuples.cs:77:18:77:35 | (..., ...) [field Item2, field Item2] : String | +| Tuples.cs:50:18:50:31 | "taint source" : String | Tuples.cs:50:17:50:56 | (..., ...) [field Item1] : String | +| Tuples.cs:50:34:50:52 | (..., ...) [field Item2] : String | Tuples.cs:50:17:50:56 | (..., ...) [field Item2, field Item2] : String | +| Tuples.cs:50:38:50:51 | "taint source" : String | Tuples.cs:50:34:50:52 | (..., ...) [field Item2] : String | +| Tuples.cs:53:18:53:57 | SSA def(t) [field Item1] : String | Tuples.cs:54:22:54:22 | access to local variable t [field Item1] : String | +| Tuples.cs:53:18:53:57 | SSA def(t) [field Item2, field Item2] : String | Tuples.cs:55:22:55:22 | access to local variable t [field Item2, field Item2] : String | +| Tuples.cs:54:22:54:22 | access to local variable t [field Item1] : String | Tuples.cs:54:22:54:28 | access to field Item1 | +| Tuples.cs:55:22:55:22 | access to local variable t [field Item2, field Item2] : String | Tuples.cs:55:22:55:28 | access to field Item2 [field Item2] : String | +| Tuples.cs:55:22:55:28 | access to field Item2 [field Item2] : String | Tuples.cs:55:22:55:34 | access to field Item2 | +| Tuples.cs:58:18:58:35 | (..., ...) [field Item1] : String | Tuples.cs:58:23:58:23 | SSA def(a) : String | +| Tuples.cs:58:18:58:35 | (..., ...) [field Item2, field Item2] : String | Tuples.cs:58:18:58:35 | (..., ...) [field Item2] : String | +| Tuples.cs:58:18:58:35 | (..., ...) [field Item2] : String | Tuples.cs:58:30:58:30 | SSA def(c) : String | | Tuples.cs:58:23:58:23 | SSA def(a) : String | Tuples.cs:59:22:59:22 | access to local variable a | | Tuples.cs:58:30:58:30 | SSA def(c) : String | Tuples.cs:60:22:60:22 | access to local variable c | -| Tuples.cs:77:18:77:35 | (..., ...) [Item1] : String | Tuples.cs:77:23:77:23 | SSA def(p) : String | -| Tuples.cs:77:18:77:35 | (..., ...) [Item2, Item2] : String | Tuples.cs:77:18:77:35 | (..., ...) [Item2] : String | -| Tuples.cs:77:18:77:35 | (..., ...) [Item2] : String | Tuples.cs:77:30:77:30 | SSA def(r) : String | +| Tuples.cs:77:18:77:35 | (..., ...) [field Item1] : String | Tuples.cs:77:23:77:23 | SSA def(p) : String | +| Tuples.cs:77:18:77:35 | (..., ...) [field Item2, field Item2] : String | Tuples.cs:77:18:77:35 | (..., ...) [field Item2] : String | +| Tuples.cs:77:18:77:35 | (..., ...) [field Item2] : String | Tuples.cs:77:30:77:30 | SSA def(r) : String | | Tuples.cs:77:23:77:23 | SSA def(p) : String | Tuples.cs:79:18:79:18 | access to local variable p | | Tuples.cs:77:30:77:30 | SSA def(r) : String | Tuples.cs:80:18:80:18 | access to local variable r | -| Tuples.cs:89:17:89:41 | object creation of type R1 [i] : String | Tuples.cs:90:14:90:14 | access to local variable r [i] : String | -| Tuples.cs:89:24:89:37 | "taint source" : String | Tuples.cs:89:17:89:41 | object creation of type R1 [i] : String | -| Tuples.cs:90:14:90:14 | access to local variable r [i] : String | Tuples.cs:90:14:90:16 | access to property i | +| Tuples.cs:89:17:89:41 | object creation of type R1 [property i] : String | Tuples.cs:90:14:90:14 | access to local variable r [property i] : String | +| Tuples.cs:89:24:89:37 | "taint source" : String | Tuples.cs:89:17:89:41 | object creation of type R1 [property i] : String | +| Tuples.cs:90:14:90:14 | access to local variable r [property i] : String | Tuples.cs:90:14:90:16 | access to property i | nodes -| Tuples.cs:7:17:7:56 | (..., ...) [Item1] : String | semmle.label | (..., ...) [Item1] : String | -| Tuples.cs:7:17:7:56 | (..., ...) [Item2, Item2] : String | semmle.label | (..., ...) [Item2, Item2] : String | +| Tuples.cs:7:17:7:56 | (..., ...) [field Item1] : String | semmle.label | (..., ...) [field Item1] : String | +| Tuples.cs:7:17:7:56 | (..., ...) [field Item2, field Item2] : String | semmle.label | (..., ...) [field Item2, field Item2] : String | | Tuples.cs:7:21:7:34 | "taint source" : String | semmle.label | "taint source" : String | -| Tuples.cs:7:37:7:55 | (..., ...) [Item2] : String | semmle.label | (..., ...) [Item2] : String | +| Tuples.cs:7:37:7:55 | (..., ...) [field Item2] : String | semmle.label | (..., ...) [field Item2] : String | | Tuples.cs:7:41:7:54 | "taint source" : String | semmle.label | "taint source" : String | -| Tuples.cs:8:9:8:23 | (..., ...) [Item1] : String | semmle.label | (..., ...) [Item1] : String | -| Tuples.cs:8:9:8:23 | (..., ...) [Item2, Item2] : String | semmle.label | (..., ...) [Item2, Item2] : String | -| Tuples.cs:8:9:8:23 | (..., ...) [Item2] : String | semmle.label | (..., ...) [Item2] : String | +| Tuples.cs:8:9:8:23 | (..., ...) [field Item1] : String | semmle.label | (..., ...) [field Item1] : String | +| Tuples.cs:8:9:8:23 | (..., ...) [field Item2, field Item2] : String | semmle.label | (..., ...) [field Item2, field Item2] : String | +| Tuples.cs:8:9:8:23 | (..., ...) [field Item2] : String | semmle.label | (..., ...) [field Item2] : String | | Tuples.cs:8:9:8:27 | SSA def(a) : String | semmle.label | SSA def(a) : String | | Tuples.cs:8:9:8:27 | SSA def(c) : String | semmle.label | SSA def(c) : String | | Tuples.cs:9:14:9:14 | access to local variable a | semmle.label | access to local variable a | | Tuples.cs:11:14:11:14 | access to local variable c | semmle.label | access to local variable c | -| Tuples.cs:13:9:13:19 | (..., ...) [Item1] : String | semmle.label | (..., ...) [Item1] : String | -| Tuples.cs:13:9:13:19 | (..., ...) [Item2, Item2] : String | semmle.label | (..., ...) [Item2, Item2] : String | +| Tuples.cs:13:9:13:19 | (..., ...) [field Item1] : String | semmle.label | (..., ...) [field Item1] : String | +| Tuples.cs:13:9:13:19 | (..., ...) [field Item2, field Item2] : String | semmle.label | (..., ...) [field Item2, field Item2] : String | | Tuples.cs:13:9:13:23 | SSA def(a) : String | semmle.label | SSA def(a) : String | | Tuples.cs:13:9:13:23 | SSA def(c) : String | semmle.label | SSA def(c) : String | -| Tuples.cs:13:13:13:18 | (..., ...) [Item2] : String | semmle.label | (..., ...) [Item2] : String | +| Tuples.cs:13:13:13:18 | (..., ...) [field Item2] : String | semmle.label | (..., ...) [field Item2] : String | | Tuples.cs:14:14:14:14 | access to local variable a | semmle.label | access to local variable a | | Tuples.cs:16:14:16:14 | access to local variable c | semmle.label | access to local variable c | -| Tuples.cs:18:9:18:22 | (..., ...) [Item1] : String | semmle.label | (..., ...) [Item1] : String | -| Tuples.cs:18:9:18:22 | (..., ...) [Item2, Item2] : String | semmle.label | (..., ...) [Item2, Item2] : String | +| Tuples.cs:18:9:18:22 | (..., ...) [field Item1] : String | semmle.label | (..., ...) [field Item1] : String | +| Tuples.cs:18:9:18:22 | (..., ...) [field Item2, field Item2] : String | semmle.label | (..., ...) [field Item2, field Item2] : String | | Tuples.cs:18:9:18:26 | SSA def(p) : String | semmle.label | SSA def(p) : String | -| Tuples.cs:18:9:18:26 | SSA def(q) [Item2] : String | semmle.label | SSA def(q) [Item2] : String | +| Tuples.cs:18:9:18:26 | SSA def(q) [field Item2] : String | semmle.label | SSA def(q) [field Item2] : String | | Tuples.cs:19:14:19:14 | access to local variable p | semmle.label | access to local variable p | -| Tuples.cs:21:14:21:14 | access to local variable q [Item2] : String | semmle.label | access to local variable q [Item2] : String | +| Tuples.cs:21:14:21:14 | access to local variable q [field Item2] : String | semmle.label | access to local variable q [field Item2] : String | | Tuples.cs:21:14:21:20 | access to field Item2 | semmle.label | access to field Item2 | -| Tuples.cs:23:14:23:14 | access to local variable x [Item1] : String | semmle.label | access to local variable x [Item1] : String | +| Tuples.cs:23:14:23:14 | access to local variable x [field Item1] : String | semmle.label | access to local variable x [field Item1] : String | | Tuples.cs:23:14:23:20 | access to field Item1 | semmle.label | access to field Item1 | -| Tuples.cs:24:14:24:14 | access to local variable x [Item1] : String | semmle.label | access to local variable x [Item1] : String | +| Tuples.cs:24:14:24:14 | access to local variable x [field Item1] : String | semmle.label | access to local variable x [field Item1] : String | | Tuples.cs:24:14:24:16 | access to field Item1 | semmle.label | access to field Item1 | -| Tuples.cs:26:14:26:14 | access to local variable x [Item2, Item2] : String | semmle.label | access to local variable x [Item2, Item2] : String | -| Tuples.cs:26:14:26:20 | access to field Item2 [Item2] : String | semmle.label | access to field Item2 [Item2] : String | +| Tuples.cs:26:14:26:14 | access to local variable x [field Item2, field Item2] : String | semmle.label | access to local variable x [field Item2, field Item2] : String | +| Tuples.cs:26:14:26:20 | access to field Item2 [field Item2] : String | semmle.label | access to field Item2 [field Item2] : String | | Tuples.cs:26:14:26:26 | access to field Item2 | semmle.label | access to field Item2 | -| Tuples.cs:31:17:31:72 | (..., ...) [Item1] : String | semmle.label | (..., ...) [Item1] : String | -| Tuples.cs:31:17:31:72 | (..., ...) [Item10] : String | semmle.label | (..., ...) [Item10] : String | +| Tuples.cs:31:17:31:72 | (..., ...) [field Item1] : String | semmle.label | (..., ...) [field Item1] : String | +| Tuples.cs:31:17:31:72 | (..., ...) [field Item10] : String | semmle.label | (..., ...) [field Item10] : String | | Tuples.cs:31:18:31:31 | "taint source" : String | semmle.label | "taint source" : String | | Tuples.cs:31:58:31:71 | "taint source" : String | semmle.label | "taint source" : String | -| Tuples.cs:32:14:32:14 | access to local variable x [Item1] : String | semmle.label | access to local variable x [Item1] : String | +| Tuples.cs:32:14:32:14 | access to local variable x [field Item1] : String | semmle.label | access to local variable x [field Item1] : String | | Tuples.cs:32:14:32:20 | access to field Item1 | semmle.label | access to field Item1 | -| Tuples.cs:34:14:34:14 | access to local variable x [Item10] : String | semmle.label | access to local variable x [Item10] : String | +| Tuples.cs:34:14:34:14 | access to local variable x [field Item10] : String | semmle.label | access to local variable x [field Item10] : String | | Tuples.cs:34:14:34:21 | access to field Item10 | semmle.label | access to field Item10 | -| Tuples.cs:39:17:39:68 | (...) ... [Item1] : String | semmle.label | (...) ... [Item1] : String | -| Tuples.cs:39:47:39:68 | (..., ...) [Item1] : String | semmle.label | (..., ...) [Item1] : String | +| Tuples.cs:39:17:39:68 | (...) ... [field Item1] : String | semmle.label | (...) ... [field Item1] : String | +| Tuples.cs:39:47:39:68 | (..., ...) [field Item1] : String | semmle.label | (..., ...) [field Item1] : String | | Tuples.cs:39:48:39:61 | "taint source" : String | semmle.label | "taint source" : String | -| Tuples.cs:40:14:40:14 | access to local variable x [Item1] : String | semmle.label | access to local variable x [Item1] : String | +| Tuples.cs:40:14:40:14 | access to local variable x [field Item1] : String | semmle.label | access to local variable x [field Item1] : String | | Tuples.cs:40:14:40:20 | access to field Item1 | semmle.label | access to field Item1 | -| Tuples.cs:50:17:50:56 | (..., ...) [Item1] : String | semmle.label | (..., ...) [Item1] : String | -| Tuples.cs:50:17:50:56 | (..., ...) [Item2, Item2] : String | semmle.label | (..., ...) [Item2, Item2] : String | +| Tuples.cs:50:17:50:56 | (..., ...) [field Item1] : String | semmle.label | (..., ...) [field Item1] : String | +| Tuples.cs:50:17:50:56 | (..., ...) [field Item2, field Item2] : String | semmle.label | (..., ...) [field Item2, field Item2] : String | | Tuples.cs:50:18:50:31 | "taint source" : String | semmle.label | "taint source" : String | -| Tuples.cs:50:34:50:52 | (..., ...) [Item2] : String | semmle.label | (..., ...) [Item2] : String | +| Tuples.cs:50:34:50:52 | (..., ...) [field Item2] : String | semmle.label | (..., ...) [field Item2] : String | | Tuples.cs:50:38:50:51 | "taint source" : String | semmle.label | "taint source" : String | -| Tuples.cs:53:18:53:57 | SSA def(t) [Item1] : String | semmle.label | SSA def(t) [Item1] : String | -| Tuples.cs:53:18:53:57 | SSA def(t) [Item2, Item2] : String | semmle.label | SSA def(t) [Item2, Item2] : String | -| Tuples.cs:54:22:54:22 | access to local variable t [Item1] : String | semmle.label | access to local variable t [Item1] : String | +| Tuples.cs:53:18:53:57 | SSA def(t) [field Item1] : String | semmle.label | SSA def(t) [field Item1] : String | +| Tuples.cs:53:18:53:57 | SSA def(t) [field Item2, field Item2] : String | semmle.label | SSA def(t) [field Item2, field Item2] : String | +| Tuples.cs:54:22:54:22 | access to local variable t [field Item1] : String | semmle.label | access to local variable t [field Item1] : String | | Tuples.cs:54:22:54:28 | access to field Item1 | semmle.label | access to field Item1 | -| Tuples.cs:55:22:55:22 | access to local variable t [Item2, Item2] : String | semmle.label | access to local variable t [Item2, Item2] : String | -| Tuples.cs:55:22:55:28 | access to field Item2 [Item2] : String | semmle.label | access to field Item2 [Item2] : String | +| Tuples.cs:55:22:55:22 | access to local variable t [field Item2, field Item2] : String | semmle.label | access to local variable t [field Item2, field Item2] : String | +| Tuples.cs:55:22:55:28 | access to field Item2 [field Item2] : String | semmle.label | access to field Item2 [field Item2] : String | | Tuples.cs:55:22:55:34 | access to field Item2 | semmle.label | access to field Item2 | -| Tuples.cs:58:18:58:35 | (..., ...) [Item1] : String | semmle.label | (..., ...) [Item1] : String | -| Tuples.cs:58:18:58:35 | (..., ...) [Item2, Item2] : String | semmle.label | (..., ...) [Item2, Item2] : String | -| Tuples.cs:58:18:58:35 | (..., ...) [Item2] : String | semmle.label | (..., ...) [Item2] : String | +| Tuples.cs:58:18:58:35 | (..., ...) [field Item1] : String | semmle.label | (..., ...) [field Item1] : String | +| Tuples.cs:58:18:58:35 | (..., ...) [field Item2, field Item2] : String | semmle.label | (..., ...) [field Item2, field Item2] : String | +| Tuples.cs:58:18:58:35 | (..., ...) [field Item2] : String | semmle.label | (..., ...) [field Item2] : String | | Tuples.cs:58:23:58:23 | SSA def(a) : String | semmle.label | SSA def(a) : String | | Tuples.cs:58:30:58:30 | SSA def(c) : String | semmle.label | SSA def(c) : String | | Tuples.cs:59:22:59:22 | access to local variable a | semmle.label | access to local variable a | | Tuples.cs:60:22:60:22 | access to local variable c | semmle.label | access to local variable c | -| Tuples.cs:77:18:77:35 | (..., ...) [Item1] : String | semmle.label | (..., ...) [Item1] : String | -| Tuples.cs:77:18:77:35 | (..., ...) [Item2, Item2] : String | semmle.label | (..., ...) [Item2, Item2] : String | -| Tuples.cs:77:18:77:35 | (..., ...) [Item2] : String | semmle.label | (..., ...) [Item2] : String | +| Tuples.cs:77:18:77:35 | (..., ...) [field Item1] : String | semmle.label | (..., ...) [field Item1] : String | +| Tuples.cs:77:18:77:35 | (..., ...) [field Item2, field Item2] : String | semmle.label | (..., ...) [field Item2, field Item2] : String | +| Tuples.cs:77:18:77:35 | (..., ...) [field Item2] : String | semmle.label | (..., ...) [field Item2] : String | | Tuples.cs:77:23:77:23 | SSA def(p) : String | semmle.label | SSA def(p) : String | | Tuples.cs:77:30:77:30 | SSA def(r) : String | semmle.label | SSA def(r) : String | | Tuples.cs:79:18:79:18 | access to local variable p | semmle.label | access to local variable p | | Tuples.cs:80:18:80:18 | access to local variable r | semmle.label | access to local variable r | -| Tuples.cs:89:17:89:41 | object creation of type R1 [i] : String | semmle.label | object creation of type R1 [i] : String | +| Tuples.cs:89:17:89:41 | object creation of type R1 [property i] : String | semmle.label | object creation of type R1 [property i] : String | | Tuples.cs:89:24:89:37 | "taint source" : String | semmle.label | "taint source" : String | -| Tuples.cs:90:14:90:14 | access to local variable r [i] : String | semmle.label | access to local variable r [i] : String | +| Tuples.cs:90:14:90:14 | access to local variable r [property i] : String | semmle.label | access to local variable r [property i] : String | | Tuples.cs:90:14:90:16 | access to property i | semmle.label | access to property i | #select | Tuples.cs:7:21:7:34 | "taint source" : String | Tuples.cs:7:21:7:34 | "taint source" : String | Tuples.cs:9:14:9:14 | access to local variable a | $@ | Tuples.cs:9:14:9:14 | access to local variable a | access to local variable a | diff --git a/csharp/ql/test/library-tests/dataflow/types/Types.expected b/csharp/ql/test/library-tests/dataflow/types/Types.expected index 43b06fb7cba..93be8ab587a 100644 --- a/csharp/ql/test/library-tests/dataflow/types/Types.expected +++ b/csharp/ql/test/library-tests/dataflow/types/Types.expected @@ -33,23 +33,23 @@ edges | Types.cs:77:22:77:22 | a : C | Types.cs:79:18:79:25 | SSA def(b) : C | | Types.cs:79:18:79:25 | SSA def(b) : C | Types.cs:80:18:80:18 | access to local variable b | | Types.cs:90:22:90:22 | e : Types.E.E2 | Types.cs:92:26:92:26 | access to parameter e : Types.E.E2 | -| Types.cs:92:13:92:16 | [post] this access [Field] : Types.E.E2 | Types.cs:93:13:93:16 | this access [Field] : Types.E.E2 | -| Types.cs:92:26:92:26 | access to parameter e : Types.E.E2 | Types.cs:92:13:92:16 | [post] this access [Field] : Types.E.E2 | -| Types.cs:93:13:93:16 | this access [Field] : Types.E.E2 | Types.cs:113:34:113:34 | this [Field] : Types.E.E2 | +| Types.cs:92:13:92:16 | [post] this access [field Field] : Types.E.E2 | Types.cs:93:13:93:16 | this access [field Field] : Types.E.E2 | +| Types.cs:92:26:92:26 | access to parameter e : Types.E.E2 | Types.cs:92:13:92:16 | [post] this access [field Field] : Types.E.E2 | +| Types.cs:93:13:93:16 | this access [field Field] : Types.E.E2 | Types.cs:113:34:113:34 | this [field Field] : Types.E.E2 | | Types.cs:110:25:110:32 | object creation of type E2 : Types.E.E2 | Types.cs:90:22:90:22 | e : Types.E.E2 | -| Types.cs:113:34:113:34 | this [Field] : Types.E.E2 | Types.cs:115:22:115:25 | this access [Field] : Types.E.E2 | -| Types.cs:115:22:115:25 | this access [Field] : Types.E.E2 | Types.cs:115:22:115:31 | access to field Field | +| Types.cs:113:34:113:34 | this [field Field] : Types.E.E2 | Types.cs:115:22:115:25 | this access [field Field] : Types.E.E2 | +| Types.cs:115:22:115:25 | this access [field Field] : Types.E.E2 | Types.cs:115:22:115:31 | access to field Field | | Types.cs:120:25:120:31 | object creation of type A : A | Types.cs:122:30:122:30 | access to local variable a : A | | Types.cs:121:26:121:33 | object creation of type E2 : Types.E.E2 | Types.cs:123:30:123:31 | access to local variable e2 : Types.E.E2 | | Types.cs:122:30:122:30 | access to local variable a : A | Types.cs:122:22:122:31 | call to method Through | | Types.cs:123:30:123:31 | access to local variable e2 : Types.E.E2 | Types.cs:123:22:123:32 | call to method Through | -| Types.cs:138:21:138:25 | this [Field] : Object | Types.cs:138:32:138:35 | this access [Field] : Object | -| Types.cs:138:32:138:35 | this access [Field] : Object | Types.cs:153:30:153:30 | this [Field] : Object | -| Types.cs:144:13:144:13 | [post] access to parameter c [Field] : Object | Types.cs:145:13:145:13 | access to parameter c [Field] : Object | -| Types.cs:144:23:144:34 | object creation of type Object : Object | Types.cs:144:13:144:13 | [post] access to parameter c [Field] : Object | -| Types.cs:145:13:145:13 | access to parameter c [Field] : Object | Types.cs:138:21:138:25 | this [Field] : Object | -| Types.cs:153:30:153:30 | this [Field] : Object | Types.cs:153:42:153:45 | this access [Field] : Object | -| Types.cs:153:42:153:45 | this access [Field] : Object | Types.cs:153:42:153:51 | access to field Field | +| Types.cs:138:21:138:25 | this [field Field] : Object | Types.cs:138:32:138:35 | this access [field Field] : Object | +| Types.cs:138:32:138:35 | this access [field Field] : Object | Types.cs:153:30:153:30 | this [field Field] : Object | +| Types.cs:144:13:144:13 | [post] access to parameter c [field Field] : Object | Types.cs:145:13:145:13 | access to parameter c [field Field] : Object | +| Types.cs:144:23:144:34 | object creation of type Object : Object | Types.cs:144:13:144:13 | [post] access to parameter c [field Field] : Object | +| Types.cs:145:13:145:13 | access to parameter c [field Field] : Object | Types.cs:138:21:138:25 | this [field Field] : Object | +| Types.cs:153:30:153:30 | this [field Field] : Object | Types.cs:153:42:153:45 | this access [field Field] : Object | +| Types.cs:153:42:153:45 | this access [field Field] : Object | Types.cs:153:42:153:51 | access to field Field | nodes | Types.cs:7:21:7:25 | this : D | semmle.label | this : D | | Types.cs:7:32:7:35 | this access : D | semmle.label | this access : D | @@ -94,12 +94,12 @@ nodes | Types.cs:79:18:79:25 | SSA def(b) : C | semmle.label | SSA def(b) : C | | Types.cs:80:18:80:18 | access to local variable b | semmle.label | access to local variable b | | Types.cs:90:22:90:22 | e : Types.E.E2 | semmle.label | e : Types.E.E2 | -| Types.cs:92:13:92:16 | [post] this access [Field] : Types.E.E2 | semmle.label | [post] this access [Field] : Types.E.E2 | +| Types.cs:92:13:92:16 | [post] this access [field Field] : Types.E.E2 | semmle.label | [post] this access [field Field] : Types.E.E2 | | Types.cs:92:26:92:26 | access to parameter e : Types.E.E2 | semmle.label | access to parameter e : Types.E.E2 | -| Types.cs:93:13:93:16 | this access [Field] : Types.E.E2 | semmle.label | this access [Field] : Types.E.E2 | +| Types.cs:93:13:93:16 | this access [field Field] : Types.E.E2 | semmle.label | this access [field Field] : Types.E.E2 | | Types.cs:110:25:110:32 | object creation of type E2 : Types.E.E2 | semmle.label | object creation of type E2 : Types.E.E2 | -| Types.cs:113:34:113:34 | this [Field] : Types.E.E2 | semmle.label | this [Field] : Types.E.E2 | -| Types.cs:115:22:115:25 | this access [Field] : Types.E.E2 | semmle.label | this access [Field] : Types.E.E2 | +| Types.cs:113:34:113:34 | this [field Field] : Types.E.E2 | semmle.label | this [field Field] : Types.E.E2 | +| Types.cs:115:22:115:25 | this access [field Field] : Types.E.E2 | semmle.label | this access [field Field] : Types.E.E2 | | Types.cs:115:22:115:31 | access to field Field | semmle.label | access to field Field | | Types.cs:120:25:120:31 | object creation of type A : A | semmle.label | object creation of type A : A | | Types.cs:121:26:121:33 | object creation of type E2 : Types.E.E2 | semmle.label | object creation of type E2 : Types.E.E2 | @@ -107,13 +107,13 @@ nodes | Types.cs:122:30:122:30 | access to local variable a : A | semmle.label | access to local variable a : A | | Types.cs:123:22:123:32 | call to method Through | semmle.label | call to method Through | | Types.cs:123:30:123:31 | access to local variable e2 : Types.E.E2 | semmle.label | access to local variable e2 : Types.E.E2 | -| Types.cs:138:21:138:25 | this [Field] : Object | semmle.label | this [Field] : Object | -| Types.cs:138:32:138:35 | this access [Field] : Object | semmle.label | this access [Field] : Object | -| Types.cs:144:13:144:13 | [post] access to parameter c [Field] : Object | semmle.label | [post] access to parameter c [Field] : Object | +| Types.cs:138:21:138:25 | this [field Field] : Object | semmle.label | this [field Field] : Object | +| Types.cs:138:32:138:35 | this access [field Field] : Object | semmle.label | this access [field Field] : Object | +| Types.cs:144:13:144:13 | [post] access to parameter c [field Field] : Object | semmle.label | [post] access to parameter c [field Field] : Object | | Types.cs:144:23:144:34 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | -| Types.cs:145:13:145:13 | access to parameter c [Field] : Object | semmle.label | access to parameter c [Field] : Object | -| Types.cs:153:30:153:30 | this [Field] : Object | semmle.label | this [Field] : Object | -| Types.cs:153:42:153:45 | this access [Field] : Object | semmle.label | this access [Field] : Object | +| Types.cs:145:13:145:13 | access to parameter c [field Field] : Object | semmle.label | access to parameter c [field Field] : Object | +| Types.cs:153:30:153:30 | this [field Field] : Object | semmle.label | this [field Field] : Object | +| Types.cs:153:42:153:45 | this access [field Field] : Object | semmle.label | this access [field Field] : Object | | Types.cs:153:42:153:51 | access to field Field | semmle.label | access to field Field | #select | Types.cs:23:12:23:18 | object creation of type C : C | Types.cs:23:12:23:18 | object creation of type C : C | Types.cs:50:18:50:18 | access to local variable c | $@ | Types.cs:50:18:50:18 | access to local variable c | access to local variable c | diff --git a/csharp/ql/test/library-tests/frameworks/EntityFramework/Dataflow.expected b/csharp/ql/test/library-tests/frameworks/EntityFramework/Dataflow.expected index 7d0bd289f9c..d58177238b5 100644 --- a/csharp/ql/test/library-tests/frameworks/EntityFramework/Dataflow.expected +++ b/csharp/ql/test/library-tests/frameworks/EntityFramework/Dataflow.expected @@ -1,97 +1,97 @@ edges -| ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [Addresses, [], Street] : String | EntityFramework.cs:214:18:214:30 | access to property Addresses [[], Street] : String | -| ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [Addresses, [], Street] : String | EntityFramework.cs:221:18:221:28 | access to property Persons [[], Addresses, [], Street] : String | -| ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [PersonAddresses, [], Address, Street] : String | EntityFramework.cs:214:18:214:30 | access to property Addresses [[], Street] : String | -| ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [PersonAddresses, [], Address, Street] : String | EntityFramework.cs:221:18:221:28 | access to property Persons [[], Addresses, [], Street] : String | -| ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [PersonAddresses, [], Person, Name] : String | EntityFramework.cs:206:18:206:28 | access to property Persons [[], Name] : String | -| ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [Persons, [], Addresses, [], Street] : String | EntityFramework.cs:214:18:214:30 | access to property Addresses [[], Street] : String | -| ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [Persons, [], Addresses, [], Street] : String | EntityFramework.cs:221:18:221:28 | access to property Persons [[], Addresses, [], Street] : String | -| ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [Persons, [], Name] : String | EntityFramework.cs:206:18:206:28 | access to property Persons [[], Name] : String | -| ../../../resources/stubs/EntityFramework.cs:41:49:41:64 | this [Persons, [], Name] : String | EntityFramework.cs:206:18:206:28 | access to property Persons [[], Name] : String | -| ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [Addresses, [], Street] : String | EntityFrameworkCore.cs:238:18:238:30 | access to property Addresses [[], Street] : String | -| ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [Addresses, [], Street] : String | EntityFrameworkCore.cs:245:18:245:28 | access to property Persons [[], Addresses, [], Street] : String | -| ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [PersonAddresses, [], Address, Street] : String | EntityFrameworkCore.cs:238:18:238:30 | access to property Addresses [[], Street] : String | -| ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [PersonAddresses, [], Address, Street] : String | EntityFrameworkCore.cs:245:18:245:28 | access to property Persons [[], Addresses, [], Street] : String | -| ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [PersonAddresses, [], Person, Name] : String | EntityFrameworkCore.cs:230:18:230:28 | access to property Persons [[], Name] : String | -| ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [Persons, [], Addresses, [], Street] : String | EntityFrameworkCore.cs:238:18:238:30 | access to property Addresses [[], Street] : String | -| ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [Persons, [], Addresses, [], Street] : String | EntityFrameworkCore.cs:245:18:245:28 | access to property Persons [[], Addresses, [], Street] : String | -| ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [Persons, [], Name] : String | EntityFrameworkCore.cs:230:18:230:28 | access to property Persons [[], Name] : String | -| ../../../resources/stubs/EntityFramework.cs:81:49:81:64 | this [Persons, [], Name] : String | EntityFrameworkCore.cs:230:18:230:28 | access to property Persons [[], Name] : String | -| EntityFramework.cs:61:13:64:13 | { ..., ... } [Name] : String | EntityFramework.cs:68:29:68:30 | access to local variable p1 [Name] : String | -| EntityFramework.cs:63:24:63:32 | "tainted" : String | EntityFramework.cs:61:13:64:13 | { ..., ... } [Name] : String | -| EntityFramework.cs:68:13:68:15 | [post] access to local variable ctx [Persons, [], Name] : String | EntityFramework.cs:70:13:70:15 | access to local variable ctx [Persons, [], Name] : String | -| EntityFramework.cs:68:13:68:23 | [post] access to property Persons [[], Name] : String | EntityFramework.cs:68:13:68:15 | [post] access to local variable ctx [Persons, [], Name] : String | -| EntityFramework.cs:68:29:68:30 | access to local variable p1 [Name] : String | EntityFramework.cs:68:13:68:23 | [post] access to property Persons [[], Name] : String | -| EntityFramework.cs:70:13:70:15 | access to local variable ctx [Persons, [], Name] : String | ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [Persons, [], Name] : String | -| EntityFramework.cs:83:13:86:13 | { ..., ... } [Name] : String | EntityFramework.cs:90:29:90:30 | access to local variable p1 [Name] : String | -| EntityFramework.cs:85:24:85:32 | "tainted" : String | EntityFramework.cs:83:13:86:13 | { ..., ... } [Name] : String | -| EntityFramework.cs:90:13:90:15 | [post] access to local variable ctx [Persons, [], Name] : String | EntityFramework.cs:92:19:92:21 | access to local variable ctx [Persons, [], Name] : String | -| EntityFramework.cs:90:13:90:23 | [post] access to property Persons [[], Name] : String | EntityFramework.cs:90:13:90:15 | [post] access to local variable ctx [Persons, [], Name] : String | -| EntityFramework.cs:90:29:90:30 | access to local variable p1 [Name] : String | EntityFramework.cs:90:13:90:23 | [post] access to property Persons [[], Name] : String | -| EntityFramework.cs:92:19:92:21 | access to local variable ctx [Persons, [], Name] : String | ../../../resources/stubs/EntityFramework.cs:41:49:41:64 | this [Persons, [], Name] : String | -| EntityFramework.cs:105:13:108:13 | { ..., ... } [Name] : String | EntityFramework.cs:111:27:111:28 | access to local variable p1 [Name] : String | -| EntityFramework.cs:107:24:107:32 | "tainted" : String | EntityFramework.cs:105:13:108:13 | { ..., ... } [Name] : String | -| EntityFramework.cs:111:27:111:28 | access to local variable p1 [Name] : String | EntityFramework.cs:195:35:195:35 | p [Name] : String | -| EntityFramework.cs:124:13:127:13 | { ..., ... } [Title] : String | EntityFramework.cs:131:18:131:19 | access to local variable p1 [Title] : String | -| EntityFramework.cs:126:25:126:33 | "tainted" : String | EntityFramework.cs:124:13:127:13 | { ..., ... } [Title] : String | -| EntityFramework.cs:131:18:131:19 | access to local variable p1 [Title] : String | EntityFramework.cs:131:18:131:25 | access to property Title | -| EntityFramework.cs:143:13:150:13 | { ..., ... } [Addresses, [], Street] : String | EntityFramework.cs:151:29:151:30 | access to local variable p1 [Addresses, [], Street] : String | -| EntityFramework.cs:144:29:149:17 | array creation of type Address[] [[], Street] : String | EntityFramework.cs:143:13:150:13 | { ..., ... } [Addresses, [], Street] : String | -| EntityFramework.cs:144:35:149:17 | { ..., ... } [[], Street] : String | EntityFramework.cs:144:29:149:17 | array creation of type Address[] [[], Street] : String | -| EntityFramework.cs:145:21:148:21 | object creation of type Address [Street] : String | EntityFramework.cs:144:35:149:17 | { ..., ... } [[], Street] : String | -| EntityFramework.cs:145:33:148:21 | { ..., ... } [Street] : String | EntityFramework.cs:145:21:148:21 | object creation of type Address [Street] : String | -| EntityFramework.cs:147:34:147:42 | "tainted" : String | EntityFramework.cs:145:33:148:21 | { ..., ... } [Street] : String | -| EntityFramework.cs:151:13:151:15 | [post] access to local variable ctx [Persons, [], Addresses, [], Street] : String | EntityFramework.cs:152:13:152:15 | access to local variable ctx [Persons, [], Addresses, [], Street] : String | -| EntityFramework.cs:151:13:151:15 | [post] access to local variable ctx [Persons, [], Addresses, [], Street] : String | EntityFramework.cs:156:13:156:15 | access to local variable ctx [Persons, [], Addresses, [], Street] : String | -| EntityFramework.cs:151:13:151:15 | [post] access to local variable ctx [Persons, [], Addresses, [], Street] : String | EntityFramework.cs:164:13:164:15 | access to local variable ctx [Persons, [], Addresses, [], Street] : String | -| EntityFramework.cs:151:13:151:15 | [post] access to local variable ctx [Persons, [], Addresses, [], Street] : String | EntityFramework.cs:168:13:168:15 | access to local variable ctx [Persons, [], Addresses, [], Street] : String | -| EntityFramework.cs:151:13:151:23 | [post] access to property Persons [[], Addresses, [], Street] : String | EntityFramework.cs:151:13:151:15 | [post] access to local variable ctx [Persons, [], Addresses, [], Street] : String | -| EntityFramework.cs:151:29:151:30 | access to local variable p1 [Addresses, [], Street] : String | EntityFramework.cs:151:13:151:23 | [post] access to property Persons [[], Addresses, [], Street] : String | -| EntityFramework.cs:152:13:152:15 | access to local variable ctx [Persons, [], Addresses, [], Street] : String | ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [Persons, [], Addresses, [], Street] : String | -| EntityFramework.cs:156:13:156:15 | access to local variable ctx [Persons, [], Addresses, [], Street] : String | ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [Persons, [], Addresses, [], Street] : String | -| EntityFramework.cs:159:13:162:13 | { ..., ... } [Street] : String | EntityFramework.cs:163:31:163:32 | access to local variable a1 [Street] : String | -| EntityFramework.cs:161:26:161:34 | "tainted" : String | EntityFramework.cs:159:13:162:13 | { ..., ... } [Street] : String | -| EntityFramework.cs:163:13:163:15 | [post] access to local variable ctx [Addresses, [], Street] : String | EntityFramework.cs:164:13:164:15 | access to local variable ctx [Addresses, [], Street] : String | -| EntityFramework.cs:163:13:163:15 | [post] access to local variable ctx [Addresses, [], Street] : String | EntityFramework.cs:168:13:168:15 | access to local variable ctx [Addresses, [], Street] : String | -| EntityFramework.cs:163:13:163:25 | [post] access to property Addresses [[], Street] : String | EntityFramework.cs:163:13:163:15 | [post] access to local variable ctx [Addresses, [], Street] : String | -| EntityFramework.cs:163:31:163:32 | access to local variable a1 [Street] : String | EntityFramework.cs:163:13:163:25 | [post] access to property Addresses [[], Street] : String | -| EntityFramework.cs:164:13:164:15 | access to local variable ctx [Addresses, [], Street] : String | ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [Addresses, [], Street] : String | -| EntityFramework.cs:164:13:164:15 | access to local variable ctx [Persons, [], Addresses, [], Street] : String | ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [Persons, [], Addresses, [], Street] : String | -| EntityFramework.cs:168:13:168:15 | access to local variable ctx [Addresses, [], Street] : String | ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [Addresses, [], Street] : String | -| EntityFramework.cs:168:13:168:15 | access to local variable ctx [Persons, [], Addresses, [], Street] : String | ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [Persons, [], Addresses, [], Street] : String | -| EntityFramework.cs:175:13:178:13 | { ..., ... } [Name] : String | EntityFramework.cs:184:71:184:72 | access to local variable p1 [Name] : String | -| EntityFramework.cs:177:24:177:32 | "tainted" : String | EntityFramework.cs:175:13:178:13 | { ..., ... } [Name] : String | -| EntityFramework.cs:180:13:183:13 | { ..., ... } [Street] : String | EntityFramework.cs:184:85:184:86 | access to local variable a1 [Street] : String | -| EntityFramework.cs:182:26:182:34 | "tainted" : String | EntityFramework.cs:180:13:183:13 | { ..., ... } [Street] : String | -| EntityFramework.cs:184:60:184:88 | { ..., ... } [Address, Street] : String | EntityFramework.cs:185:37:185:53 | access to local variable personAddressMap1 [Address, Street] : String | -| EntityFramework.cs:184:60:184:88 | { ..., ... } [Person, Name] : String | EntityFramework.cs:185:37:185:53 | access to local variable personAddressMap1 [Person, Name] : String | -| EntityFramework.cs:184:71:184:72 | access to local variable p1 [Name] : String | EntityFramework.cs:184:60:184:88 | { ..., ... } [Person, Name] : String | -| EntityFramework.cs:184:85:184:86 | access to local variable a1 [Street] : String | EntityFramework.cs:184:60:184:88 | { ..., ... } [Address, Street] : String | -| EntityFramework.cs:185:13:185:15 | [post] access to local variable ctx [PersonAddresses, [], Address, Street] : String | EntityFramework.cs:186:13:186:15 | access to local variable ctx [PersonAddresses, [], Address, Street] : String | -| EntityFramework.cs:185:13:185:15 | [post] access to local variable ctx [PersonAddresses, [], Address, Street] : String | EntityFramework.cs:192:13:192:15 | access to local variable ctx [PersonAddresses, [], Address, Street] : String | -| EntityFramework.cs:185:13:185:15 | [post] access to local variable ctx [PersonAddresses, [], Person, Name] : String | EntityFramework.cs:186:13:186:15 | access to local variable ctx [PersonAddresses, [], Person, Name] : String | -| EntityFramework.cs:185:13:185:15 | [post] access to local variable ctx [PersonAddresses, [], Person, Name] : String | EntityFramework.cs:192:13:192:15 | access to local variable ctx [PersonAddresses, [], Person, Name] : String | -| EntityFramework.cs:185:13:185:31 | [post] access to property PersonAddresses [[], Address, Street] : String | EntityFramework.cs:185:13:185:15 | [post] access to local variable ctx [PersonAddresses, [], Address, Street] : String | -| EntityFramework.cs:185:13:185:31 | [post] access to property PersonAddresses [[], Person, Name] : String | EntityFramework.cs:185:13:185:15 | [post] access to local variable ctx [PersonAddresses, [], Person, Name] : String | -| EntityFramework.cs:185:37:185:53 | access to local variable personAddressMap1 [Address, Street] : String | EntityFramework.cs:185:13:185:31 | [post] access to property PersonAddresses [[], Address, Street] : String | -| EntityFramework.cs:185:37:185:53 | access to local variable personAddressMap1 [Person, Name] : String | EntityFramework.cs:185:13:185:31 | [post] access to property PersonAddresses [[], Person, Name] : String | -| EntityFramework.cs:186:13:186:15 | access to local variable ctx [PersonAddresses, [], Address, Street] : String | ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [PersonAddresses, [], Address, Street] : String | -| EntityFramework.cs:186:13:186:15 | access to local variable ctx [PersonAddresses, [], Person, Name] : String | ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [PersonAddresses, [], Person, Name] : String | -| EntityFramework.cs:192:13:192:15 | access to local variable ctx [PersonAddresses, [], Address, Street] : String | ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [PersonAddresses, [], Address, Street] : String | -| EntityFramework.cs:192:13:192:15 | access to local variable ctx [PersonAddresses, [], Person, Name] : String | ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [PersonAddresses, [], Person, Name] : String | -| EntityFramework.cs:195:35:195:35 | p [Name] : String | EntityFramework.cs:198:29:198:29 | access to parameter p [Name] : String | -| EntityFramework.cs:198:13:198:15 | [post] access to local variable ctx [Persons, [], Name] : String | EntityFramework.cs:199:13:199:15 | access to local variable ctx [Persons, [], Name] : String | -| EntityFramework.cs:198:13:198:23 | [post] access to property Persons [[], Name] : String | EntityFramework.cs:198:13:198:15 | [post] access to local variable ctx [Persons, [], Name] : String | -| EntityFramework.cs:198:29:198:29 | access to parameter p [Name] : String | EntityFramework.cs:198:13:198:23 | [post] access to property Persons [[], Name] : String | -| EntityFramework.cs:199:13:199:15 | access to local variable ctx [Persons, [], Name] : String | ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [Persons, [], Name] : String | -| EntityFramework.cs:206:18:206:28 | access to property Persons [[], Name] : String | EntityFramework.cs:206:18:206:36 | call to method First [Name] : String | -| EntityFramework.cs:206:18:206:36 | call to method First [Name] : String | EntityFramework.cs:206:18:206:41 | access to property Name | -| EntityFramework.cs:214:18:214:30 | access to property Addresses [[], Street] : String | EntityFramework.cs:214:18:214:38 | call to method First [Street] : String | -| EntityFramework.cs:214:18:214:38 | call to method First [Street] : String | EntityFramework.cs:214:18:214:45 | access to property Street | -| EntityFramework.cs:221:18:221:28 | access to property Persons [[], Addresses, [], Street] : String | EntityFramework.cs:221:18:221:36 | call to method First [Addresses, [], Street] : String | -| EntityFramework.cs:221:18:221:36 | call to method First [Addresses, [], Street] : String | EntityFramework.cs:221:18:221:46 | access to property Addresses [[], Street] : String | -| EntityFramework.cs:221:18:221:46 | access to property Addresses [[], Street] : String | EntityFramework.cs:221:18:221:54 | call to method First [Street] : String | -| EntityFramework.cs:221:18:221:54 | call to method First [Street] : String | EntityFramework.cs:221:18:221:61 | access to property Street | +| ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [property Addresses, element, property Street] : String | EntityFramework.cs:214:18:214:30 | access to property Addresses [element, property Street] : String | +| ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [property Addresses, element, property Street] : String | EntityFramework.cs:221:18:221:28 | access to property Persons [element, property Addresses, element, property Street] : String | +| ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [property PersonAddresses, element, property Address, property Street] : String | EntityFramework.cs:214:18:214:30 | access to property Addresses [element, property Street] : String | +| ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [property PersonAddresses, element, property Address, property Street] : String | EntityFramework.cs:221:18:221:28 | access to property Persons [element, property Addresses, element, property Street] : String | +| ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [property PersonAddresses, element, property Person, property Name] : String | EntityFramework.cs:206:18:206:28 | access to property Persons [element, property Name] : String | +| ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [property Persons, element, property Addresses, element, property Street] : String | EntityFramework.cs:214:18:214:30 | access to property Addresses [element, property Street] : String | +| ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [property Persons, element, property Addresses, element, property Street] : String | EntityFramework.cs:221:18:221:28 | access to property Persons [element, property Addresses, element, property Street] : String | +| ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [property Persons, element, property Name] : String | EntityFramework.cs:206:18:206:28 | access to property Persons [element, property Name] : String | +| ../../../resources/stubs/EntityFramework.cs:41:49:41:64 | this [property Persons, element, property Name] : String | EntityFramework.cs:206:18:206:28 | access to property Persons [element, property Name] : String | +| ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [property Addresses, element, property Street] : String | EntityFrameworkCore.cs:238:18:238:30 | access to property Addresses [element, property Street] : String | +| ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [property Addresses, element, property Street] : String | EntityFrameworkCore.cs:245:18:245:28 | access to property Persons [element, property Addresses, element, property Street] : String | +| ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [property PersonAddresses, element, property Address, property Street] : String | EntityFrameworkCore.cs:238:18:238:30 | access to property Addresses [element, property Street] : String | +| ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [property PersonAddresses, element, property Address, property Street] : String | EntityFrameworkCore.cs:245:18:245:28 | access to property Persons [element, property Addresses, element, property Street] : String | +| ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [property PersonAddresses, element, property Person, property Name] : String | EntityFrameworkCore.cs:230:18:230:28 | access to property Persons [element, property Name] : String | +| ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [property Persons, element, property Addresses, element, property Street] : String | EntityFrameworkCore.cs:238:18:238:30 | access to property Addresses [element, property Street] : String | +| ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [property Persons, element, property Addresses, element, property Street] : String | EntityFrameworkCore.cs:245:18:245:28 | access to property Persons [element, property Addresses, element, property Street] : String | +| ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [property Persons, element, property Name] : String | EntityFrameworkCore.cs:230:18:230:28 | access to property Persons [element, property Name] : String | +| ../../../resources/stubs/EntityFramework.cs:81:49:81:64 | this [property Persons, element, property Name] : String | EntityFrameworkCore.cs:230:18:230:28 | access to property Persons [element, property Name] : String | +| EntityFramework.cs:61:13:64:13 | { ..., ... } [property Name] : String | EntityFramework.cs:68:29:68:30 | access to local variable p1 [property Name] : String | +| EntityFramework.cs:63:24:63:32 | "tainted" : String | EntityFramework.cs:61:13:64:13 | { ..., ... } [property Name] : String | +| EntityFramework.cs:68:13:68:15 | [post] access to local variable ctx [property Persons, element, property Name] : String | EntityFramework.cs:70:13:70:15 | access to local variable ctx [property Persons, element, property Name] : String | +| EntityFramework.cs:68:13:68:23 | [post] access to property Persons [element, property Name] : String | EntityFramework.cs:68:13:68:15 | [post] access to local variable ctx [property Persons, element, property Name] : String | +| EntityFramework.cs:68:29:68:30 | access to local variable p1 [property Name] : String | EntityFramework.cs:68:13:68:23 | [post] access to property Persons [element, property Name] : String | +| EntityFramework.cs:70:13:70:15 | access to local variable ctx [property Persons, element, property Name] : String | ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [property Persons, element, property Name] : String | +| EntityFramework.cs:83:13:86:13 | { ..., ... } [property Name] : String | EntityFramework.cs:90:29:90:30 | access to local variable p1 [property Name] : String | +| EntityFramework.cs:85:24:85:32 | "tainted" : String | EntityFramework.cs:83:13:86:13 | { ..., ... } [property Name] : String | +| EntityFramework.cs:90:13:90:15 | [post] access to local variable ctx [property Persons, element, property Name] : String | EntityFramework.cs:92:19:92:21 | access to local variable ctx [property Persons, element, property Name] : String | +| EntityFramework.cs:90:13:90:23 | [post] access to property Persons [element, property Name] : String | EntityFramework.cs:90:13:90:15 | [post] access to local variable ctx [property Persons, element, property Name] : String | +| EntityFramework.cs:90:29:90:30 | access to local variable p1 [property Name] : String | EntityFramework.cs:90:13:90:23 | [post] access to property Persons [element, property Name] : String | +| EntityFramework.cs:92:19:92:21 | access to local variable ctx [property Persons, element, property Name] : String | ../../../resources/stubs/EntityFramework.cs:41:49:41:64 | this [property Persons, element, property Name] : String | +| EntityFramework.cs:105:13:108:13 | { ..., ... } [property Name] : String | EntityFramework.cs:111:27:111:28 | access to local variable p1 [property Name] : String | +| EntityFramework.cs:107:24:107:32 | "tainted" : String | EntityFramework.cs:105:13:108:13 | { ..., ... } [property Name] : String | +| EntityFramework.cs:111:27:111:28 | access to local variable p1 [property Name] : String | EntityFramework.cs:195:35:195:35 | p [property Name] : String | +| EntityFramework.cs:124:13:127:13 | { ..., ... } [property Title] : String | EntityFramework.cs:131:18:131:19 | access to local variable p1 [property Title] : String | +| EntityFramework.cs:126:25:126:33 | "tainted" : String | EntityFramework.cs:124:13:127:13 | { ..., ... } [property Title] : String | +| EntityFramework.cs:131:18:131:19 | access to local variable p1 [property Title] : String | EntityFramework.cs:131:18:131:25 | access to property Title | +| EntityFramework.cs:143:13:150:13 | { ..., ... } [property Addresses, element, property Street] : String | EntityFramework.cs:151:29:151:30 | access to local variable p1 [property Addresses, element, property Street] : String | +| EntityFramework.cs:144:29:149:17 | array creation of type Address[] [element, property Street] : String | EntityFramework.cs:143:13:150:13 | { ..., ... } [property Addresses, element, property Street] : String | +| EntityFramework.cs:144:35:149:17 | { ..., ... } [element, property Street] : String | EntityFramework.cs:144:29:149:17 | array creation of type Address[] [element, property Street] : String | +| EntityFramework.cs:145:21:148:21 | object creation of type Address [property Street] : String | EntityFramework.cs:144:35:149:17 | { ..., ... } [element, property Street] : String | +| EntityFramework.cs:145:33:148:21 | { ..., ... } [property Street] : String | EntityFramework.cs:145:21:148:21 | object creation of type Address [property Street] : String | +| EntityFramework.cs:147:34:147:42 | "tainted" : String | EntityFramework.cs:145:33:148:21 | { ..., ... } [property Street] : String | +| EntityFramework.cs:151:13:151:15 | [post] access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | EntityFramework.cs:152:13:152:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | +| EntityFramework.cs:151:13:151:15 | [post] access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | EntityFramework.cs:156:13:156:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | +| EntityFramework.cs:151:13:151:15 | [post] access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | EntityFramework.cs:164:13:164:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | +| EntityFramework.cs:151:13:151:15 | [post] access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | EntityFramework.cs:168:13:168:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | +| EntityFramework.cs:151:13:151:23 | [post] access to property Persons [element, property Addresses, element, property Street] : String | EntityFramework.cs:151:13:151:15 | [post] access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | +| EntityFramework.cs:151:29:151:30 | access to local variable p1 [property Addresses, element, property Street] : String | EntityFramework.cs:151:13:151:23 | [post] access to property Persons [element, property Addresses, element, property Street] : String | +| EntityFramework.cs:152:13:152:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [property Persons, element, property Addresses, element, property Street] : String | +| EntityFramework.cs:156:13:156:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [property Persons, element, property Addresses, element, property Street] : String | +| EntityFramework.cs:159:13:162:13 | { ..., ... } [property Street] : String | EntityFramework.cs:163:31:163:32 | access to local variable a1 [property Street] : String | +| EntityFramework.cs:161:26:161:34 | "tainted" : String | EntityFramework.cs:159:13:162:13 | { ..., ... } [property Street] : String | +| EntityFramework.cs:163:13:163:15 | [post] access to local variable ctx [property Addresses, element, property Street] : String | EntityFramework.cs:164:13:164:15 | access to local variable ctx [property Addresses, element, property Street] : String | +| EntityFramework.cs:163:13:163:15 | [post] access to local variable ctx [property Addresses, element, property Street] : String | EntityFramework.cs:168:13:168:15 | access to local variable ctx [property Addresses, element, property Street] : String | +| EntityFramework.cs:163:13:163:25 | [post] access to property Addresses [element, property Street] : String | EntityFramework.cs:163:13:163:15 | [post] access to local variable ctx [property Addresses, element, property Street] : String | +| EntityFramework.cs:163:31:163:32 | access to local variable a1 [property Street] : String | EntityFramework.cs:163:13:163:25 | [post] access to property Addresses [element, property Street] : String | +| EntityFramework.cs:164:13:164:15 | access to local variable ctx [property Addresses, element, property Street] : String | ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [property Addresses, element, property Street] : String | +| EntityFramework.cs:164:13:164:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [property Persons, element, property Addresses, element, property Street] : String | +| EntityFramework.cs:168:13:168:15 | access to local variable ctx [property Addresses, element, property Street] : String | ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [property Addresses, element, property Street] : String | +| EntityFramework.cs:168:13:168:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [property Persons, element, property Addresses, element, property Street] : String | +| EntityFramework.cs:175:13:178:13 | { ..., ... } [property Name] : String | EntityFramework.cs:184:71:184:72 | access to local variable p1 [property Name] : String | +| EntityFramework.cs:177:24:177:32 | "tainted" : String | EntityFramework.cs:175:13:178:13 | { ..., ... } [property Name] : String | +| EntityFramework.cs:180:13:183:13 | { ..., ... } [property Street] : String | EntityFramework.cs:184:85:184:86 | access to local variable a1 [property Street] : String | +| EntityFramework.cs:182:26:182:34 | "tainted" : String | EntityFramework.cs:180:13:183:13 | { ..., ... } [property Street] : String | +| EntityFramework.cs:184:60:184:88 | { ..., ... } [property Address, property Street] : String | EntityFramework.cs:185:37:185:53 | access to local variable personAddressMap1 [property Address, property Street] : String | +| EntityFramework.cs:184:60:184:88 | { ..., ... } [property Person, property Name] : String | EntityFramework.cs:185:37:185:53 | access to local variable personAddressMap1 [property Person, property Name] : String | +| EntityFramework.cs:184:71:184:72 | access to local variable p1 [property Name] : String | EntityFramework.cs:184:60:184:88 | { ..., ... } [property Person, property Name] : String | +| EntityFramework.cs:184:85:184:86 | access to local variable a1 [property Street] : String | EntityFramework.cs:184:60:184:88 | { ..., ... } [property Address, property Street] : String | +| EntityFramework.cs:185:13:185:15 | [post] access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | EntityFramework.cs:186:13:186:15 | access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | +| EntityFramework.cs:185:13:185:15 | [post] access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | EntityFramework.cs:192:13:192:15 | access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | +| EntityFramework.cs:185:13:185:15 | [post] access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | EntityFramework.cs:186:13:186:15 | access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | +| EntityFramework.cs:185:13:185:15 | [post] access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | EntityFramework.cs:192:13:192:15 | access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | +| EntityFramework.cs:185:13:185:31 | [post] access to property PersonAddresses [element, property Address, property Street] : String | EntityFramework.cs:185:13:185:15 | [post] access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | +| EntityFramework.cs:185:13:185:31 | [post] access to property PersonAddresses [element, property Person, property Name] : String | EntityFramework.cs:185:13:185:15 | [post] access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | +| EntityFramework.cs:185:37:185:53 | access to local variable personAddressMap1 [property Address, property Street] : String | EntityFramework.cs:185:13:185:31 | [post] access to property PersonAddresses [element, property Address, property Street] : String | +| EntityFramework.cs:185:37:185:53 | access to local variable personAddressMap1 [property Person, property Name] : String | EntityFramework.cs:185:13:185:31 | [post] access to property PersonAddresses [element, property Person, property Name] : String | +| EntityFramework.cs:186:13:186:15 | access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [property PersonAddresses, element, property Address, property Street] : String | +| EntityFramework.cs:186:13:186:15 | access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [property PersonAddresses, element, property Person, property Name] : String | +| EntityFramework.cs:192:13:192:15 | access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [property PersonAddresses, element, property Address, property Street] : String | +| EntityFramework.cs:192:13:192:15 | access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [property PersonAddresses, element, property Person, property Name] : String | +| EntityFramework.cs:195:35:195:35 | p [property Name] : String | EntityFramework.cs:198:29:198:29 | access to parameter p [property Name] : String | +| EntityFramework.cs:198:13:198:15 | [post] access to local variable ctx [property Persons, element, property Name] : String | EntityFramework.cs:199:13:199:15 | access to local variable ctx [property Persons, element, property Name] : String | +| EntityFramework.cs:198:13:198:23 | [post] access to property Persons [element, property Name] : String | EntityFramework.cs:198:13:198:15 | [post] access to local variable ctx [property Persons, element, property Name] : String | +| EntityFramework.cs:198:29:198:29 | access to parameter p [property Name] : String | EntityFramework.cs:198:13:198:23 | [post] access to property Persons [element, property Name] : String | +| EntityFramework.cs:199:13:199:15 | access to local variable ctx [property Persons, element, property Name] : String | ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [property Persons, element, property Name] : String | +| EntityFramework.cs:206:18:206:28 | access to property Persons [element, property Name] : String | EntityFramework.cs:206:18:206:36 | call to method First [property Name] : String | +| EntityFramework.cs:206:18:206:36 | call to method First [property Name] : String | EntityFramework.cs:206:18:206:41 | access to property Name | +| EntityFramework.cs:214:18:214:30 | access to property Addresses [element, property Street] : String | EntityFramework.cs:214:18:214:38 | call to method First [property Street] : String | +| EntityFramework.cs:214:18:214:38 | call to method First [property Street] : String | EntityFramework.cs:214:18:214:45 | access to property Street | +| EntityFramework.cs:221:18:221:28 | access to property Persons [element, property Addresses, element, property Street] : String | EntityFramework.cs:221:18:221:36 | call to method First [property Addresses, element, property Street] : String | +| EntityFramework.cs:221:18:221:36 | call to method First [property Addresses, element, property Street] : String | EntityFramework.cs:221:18:221:46 | access to property Addresses [element, property Street] : String | +| EntityFramework.cs:221:18:221:46 | access to property Addresses [element, property Street] : String | EntityFramework.cs:221:18:221:54 | call to method First [property Street] : String | +| EntityFramework.cs:221:18:221:54 | call to method First [property Street] : String | EntityFramework.cs:221:18:221:61 | access to property Street | | EntityFrameworkCore.cs:75:31:75:39 | "tainted" : String | EntityFrameworkCore.cs:76:18:76:28 | access to local variable taintSource | | EntityFrameworkCore.cs:75:31:75:39 | "tainted" : String | EntityFrameworkCore.cs:77:35:77:45 | access to local variable taintSource : String | | EntityFrameworkCore.cs:75:31:75:39 | "tainted" : String | EntityFrameworkCore.cs:78:32:78:42 | access to local variable taintSource : String | @@ -99,166 +99,166 @@ edges | EntityFrameworkCore.cs:77:35:77:45 | access to local variable taintSource : String | EntityFrameworkCore.cs:77:18:77:46 | object creation of type RawSqlString : RawSqlString | | EntityFrameworkCore.cs:78:18:78:42 | call to operator implicit conversion : RawSqlString | EntityFrameworkCore.cs:78:18:78:42 | (...) ... | | EntityFrameworkCore.cs:78:32:78:42 | access to local variable taintSource : String | EntityFrameworkCore.cs:78:18:78:42 | call to operator implicit conversion : RawSqlString | -| EntityFrameworkCore.cs:85:13:88:13 | { ..., ... } [Name] : String | EntityFrameworkCore.cs:92:29:92:30 | access to local variable p1 [Name] : String | -| EntityFrameworkCore.cs:87:24:87:32 | "tainted" : String | EntityFrameworkCore.cs:85:13:88:13 | { ..., ... } [Name] : String | -| EntityFrameworkCore.cs:92:13:92:15 | [post] access to local variable ctx [Persons, [], Name] : String | EntityFrameworkCore.cs:94:13:94:15 | access to local variable ctx [Persons, [], Name] : String | -| EntityFrameworkCore.cs:92:13:92:23 | [post] access to property Persons [[], Name] : String | EntityFrameworkCore.cs:92:13:92:15 | [post] access to local variable ctx [Persons, [], Name] : String | -| EntityFrameworkCore.cs:92:29:92:30 | access to local variable p1 [Name] : String | EntityFrameworkCore.cs:92:13:92:23 | [post] access to property Persons [[], Name] : String | -| EntityFrameworkCore.cs:94:13:94:15 | access to local variable ctx [Persons, [], Name] : String | ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [Persons, [], Name] : String | -| EntityFrameworkCore.cs:107:13:110:13 | { ..., ... } [Name] : String | EntityFrameworkCore.cs:114:29:114:30 | access to local variable p1 [Name] : String | -| EntityFrameworkCore.cs:109:24:109:32 | "tainted" : String | EntityFrameworkCore.cs:107:13:110:13 | { ..., ... } [Name] : String | -| EntityFrameworkCore.cs:114:13:114:15 | [post] access to local variable ctx [Persons, [], Name] : String | EntityFrameworkCore.cs:116:19:116:21 | access to local variable ctx [Persons, [], Name] : String | -| EntityFrameworkCore.cs:114:13:114:23 | [post] access to property Persons [[], Name] : String | EntityFrameworkCore.cs:114:13:114:15 | [post] access to local variable ctx [Persons, [], Name] : String | -| EntityFrameworkCore.cs:114:29:114:30 | access to local variable p1 [Name] : String | EntityFrameworkCore.cs:114:13:114:23 | [post] access to property Persons [[], Name] : String | -| EntityFrameworkCore.cs:116:19:116:21 | access to local variable ctx [Persons, [], Name] : String | ../../../resources/stubs/EntityFramework.cs:81:49:81:64 | this [Persons, [], Name] : String | -| EntityFrameworkCore.cs:129:13:132:13 | { ..., ... } [Name] : String | EntityFrameworkCore.cs:135:27:135:28 | access to local variable p1 [Name] : String | -| EntityFrameworkCore.cs:131:24:131:32 | "tainted" : String | EntityFrameworkCore.cs:129:13:132:13 | { ..., ... } [Name] : String | -| EntityFrameworkCore.cs:135:27:135:28 | access to local variable p1 [Name] : String | EntityFrameworkCore.cs:219:35:219:35 | p [Name] : String | -| EntityFrameworkCore.cs:148:13:151:13 | { ..., ... } [Title] : String | EntityFrameworkCore.cs:155:18:155:19 | access to local variable p1 [Title] : String | -| EntityFrameworkCore.cs:150:25:150:33 | "tainted" : String | EntityFrameworkCore.cs:148:13:151:13 | { ..., ... } [Title] : String | -| EntityFrameworkCore.cs:155:18:155:19 | access to local variable p1 [Title] : String | EntityFrameworkCore.cs:155:18:155:25 | access to property Title | -| EntityFrameworkCore.cs:167:13:174:13 | { ..., ... } [Addresses, [], Street] : String | EntityFrameworkCore.cs:175:29:175:30 | access to local variable p1 [Addresses, [], Street] : String | -| EntityFrameworkCore.cs:168:29:173:17 | array creation of type Address[] [[], Street] : String | EntityFrameworkCore.cs:167:13:174:13 | { ..., ... } [Addresses, [], Street] : String | -| EntityFrameworkCore.cs:168:35:173:17 | { ..., ... } [[], Street] : String | EntityFrameworkCore.cs:168:29:173:17 | array creation of type Address[] [[], Street] : String | -| EntityFrameworkCore.cs:169:21:172:21 | object creation of type Address [Street] : String | EntityFrameworkCore.cs:168:35:173:17 | { ..., ... } [[], Street] : String | -| EntityFrameworkCore.cs:169:33:172:21 | { ..., ... } [Street] : String | EntityFrameworkCore.cs:169:21:172:21 | object creation of type Address [Street] : String | -| EntityFrameworkCore.cs:171:34:171:42 | "tainted" : String | EntityFrameworkCore.cs:169:33:172:21 | { ..., ... } [Street] : String | -| EntityFrameworkCore.cs:175:13:175:15 | [post] access to local variable ctx [Persons, [], Addresses, [], Street] : String | EntityFrameworkCore.cs:176:13:176:15 | access to local variable ctx [Persons, [], Addresses, [], Street] : String | -| EntityFrameworkCore.cs:175:13:175:15 | [post] access to local variable ctx [Persons, [], Addresses, [], Street] : String | EntityFrameworkCore.cs:180:13:180:15 | access to local variable ctx [Persons, [], Addresses, [], Street] : String | -| EntityFrameworkCore.cs:175:13:175:15 | [post] access to local variable ctx [Persons, [], Addresses, [], Street] : String | EntityFrameworkCore.cs:188:13:188:15 | access to local variable ctx [Persons, [], Addresses, [], Street] : String | -| EntityFrameworkCore.cs:175:13:175:15 | [post] access to local variable ctx [Persons, [], Addresses, [], Street] : String | EntityFrameworkCore.cs:192:13:192:15 | access to local variable ctx [Persons, [], Addresses, [], Street] : String | -| EntityFrameworkCore.cs:175:13:175:23 | [post] access to property Persons [[], Addresses, [], Street] : String | EntityFrameworkCore.cs:175:13:175:15 | [post] access to local variable ctx [Persons, [], Addresses, [], Street] : String | -| EntityFrameworkCore.cs:175:29:175:30 | access to local variable p1 [Addresses, [], Street] : String | EntityFrameworkCore.cs:175:13:175:23 | [post] access to property Persons [[], Addresses, [], Street] : String | -| EntityFrameworkCore.cs:176:13:176:15 | access to local variable ctx [Persons, [], Addresses, [], Street] : String | ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [Persons, [], Addresses, [], Street] : String | -| EntityFrameworkCore.cs:180:13:180:15 | access to local variable ctx [Persons, [], Addresses, [], Street] : String | ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [Persons, [], Addresses, [], Street] : String | -| EntityFrameworkCore.cs:183:13:186:13 | { ..., ... } [Street] : String | EntityFrameworkCore.cs:187:31:187:32 | access to local variable a1 [Street] : String | -| EntityFrameworkCore.cs:185:26:185:34 | "tainted" : String | EntityFrameworkCore.cs:183:13:186:13 | { ..., ... } [Street] : String | -| EntityFrameworkCore.cs:187:13:187:15 | [post] access to local variable ctx [Addresses, [], Street] : String | EntityFrameworkCore.cs:188:13:188:15 | access to local variable ctx [Addresses, [], Street] : String | -| EntityFrameworkCore.cs:187:13:187:15 | [post] access to local variable ctx [Addresses, [], Street] : String | EntityFrameworkCore.cs:192:13:192:15 | access to local variable ctx [Addresses, [], Street] : String | -| EntityFrameworkCore.cs:187:13:187:25 | [post] access to property Addresses [[], Street] : String | EntityFrameworkCore.cs:187:13:187:15 | [post] access to local variable ctx [Addresses, [], Street] : String | -| EntityFrameworkCore.cs:187:31:187:32 | access to local variable a1 [Street] : String | EntityFrameworkCore.cs:187:13:187:25 | [post] access to property Addresses [[], Street] : String | -| EntityFrameworkCore.cs:188:13:188:15 | access to local variable ctx [Addresses, [], Street] : String | ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [Addresses, [], Street] : String | -| EntityFrameworkCore.cs:188:13:188:15 | access to local variable ctx [Persons, [], Addresses, [], Street] : String | ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [Persons, [], Addresses, [], Street] : String | -| EntityFrameworkCore.cs:192:13:192:15 | access to local variable ctx [Addresses, [], Street] : String | ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [Addresses, [], Street] : String | -| EntityFrameworkCore.cs:192:13:192:15 | access to local variable ctx [Persons, [], Addresses, [], Street] : String | ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [Persons, [], Addresses, [], Street] : String | -| EntityFrameworkCore.cs:199:13:202:13 | { ..., ... } [Name] : String | EntityFrameworkCore.cs:208:71:208:72 | access to local variable p1 [Name] : String | -| EntityFrameworkCore.cs:201:24:201:32 | "tainted" : String | EntityFrameworkCore.cs:199:13:202:13 | { ..., ... } [Name] : String | -| EntityFrameworkCore.cs:204:13:207:13 | { ..., ... } [Street] : String | EntityFrameworkCore.cs:208:85:208:86 | access to local variable a1 [Street] : String | -| EntityFrameworkCore.cs:206:26:206:34 | "tainted" : String | EntityFrameworkCore.cs:204:13:207:13 | { ..., ... } [Street] : String | -| EntityFrameworkCore.cs:208:60:208:88 | { ..., ... } [Address, Street] : String | EntityFrameworkCore.cs:209:37:209:53 | access to local variable personAddressMap1 [Address, Street] : String | -| EntityFrameworkCore.cs:208:60:208:88 | { ..., ... } [Person, Name] : String | EntityFrameworkCore.cs:209:37:209:53 | access to local variable personAddressMap1 [Person, Name] : String | -| EntityFrameworkCore.cs:208:71:208:72 | access to local variable p1 [Name] : String | EntityFrameworkCore.cs:208:60:208:88 | { ..., ... } [Person, Name] : String | -| EntityFrameworkCore.cs:208:85:208:86 | access to local variable a1 [Street] : String | EntityFrameworkCore.cs:208:60:208:88 | { ..., ... } [Address, Street] : String | -| EntityFrameworkCore.cs:209:13:209:15 | [post] access to local variable ctx [PersonAddresses, [], Address, Street] : String | EntityFrameworkCore.cs:210:13:210:15 | access to local variable ctx [PersonAddresses, [], Address, Street] : String | -| EntityFrameworkCore.cs:209:13:209:15 | [post] access to local variable ctx [PersonAddresses, [], Address, Street] : String | EntityFrameworkCore.cs:216:13:216:15 | access to local variable ctx [PersonAddresses, [], Address, Street] : String | -| EntityFrameworkCore.cs:209:13:209:15 | [post] access to local variable ctx [PersonAddresses, [], Person, Name] : String | EntityFrameworkCore.cs:210:13:210:15 | access to local variable ctx [PersonAddresses, [], Person, Name] : String | -| EntityFrameworkCore.cs:209:13:209:15 | [post] access to local variable ctx [PersonAddresses, [], Person, Name] : String | EntityFrameworkCore.cs:216:13:216:15 | access to local variable ctx [PersonAddresses, [], Person, Name] : String | -| EntityFrameworkCore.cs:209:13:209:31 | [post] access to property PersonAddresses [[], Address, Street] : String | EntityFrameworkCore.cs:209:13:209:15 | [post] access to local variable ctx [PersonAddresses, [], Address, Street] : String | -| EntityFrameworkCore.cs:209:13:209:31 | [post] access to property PersonAddresses [[], Person, Name] : String | EntityFrameworkCore.cs:209:13:209:15 | [post] access to local variable ctx [PersonAddresses, [], Person, Name] : String | -| EntityFrameworkCore.cs:209:37:209:53 | access to local variable personAddressMap1 [Address, Street] : String | EntityFrameworkCore.cs:209:13:209:31 | [post] access to property PersonAddresses [[], Address, Street] : String | -| EntityFrameworkCore.cs:209:37:209:53 | access to local variable personAddressMap1 [Person, Name] : String | EntityFrameworkCore.cs:209:13:209:31 | [post] access to property PersonAddresses [[], Person, Name] : String | -| EntityFrameworkCore.cs:210:13:210:15 | access to local variable ctx [PersonAddresses, [], Address, Street] : String | ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [PersonAddresses, [], Address, Street] : String | -| EntityFrameworkCore.cs:210:13:210:15 | access to local variable ctx [PersonAddresses, [], Person, Name] : String | ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [PersonAddresses, [], Person, Name] : String | -| EntityFrameworkCore.cs:216:13:216:15 | access to local variable ctx [PersonAddresses, [], Address, Street] : String | ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [PersonAddresses, [], Address, Street] : String | -| EntityFrameworkCore.cs:216:13:216:15 | access to local variable ctx [PersonAddresses, [], Person, Name] : String | ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [PersonAddresses, [], Person, Name] : String | -| EntityFrameworkCore.cs:219:35:219:35 | p [Name] : String | EntityFrameworkCore.cs:222:29:222:29 | access to parameter p [Name] : String | -| EntityFrameworkCore.cs:222:13:222:15 | [post] access to local variable ctx [Persons, [], Name] : String | EntityFrameworkCore.cs:223:13:223:15 | access to local variable ctx [Persons, [], Name] : String | -| EntityFrameworkCore.cs:222:13:222:23 | [post] access to property Persons [[], Name] : String | EntityFrameworkCore.cs:222:13:222:15 | [post] access to local variable ctx [Persons, [], Name] : String | -| EntityFrameworkCore.cs:222:29:222:29 | access to parameter p [Name] : String | EntityFrameworkCore.cs:222:13:222:23 | [post] access to property Persons [[], Name] : String | -| EntityFrameworkCore.cs:223:13:223:15 | access to local variable ctx [Persons, [], Name] : String | ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [Persons, [], Name] : String | -| EntityFrameworkCore.cs:230:18:230:28 | access to property Persons [[], Name] : String | EntityFrameworkCore.cs:230:18:230:36 | call to method First [Name] : String | -| EntityFrameworkCore.cs:230:18:230:36 | call to method First [Name] : String | EntityFrameworkCore.cs:230:18:230:41 | access to property Name | -| EntityFrameworkCore.cs:238:18:238:30 | access to property Addresses [[], Street] : String | EntityFrameworkCore.cs:238:18:238:38 | call to method First [Street] : String | -| EntityFrameworkCore.cs:238:18:238:38 | call to method First [Street] : String | EntityFrameworkCore.cs:238:18:238:45 | access to property Street | -| EntityFrameworkCore.cs:245:18:245:28 | access to property Persons [[], Addresses, [], Street] : String | EntityFrameworkCore.cs:245:18:245:36 | call to method First [Addresses, [], Street] : String | -| EntityFrameworkCore.cs:245:18:245:36 | call to method First [Addresses, [], Street] : String | EntityFrameworkCore.cs:245:18:245:46 | access to property Addresses [[], Street] : String | -| EntityFrameworkCore.cs:245:18:245:46 | access to property Addresses [[], Street] : String | EntityFrameworkCore.cs:245:18:245:54 | call to method First [Street] : String | -| EntityFrameworkCore.cs:245:18:245:54 | call to method First [Street] : String | EntityFrameworkCore.cs:245:18:245:61 | access to property Street | +| EntityFrameworkCore.cs:85:13:88:13 | { ..., ... } [property Name] : String | EntityFrameworkCore.cs:92:29:92:30 | access to local variable p1 [property Name] : String | +| EntityFrameworkCore.cs:87:24:87:32 | "tainted" : String | EntityFrameworkCore.cs:85:13:88:13 | { ..., ... } [property Name] : String | +| EntityFrameworkCore.cs:92:13:92:15 | [post] access to local variable ctx [property Persons, element, property Name] : String | EntityFrameworkCore.cs:94:13:94:15 | access to local variable ctx [property Persons, element, property Name] : String | +| EntityFrameworkCore.cs:92:13:92:23 | [post] access to property Persons [element, property Name] : String | EntityFrameworkCore.cs:92:13:92:15 | [post] access to local variable ctx [property Persons, element, property Name] : String | +| EntityFrameworkCore.cs:92:29:92:30 | access to local variable p1 [property Name] : String | EntityFrameworkCore.cs:92:13:92:23 | [post] access to property Persons [element, property Name] : String | +| EntityFrameworkCore.cs:94:13:94:15 | access to local variable ctx [property Persons, element, property Name] : String | ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [property Persons, element, property Name] : String | +| EntityFrameworkCore.cs:107:13:110:13 | { ..., ... } [property Name] : String | EntityFrameworkCore.cs:114:29:114:30 | access to local variable p1 [property Name] : String | +| EntityFrameworkCore.cs:109:24:109:32 | "tainted" : String | EntityFrameworkCore.cs:107:13:110:13 | { ..., ... } [property Name] : String | +| EntityFrameworkCore.cs:114:13:114:15 | [post] access to local variable ctx [property Persons, element, property Name] : String | EntityFrameworkCore.cs:116:19:116:21 | access to local variable ctx [property Persons, element, property Name] : String | +| EntityFrameworkCore.cs:114:13:114:23 | [post] access to property Persons [element, property Name] : String | EntityFrameworkCore.cs:114:13:114:15 | [post] access to local variable ctx [property Persons, element, property Name] : String | +| EntityFrameworkCore.cs:114:29:114:30 | access to local variable p1 [property Name] : String | EntityFrameworkCore.cs:114:13:114:23 | [post] access to property Persons [element, property Name] : String | +| EntityFrameworkCore.cs:116:19:116:21 | access to local variable ctx [property Persons, element, property Name] : String | ../../../resources/stubs/EntityFramework.cs:81:49:81:64 | this [property Persons, element, property Name] : String | +| EntityFrameworkCore.cs:129:13:132:13 | { ..., ... } [property Name] : String | EntityFrameworkCore.cs:135:27:135:28 | access to local variable p1 [property Name] : String | +| EntityFrameworkCore.cs:131:24:131:32 | "tainted" : String | EntityFrameworkCore.cs:129:13:132:13 | { ..., ... } [property Name] : String | +| EntityFrameworkCore.cs:135:27:135:28 | access to local variable p1 [property Name] : String | EntityFrameworkCore.cs:219:35:219:35 | p [property Name] : String | +| EntityFrameworkCore.cs:148:13:151:13 | { ..., ... } [property Title] : String | EntityFrameworkCore.cs:155:18:155:19 | access to local variable p1 [property Title] : String | +| EntityFrameworkCore.cs:150:25:150:33 | "tainted" : String | EntityFrameworkCore.cs:148:13:151:13 | { ..., ... } [property Title] : String | +| EntityFrameworkCore.cs:155:18:155:19 | access to local variable p1 [property Title] : String | EntityFrameworkCore.cs:155:18:155:25 | access to property Title | +| EntityFrameworkCore.cs:167:13:174:13 | { ..., ... } [property Addresses, element, property Street] : String | EntityFrameworkCore.cs:175:29:175:30 | access to local variable p1 [property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:168:29:173:17 | array creation of type Address[] [element, property Street] : String | EntityFrameworkCore.cs:167:13:174:13 | { ..., ... } [property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:168:35:173:17 | { ..., ... } [element, property Street] : String | EntityFrameworkCore.cs:168:29:173:17 | array creation of type Address[] [element, property Street] : String | +| EntityFrameworkCore.cs:169:21:172:21 | object creation of type Address [property Street] : String | EntityFrameworkCore.cs:168:35:173:17 | { ..., ... } [element, property Street] : String | +| EntityFrameworkCore.cs:169:33:172:21 | { ..., ... } [property Street] : String | EntityFrameworkCore.cs:169:21:172:21 | object creation of type Address [property Street] : String | +| EntityFrameworkCore.cs:171:34:171:42 | "tainted" : String | EntityFrameworkCore.cs:169:33:172:21 | { ..., ... } [property Street] : String | +| EntityFrameworkCore.cs:175:13:175:15 | [post] access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | EntityFrameworkCore.cs:176:13:176:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:175:13:175:15 | [post] access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | EntityFrameworkCore.cs:180:13:180:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:175:13:175:15 | [post] access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | EntityFrameworkCore.cs:188:13:188:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:175:13:175:15 | [post] access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | EntityFrameworkCore.cs:192:13:192:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:175:13:175:23 | [post] access to property Persons [element, property Addresses, element, property Street] : String | EntityFrameworkCore.cs:175:13:175:15 | [post] access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:175:29:175:30 | access to local variable p1 [property Addresses, element, property Street] : String | EntityFrameworkCore.cs:175:13:175:23 | [post] access to property Persons [element, property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:176:13:176:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [property Persons, element, property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:180:13:180:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [property Persons, element, property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:183:13:186:13 | { ..., ... } [property Street] : String | EntityFrameworkCore.cs:187:31:187:32 | access to local variable a1 [property Street] : String | +| EntityFrameworkCore.cs:185:26:185:34 | "tainted" : String | EntityFrameworkCore.cs:183:13:186:13 | { ..., ... } [property Street] : String | +| EntityFrameworkCore.cs:187:13:187:15 | [post] access to local variable ctx [property Addresses, element, property Street] : String | EntityFrameworkCore.cs:188:13:188:15 | access to local variable ctx [property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:187:13:187:15 | [post] access to local variable ctx [property Addresses, element, property Street] : String | EntityFrameworkCore.cs:192:13:192:15 | access to local variable ctx [property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:187:13:187:25 | [post] access to property Addresses [element, property Street] : String | EntityFrameworkCore.cs:187:13:187:15 | [post] access to local variable ctx [property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:187:31:187:32 | access to local variable a1 [property Street] : String | EntityFrameworkCore.cs:187:13:187:25 | [post] access to property Addresses [element, property Street] : String | +| EntityFrameworkCore.cs:188:13:188:15 | access to local variable ctx [property Addresses, element, property Street] : String | ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:188:13:188:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [property Persons, element, property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:192:13:192:15 | access to local variable ctx [property Addresses, element, property Street] : String | ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:192:13:192:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [property Persons, element, property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:199:13:202:13 | { ..., ... } [property Name] : String | EntityFrameworkCore.cs:208:71:208:72 | access to local variable p1 [property Name] : String | +| EntityFrameworkCore.cs:201:24:201:32 | "tainted" : String | EntityFrameworkCore.cs:199:13:202:13 | { ..., ... } [property Name] : String | +| EntityFrameworkCore.cs:204:13:207:13 | { ..., ... } [property Street] : String | EntityFrameworkCore.cs:208:85:208:86 | access to local variable a1 [property Street] : String | +| EntityFrameworkCore.cs:206:26:206:34 | "tainted" : String | EntityFrameworkCore.cs:204:13:207:13 | { ..., ... } [property Street] : String | +| EntityFrameworkCore.cs:208:60:208:88 | { ..., ... } [property Address, property Street] : String | EntityFrameworkCore.cs:209:37:209:53 | access to local variable personAddressMap1 [property Address, property Street] : String | +| EntityFrameworkCore.cs:208:60:208:88 | { ..., ... } [property Person, property Name] : String | EntityFrameworkCore.cs:209:37:209:53 | access to local variable personAddressMap1 [property Person, property Name] : String | +| EntityFrameworkCore.cs:208:71:208:72 | access to local variable p1 [property Name] : String | EntityFrameworkCore.cs:208:60:208:88 | { ..., ... } [property Person, property Name] : String | +| EntityFrameworkCore.cs:208:85:208:86 | access to local variable a1 [property Street] : String | EntityFrameworkCore.cs:208:60:208:88 | { ..., ... } [property Address, property Street] : String | +| EntityFrameworkCore.cs:209:13:209:15 | [post] access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | EntityFrameworkCore.cs:210:13:210:15 | access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | +| EntityFrameworkCore.cs:209:13:209:15 | [post] access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | EntityFrameworkCore.cs:216:13:216:15 | access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | +| EntityFrameworkCore.cs:209:13:209:15 | [post] access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | EntityFrameworkCore.cs:210:13:210:15 | access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | +| EntityFrameworkCore.cs:209:13:209:15 | [post] access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | EntityFrameworkCore.cs:216:13:216:15 | access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | +| EntityFrameworkCore.cs:209:13:209:31 | [post] access to property PersonAddresses [element, property Address, property Street] : String | EntityFrameworkCore.cs:209:13:209:15 | [post] access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | +| EntityFrameworkCore.cs:209:13:209:31 | [post] access to property PersonAddresses [element, property Person, property Name] : String | EntityFrameworkCore.cs:209:13:209:15 | [post] access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | +| EntityFrameworkCore.cs:209:37:209:53 | access to local variable personAddressMap1 [property Address, property Street] : String | EntityFrameworkCore.cs:209:13:209:31 | [post] access to property PersonAddresses [element, property Address, property Street] : String | +| EntityFrameworkCore.cs:209:37:209:53 | access to local variable personAddressMap1 [property Person, property Name] : String | EntityFrameworkCore.cs:209:13:209:31 | [post] access to property PersonAddresses [element, property Person, property Name] : String | +| EntityFrameworkCore.cs:210:13:210:15 | access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [property PersonAddresses, element, property Address, property Street] : String | +| EntityFrameworkCore.cs:210:13:210:15 | access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [property PersonAddresses, element, property Person, property Name] : String | +| EntityFrameworkCore.cs:216:13:216:15 | access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [property PersonAddresses, element, property Address, property Street] : String | +| EntityFrameworkCore.cs:216:13:216:15 | access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [property PersonAddresses, element, property Person, property Name] : String | +| EntityFrameworkCore.cs:219:35:219:35 | p [property Name] : String | EntityFrameworkCore.cs:222:29:222:29 | access to parameter p [property Name] : String | +| EntityFrameworkCore.cs:222:13:222:15 | [post] access to local variable ctx [property Persons, element, property Name] : String | EntityFrameworkCore.cs:223:13:223:15 | access to local variable ctx [property Persons, element, property Name] : String | +| EntityFrameworkCore.cs:222:13:222:23 | [post] access to property Persons [element, property Name] : String | EntityFrameworkCore.cs:222:13:222:15 | [post] access to local variable ctx [property Persons, element, property Name] : String | +| EntityFrameworkCore.cs:222:29:222:29 | access to parameter p [property Name] : String | EntityFrameworkCore.cs:222:13:222:23 | [post] access to property Persons [element, property Name] : String | +| EntityFrameworkCore.cs:223:13:223:15 | access to local variable ctx [property Persons, element, property Name] : String | ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [property Persons, element, property Name] : String | +| EntityFrameworkCore.cs:230:18:230:28 | access to property Persons [element, property Name] : String | EntityFrameworkCore.cs:230:18:230:36 | call to method First [property Name] : String | +| EntityFrameworkCore.cs:230:18:230:36 | call to method First [property Name] : String | EntityFrameworkCore.cs:230:18:230:41 | access to property Name | +| EntityFrameworkCore.cs:238:18:238:30 | access to property Addresses [element, property Street] : String | EntityFrameworkCore.cs:238:18:238:38 | call to method First [property Street] : String | +| EntityFrameworkCore.cs:238:18:238:38 | call to method First [property Street] : String | EntityFrameworkCore.cs:238:18:238:45 | access to property Street | +| EntityFrameworkCore.cs:245:18:245:28 | access to property Persons [element, property Addresses, element, property Street] : String | EntityFrameworkCore.cs:245:18:245:36 | call to method First [property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:245:18:245:36 | call to method First [property Addresses, element, property Street] : String | EntityFrameworkCore.cs:245:18:245:46 | access to property Addresses [element, property Street] : String | +| EntityFrameworkCore.cs:245:18:245:46 | access to property Addresses [element, property Street] : String | EntityFrameworkCore.cs:245:18:245:54 | call to method First [property Street] : String | +| EntityFrameworkCore.cs:245:18:245:54 | call to method First [property Street] : String | EntityFrameworkCore.cs:245:18:245:61 | access to property Street | nodes -| ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [Addresses, [], Street] : String | semmle.label | this [Addresses, [], Street] : String | -| ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [PersonAddresses, [], Address, Street] : String | semmle.label | this [PersonAddresses, [], Address, Street] : String | -| ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [PersonAddresses, [], Person, Name] : String | semmle.label | this [PersonAddresses, [], Person, Name] : String | -| ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [Persons, [], Addresses, [], Street] : String | semmle.label | this [Persons, [], Addresses, [], Street] : String | -| ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [Persons, [], Name] : String | semmle.label | this [Persons, [], Name] : String | -| ../../../resources/stubs/EntityFramework.cs:41:49:41:64 | this [Persons, [], Name] : String | semmle.label | this [Persons, [], Name] : String | -| ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [Addresses, [], Street] : String | semmle.label | this [Addresses, [], Street] : String | -| ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [PersonAddresses, [], Address, Street] : String | semmle.label | this [PersonAddresses, [], Address, Street] : String | -| ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [PersonAddresses, [], Person, Name] : String | semmle.label | this [PersonAddresses, [], Person, Name] : String | -| ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [Persons, [], Addresses, [], Street] : String | semmle.label | this [Persons, [], Addresses, [], Street] : String | -| ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [Persons, [], Name] : String | semmle.label | this [Persons, [], Name] : String | -| ../../../resources/stubs/EntityFramework.cs:81:49:81:64 | this [Persons, [], Name] : String | semmle.label | this [Persons, [], Name] : String | -| EntityFramework.cs:61:13:64:13 | { ..., ... } [Name] : String | semmle.label | { ..., ... } [Name] : String | +| ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [property Addresses, element, property Street] : String | semmle.label | this [property Addresses, element, property Street] : String | +| ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [property PersonAddresses, element, property Address, property Street] : String | semmle.label | this [property PersonAddresses, element, property Address, property Street] : String | +| ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [property PersonAddresses, element, property Person, property Name] : String | semmle.label | this [property PersonAddresses, element, property Person, property Name] : String | +| ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [property Persons, element, property Addresses, element, property Street] : String | semmle.label | this [property Persons, element, property Addresses, element, property Street] : String | +| ../../../resources/stubs/EntityFramework.cs:40:20:40:30 | this [property Persons, element, property Name] : String | semmle.label | this [property Persons, element, property Name] : String | +| ../../../resources/stubs/EntityFramework.cs:41:49:41:64 | this [property Persons, element, property Name] : String | semmle.label | this [property Persons, element, property Name] : String | +| ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [property Addresses, element, property Street] : String | semmle.label | this [property Addresses, element, property Street] : String | +| ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [property PersonAddresses, element, property Address, property Street] : String | semmle.label | this [property PersonAddresses, element, property Address, property Street] : String | +| ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [property PersonAddresses, element, property Person, property Name] : String | semmle.label | this [property PersonAddresses, element, property Person, property Name] : String | +| ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [property Persons, element, property Addresses, element, property Street] : String | semmle.label | this [property Persons, element, property Addresses, element, property Street] : String | +| ../../../resources/stubs/EntityFramework.cs:80:20:80:30 | this [property Persons, element, property Name] : String | semmle.label | this [property Persons, element, property Name] : String | +| ../../../resources/stubs/EntityFramework.cs:81:49:81:64 | this [property Persons, element, property Name] : String | semmle.label | this [property Persons, element, property Name] : String | +| EntityFramework.cs:61:13:64:13 | { ..., ... } [property Name] : String | semmle.label | { ..., ... } [property Name] : String | | EntityFramework.cs:63:24:63:32 | "tainted" : String | semmle.label | "tainted" : String | -| EntityFramework.cs:68:13:68:15 | [post] access to local variable ctx [Persons, [], Name] : String | semmle.label | [post] access to local variable ctx [Persons, [], Name] : String | -| EntityFramework.cs:68:13:68:23 | [post] access to property Persons [[], Name] : String | semmle.label | [post] access to property Persons [[], Name] : String | -| EntityFramework.cs:68:29:68:30 | access to local variable p1 [Name] : String | semmle.label | access to local variable p1 [Name] : String | -| EntityFramework.cs:70:13:70:15 | access to local variable ctx [Persons, [], Name] : String | semmle.label | access to local variable ctx [Persons, [], Name] : String | -| EntityFramework.cs:83:13:86:13 | { ..., ... } [Name] : String | semmle.label | { ..., ... } [Name] : String | +| EntityFramework.cs:68:13:68:15 | [post] access to local variable ctx [property Persons, element, property Name] : String | semmle.label | [post] access to local variable ctx [property Persons, element, property Name] : String | +| EntityFramework.cs:68:13:68:23 | [post] access to property Persons [element, property Name] : String | semmle.label | [post] access to property Persons [element, property Name] : String | +| EntityFramework.cs:68:29:68:30 | access to local variable p1 [property Name] : String | semmle.label | access to local variable p1 [property Name] : String | +| EntityFramework.cs:70:13:70:15 | access to local variable ctx [property Persons, element, property Name] : String | semmle.label | access to local variable ctx [property Persons, element, property Name] : String | +| EntityFramework.cs:83:13:86:13 | { ..., ... } [property Name] : String | semmle.label | { ..., ... } [property Name] : String | | EntityFramework.cs:85:24:85:32 | "tainted" : String | semmle.label | "tainted" : String | -| EntityFramework.cs:90:13:90:15 | [post] access to local variable ctx [Persons, [], Name] : String | semmle.label | [post] access to local variable ctx [Persons, [], Name] : String | -| EntityFramework.cs:90:13:90:23 | [post] access to property Persons [[], Name] : String | semmle.label | [post] access to property Persons [[], Name] : String | -| EntityFramework.cs:90:29:90:30 | access to local variable p1 [Name] : String | semmle.label | access to local variable p1 [Name] : String | -| EntityFramework.cs:92:19:92:21 | access to local variable ctx [Persons, [], Name] : String | semmle.label | access to local variable ctx [Persons, [], Name] : String | -| EntityFramework.cs:105:13:108:13 | { ..., ... } [Name] : String | semmle.label | { ..., ... } [Name] : String | +| EntityFramework.cs:90:13:90:15 | [post] access to local variable ctx [property Persons, element, property Name] : String | semmle.label | [post] access to local variable ctx [property Persons, element, property Name] : String | +| EntityFramework.cs:90:13:90:23 | [post] access to property Persons [element, property Name] : String | semmle.label | [post] access to property Persons [element, property Name] : String | +| EntityFramework.cs:90:29:90:30 | access to local variable p1 [property Name] : String | semmle.label | access to local variable p1 [property Name] : String | +| EntityFramework.cs:92:19:92:21 | access to local variable ctx [property Persons, element, property Name] : String | semmle.label | access to local variable ctx [property Persons, element, property Name] : String | +| EntityFramework.cs:105:13:108:13 | { ..., ... } [property Name] : String | semmle.label | { ..., ... } [property Name] : String | | EntityFramework.cs:107:24:107:32 | "tainted" : String | semmle.label | "tainted" : String | -| EntityFramework.cs:111:27:111:28 | access to local variable p1 [Name] : String | semmle.label | access to local variable p1 [Name] : String | -| EntityFramework.cs:124:13:127:13 | { ..., ... } [Title] : String | semmle.label | { ..., ... } [Title] : String | +| EntityFramework.cs:111:27:111:28 | access to local variable p1 [property Name] : String | semmle.label | access to local variable p1 [property Name] : String | +| EntityFramework.cs:124:13:127:13 | { ..., ... } [property Title] : String | semmle.label | { ..., ... } [property Title] : String | | EntityFramework.cs:126:25:126:33 | "tainted" : String | semmle.label | "tainted" : String | -| EntityFramework.cs:131:18:131:19 | access to local variable p1 [Title] : String | semmle.label | access to local variable p1 [Title] : String | +| EntityFramework.cs:131:18:131:19 | access to local variable p1 [property Title] : String | semmle.label | access to local variable p1 [property Title] : String | | EntityFramework.cs:131:18:131:25 | access to property Title | semmle.label | access to property Title | -| EntityFramework.cs:143:13:150:13 | { ..., ... } [Addresses, [], Street] : String | semmle.label | { ..., ... } [Addresses, [], Street] : String | -| EntityFramework.cs:144:29:149:17 | array creation of type Address[] [[], Street] : String | semmle.label | array creation of type Address[] [[], Street] : String | -| EntityFramework.cs:144:35:149:17 | { ..., ... } [[], Street] : String | semmle.label | { ..., ... } [[], Street] : String | -| EntityFramework.cs:145:21:148:21 | object creation of type Address [Street] : String | semmle.label | object creation of type Address [Street] : String | -| EntityFramework.cs:145:33:148:21 | { ..., ... } [Street] : String | semmle.label | { ..., ... } [Street] : String | +| EntityFramework.cs:143:13:150:13 | { ..., ... } [property Addresses, element, property Street] : String | semmle.label | { ..., ... } [property Addresses, element, property Street] : String | +| EntityFramework.cs:144:29:149:17 | array creation of type Address[] [element, property Street] : String | semmle.label | array creation of type Address[] [element, property Street] : String | +| EntityFramework.cs:144:35:149:17 | { ..., ... } [element, property Street] : String | semmle.label | { ..., ... } [element, property Street] : String | +| EntityFramework.cs:145:21:148:21 | object creation of type Address [property Street] : String | semmle.label | object creation of type Address [property Street] : String | +| EntityFramework.cs:145:33:148:21 | { ..., ... } [property Street] : String | semmle.label | { ..., ... } [property Street] : String | | EntityFramework.cs:147:34:147:42 | "tainted" : String | semmle.label | "tainted" : String | -| EntityFramework.cs:151:13:151:15 | [post] access to local variable ctx [Persons, [], Addresses, [], Street] : String | semmle.label | [post] access to local variable ctx [Persons, [], Addresses, [], Street] : String | -| EntityFramework.cs:151:13:151:23 | [post] access to property Persons [[], Addresses, [], Street] : String | semmle.label | [post] access to property Persons [[], Addresses, [], Street] : String | -| EntityFramework.cs:151:29:151:30 | access to local variable p1 [Addresses, [], Street] : String | semmle.label | access to local variable p1 [Addresses, [], Street] : String | -| EntityFramework.cs:152:13:152:15 | access to local variable ctx [Persons, [], Addresses, [], Street] : String | semmle.label | access to local variable ctx [Persons, [], Addresses, [], Street] : String | -| EntityFramework.cs:156:13:156:15 | access to local variable ctx [Persons, [], Addresses, [], Street] : String | semmle.label | access to local variable ctx [Persons, [], Addresses, [], Street] : String | -| EntityFramework.cs:159:13:162:13 | { ..., ... } [Street] : String | semmle.label | { ..., ... } [Street] : String | +| EntityFramework.cs:151:13:151:15 | [post] access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | semmle.label | [post] access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | +| EntityFramework.cs:151:13:151:23 | [post] access to property Persons [element, property Addresses, element, property Street] : String | semmle.label | [post] access to property Persons [element, property Addresses, element, property Street] : String | +| EntityFramework.cs:151:29:151:30 | access to local variable p1 [property Addresses, element, property Street] : String | semmle.label | access to local variable p1 [property Addresses, element, property Street] : String | +| EntityFramework.cs:152:13:152:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | semmle.label | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | +| EntityFramework.cs:156:13:156:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | semmle.label | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | +| EntityFramework.cs:159:13:162:13 | { ..., ... } [property Street] : String | semmle.label | { ..., ... } [property Street] : String | | EntityFramework.cs:161:26:161:34 | "tainted" : String | semmle.label | "tainted" : String | -| EntityFramework.cs:163:13:163:15 | [post] access to local variable ctx [Addresses, [], Street] : String | semmle.label | [post] access to local variable ctx [Addresses, [], Street] : String | -| EntityFramework.cs:163:13:163:25 | [post] access to property Addresses [[], Street] : String | semmle.label | [post] access to property Addresses [[], Street] : String | -| EntityFramework.cs:163:31:163:32 | access to local variable a1 [Street] : String | semmle.label | access to local variable a1 [Street] : String | -| EntityFramework.cs:164:13:164:15 | access to local variable ctx [Addresses, [], Street] : String | semmle.label | access to local variable ctx [Addresses, [], Street] : String | -| EntityFramework.cs:164:13:164:15 | access to local variable ctx [Persons, [], Addresses, [], Street] : String | semmle.label | access to local variable ctx [Persons, [], Addresses, [], Street] : String | -| EntityFramework.cs:168:13:168:15 | access to local variable ctx [Addresses, [], Street] : String | semmle.label | access to local variable ctx [Addresses, [], Street] : String | -| EntityFramework.cs:168:13:168:15 | access to local variable ctx [Persons, [], Addresses, [], Street] : String | semmle.label | access to local variable ctx [Persons, [], Addresses, [], Street] : String | -| EntityFramework.cs:175:13:178:13 | { ..., ... } [Name] : String | semmle.label | { ..., ... } [Name] : String | +| EntityFramework.cs:163:13:163:15 | [post] access to local variable ctx [property Addresses, element, property Street] : String | semmle.label | [post] access to local variable ctx [property Addresses, element, property Street] : String | +| EntityFramework.cs:163:13:163:25 | [post] access to property Addresses [element, property Street] : String | semmle.label | [post] access to property Addresses [element, property Street] : String | +| EntityFramework.cs:163:31:163:32 | access to local variable a1 [property Street] : String | semmle.label | access to local variable a1 [property Street] : String | +| EntityFramework.cs:164:13:164:15 | access to local variable ctx [property Addresses, element, property Street] : String | semmle.label | access to local variable ctx [property Addresses, element, property Street] : String | +| EntityFramework.cs:164:13:164:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | semmle.label | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | +| EntityFramework.cs:168:13:168:15 | access to local variable ctx [property Addresses, element, property Street] : String | semmle.label | access to local variable ctx [property Addresses, element, property Street] : String | +| EntityFramework.cs:168:13:168:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | semmle.label | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | +| EntityFramework.cs:175:13:178:13 | { ..., ... } [property Name] : String | semmle.label | { ..., ... } [property Name] : String | | EntityFramework.cs:177:24:177:32 | "tainted" : String | semmle.label | "tainted" : String | -| EntityFramework.cs:180:13:183:13 | { ..., ... } [Street] : String | semmle.label | { ..., ... } [Street] : String | +| EntityFramework.cs:180:13:183:13 | { ..., ... } [property Street] : String | semmle.label | { ..., ... } [property Street] : String | | EntityFramework.cs:182:26:182:34 | "tainted" : String | semmle.label | "tainted" : String | -| EntityFramework.cs:184:60:184:88 | { ..., ... } [Address, Street] : String | semmle.label | { ..., ... } [Address, Street] : String | -| EntityFramework.cs:184:60:184:88 | { ..., ... } [Person, Name] : String | semmle.label | { ..., ... } [Person, Name] : String | -| EntityFramework.cs:184:71:184:72 | access to local variable p1 [Name] : String | semmle.label | access to local variable p1 [Name] : String | -| EntityFramework.cs:184:85:184:86 | access to local variable a1 [Street] : String | semmle.label | access to local variable a1 [Street] : String | -| EntityFramework.cs:185:13:185:15 | [post] access to local variable ctx [PersonAddresses, [], Address, Street] : String | semmle.label | [post] access to local variable ctx [PersonAddresses, [], Address, Street] : String | -| EntityFramework.cs:185:13:185:15 | [post] access to local variable ctx [PersonAddresses, [], Person, Name] : String | semmle.label | [post] access to local variable ctx [PersonAddresses, [], Person, Name] : String | -| EntityFramework.cs:185:13:185:31 | [post] access to property PersonAddresses [[], Address, Street] : String | semmle.label | [post] access to property PersonAddresses [[], Address, Street] : String | -| EntityFramework.cs:185:13:185:31 | [post] access to property PersonAddresses [[], Person, Name] : String | semmle.label | [post] access to property PersonAddresses [[], Person, Name] : String | -| EntityFramework.cs:185:37:185:53 | access to local variable personAddressMap1 [Address, Street] : String | semmle.label | access to local variable personAddressMap1 [Address, Street] : String | -| EntityFramework.cs:185:37:185:53 | access to local variable personAddressMap1 [Person, Name] : String | semmle.label | access to local variable personAddressMap1 [Person, Name] : String | -| EntityFramework.cs:186:13:186:15 | access to local variable ctx [PersonAddresses, [], Address, Street] : String | semmle.label | access to local variable ctx [PersonAddresses, [], Address, Street] : String | -| EntityFramework.cs:186:13:186:15 | access to local variable ctx [PersonAddresses, [], Person, Name] : String | semmle.label | access to local variable ctx [PersonAddresses, [], Person, Name] : String | -| EntityFramework.cs:192:13:192:15 | access to local variable ctx [PersonAddresses, [], Address, Street] : String | semmle.label | access to local variable ctx [PersonAddresses, [], Address, Street] : String | -| EntityFramework.cs:192:13:192:15 | access to local variable ctx [PersonAddresses, [], Person, Name] : String | semmle.label | access to local variable ctx [PersonAddresses, [], Person, Name] : String | -| EntityFramework.cs:195:35:195:35 | p [Name] : String | semmle.label | p [Name] : String | -| EntityFramework.cs:198:13:198:15 | [post] access to local variable ctx [Persons, [], Name] : String | semmle.label | [post] access to local variable ctx [Persons, [], Name] : String | -| EntityFramework.cs:198:13:198:23 | [post] access to property Persons [[], Name] : String | semmle.label | [post] access to property Persons [[], Name] : String | -| EntityFramework.cs:198:29:198:29 | access to parameter p [Name] : String | semmle.label | access to parameter p [Name] : String | -| EntityFramework.cs:199:13:199:15 | access to local variable ctx [Persons, [], Name] : String | semmle.label | access to local variable ctx [Persons, [], Name] : String | -| EntityFramework.cs:206:18:206:28 | access to property Persons [[], Name] : String | semmle.label | access to property Persons [[], Name] : String | -| EntityFramework.cs:206:18:206:36 | call to method First [Name] : String | semmle.label | call to method First [Name] : String | +| EntityFramework.cs:184:60:184:88 | { ..., ... } [property Address, property Street] : String | semmle.label | { ..., ... } [property Address, property Street] : String | +| EntityFramework.cs:184:60:184:88 | { ..., ... } [property Person, property Name] : String | semmle.label | { ..., ... } [property Person, property Name] : String | +| EntityFramework.cs:184:71:184:72 | access to local variable p1 [property Name] : String | semmle.label | access to local variable p1 [property Name] : String | +| EntityFramework.cs:184:85:184:86 | access to local variable a1 [property Street] : String | semmle.label | access to local variable a1 [property Street] : String | +| EntityFramework.cs:185:13:185:15 | [post] access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | semmle.label | [post] access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | +| EntityFramework.cs:185:13:185:15 | [post] access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | semmle.label | [post] access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | +| EntityFramework.cs:185:13:185:31 | [post] access to property PersonAddresses [element, property Address, property Street] : String | semmle.label | [post] access to property PersonAddresses [element, property Address, property Street] : String | +| EntityFramework.cs:185:13:185:31 | [post] access to property PersonAddresses [element, property Person, property Name] : String | semmle.label | [post] access to property PersonAddresses [element, property Person, property Name] : String | +| EntityFramework.cs:185:37:185:53 | access to local variable personAddressMap1 [property Address, property Street] : String | semmle.label | access to local variable personAddressMap1 [property Address, property Street] : String | +| EntityFramework.cs:185:37:185:53 | access to local variable personAddressMap1 [property Person, property Name] : String | semmle.label | access to local variable personAddressMap1 [property Person, property Name] : String | +| EntityFramework.cs:186:13:186:15 | access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | semmle.label | access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | +| EntityFramework.cs:186:13:186:15 | access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | semmle.label | access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | +| EntityFramework.cs:192:13:192:15 | access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | semmle.label | access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | +| EntityFramework.cs:192:13:192:15 | access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | semmle.label | access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | +| EntityFramework.cs:195:35:195:35 | p [property Name] : String | semmle.label | p [property Name] : String | +| EntityFramework.cs:198:13:198:15 | [post] access to local variable ctx [property Persons, element, property Name] : String | semmle.label | [post] access to local variable ctx [property Persons, element, property Name] : String | +| EntityFramework.cs:198:13:198:23 | [post] access to property Persons [element, property Name] : String | semmle.label | [post] access to property Persons [element, property Name] : String | +| EntityFramework.cs:198:29:198:29 | access to parameter p [property Name] : String | semmle.label | access to parameter p [property Name] : String | +| EntityFramework.cs:199:13:199:15 | access to local variable ctx [property Persons, element, property Name] : String | semmle.label | access to local variable ctx [property Persons, element, property Name] : String | +| EntityFramework.cs:206:18:206:28 | access to property Persons [element, property Name] : String | semmle.label | access to property Persons [element, property Name] : String | +| EntityFramework.cs:206:18:206:36 | call to method First [property Name] : String | semmle.label | call to method First [property Name] : String | | EntityFramework.cs:206:18:206:41 | access to property Name | semmle.label | access to property Name | -| EntityFramework.cs:214:18:214:30 | access to property Addresses [[], Street] : String | semmle.label | access to property Addresses [[], Street] : String | -| EntityFramework.cs:214:18:214:38 | call to method First [Street] : String | semmle.label | call to method First [Street] : String | +| EntityFramework.cs:214:18:214:30 | access to property Addresses [element, property Street] : String | semmle.label | access to property Addresses [element, property Street] : String | +| EntityFramework.cs:214:18:214:38 | call to method First [property Street] : String | semmle.label | call to method First [property Street] : String | | EntityFramework.cs:214:18:214:45 | access to property Street | semmle.label | access to property Street | -| EntityFramework.cs:221:18:221:28 | access to property Persons [[], Addresses, [], Street] : String | semmle.label | access to property Persons [[], Addresses, [], Street] : String | -| EntityFramework.cs:221:18:221:36 | call to method First [Addresses, [], Street] : String | semmle.label | call to method First [Addresses, [], Street] : String | -| EntityFramework.cs:221:18:221:46 | access to property Addresses [[], Street] : String | semmle.label | access to property Addresses [[], Street] : String | -| EntityFramework.cs:221:18:221:54 | call to method First [Street] : String | semmle.label | call to method First [Street] : String | +| EntityFramework.cs:221:18:221:28 | access to property Persons [element, property Addresses, element, property Street] : String | semmle.label | access to property Persons [element, property Addresses, element, property Street] : String | +| EntityFramework.cs:221:18:221:36 | call to method First [property Addresses, element, property Street] : String | semmle.label | call to method First [property Addresses, element, property Street] : String | +| EntityFramework.cs:221:18:221:46 | access to property Addresses [element, property Street] : String | semmle.label | access to property Addresses [element, property Street] : String | +| EntityFramework.cs:221:18:221:54 | call to method First [property Street] : String | semmle.label | call to method First [property Street] : String | | EntityFramework.cs:221:18:221:61 | access to property Street | semmle.label | access to property Street | | EntityFrameworkCore.cs:75:31:75:39 | "tainted" : String | semmle.label | "tainted" : String | | EntityFrameworkCore.cs:76:18:76:28 | access to local variable taintSource | semmle.label | access to local variable taintSource | @@ -268,78 +268,78 @@ nodes | EntityFrameworkCore.cs:78:18:78:42 | (...) ... | semmle.label | (...) ... | | EntityFrameworkCore.cs:78:18:78:42 | call to operator implicit conversion : RawSqlString | semmle.label | call to operator implicit conversion : RawSqlString | | EntityFrameworkCore.cs:78:32:78:42 | access to local variable taintSource : String | semmle.label | access to local variable taintSource : String | -| EntityFrameworkCore.cs:85:13:88:13 | { ..., ... } [Name] : String | semmle.label | { ..., ... } [Name] : String | +| EntityFrameworkCore.cs:85:13:88:13 | { ..., ... } [property Name] : String | semmle.label | { ..., ... } [property Name] : String | | EntityFrameworkCore.cs:87:24:87:32 | "tainted" : String | semmle.label | "tainted" : String | -| EntityFrameworkCore.cs:92:13:92:15 | [post] access to local variable ctx [Persons, [], Name] : String | semmle.label | [post] access to local variable ctx [Persons, [], Name] : String | -| EntityFrameworkCore.cs:92:13:92:23 | [post] access to property Persons [[], Name] : String | semmle.label | [post] access to property Persons [[], Name] : String | -| EntityFrameworkCore.cs:92:29:92:30 | access to local variable p1 [Name] : String | semmle.label | access to local variable p1 [Name] : String | -| EntityFrameworkCore.cs:94:13:94:15 | access to local variable ctx [Persons, [], Name] : String | semmle.label | access to local variable ctx [Persons, [], Name] : String | -| EntityFrameworkCore.cs:107:13:110:13 | { ..., ... } [Name] : String | semmle.label | { ..., ... } [Name] : String | +| EntityFrameworkCore.cs:92:13:92:15 | [post] access to local variable ctx [property Persons, element, property Name] : String | semmle.label | [post] access to local variable ctx [property Persons, element, property Name] : String | +| EntityFrameworkCore.cs:92:13:92:23 | [post] access to property Persons [element, property Name] : String | semmle.label | [post] access to property Persons [element, property Name] : String | +| EntityFrameworkCore.cs:92:29:92:30 | access to local variable p1 [property Name] : String | semmle.label | access to local variable p1 [property Name] : String | +| EntityFrameworkCore.cs:94:13:94:15 | access to local variable ctx [property Persons, element, property Name] : String | semmle.label | access to local variable ctx [property Persons, element, property Name] : String | +| EntityFrameworkCore.cs:107:13:110:13 | { ..., ... } [property Name] : String | semmle.label | { ..., ... } [property Name] : String | | EntityFrameworkCore.cs:109:24:109:32 | "tainted" : String | semmle.label | "tainted" : String | -| EntityFrameworkCore.cs:114:13:114:15 | [post] access to local variable ctx [Persons, [], Name] : String | semmle.label | [post] access to local variable ctx [Persons, [], Name] : String | -| EntityFrameworkCore.cs:114:13:114:23 | [post] access to property Persons [[], Name] : String | semmle.label | [post] access to property Persons [[], Name] : String | -| EntityFrameworkCore.cs:114:29:114:30 | access to local variable p1 [Name] : String | semmle.label | access to local variable p1 [Name] : String | -| EntityFrameworkCore.cs:116:19:116:21 | access to local variable ctx [Persons, [], Name] : String | semmle.label | access to local variable ctx [Persons, [], Name] : String | -| EntityFrameworkCore.cs:129:13:132:13 | { ..., ... } [Name] : String | semmle.label | { ..., ... } [Name] : String | +| EntityFrameworkCore.cs:114:13:114:15 | [post] access to local variable ctx [property Persons, element, property Name] : String | semmle.label | [post] access to local variable ctx [property Persons, element, property Name] : String | +| EntityFrameworkCore.cs:114:13:114:23 | [post] access to property Persons [element, property Name] : String | semmle.label | [post] access to property Persons [element, property Name] : String | +| EntityFrameworkCore.cs:114:29:114:30 | access to local variable p1 [property Name] : String | semmle.label | access to local variable p1 [property Name] : String | +| EntityFrameworkCore.cs:116:19:116:21 | access to local variable ctx [property Persons, element, property Name] : String | semmle.label | access to local variable ctx [property Persons, element, property Name] : String | +| EntityFrameworkCore.cs:129:13:132:13 | { ..., ... } [property Name] : String | semmle.label | { ..., ... } [property Name] : String | | EntityFrameworkCore.cs:131:24:131:32 | "tainted" : String | semmle.label | "tainted" : String | -| EntityFrameworkCore.cs:135:27:135:28 | access to local variable p1 [Name] : String | semmle.label | access to local variable p1 [Name] : String | -| EntityFrameworkCore.cs:148:13:151:13 | { ..., ... } [Title] : String | semmle.label | { ..., ... } [Title] : String | +| EntityFrameworkCore.cs:135:27:135:28 | access to local variable p1 [property Name] : String | semmle.label | access to local variable p1 [property Name] : String | +| EntityFrameworkCore.cs:148:13:151:13 | { ..., ... } [property Title] : String | semmle.label | { ..., ... } [property Title] : String | | EntityFrameworkCore.cs:150:25:150:33 | "tainted" : String | semmle.label | "tainted" : String | -| EntityFrameworkCore.cs:155:18:155:19 | access to local variable p1 [Title] : String | semmle.label | access to local variable p1 [Title] : String | +| EntityFrameworkCore.cs:155:18:155:19 | access to local variable p1 [property Title] : String | semmle.label | access to local variable p1 [property Title] : String | | EntityFrameworkCore.cs:155:18:155:25 | access to property Title | semmle.label | access to property Title | -| EntityFrameworkCore.cs:167:13:174:13 | { ..., ... } [Addresses, [], Street] : String | semmle.label | { ..., ... } [Addresses, [], Street] : String | -| EntityFrameworkCore.cs:168:29:173:17 | array creation of type Address[] [[], Street] : String | semmle.label | array creation of type Address[] [[], Street] : String | -| EntityFrameworkCore.cs:168:35:173:17 | { ..., ... } [[], Street] : String | semmle.label | { ..., ... } [[], Street] : String | -| EntityFrameworkCore.cs:169:21:172:21 | object creation of type Address [Street] : String | semmle.label | object creation of type Address [Street] : String | -| EntityFrameworkCore.cs:169:33:172:21 | { ..., ... } [Street] : String | semmle.label | { ..., ... } [Street] : String | +| EntityFrameworkCore.cs:167:13:174:13 | { ..., ... } [property Addresses, element, property Street] : String | semmle.label | { ..., ... } [property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:168:29:173:17 | array creation of type Address[] [element, property Street] : String | semmle.label | array creation of type Address[] [element, property Street] : String | +| EntityFrameworkCore.cs:168:35:173:17 | { ..., ... } [element, property Street] : String | semmle.label | { ..., ... } [element, property Street] : String | +| EntityFrameworkCore.cs:169:21:172:21 | object creation of type Address [property Street] : String | semmle.label | object creation of type Address [property Street] : String | +| EntityFrameworkCore.cs:169:33:172:21 | { ..., ... } [property Street] : String | semmle.label | { ..., ... } [property Street] : String | | EntityFrameworkCore.cs:171:34:171:42 | "tainted" : String | semmle.label | "tainted" : String | -| EntityFrameworkCore.cs:175:13:175:15 | [post] access to local variable ctx [Persons, [], Addresses, [], Street] : String | semmle.label | [post] access to local variable ctx [Persons, [], Addresses, [], Street] : String | -| EntityFrameworkCore.cs:175:13:175:23 | [post] access to property Persons [[], Addresses, [], Street] : String | semmle.label | [post] access to property Persons [[], Addresses, [], Street] : String | -| EntityFrameworkCore.cs:175:29:175:30 | access to local variable p1 [Addresses, [], Street] : String | semmle.label | access to local variable p1 [Addresses, [], Street] : String | -| EntityFrameworkCore.cs:176:13:176:15 | access to local variable ctx [Persons, [], Addresses, [], Street] : String | semmle.label | access to local variable ctx [Persons, [], Addresses, [], Street] : String | -| EntityFrameworkCore.cs:180:13:180:15 | access to local variable ctx [Persons, [], Addresses, [], Street] : String | semmle.label | access to local variable ctx [Persons, [], Addresses, [], Street] : String | -| EntityFrameworkCore.cs:183:13:186:13 | { ..., ... } [Street] : String | semmle.label | { ..., ... } [Street] : String | +| EntityFrameworkCore.cs:175:13:175:15 | [post] access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | semmle.label | [post] access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:175:13:175:23 | [post] access to property Persons [element, property Addresses, element, property Street] : String | semmle.label | [post] access to property Persons [element, property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:175:29:175:30 | access to local variable p1 [property Addresses, element, property Street] : String | semmle.label | access to local variable p1 [property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:176:13:176:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | semmle.label | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:180:13:180:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | semmle.label | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:183:13:186:13 | { ..., ... } [property Street] : String | semmle.label | { ..., ... } [property Street] : String | | EntityFrameworkCore.cs:185:26:185:34 | "tainted" : String | semmle.label | "tainted" : String | -| EntityFrameworkCore.cs:187:13:187:15 | [post] access to local variable ctx [Addresses, [], Street] : String | semmle.label | [post] access to local variable ctx [Addresses, [], Street] : String | -| EntityFrameworkCore.cs:187:13:187:25 | [post] access to property Addresses [[], Street] : String | semmle.label | [post] access to property Addresses [[], Street] : String | -| EntityFrameworkCore.cs:187:31:187:32 | access to local variable a1 [Street] : String | semmle.label | access to local variable a1 [Street] : String | -| EntityFrameworkCore.cs:188:13:188:15 | access to local variable ctx [Addresses, [], Street] : String | semmle.label | access to local variable ctx [Addresses, [], Street] : String | -| EntityFrameworkCore.cs:188:13:188:15 | access to local variable ctx [Persons, [], Addresses, [], Street] : String | semmle.label | access to local variable ctx [Persons, [], Addresses, [], Street] : String | -| EntityFrameworkCore.cs:192:13:192:15 | access to local variable ctx [Addresses, [], Street] : String | semmle.label | access to local variable ctx [Addresses, [], Street] : String | -| EntityFrameworkCore.cs:192:13:192:15 | access to local variable ctx [Persons, [], Addresses, [], Street] : String | semmle.label | access to local variable ctx [Persons, [], Addresses, [], Street] : String | -| EntityFrameworkCore.cs:199:13:202:13 | { ..., ... } [Name] : String | semmle.label | { ..., ... } [Name] : String | +| EntityFrameworkCore.cs:187:13:187:15 | [post] access to local variable ctx [property Addresses, element, property Street] : String | semmle.label | [post] access to local variable ctx [property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:187:13:187:25 | [post] access to property Addresses [element, property Street] : String | semmle.label | [post] access to property Addresses [element, property Street] : String | +| EntityFrameworkCore.cs:187:31:187:32 | access to local variable a1 [property Street] : String | semmle.label | access to local variable a1 [property Street] : String | +| EntityFrameworkCore.cs:188:13:188:15 | access to local variable ctx [property Addresses, element, property Street] : String | semmle.label | access to local variable ctx [property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:188:13:188:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | semmle.label | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:192:13:192:15 | access to local variable ctx [property Addresses, element, property Street] : String | semmle.label | access to local variable ctx [property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:192:13:192:15 | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | semmle.label | access to local variable ctx [property Persons, element, property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:199:13:202:13 | { ..., ... } [property Name] : String | semmle.label | { ..., ... } [property Name] : String | | EntityFrameworkCore.cs:201:24:201:32 | "tainted" : String | semmle.label | "tainted" : String | -| EntityFrameworkCore.cs:204:13:207:13 | { ..., ... } [Street] : String | semmle.label | { ..., ... } [Street] : String | +| EntityFrameworkCore.cs:204:13:207:13 | { ..., ... } [property Street] : String | semmle.label | { ..., ... } [property Street] : String | | EntityFrameworkCore.cs:206:26:206:34 | "tainted" : String | semmle.label | "tainted" : String | -| EntityFrameworkCore.cs:208:60:208:88 | { ..., ... } [Address, Street] : String | semmle.label | { ..., ... } [Address, Street] : String | -| EntityFrameworkCore.cs:208:60:208:88 | { ..., ... } [Person, Name] : String | semmle.label | { ..., ... } [Person, Name] : String | -| EntityFrameworkCore.cs:208:71:208:72 | access to local variable p1 [Name] : String | semmle.label | access to local variable p1 [Name] : String | -| EntityFrameworkCore.cs:208:85:208:86 | access to local variable a1 [Street] : String | semmle.label | access to local variable a1 [Street] : String | -| EntityFrameworkCore.cs:209:13:209:15 | [post] access to local variable ctx [PersonAddresses, [], Address, Street] : String | semmle.label | [post] access to local variable ctx [PersonAddresses, [], Address, Street] : String | -| EntityFrameworkCore.cs:209:13:209:15 | [post] access to local variable ctx [PersonAddresses, [], Person, Name] : String | semmle.label | [post] access to local variable ctx [PersonAddresses, [], Person, Name] : String | -| EntityFrameworkCore.cs:209:13:209:31 | [post] access to property PersonAddresses [[], Address, Street] : String | semmle.label | [post] access to property PersonAddresses [[], Address, Street] : String | -| EntityFrameworkCore.cs:209:13:209:31 | [post] access to property PersonAddresses [[], Person, Name] : String | semmle.label | [post] access to property PersonAddresses [[], Person, Name] : String | -| EntityFrameworkCore.cs:209:37:209:53 | access to local variable personAddressMap1 [Address, Street] : String | semmle.label | access to local variable personAddressMap1 [Address, Street] : String | -| EntityFrameworkCore.cs:209:37:209:53 | access to local variable personAddressMap1 [Person, Name] : String | semmle.label | access to local variable personAddressMap1 [Person, Name] : String | -| EntityFrameworkCore.cs:210:13:210:15 | access to local variable ctx [PersonAddresses, [], Address, Street] : String | semmle.label | access to local variable ctx [PersonAddresses, [], Address, Street] : String | -| EntityFrameworkCore.cs:210:13:210:15 | access to local variable ctx [PersonAddresses, [], Person, Name] : String | semmle.label | access to local variable ctx [PersonAddresses, [], Person, Name] : String | -| EntityFrameworkCore.cs:216:13:216:15 | access to local variable ctx [PersonAddresses, [], Address, Street] : String | semmle.label | access to local variable ctx [PersonAddresses, [], Address, Street] : String | -| EntityFrameworkCore.cs:216:13:216:15 | access to local variable ctx [PersonAddresses, [], Person, Name] : String | semmle.label | access to local variable ctx [PersonAddresses, [], Person, Name] : String | -| EntityFrameworkCore.cs:219:35:219:35 | p [Name] : String | semmle.label | p [Name] : String | -| EntityFrameworkCore.cs:222:13:222:15 | [post] access to local variable ctx [Persons, [], Name] : String | semmle.label | [post] access to local variable ctx [Persons, [], Name] : String | -| EntityFrameworkCore.cs:222:13:222:23 | [post] access to property Persons [[], Name] : String | semmle.label | [post] access to property Persons [[], Name] : String | -| EntityFrameworkCore.cs:222:29:222:29 | access to parameter p [Name] : String | semmle.label | access to parameter p [Name] : String | -| EntityFrameworkCore.cs:223:13:223:15 | access to local variable ctx [Persons, [], Name] : String | semmle.label | access to local variable ctx [Persons, [], Name] : String | -| EntityFrameworkCore.cs:230:18:230:28 | access to property Persons [[], Name] : String | semmle.label | access to property Persons [[], Name] : String | -| EntityFrameworkCore.cs:230:18:230:36 | call to method First [Name] : String | semmle.label | call to method First [Name] : String | +| EntityFrameworkCore.cs:208:60:208:88 | { ..., ... } [property Address, property Street] : String | semmle.label | { ..., ... } [property Address, property Street] : String | +| EntityFrameworkCore.cs:208:60:208:88 | { ..., ... } [property Person, property Name] : String | semmle.label | { ..., ... } [property Person, property Name] : String | +| EntityFrameworkCore.cs:208:71:208:72 | access to local variable p1 [property Name] : String | semmle.label | access to local variable p1 [property Name] : String | +| EntityFrameworkCore.cs:208:85:208:86 | access to local variable a1 [property Street] : String | semmle.label | access to local variable a1 [property Street] : String | +| EntityFrameworkCore.cs:209:13:209:15 | [post] access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | semmle.label | [post] access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | +| EntityFrameworkCore.cs:209:13:209:15 | [post] access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | semmle.label | [post] access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | +| EntityFrameworkCore.cs:209:13:209:31 | [post] access to property PersonAddresses [element, property Address, property Street] : String | semmle.label | [post] access to property PersonAddresses [element, property Address, property Street] : String | +| EntityFrameworkCore.cs:209:13:209:31 | [post] access to property PersonAddresses [element, property Person, property Name] : String | semmle.label | [post] access to property PersonAddresses [element, property Person, property Name] : String | +| EntityFrameworkCore.cs:209:37:209:53 | access to local variable personAddressMap1 [property Address, property Street] : String | semmle.label | access to local variable personAddressMap1 [property Address, property Street] : String | +| EntityFrameworkCore.cs:209:37:209:53 | access to local variable personAddressMap1 [property Person, property Name] : String | semmle.label | access to local variable personAddressMap1 [property Person, property Name] : String | +| EntityFrameworkCore.cs:210:13:210:15 | access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | semmle.label | access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | +| EntityFrameworkCore.cs:210:13:210:15 | access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | semmle.label | access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | +| EntityFrameworkCore.cs:216:13:216:15 | access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | semmle.label | access to local variable ctx [property PersonAddresses, element, property Address, property Street] : String | +| EntityFrameworkCore.cs:216:13:216:15 | access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | semmle.label | access to local variable ctx [property PersonAddresses, element, property Person, property Name] : String | +| EntityFrameworkCore.cs:219:35:219:35 | p [property Name] : String | semmle.label | p [property Name] : String | +| EntityFrameworkCore.cs:222:13:222:15 | [post] access to local variable ctx [property Persons, element, property Name] : String | semmle.label | [post] access to local variable ctx [property Persons, element, property Name] : String | +| EntityFrameworkCore.cs:222:13:222:23 | [post] access to property Persons [element, property Name] : String | semmle.label | [post] access to property Persons [element, property Name] : String | +| EntityFrameworkCore.cs:222:29:222:29 | access to parameter p [property Name] : String | semmle.label | access to parameter p [property Name] : String | +| EntityFrameworkCore.cs:223:13:223:15 | access to local variable ctx [property Persons, element, property Name] : String | semmle.label | access to local variable ctx [property Persons, element, property Name] : String | +| EntityFrameworkCore.cs:230:18:230:28 | access to property Persons [element, property Name] : String | semmle.label | access to property Persons [element, property Name] : String | +| EntityFrameworkCore.cs:230:18:230:36 | call to method First [property Name] : String | semmle.label | call to method First [property Name] : String | | EntityFrameworkCore.cs:230:18:230:41 | access to property Name | semmle.label | access to property Name | -| EntityFrameworkCore.cs:238:18:238:30 | access to property Addresses [[], Street] : String | semmle.label | access to property Addresses [[], Street] : String | -| EntityFrameworkCore.cs:238:18:238:38 | call to method First [Street] : String | semmle.label | call to method First [Street] : String | +| EntityFrameworkCore.cs:238:18:238:30 | access to property Addresses [element, property Street] : String | semmle.label | access to property Addresses [element, property Street] : String | +| EntityFrameworkCore.cs:238:18:238:38 | call to method First [property Street] : String | semmle.label | call to method First [property Street] : String | | EntityFrameworkCore.cs:238:18:238:45 | access to property Street | semmle.label | access to property Street | -| EntityFrameworkCore.cs:245:18:245:28 | access to property Persons [[], Addresses, [], Street] : String | semmle.label | access to property Persons [[], Addresses, [], Street] : String | -| EntityFrameworkCore.cs:245:18:245:36 | call to method First [Addresses, [], Street] : String | semmle.label | call to method First [Addresses, [], Street] : String | -| EntityFrameworkCore.cs:245:18:245:46 | access to property Addresses [[], Street] : String | semmle.label | access to property Addresses [[], Street] : String | -| EntityFrameworkCore.cs:245:18:245:54 | call to method First [Street] : String | semmle.label | call to method First [Street] : String | +| EntityFrameworkCore.cs:245:18:245:28 | access to property Persons [element, property Addresses, element, property Street] : String | semmle.label | access to property Persons [element, property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:245:18:245:36 | call to method First [property Addresses, element, property Street] : String | semmle.label | call to method First [property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:245:18:245:46 | access to property Addresses [element, property Street] : String | semmle.label | access to property Addresses [element, property Street] : String | +| EntityFrameworkCore.cs:245:18:245:54 | call to method First [property Street] : String | semmle.label | call to method First [property Street] : String | | EntityFrameworkCore.cs:245:18:245:61 | access to property Street | semmle.label | access to property Street | #select | EntityFramework.cs:131:18:131:25 | access to property Title | EntityFramework.cs:126:25:126:33 | "tainted" : String | EntityFramework.cs:131:18:131:25 | access to property Title | $@ | EntityFramework.cs:126:25:126:33 | "tainted" : String | "tainted" : String | diff --git a/csharp/ql/test/library-tests/frameworks/EntityFramework/FlowSummaries.expected b/csharp/ql/test/library-tests/frameworks/EntityFramework/FlowSummaries.expected index 255b6ac988b..a28d064f2d1 100644 --- a/csharp/ql/test/library-tests/frameworks/EntityFramework/FlowSummaries.expected +++ b/csharp/ql/test/library-tests/frameworks/EntityFramework/FlowSummaries.expected @@ -1,158 +1,158 @@ -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [Addresses, [], Id] -> jump to get_Addresses (return) [[], Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [Addresses, [], Id] -> jump to get_PersonAddresses (return) [[], Address, Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [Addresses, [], Id] -> jump to get_PersonAddresses (return) [[], Person, Addresses, [], Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [Addresses, [], Id] -> jump to get_Persons (return) [[], Addresses, [], Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [Addresses, [], Street] -> jump to get_Addresses (return) [[], Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [Addresses, [], Street] -> jump to get_PersonAddresses (return) [[], Address, Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [Addresses, [], Street] -> jump to get_PersonAddresses (return) [[], Person, Addresses, [], Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [Addresses, [], Street] -> jump to get_Persons (return) [[], Addresses, [], Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [PersonAddresses, [], Address, Id] -> jump to get_Addresses (return) [[], Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [PersonAddresses, [], Address, Id] -> jump to get_PersonAddresses (return) [[], Address, Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [PersonAddresses, [], Address, Id] -> jump to get_PersonAddresses (return) [[], Person, Addresses, [], Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [PersonAddresses, [], Address, Id] -> jump to get_Persons (return) [[], Addresses, [], Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [PersonAddresses, [], Address, Street] -> jump to get_Addresses (return) [[], Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [PersonAddresses, [], Address, Street] -> jump to get_PersonAddresses (return) [[], Address, Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [PersonAddresses, [], Address, Street] -> jump to get_PersonAddresses (return) [[], Person, Addresses, [], Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [PersonAddresses, [], Address, Street] -> jump to get_Persons (return) [[], Addresses, [], Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [PersonAddresses, [], AddressId] -> jump to get_PersonAddresses (return) [[], AddressId] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [PersonAddresses, [], Id] -> jump to get_PersonAddresses (return) [[], Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [PersonAddresses, [], Person, Id] -> jump to get_PersonAddresses (return) [[], Person, Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [PersonAddresses, [], Person, Id] -> jump to get_Persons (return) [[], Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [PersonAddresses, [], Person, Name] -> jump to get_PersonAddresses (return) [[], Person, Name] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [PersonAddresses, [], Person, Name] -> jump to get_Persons (return) [[], Name] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [PersonAddresses, [], PersonId] -> jump to get_PersonAddresses (return) [[], PersonId] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [Persons, [], Addresses, [], Id] -> jump to get_Addresses (return) [[], Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [Persons, [], Addresses, [], Id] -> jump to get_PersonAddresses (return) [[], Address, Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [Persons, [], Addresses, [], Id] -> jump to get_PersonAddresses (return) [[], Person, Addresses, [], Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [Persons, [], Addresses, [], Id] -> jump to get_Persons (return) [[], Addresses, [], Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [Persons, [], Addresses, [], Street] -> jump to get_Addresses (return) [[], Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [Persons, [], Addresses, [], Street] -> jump to get_PersonAddresses (return) [[], Address, Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [Persons, [], Addresses, [], Street] -> jump to get_PersonAddresses (return) [[], Person, Addresses, [], Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [Persons, [], Addresses, [], Street] -> jump to get_Persons (return) [[], Addresses, [], Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [Persons, [], Id] -> jump to get_PersonAddresses (return) [[], Person, Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [Persons, [], Id] -> jump to get_Persons (return) [[], Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [Persons, [], Name] -> jump to get_PersonAddresses (return) [[], Person, Name] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [Persons, [], Name] -> jump to get_Persons (return) [[], Name] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [Addresses, [], Id] -> jump to get_Addresses (return) [[], Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [Addresses, [], Id] -> jump to get_PersonAddresses (return) [[], Address, Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [Addresses, [], Id] -> jump to get_PersonAddresses (return) [[], Person, Addresses, [], Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [Addresses, [], Id] -> jump to get_Persons (return) [[], Addresses, [], Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [Addresses, [], Street] -> jump to get_Addresses (return) [[], Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [Addresses, [], Street] -> jump to get_PersonAddresses (return) [[], Address, Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [Addresses, [], Street] -> jump to get_PersonAddresses (return) [[], Person, Addresses, [], Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [Addresses, [], Street] -> jump to get_Persons (return) [[], Addresses, [], Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [PersonAddresses, [], Address, Id] -> jump to get_Addresses (return) [[], Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [PersonAddresses, [], Address, Id] -> jump to get_PersonAddresses (return) [[], Address, Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [PersonAddresses, [], Address, Id] -> jump to get_PersonAddresses (return) [[], Person, Addresses, [], Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [PersonAddresses, [], Address, Id] -> jump to get_Persons (return) [[], Addresses, [], Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [PersonAddresses, [], Address, Street] -> jump to get_Addresses (return) [[], Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [PersonAddresses, [], Address, Street] -> jump to get_PersonAddresses (return) [[], Address, Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [PersonAddresses, [], Address, Street] -> jump to get_PersonAddresses (return) [[], Person, Addresses, [], Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [PersonAddresses, [], Address, Street] -> jump to get_Persons (return) [[], Addresses, [], Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [PersonAddresses, [], AddressId] -> jump to get_PersonAddresses (return) [[], AddressId] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [PersonAddresses, [], Id] -> jump to get_PersonAddresses (return) [[], Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [PersonAddresses, [], Person, Id] -> jump to get_PersonAddresses (return) [[], Person, Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [PersonAddresses, [], Person, Id] -> jump to get_Persons (return) [[], Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [PersonAddresses, [], Person, Name] -> jump to get_PersonAddresses (return) [[], Person, Name] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [PersonAddresses, [], Person, Name] -> jump to get_Persons (return) [[], Name] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [PersonAddresses, [], PersonId] -> jump to get_PersonAddresses (return) [[], PersonId] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [Persons, [], Addresses, [], Id] -> jump to get_Addresses (return) [[], Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [Persons, [], Addresses, [], Id] -> jump to get_PersonAddresses (return) [[], Address, Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [Persons, [], Addresses, [], Id] -> jump to get_PersonAddresses (return) [[], Person, Addresses, [], Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [Persons, [], Addresses, [], Id] -> jump to get_Persons (return) [[], Addresses, [], Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [Persons, [], Addresses, [], Street] -> jump to get_Addresses (return) [[], Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [Persons, [], Addresses, [], Street] -> jump to get_PersonAddresses (return) [[], Address, Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [Persons, [], Addresses, [], Street] -> jump to get_PersonAddresses (return) [[], Person, Addresses, [], Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [Persons, [], Addresses, [], Street] -> jump to get_Persons (return) [[], Addresses, [], Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [Persons, [], Id] -> jump to get_PersonAddresses (return) [[], Person, Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [Persons, [], Id] -> jump to get_Persons (return) [[], Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [Persons, [], Name] -> jump to get_PersonAddresses (return) [[], Person, Name] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [Persons, [], Name] -> jump to get_Persons (return) [[], Name] | true | -| Microsoft.EntityFrameworkCore.DbSet<>.Add(T) | parameter 0 -> this parameter [[]] | true | -| Microsoft.EntityFrameworkCore.DbSet<>.AddAsync(T) | parameter 0 -> this parameter [[]] | true | -| Microsoft.EntityFrameworkCore.DbSet<>.AddRange(IEnumerable) | parameter 0 [[]] -> this parameter [[]] | true | -| Microsoft.EntityFrameworkCore.DbSet<>.AddRangeAsync(IEnumerable) | parameter 0 [[]] -> this parameter [[]] | true | -| Microsoft.EntityFrameworkCore.DbSet<>.Attach(T) | parameter 0 -> this parameter [[]] | true | -| Microsoft.EntityFrameworkCore.DbSet<>.AttachRange(IEnumerable) | parameter 0 [[]] -> this parameter [[]] | true | -| Microsoft.EntityFrameworkCore.DbSet<>.Update(T) | parameter 0 -> this parameter [[]] | true | -| Microsoft.EntityFrameworkCore.DbSet<>.UpdateRange(IEnumerable) | parameter 0 [[]] -> this parameter [[]] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Addresses, element, property Id] -> jump to get_Addresses (normal) [element, property Id] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Addresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Address, property Id] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Addresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Id] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Addresses, element, property Id] -> jump to get_Persons (normal) [element, property Addresses, element, property Id] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Addresses, element, property Street] -> jump to get_Addresses (normal) [element, property Street] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Addresses, element, property Street] -> jump to get_PersonAddresses (normal) [element, property Address, property Street] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Addresses, element, property Street] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Street] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Addresses, element, property Street] -> jump to get_Persons (normal) [element, property Addresses, element, property Street] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Address, property Id] -> jump to get_Addresses (normal) [element, property Id] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Address, property Id] -> jump to get_PersonAddresses (normal) [element, property Address, property Id] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Address, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Id] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Address, property Id] -> jump to get_Persons (normal) [element, property Addresses, element, property Id] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Address, property Street] -> jump to get_Addresses (normal) [element, property Street] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Address, property Street] -> jump to get_PersonAddresses (normal) [element, property Address, property Street] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Address, property Street] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Street] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Address, property Street] -> jump to get_Persons (normal) [element, property Addresses, element, property Street] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property AddressId] -> jump to get_PersonAddresses (normal) [element, property AddressId] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Id] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Person, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Id] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Person, property Id] -> jump to get_Persons (normal) [element, property Id] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Person, property Name] -> jump to get_PersonAddresses (normal) [element, property Person, property Name] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Person, property Name] -> jump to get_Persons (normal) [element, property Name] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property PersonId] -> jump to get_PersonAddresses (normal) [element, property PersonId] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Persons, element, property Addresses, element, property Id] -> jump to get_Addresses (normal) [element, property Id] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Persons, element, property Addresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Address, property Id] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Persons, element, property Addresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Id] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Persons, element, property Addresses, element, property Id] -> jump to get_Persons (normal) [element, property Addresses, element, property Id] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Persons, element, property Addresses, element, property Street] -> jump to get_Addresses (normal) [element, property Street] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Persons, element, property Addresses, element, property Street] -> jump to get_PersonAddresses (normal) [element, property Address, property Street] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Persons, element, property Addresses, element, property Street] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Street] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Persons, element, property Addresses, element, property Street] -> jump to get_Persons (normal) [element, property Addresses, element, property Street] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Persons, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Id] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Persons, element, property Id] -> jump to get_Persons (normal) [element, property Id] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Persons, element, property Name] -> jump to get_PersonAddresses (normal) [element, property Person, property Name] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Persons, element, property Name] -> jump to get_Persons (normal) [element, property Name] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Addresses, element, property Id] -> jump to get_Addresses (normal) [element, property Id] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Addresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Address, property Id] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Addresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Id] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Addresses, element, property Id] -> jump to get_Persons (normal) [element, property Addresses, element, property Id] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Addresses, element, property Street] -> jump to get_Addresses (normal) [element, property Street] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Addresses, element, property Street] -> jump to get_PersonAddresses (normal) [element, property Address, property Street] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Addresses, element, property Street] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Street] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Addresses, element, property Street] -> jump to get_Persons (normal) [element, property Addresses, element, property Street] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Address, property Id] -> jump to get_Addresses (normal) [element, property Id] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Address, property Id] -> jump to get_PersonAddresses (normal) [element, property Address, property Id] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Address, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Id] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Address, property Id] -> jump to get_Persons (normal) [element, property Addresses, element, property Id] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Address, property Street] -> jump to get_Addresses (normal) [element, property Street] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Address, property Street] -> jump to get_PersonAddresses (normal) [element, property Address, property Street] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Address, property Street] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Street] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Address, property Street] -> jump to get_Persons (normal) [element, property Addresses, element, property Street] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property AddressId] -> jump to get_PersonAddresses (normal) [element, property AddressId] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Id] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Person, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Id] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Person, property Id] -> jump to get_Persons (normal) [element, property Id] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Person, property Name] -> jump to get_PersonAddresses (normal) [element, property Person, property Name] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Person, property Name] -> jump to get_Persons (normal) [element, property Name] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property PersonId] -> jump to get_PersonAddresses (normal) [element, property PersonId] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Addresses, element, property Id] -> jump to get_Addresses (normal) [element, property Id] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Addresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Address, property Id] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Addresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Id] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Addresses, element, property Id] -> jump to get_Persons (normal) [element, property Addresses, element, property Id] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Addresses, element, property Street] -> jump to get_Addresses (normal) [element, property Street] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Addresses, element, property Street] -> jump to get_PersonAddresses (normal) [element, property Address, property Street] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Addresses, element, property Street] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Street] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Addresses, element, property Street] -> jump to get_Persons (normal) [element, property Addresses, element, property Street] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Id] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Id] -> jump to get_Persons (normal) [element, property Id] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Name] -> jump to get_PersonAddresses (normal) [element, property Person, property Name] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Name] -> jump to get_Persons (normal) [element, property Name] | true | +| Microsoft.EntityFrameworkCore.DbSet<>.Add(T) | parameter 0 -> this parameter [element] | true | +| Microsoft.EntityFrameworkCore.DbSet<>.AddAsync(T) | parameter 0 -> this parameter [element] | true | +| Microsoft.EntityFrameworkCore.DbSet<>.AddRange(IEnumerable) | parameter 0 [element] -> this parameter [element] | true | +| Microsoft.EntityFrameworkCore.DbSet<>.AddRangeAsync(IEnumerable) | parameter 0 [element] -> this parameter [element] | true | +| Microsoft.EntityFrameworkCore.DbSet<>.Attach(T) | parameter 0 -> this parameter [element] | true | +| Microsoft.EntityFrameworkCore.DbSet<>.AttachRange(IEnumerable) | parameter 0 [element] -> this parameter [element] | true | +| Microsoft.EntityFrameworkCore.DbSet<>.Update(T) | parameter 0 -> this parameter [element] | true | +| Microsoft.EntityFrameworkCore.DbSet<>.UpdateRange(IEnumerable) | parameter 0 [element] -> this parameter [element] | true | | Microsoft.EntityFrameworkCore.RawSqlString.RawSqlString(string) | parameter 0 -> return | false | | Microsoft.EntityFrameworkCore.RawSqlString.implicit conversion(string) | parameter 0 -> return | false | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [Addresses, [], Id] -> jump to get_Addresses (return) [[], Id] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [Addresses, [], Id] -> jump to get_PersonAddresses (return) [[], Address, Id] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [Addresses, [], Id] -> jump to get_PersonAddresses (return) [[], Person, Addresses, [], Id] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [Addresses, [], Id] -> jump to get_Persons (return) [[], Addresses, [], Id] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [Addresses, [], Street] -> jump to get_Addresses (return) [[], Street] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [Addresses, [], Street] -> jump to get_PersonAddresses (return) [[], Address, Street] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [Addresses, [], Street] -> jump to get_PersonAddresses (return) [[], Person, Addresses, [], Street] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [Addresses, [], Street] -> jump to get_Persons (return) [[], Addresses, [], Street] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [PersonAddresses, [], Address, Id] -> jump to get_Addresses (return) [[], Id] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [PersonAddresses, [], Address, Id] -> jump to get_PersonAddresses (return) [[], Address, Id] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [PersonAddresses, [], Address, Id] -> jump to get_PersonAddresses (return) [[], Person, Addresses, [], Id] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [PersonAddresses, [], Address, Id] -> jump to get_Persons (return) [[], Addresses, [], Id] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [PersonAddresses, [], Address, Street] -> jump to get_Addresses (return) [[], Street] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [PersonAddresses, [], Address, Street] -> jump to get_PersonAddresses (return) [[], Address, Street] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [PersonAddresses, [], Address, Street] -> jump to get_PersonAddresses (return) [[], Person, Addresses, [], Street] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [PersonAddresses, [], Address, Street] -> jump to get_Persons (return) [[], Addresses, [], Street] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [PersonAddresses, [], AddressId] -> jump to get_PersonAddresses (return) [[], AddressId] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [PersonAddresses, [], Id] -> jump to get_PersonAddresses (return) [[], Id] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [PersonAddresses, [], Person, Id] -> jump to get_PersonAddresses (return) [[], Person, Id] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [PersonAddresses, [], Person, Id] -> jump to get_Persons (return) [[], Id] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [PersonAddresses, [], Person, Name] -> jump to get_PersonAddresses (return) [[], Person, Name] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [PersonAddresses, [], Person, Name] -> jump to get_Persons (return) [[], Name] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [PersonAddresses, [], PersonId] -> jump to get_PersonAddresses (return) [[], PersonId] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [Persons, [], Addresses, [], Id] -> jump to get_Addresses (return) [[], Id] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [Persons, [], Addresses, [], Id] -> jump to get_PersonAddresses (return) [[], Address, Id] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [Persons, [], Addresses, [], Id] -> jump to get_PersonAddresses (return) [[], Person, Addresses, [], Id] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [Persons, [], Addresses, [], Id] -> jump to get_Persons (return) [[], Addresses, [], Id] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [Persons, [], Addresses, [], Street] -> jump to get_Addresses (return) [[], Street] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [Persons, [], Addresses, [], Street] -> jump to get_PersonAddresses (return) [[], Address, Street] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [Persons, [], Addresses, [], Street] -> jump to get_PersonAddresses (return) [[], Person, Addresses, [], Street] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [Persons, [], Addresses, [], Street] -> jump to get_Persons (return) [[], Addresses, [], Street] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [Persons, [], Id] -> jump to get_PersonAddresses (return) [[], Person, Id] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [Persons, [], Id] -> jump to get_Persons (return) [[], Id] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [Persons, [], Name] -> jump to get_PersonAddresses (return) [[], Person, Name] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [Persons, [], Name] -> jump to get_Persons (return) [[], Name] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [Addresses, [], Id] -> jump to get_Addresses (return) [[], Id] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [Addresses, [], Id] -> jump to get_PersonAddresses (return) [[], Address, Id] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [Addresses, [], Id] -> jump to get_PersonAddresses (return) [[], Person, Addresses, [], Id] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [Addresses, [], Id] -> jump to get_Persons (return) [[], Addresses, [], Id] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [Addresses, [], Street] -> jump to get_Addresses (return) [[], Street] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [Addresses, [], Street] -> jump to get_PersonAddresses (return) [[], Address, Street] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [Addresses, [], Street] -> jump to get_PersonAddresses (return) [[], Person, Addresses, [], Street] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [Addresses, [], Street] -> jump to get_Persons (return) [[], Addresses, [], Street] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [PersonAddresses, [], Address, Id] -> jump to get_Addresses (return) [[], Id] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [PersonAddresses, [], Address, Id] -> jump to get_PersonAddresses (return) [[], Address, Id] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [PersonAddresses, [], Address, Id] -> jump to get_PersonAddresses (return) [[], Person, Addresses, [], Id] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [PersonAddresses, [], Address, Id] -> jump to get_Persons (return) [[], Addresses, [], Id] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [PersonAddresses, [], Address, Street] -> jump to get_Addresses (return) [[], Street] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [PersonAddresses, [], Address, Street] -> jump to get_PersonAddresses (return) [[], Address, Street] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [PersonAddresses, [], Address, Street] -> jump to get_PersonAddresses (return) [[], Person, Addresses, [], Street] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [PersonAddresses, [], Address, Street] -> jump to get_Persons (return) [[], Addresses, [], Street] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [PersonAddresses, [], AddressId] -> jump to get_PersonAddresses (return) [[], AddressId] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [PersonAddresses, [], Id] -> jump to get_PersonAddresses (return) [[], Id] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [PersonAddresses, [], Person, Id] -> jump to get_PersonAddresses (return) [[], Person, Id] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [PersonAddresses, [], Person, Id] -> jump to get_Persons (return) [[], Id] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [PersonAddresses, [], Person, Name] -> jump to get_PersonAddresses (return) [[], Person, Name] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [PersonAddresses, [], Person, Name] -> jump to get_Persons (return) [[], Name] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [PersonAddresses, [], PersonId] -> jump to get_PersonAddresses (return) [[], PersonId] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [Persons, [], Addresses, [], Id] -> jump to get_Addresses (return) [[], Id] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [Persons, [], Addresses, [], Id] -> jump to get_PersonAddresses (return) [[], Address, Id] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [Persons, [], Addresses, [], Id] -> jump to get_PersonAddresses (return) [[], Person, Addresses, [], Id] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [Persons, [], Addresses, [], Id] -> jump to get_Persons (return) [[], Addresses, [], Id] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [Persons, [], Addresses, [], Street] -> jump to get_Addresses (return) [[], Street] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [Persons, [], Addresses, [], Street] -> jump to get_PersonAddresses (return) [[], Address, Street] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [Persons, [], Addresses, [], Street] -> jump to get_PersonAddresses (return) [[], Person, Addresses, [], Street] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [Persons, [], Addresses, [], Street] -> jump to get_Persons (return) [[], Addresses, [], Street] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [Persons, [], Id] -> jump to get_PersonAddresses (return) [[], Person, Id] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [Persons, [], Id] -> jump to get_Persons (return) [[], Id] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [Persons, [], Name] -> jump to get_PersonAddresses (return) [[], Person, Name] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [Persons, [], Name] -> jump to get_Persons (return) [[], Name] | true | -| System.Data.Entity.DbSet<>.Add(T) | parameter 0 -> this parameter [[]] | true | -| System.Data.Entity.DbSet<>.AddAsync(T) | parameter 0 -> this parameter [[]] | true | -| System.Data.Entity.DbSet<>.AddRange(IEnumerable) | parameter 0 [[]] -> this parameter [[]] | true | -| System.Data.Entity.DbSet<>.AddRangeAsync(IEnumerable) | parameter 0 [[]] -> this parameter [[]] | true | -| System.Data.Entity.DbSet<>.Attach(T) | parameter 0 -> this parameter [[]] | true | -| System.Data.Entity.DbSet<>.AttachRange(IEnumerable) | parameter 0 [[]] -> this parameter [[]] | true | -| System.Data.Entity.DbSet<>.Update(T) | parameter 0 -> this parameter [[]] | true | -| System.Data.Entity.DbSet<>.UpdateRange(IEnumerable) | parameter 0 [[]] -> this parameter [[]] | true | +| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Addresses, element, property Id] -> jump to get_Addresses (normal) [element, property Id] | true | +| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Addresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Address, property Id] | true | +| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Addresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Id] | true | +| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Addresses, element, property Id] -> jump to get_Persons (normal) [element, property Addresses, element, property Id] | true | +| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Addresses, element, property Street] -> jump to get_Addresses (normal) [element, property Street] | true | +| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Addresses, element, property Street] -> jump to get_PersonAddresses (normal) [element, property Address, property Street] | true | +| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Addresses, element, property Street] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Street] | true | +| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Addresses, element, property Street] -> jump to get_Persons (normal) [element, property Addresses, element, property Street] | true | +| System.Data.Entity.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Address, property Id] -> jump to get_Addresses (normal) [element, property Id] | true | +| System.Data.Entity.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Address, property Id] -> jump to get_PersonAddresses (normal) [element, property Address, property Id] | true | +| System.Data.Entity.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Address, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Id] | true | +| System.Data.Entity.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Address, property Id] -> jump to get_Persons (normal) [element, property Addresses, element, property Id] | true | +| System.Data.Entity.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Address, property Street] -> jump to get_Addresses (normal) [element, property Street] | true | +| System.Data.Entity.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Address, property Street] -> jump to get_PersonAddresses (normal) [element, property Address, property Street] | true | +| System.Data.Entity.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Address, property Street] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Street] | true | +| System.Data.Entity.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Address, property Street] -> jump to get_Persons (normal) [element, property Addresses, element, property Street] | true | +| System.Data.Entity.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property AddressId] -> jump to get_PersonAddresses (normal) [element, property AddressId] | true | +| System.Data.Entity.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Id] | true | +| System.Data.Entity.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Person, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Id] | true | +| System.Data.Entity.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Person, property Id] -> jump to get_Persons (normal) [element, property Id] | true | +| System.Data.Entity.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Person, property Name] -> jump to get_PersonAddresses (normal) [element, property Person, property Name] | true | +| System.Data.Entity.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Person, property Name] -> jump to get_Persons (normal) [element, property Name] | true | +| System.Data.Entity.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property PersonId] -> jump to get_PersonAddresses (normal) [element, property PersonId] | true | +| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Persons, element, property Addresses, element, property Id] -> jump to get_Addresses (normal) [element, property Id] | true | +| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Persons, element, property Addresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Address, property Id] | true | +| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Persons, element, property Addresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Id] | true | +| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Persons, element, property Addresses, element, property Id] -> jump to get_Persons (normal) [element, property Addresses, element, property Id] | true | +| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Persons, element, property Addresses, element, property Street] -> jump to get_Addresses (normal) [element, property Street] | true | +| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Persons, element, property Addresses, element, property Street] -> jump to get_PersonAddresses (normal) [element, property Address, property Street] | true | +| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Persons, element, property Addresses, element, property Street] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Street] | true | +| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Persons, element, property Addresses, element, property Street] -> jump to get_Persons (normal) [element, property Addresses, element, property Street] | true | +| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Persons, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Id] | true | +| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Persons, element, property Id] -> jump to get_Persons (normal) [element, property Id] | true | +| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Persons, element, property Name] -> jump to get_PersonAddresses (normal) [element, property Person, property Name] | true | +| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Persons, element, property Name] -> jump to get_Persons (normal) [element, property Name] | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Addresses, element, property Id] -> jump to get_Addresses (normal) [element, property Id] | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Addresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Address, property Id] | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Addresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Id] | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Addresses, element, property Id] -> jump to get_Persons (normal) [element, property Addresses, element, property Id] | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Addresses, element, property Street] -> jump to get_Addresses (normal) [element, property Street] | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Addresses, element, property Street] -> jump to get_PersonAddresses (normal) [element, property Address, property Street] | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Addresses, element, property Street] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Street] | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Addresses, element, property Street] -> jump to get_Persons (normal) [element, property Addresses, element, property Street] | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Address, property Id] -> jump to get_Addresses (normal) [element, property Id] | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Address, property Id] -> jump to get_PersonAddresses (normal) [element, property Address, property Id] | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Address, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Id] | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Address, property Id] -> jump to get_Persons (normal) [element, property Addresses, element, property Id] | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Address, property Street] -> jump to get_Addresses (normal) [element, property Street] | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Address, property Street] -> jump to get_PersonAddresses (normal) [element, property Address, property Street] | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Address, property Street] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Street] | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Address, property Street] -> jump to get_Persons (normal) [element, property Addresses, element, property Street] | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property AddressId] -> jump to get_PersonAddresses (normal) [element, property AddressId] | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Id] | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Person, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Id] | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Person, property Id] -> jump to get_Persons (normal) [element, property Id] | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Person, property Name] -> jump to get_PersonAddresses (normal) [element, property Person, property Name] | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Person, property Name] -> jump to get_Persons (normal) [element, property Name] | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property PersonId] -> jump to get_PersonAddresses (normal) [element, property PersonId] | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Addresses, element, property Id] -> jump to get_Addresses (normal) [element, property Id] | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Addresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Address, property Id] | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Addresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Id] | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Addresses, element, property Id] -> jump to get_Persons (normal) [element, property Addresses, element, property Id] | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Addresses, element, property Street] -> jump to get_Addresses (normal) [element, property Street] | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Addresses, element, property Street] -> jump to get_PersonAddresses (normal) [element, property Address, property Street] | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Addresses, element, property Street] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Street] | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Addresses, element, property Street] -> jump to get_Persons (normal) [element, property Addresses, element, property Street] | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Id] | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Id] -> jump to get_Persons (normal) [element, property Id] | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Name] -> jump to get_PersonAddresses (normal) [element, property Person, property Name] | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Name] -> jump to get_Persons (normal) [element, property Name] | true | +| System.Data.Entity.DbSet<>.Add(T) | parameter 0 -> this parameter [element] | true | +| System.Data.Entity.DbSet<>.AddAsync(T) | parameter 0 -> this parameter [element] | true | +| System.Data.Entity.DbSet<>.AddRange(IEnumerable) | parameter 0 [element] -> this parameter [element] | true | +| System.Data.Entity.DbSet<>.AddRangeAsync(IEnumerable) | parameter 0 [element] -> this parameter [element] | true | +| System.Data.Entity.DbSet<>.Attach(T) | parameter 0 -> this parameter [element] | true | +| System.Data.Entity.DbSet<>.AttachRange(IEnumerable) | parameter 0 [element] -> this parameter [element] | true | +| System.Data.Entity.DbSet<>.Update(T) | parameter 0 -> this parameter [element] | true | +| System.Data.Entity.DbSet<>.UpdateRange(IEnumerable) | parameter 0 [element] -> this parameter [element] | true | diff --git a/csharp/ql/test/query-tests/Security Features/CWE-079/StoredXSS/XSS.expected b/csharp/ql/test/query-tests/Security Features/CWE-079/StoredXSS/XSS.expected index a661a86c71c..b4137bdb36d 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-079/StoredXSS/XSS.expected +++ b/csharp/ql/test/query-tests/Security Features/CWE-079/StoredXSS/XSS.expected @@ -1,12 +1,12 @@ edges -| XSS.cs:25:13:25:21 | [post] access to local variable userInput [[]] : String | XSS.cs:26:32:26:40 | access to local variable userInput [[]] : String | -| XSS.cs:25:13:25:21 | [post] access to local variable userInput [[]] : String | XSS.cs:27:29:27:37 | access to local variable userInput [[]] : String | -| XSS.cs:25:13:25:21 | [post] access to local variable userInput [[]] : String | XSS.cs:28:26:28:34 | access to local variable userInput [[]] : String | +| XSS.cs:25:13:25:21 | [post] access to local variable userInput [element] : String | XSS.cs:26:32:26:40 | access to local variable userInput [element] : String | +| XSS.cs:25:13:25:21 | [post] access to local variable userInput [element] : String | XSS.cs:27:29:27:37 | access to local variable userInput [element] : String | +| XSS.cs:25:13:25:21 | [post] access to local variable userInput [element] : String | XSS.cs:28:26:28:34 | access to local variable userInput [element] : String | | XSS.cs:25:48:25:62 | access to field categoryTextBox : TextBox | XSS.cs:25:48:25:67 | access to property Text : String | -| XSS.cs:25:48:25:67 | access to property Text : String | XSS.cs:25:13:25:21 | [post] access to local variable userInput [[]] : String | -| XSS.cs:26:32:26:40 | access to local variable userInput [[]] : String | XSS.cs:26:32:26:51 | call to method ToString | -| XSS.cs:27:29:27:37 | access to local variable userInput [[]] : String | XSS.cs:27:29:27:48 | call to method ToString | -| XSS.cs:28:26:28:34 | access to local variable userInput [[]] : String | XSS.cs:28:26:28:45 | call to method ToString | +| XSS.cs:25:48:25:67 | access to property Text : String | XSS.cs:25:13:25:21 | [post] access to local variable userInput [element] : String | +| XSS.cs:26:32:26:40 | access to local variable userInput [element] : String | XSS.cs:26:32:26:51 | call to method ToString | +| XSS.cs:27:29:27:37 | access to local variable userInput [element] : String | XSS.cs:27:29:27:48 | call to method ToString | +| XSS.cs:28:26:28:34 | access to local variable userInput [element] : String | XSS.cs:28:26:28:45 | call to method ToString | | XSS.cs:37:27:37:53 | access to property QueryString : NameValueCollection | XSS.cs:38:36:38:39 | access to local variable name | | XSS.cs:57:27:57:65 | access to property QueryString : NameValueCollection | XSS.cs:59:22:59:25 | access to local variable name | | XSS.cs:75:27:75:53 | access to property QueryString : NameValueCollection | XSS.cs:76:36:76:39 | access to local variable name | diff --git a/csharp/ql/test/query-tests/Security Features/CWE-338/InsecureRandomness.expected b/csharp/ql/test/query-tests/Security Features/CWE-338/InsecureRandomness.expected index 138451c31dc..6b2615a85ce 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-338/InsecureRandomness.expected +++ b/csharp/ql/test/query-tests/Security Features/CWE-338/InsecureRandomness.expected @@ -1,11 +1,11 @@ edges -| InsecureRandomness.cs:28:13:28:16 | [post] access to local variable data [[]] : Int32 | InsecureRandomness.cs:29:57:29:60 | access to local variable data [[]] : Int32 | -| InsecureRandomness.cs:28:23:28:43 | (...) ... : Int32 | InsecureRandomness.cs:28:13:28:16 | [post] access to local variable data [[]] : Int32 | +| InsecureRandomness.cs:28:13:28:16 | [post] access to local variable data [element] : Int32 | InsecureRandomness.cs:29:57:29:60 | access to local variable data [element] : Int32 | +| InsecureRandomness.cs:28:23:28:43 | (...) ... : Int32 | InsecureRandomness.cs:28:13:28:16 | [post] access to local variable data [element] : Int32 | | InsecureRandomness.cs:28:29:28:43 | call to method Next : Int32 | InsecureRandomness.cs:28:23:28:43 | (...) ... : Int32 | -| InsecureRandomness.cs:29:13:29:18 | [post] access to local variable result [[]] : String | InsecureRandomness.cs:31:16:31:21 | access to local variable result [[]] : String | -| InsecureRandomness.cs:29:27:29:61 | call to method GetString : String | InsecureRandomness.cs:29:13:29:18 | [post] access to local variable result [[]] : String | -| InsecureRandomness.cs:29:57:29:60 | access to local variable data [[]] : Int32 | InsecureRandomness.cs:29:27:29:61 | call to method GetString : String | -| InsecureRandomness.cs:31:16:31:21 | access to local variable result [[]] : String | InsecureRandomness.cs:31:16:31:32 | call to method ToString : String | +| InsecureRandomness.cs:29:13:29:18 | [post] access to local variable result [element] : String | InsecureRandomness.cs:31:16:31:21 | access to local variable result [element] : String | +| InsecureRandomness.cs:29:27:29:61 | call to method GetString : String | InsecureRandomness.cs:29:13:29:18 | [post] access to local variable result [element] : String | +| InsecureRandomness.cs:29:57:29:60 | access to local variable data [element] : Int32 | InsecureRandomness.cs:29:27:29:61 | call to method GetString : String | +| InsecureRandomness.cs:31:16:31:21 | access to local variable result [element] : String | InsecureRandomness.cs:31:16:31:32 | call to method ToString : String | | InsecureRandomness.cs:31:16:31:32 | call to method ToString : String | InsecureRandomness.cs:12:27:12:50 | call to method InsecureRandomString | | InsecureRandomness.cs:60:31:60:39 | call to method Next : Int32 | InsecureRandomness.cs:62:16:62:21 | access to local variable result : String | | InsecureRandomness.cs:62:16:62:21 | access to local variable result : String | InsecureRandomness.cs:62:16:62:32 | call to method ToString : String | @@ -16,13 +16,13 @@ nodes | InsecureRandomness.cs:12:27:12:50 | call to method InsecureRandomString | semmle.label | call to method InsecureRandomString | | InsecureRandomness.cs:13:20:13:56 | call to method InsecureRandomStringFromSelection | semmle.label | call to method InsecureRandomStringFromSelection | | InsecureRandomness.cs:14:20:14:54 | call to method InsecureRandomStringFromIndexer | semmle.label | call to method InsecureRandomStringFromIndexer | -| InsecureRandomness.cs:28:13:28:16 | [post] access to local variable data [[]] : Int32 | semmle.label | [post] access to local variable data [[]] : Int32 | +| InsecureRandomness.cs:28:13:28:16 | [post] access to local variable data [element] : Int32 | semmle.label | [post] access to local variable data [element] : Int32 | | InsecureRandomness.cs:28:23:28:43 | (...) ... : Int32 | semmle.label | (...) ... : Int32 | | InsecureRandomness.cs:28:29:28:43 | call to method Next : Int32 | semmle.label | call to method Next : Int32 | -| InsecureRandomness.cs:29:13:29:18 | [post] access to local variable result [[]] : String | semmle.label | [post] access to local variable result [[]] : String | +| InsecureRandomness.cs:29:13:29:18 | [post] access to local variable result [element] : String | semmle.label | [post] access to local variable result [element] : String | | InsecureRandomness.cs:29:27:29:61 | call to method GetString : String | semmle.label | call to method GetString : String | -| InsecureRandomness.cs:29:57:29:60 | access to local variable data [[]] : Int32 | semmle.label | access to local variable data [[]] : Int32 | -| InsecureRandomness.cs:31:16:31:21 | access to local variable result [[]] : String | semmle.label | access to local variable result [[]] : String | +| InsecureRandomness.cs:29:57:29:60 | access to local variable data [element] : Int32 | semmle.label | access to local variable data [element] : Int32 | +| InsecureRandomness.cs:31:16:31:21 | access to local variable result [element] : String | semmle.label | access to local variable result [element] : String | | InsecureRandomness.cs:31:16:31:32 | call to method ToString : String | semmle.label | call to method ToString : String | | InsecureRandomness.cs:60:31:60:39 | call to method Next : Int32 | semmle.label | call to method Next : Int32 | | InsecureRandomness.cs:62:16:62:21 | access to local variable result : String | semmle.label | access to local variable result : String | From 4289e358bf0883e7fe0f40cbf82f6f4fe2e2a617 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Tue, 23 Mar 2021 18:13:20 +0100 Subject: [PATCH 312/725] Python: Add module import test case This one will require some explanation... First, the file structure. This commit adds a test consisting representing a few different kinds of imports. - Absolute imports, from `module.py` to `main.py` when the latter is executed directly. - A package (contained in the `package` folder) - A namespace package (contained in the `namespace_package` folder) All of these are inside a folder called `code` for reasons I will detail later. The file `main.py` is identified as a script, by the presence of the `!#` comment in its first line. The files themselves are executable, and `python3 main.py` will print out all modules in the order they are imported. The test itself is very simple. It simply lists all modules and their corresponding names. As is plainly visible, without modification we only pick up `package` and its component modules as having names. This is the bit that needs to be fixed. Convincing the test runner to extract this test in a way that mimics reality is, unfortunately, a bit complicated. By default, the test runner itself includes any Python files in the test directory as modules in the invocation of the extractor, and so we must hide everything in the `code` subdirectory. Secondly, a `--path` argument (set to the test directory) is automatically added, and this would also interfere with extraction, and hence we must prevent this. Luckily, if we supply our own `--path` argument -- even if it doesn't make any sense -- then the other argument is left out. Finally, we must actually tell the extractor to extract the files (or it would just happily pass the test with zero files extracted), so the `-R .` argument ensures that we recurse over the files in the test directory after all. --- .../test/3/library-tests/modules/entry_point/code/main.py | 7 +++++++ .../3/library-tests/modules/entry_point/code/module.py | 2 ++ .../code/namespace_package/namespace_package_main.py | 2 ++ .../code/namespace_package/namespace_package_module.py | 1 + .../modules/entry_point/code/package/__init__.py | 2 ++ .../modules/entry_point/code/package/package_main.py | 2 ++ .../modules/entry_point/code/package/package_module.py | 1 + .../3/library-tests/modules/entry_point/modules.expected | 4 ++++ .../ql/test/3/library-tests/modules/entry_point/modules.ql | 4 ++++ python/ql/test/3/library-tests/modules/entry_point/options | 1 + 10 files changed, 26 insertions(+) create mode 100755 python/ql/test/3/library-tests/modules/entry_point/code/main.py create mode 100644 python/ql/test/3/library-tests/modules/entry_point/code/module.py create mode 100644 python/ql/test/3/library-tests/modules/entry_point/code/namespace_package/namespace_package_main.py create mode 100644 python/ql/test/3/library-tests/modules/entry_point/code/namespace_package/namespace_package_module.py create mode 100644 python/ql/test/3/library-tests/modules/entry_point/code/package/__init__.py create mode 100644 python/ql/test/3/library-tests/modules/entry_point/code/package/package_main.py create mode 100644 python/ql/test/3/library-tests/modules/entry_point/code/package/package_module.py create mode 100644 python/ql/test/3/library-tests/modules/entry_point/modules.expected create mode 100644 python/ql/test/3/library-tests/modules/entry_point/modules.ql create mode 100644 python/ql/test/3/library-tests/modules/entry_point/options diff --git a/python/ql/test/3/library-tests/modules/entry_point/code/main.py b/python/ql/test/3/library-tests/modules/entry_point/code/main.py new file mode 100755 index 00000000000..ad619e5cbd8 --- /dev/null +++ b/python/ql/test/3/library-tests/modules/entry_point/code/main.py @@ -0,0 +1,7 @@ +#! /usr/bin/python3 +print(__file__) +import module +import package +import namespace_package +import namespace_package.namespace_package_main +print(module.message) diff --git a/python/ql/test/3/library-tests/modules/entry_point/code/module.py b/python/ql/test/3/library-tests/modules/entry_point/code/module.py new file mode 100644 index 00000000000..36206ca60b7 --- /dev/null +++ b/python/ql/test/3/library-tests/modules/entry_point/code/module.py @@ -0,0 +1,2 @@ +print(__file__.split("entry_point")[1]) +message = "Hello world!" diff --git a/python/ql/test/3/library-tests/modules/entry_point/code/namespace_package/namespace_package_main.py b/python/ql/test/3/library-tests/modules/entry_point/code/namespace_package/namespace_package_main.py new file mode 100644 index 00000000000..5db80f18a27 --- /dev/null +++ b/python/ql/test/3/library-tests/modules/entry_point/code/namespace_package/namespace_package_main.py @@ -0,0 +1,2 @@ +print(__file__.split("entry_point")[1]) +import namespace_package.namespace_package_module diff --git a/python/ql/test/3/library-tests/modules/entry_point/code/namespace_package/namespace_package_module.py b/python/ql/test/3/library-tests/modules/entry_point/code/namespace_package/namespace_package_module.py new file mode 100644 index 00000000000..567a23d59ce --- /dev/null +++ b/python/ql/test/3/library-tests/modules/entry_point/code/namespace_package/namespace_package_module.py @@ -0,0 +1 @@ +print(__file__.split("entry_point")[1]) diff --git a/python/ql/test/3/library-tests/modules/entry_point/code/package/__init__.py b/python/ql/test/3/library-tests/modules/entry_point/code/package/__init__.py new file mode 100644 index 00000000000..ca14a9f5804 --- /dev/null +++ b/python/ql/test/3/library-tests/modules/entry_point/code/package/__init__.py @@ -0,0 +1,2 @@ +print(__file__.split("entry_point")[1]) +from . import package_main diff --git a/python/ql/test/3/library-tests/modules/entry_point/code/package/package_main.py b/python/ql/test/3/library-tests/modules/entry_point/code/package/package_main.py new file mode 100644 index 00000000000..158b12678e3 --- /dev/null +++ b/python/ql/test/3/library-tests/modules/entry_point/code/package/package_main.py @@ -0,0 +1,2 @@ +print(__file__.split("entry_point")[1]) +from . import package_module diff --git a/python/ql/test/3/library-tests/modules/entry_point/code/package/package_module.py b/python/ql/test/3/library-tests/modules/entry_point/code/package/package_module.py new file mode 100644 index 00000000000..567a23d59ce --- /dev/null +++ b/python/ql/test/3/library-tests/modules/entry_point/code/package/package_module.py @@ -0,0 +1 @@ +print(__file__.split("entry_point")[1]) diff --git a/python/ql/test/3/library-tests/modules/entry_point/modules.expected b/python/ql/test/3/library-tests/modules/entry_point/modules.expected new file mode 100644 index 00000000000..4ec91243782 --- /dev/null +++ b/python/ql/test/3/library-tests/modules/entry_point/modules.expected @@ -0,0 +1,4 @@ +| package | code/package:0:0:0:0 | Package package | +| package.__init__ | code/package/__init__.py:0:0:0:0 | Module package.__init__ | +| package.package_main | code/package/package_main.py:0:0:0:0 | Module package.package_main | +| package.package_module | code/package/package_module.py:0:0:0:0 | Module package.package_module | diff --git a/python/ql/test/3/library-tests/modules/entry_point/modules.ql b/python/ql/test/3/library-tests/modules/entry_point/modules.ql new file mode 100644 index 00000000000..10c390e8616 --- /dev/null +++ b/python/ql/test/3/library-tests/modules/entry_point/modules.ql @@ -0,0 +1,4 @@ +import python + +from Module m +select m.getName(), m diff --git a/python/ql/test/3/library-tests/modules/entry_point/options b/python/ql/test/3/library-tests/modules/entry_point/options new file mode 100644 index 00000000000..619afd242ed --- /dev/null +++ b/python/ql/test/3/library-tests/modules/entry_point/options @@ -0,0 +1 @@ +semmle-extractor-options: --lang=3 --path bogus -R . From 17d17682597bc6f7f495b100263d24d5e99da88b Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Tue, 23 Mar 2021 18:20:53 +0100 Subject: [PATCH 313/725] Python: Allow absolute imports in directories with scripts Fixes the import logic to account for absolute imports. We do this by classifying which files and folders may serve as the entry point for execution, based on a few simple heuristics. If the file `module.py` is in the same folder as a file `main.py` that may be executed directly, then we allow `module` to be a valid name for `module.py` so that `import module` will work as expected. --- python/ql/src/semmle/python/Files.qll | 30 +++++++++++++++++++ python/ql/src/semmle/python/Module.qll | 7 ++++- .../modules/entry_point/modules.expected | 2 ++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/Files.qll b/python/ql/src/semmle/python/Files.qll index ef6484fbdc6..07bbbed2154 100644 --- a/python/ql/src/semmle/python/Files.qll +++ b/python/ql/src/semmle/python/Files.qll @@ -72,6 +72,33 @@ class File extends Container { * are specified to be extracted. */ string getContents() { file_contents(this, result) } + + /** Holds if this file is likely to get executed directly, and thus act as an entry point for execution. */ + predicate maybeExecutedDirectly() { + // Only consider files in the source code, and not things like the standard library + exists(this.getRelativePath()) and + ( + // The file doesn't have the extension `.py` but still contains Python statements + not this.getExtension() = "py" and + exists(Stmt s | s.getLocation().getFile() = this) + or + // The file contains the usual `if __name__ == '__main__':` construction + exists(If i, Name name, StrConst main, Cmpop op | + i.getScope().(Module).getFile() = this and + op instanceof Eq and + i.getTest().(Compare).compares(name, op, main) and + name.getId() = "__name__" and + main.getText() = "__main__" + ) + or + // The file contains a `#!` line referencing the python interpreter + exists(Comment c | + c.getLocation().getFile() = this and + c.getLocation().getStartLine() = 1 and + c.getText().regexpMatch("^#! */.*python(2|3)?[ \\\\t]*$") + ) + ) + } } private predicate occupied_line(File f, int n) { @@ -121,6 +148,9 @@ class Folder extends Container { this.getBaseName().regexpMatch("[^\\d\\W]\\w*") and result = this.getParent().getImportRoot(n) } + + /** Holds if execution may start in a file in this directory. */ + predicate mayContainEntryPoint() { any(File f | f.getParent() = this).maybeExecutedDirectly() } } /** diff --git a/python/ql/src/semmle/python/Module.qll b/python/ql/src/semmle/python/Module.qll index fcf1c0b2925..8a420a800ea 100644 --- a/python/ql/src/semmle/python/Module.qll +++ b/python/ql/src/semmle/python/Module.qll @@ -204,8 +204,13 @@ private string moduleNameFromBase(Container file) { string moduleNameFromFile(Container file) { exists(string basename | basename = moduleNameFromBase(file) and - legalShortName(basename) and + legalShortName(basename) + | result = moduleNameFromFile(file.getParent()) + "." + basename + or + // If execution can start in the folder containing this module, then we will assume `file` can + // be imported as an absolute import, and hence return `basename` as a possible name. + file.getParent().(Folder).mayContainEntryPoint() and result = basename ) or isPotentialSourcePackage(file) and diff --git a/python/ql/test/3/library-tests/modules/entry_point/modules.expected b/python/ql/test/3/library-tests/modules/entry_point/modules.expected index 4ec91243782..8c96490597c 100644 --- a/python/ql/test/3/library-tests/modules/entry_point/modules.expected +++ b/python/ql/test/3/library-tests/modules/entry_point/modules.expected @@ -1,3 +1,5 @@ +| main | code/main.py:0:0:0:0 | Script main | +| module | code/module.py:0:0:0:0 | Module module | | package | code/package:0:0:0:0 | Package package | | package.__init__ | code/package/__init__.py:0:0:0:0 | Module package.__init__ | | package.package_main | code/package/package_main.py:0:0:0:0 | Module package.package_main | From 93bcc3724ab55df5dfe75e01f03f9768b6c759db Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 22 Mar 2021 00:20:49 +0100 Subject: [PATCH 314/725] use pragma to improve 2 join-orders in TaintTracking --- .../src/semmle/javascript/dataflow/TaintTracking.qll | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll index de41392cada..b834f955933 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll @@ -738,7 +738,10 @@ module TaintTracking { pragma[nomagic] private DataFlow::MethodCallNode execMethodCall() { result.getMethodName() = "exec" and - result.getReceiver().analyze().getAType() = TTRegExp() + exists(DataFlow::AnalyzedNode analyzed | + pragma[only_bind_into](analyzed) = result.getReceiver().analyze() and + analyzed.getAType() = TTRegExp() + ) } /** @@ -759,7 +762,10 @@ module TaintTracking { pragma[nomagic] private DataFlow::MethodCallNode matchMethodCall() { result.getMethodName() = "match" and - result.getArgument(0).analyze().getAType() = TTRegExp() + exists(DataFlow::AnalyzedNode analyzed | + pragma[only_bind_into](analyzed) = result.getArgument(0).analyze() and + analyzed.getAType() = TTRegExp() + ) } /** From b8bfdcc719bcfc34d9518e33c1f3fe22ed6d6dfd Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 23 Mar 2021 15:36:27 +0100 Subject: [PATCH 315/725] improve performance in ServiceDefinitions by inlining, and refactoring away a SourceNode --- .../AngularJS/ServiceDefinitions.qll | 49 +++++++++---------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/AngularJS/ServiceDefinitions.qll b/javascript/ql/src/semmle/javascript/frameworks/AngularJS/ServiceDefinitions.qll index efd54236029..2956f6d07ae 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/AngularJS/ServiceDefinitions.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/AngularJS/ServiceDefinitions.qll @@ -297,34 +297,29 @@ abstract private class CustomSpecialServiceDefinition extends CustomServiceDefin /** * Holds if `mce` defines a service of type `moduleMethodName` with name `serviceName` using the `factoryFunction` as the factory function. */ +bindingset[moduleMethodName] private predicate isCustomServiceDefinitionOnModule( DataFlow::CallNode mce, string moduleMethodName, string serviceName, - DataFlow::SourceNode factoryFunction + DataFlow::SourceNode factoryArgument ) { mce = moduleRef(_).getAMethodCall(moduleMethodName) and - ( - moduleMethodName = "controller" or - moduleMethodName = "filter" or - moduleMethodName = "directive" or - moduleMethodName = "component" or - moduleMethodName = "animation" - ) and mce.getArgument(0).asExpr().mayHaveStringValue(serviceName) and - factoryFunction.flowsTo(mce.getArgument(1)) + factoryArgument = mce.getArgument(1) } +pragma[inline] private predicate isCustomServiceDefinitionOnProvider( DataFlow::CallNode mce, string providerName, string providerMethodName, string serviceName, - DataFlow::SourceNode factoryFunction + DataFlow::Node factoryArgument ) { mce = builtinServiceRef(providerName).getAMethodCall(providerMethodName) and ( mce.getNumArgument() = 1 and - factoryFunction.flowsTo(mce.getOptionArgument(0, serviceName)) + factoryArgument = mce.getOptionArgument(0, serviceName) or mce.getNumArgument() = 2 and mce.getArgument(0).asExpr().mayHaveStringValue(serviceName) and - factoryFunction.flowsTo(mce.getArgument(1)) + factoryArgument = mce.getArgument(1) ) } @@ -333,7 +328,7 @@ private predicate isCustomServiceDefinitionOnProvider( */ class ControllerDefinition extends CustomSpecialServiceDefinition { string name; - DataFlow::SourceNode factoryFunction; + DataFlow::Node factoryFunction; ControllerDefinition() { isCustomServiceDefinitionOnModule(this, "controller", name, factoryFunction) or @@ -343,9 +338,9 @@ class ControllerDefinition extends CustomSpecialServiceDefinition { override string getName() { result = name } - override DataFlow::SourceNode getAService() { result = factoryFunction } + override DataFlow::SourceNode getAService() { result = factoryFunction.getALocalSource() } - override DataFlow::SourceNode getAFactoryFunction() { result = factoryFunction } + override DataFlow::SourceNode getAFactoryFunction() { result = factoryFunction.getALocalSource() } } /** @@ -353,7 +348,7 @@ class ControllerDefinition extends CustomSpecialServiceDefinition { */ class FilterDefinition extends CustomSpecialServiceDefinition { string name; - DataFlow::SourceNode factoryFunction; + DataFlow::Node factoryFunction; FilterDefinition() { isCustomServiceDefinitionOnModule(this, "filter", name, factoryFunction) or @@ -364,12 +359,12 @@ class FilterDefinition extends CustomSpecialServiceDefinition { override DataFlow::SourceNode getAService() { exists(InjectableFunction f | - f = factoryFunction and + f = factoryFunction.getALocalSource() and result.flowsToExpr(f.asFunction().getAReturnedExpr()) ) } - override DataFlow::SourceNode getAFactoryFunction() { result = factoryFunction } + override DataFlow::SourceNode getAFactoryFunction() { result = factoryFunction.getALocalSource() } } /** @@ -377,7 +372,7 @@ class FilterDefinition extends CustomSpecialServiceDefinition { */ class DirectiveDefinition extends CustomSpecialServiceDefinition { string name; - DataFlow::SourceNode factoryFunction; + DataFlow::Node factoryFunction; DirectiveDefinition() { isCustomServiceDefinitionOnModule(this, "directive", name, factoryFunction) or @@ -393,7 +388,7 @@ class DirectiveDefinition extends CustomSpecialServiceDefinition { ) } - override DataFlow::SourceNode getAFactoryFunction() { result = factoryFunction } + override DataFlow::SourceNode getAFactoryFunction() { result = factoryFunction.getALocalSource() } } private class CustomDirectiveControllerDependencyInjection extends DependencyInjection { @@ -416,7 +411,7 @@ private class CustomDirectiveControllerDependencyInjection extends DependencyInj */ class ComponentDefinition extends CustomSpecialServiceDefinition { string name; - DataFlow::SourceNode config; + DataFlow::Node config; ComponentDefinition() { isCustomServiceDefinitionOnModule(this, "component", name, config) or @@ -435,7 +430,7 @@ class ComponentDefinition extends CustomSpecialServiceDefinition { override DataFlow::SourceNode getAFactoryFunction() { none() } /** Gets the configuration object for the defined component. */ - DataFlow::SourceNode getConfig() { result = config } + DataFlow::SourceNode getConfig() { result = config.getALocalSource() } } /** @@ -443,7 +438,7 @@ class ComponentDefinition extends CustomSpecialServiceDefinition { */ class AnimationDefinition extends CustomSpecialServiceDefinition { string name; - DataFlow::SourceNode factoryFunction; + DataFlow::Node factoryFunction; AnimationDefinition() { isCustomServiceDefinitionOnModule(this, "animation", name, factoryFunction) or @@ -454,12 +449,12 @@ class AnimationDefinition extends CustomSpecialServiceDefinition { override DataFlow::SourceNode getAService() { exists(InjectableFunction f | - f = factoryFunction and + f = factoryFunction.getALocalSource() and result.flowsToExpr(f.asFunction().getAReturnedExpr()) ) } - override DataFlow::SourceNode getAFactoryFunction() { result = factoryFunction } + override DataFlow::SourceNode getAFactoryFunction() { result = factoryFunction.getALocalSource() } } /** @@ -500,7 +495,7 @@ private class LinkFunctionWithScopeInjection extends ServiceRequest { class InjectableFunctionServiceRequest extends ServiceRequest { InjectableFunction injectedFunction; - InjectableFunctionServiceRequest() { DataFlow::valueNode(this) = injectedFunction } + InjectableFunctionServiceRequest() { injectedFunction.getAstNode() = this } /** * Gets the function of this request. @@ -589,7 +584,7 @@ class ServiceRecipeDefinition extends RecipeDefinition { exists(InjectableFunction f | f = getAFactoryFunction() and - result = DataFlow::valueNode(f.asFunction()) + result.getAstNode() = f.asFunction() ) } } From 61cff8faed6bc82e50003fca54a27b4918662677 Mon Sep 17 00:00:00 2001 From: yoff Date: Wed, 24 Mar 2021 01:06:03 +0100 Subject: [PATCH 316/725] Update python/ql/src/experimental/semmle/python/Concepts.qll Co-authored-by: Rasmus Wriedt Larsen --- python/ql/src/experimental/semmle/python/Concepts.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/experimental/semmle/python/Concepts.qll b/python/ql/src/experimental/semmle/python/Concepts.qll index 38d7ffb11c2..904b7967ee8 100644 --- a/python/ql/src/experimental/semmle/python/Concepts.qll +++ b/python/ql/src/experimental/semmle/python/Concepts.qll @@ -8,7 +8,7 @@ * provide concrete subclasses. */ -import python +private import python private import semmle.python.dataflow.new.DataFlow private import semmle.python.dataflow.new.RemoteFlowSources private import semmle.python.dataflow.new.TaintTracking From ac0430883ac25c3e45ca710c8077f11525e14fa0 Mon Sep 17 00:00:00 2001 From: yoff Date: Wed, 24 Mar 2021 01:08:12 +0100 Subject: [PATCH 317/725] Update docs/codeql/codeql-language-guides/using-api-graphs-in-python.rst Co-authored-by: Rasmus Wriedt Larsen --- .../codeql-language-guides/using-api-graphs-in-python.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/codeql/codeql-language-guides/using-api-graphs-in-python.rst b/docs/codeql/codeql-language-guides/using-api-graphs-in-python.rst index 38386f52887..ba274933d0f 100644 --- a/docs/codeql/codeql-language-guides/using-api-graphs-in-python.rst +++ b/docs/codeql/codeql-language-guides/using-api-graphs-in-python.rst @@ -31,7 +31,7 @@ following snippet demonstrates. ➤ `See this in the query console on LGTM.com `__. -This query selects the API graph node corresponding to the ``re`` module. This node represent the fact that the ``re`` module has been imported rather than a specific place in the program where the import happens. There will, therefore, be at most one result per file, and it will not have a useful location, so you have to click `Show 1 non-source result` in order to see it. +This query selects the API graph node corresponding to the ``re`` module. This node represent the fact that the ``re`` module has been imported rather than a specific place in the program where the import happens. Therefore, there will be at most one result per project, and it will not have a useful location, so you have to click `Show 1 non-source result` in order to see it. To find places in the program where the ``re`` module is referenced, you can use the ``getAUse`` method. The following query selects all references to the ``re`` module in the current database. From a9af135d7e892f690669f57e1a8662970cdd2acf Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Wed, 24 Mar 2021 01:22:21 +0100 Subject: [PATCH 318/725] Python: Remove `getALocalTaintSource` and `taintFlowsTo` for now.. --- .../2021-03-12-small-api-enhancements.md | 1 - .../dataflow/new/internal/DataFlowPublic.qll | 5 ---- .../dataflow/new/internal/LocalSources.qll | 23 ------------------- .../locations/general/Locations.expected | 1 - .../locations/general/Locations.expected | 1 - 5 files changed, 31 deletions(-) diff --git a/python/change-notes/2021-03-12-small-api-enhancements.md b/python/change-notes/2021-03-12-small-api-enhancements.md index ce7421cde7c..8d3c5c67b5f 100644 --- a/python/change-notes/2021-03-12-small-api-enhancements.md +++ b/python/change-notes/2021-03-12-small-api-enhancements.md @@ -1,4 +1,3 @@ lgtm,codescanning * The class ParameterNode now extends LocalSourceNode, thus making methods like flowsTo available. -* Local taint tracking can now be performed using the `taintFlowsTo` method on the `LocalSourceNode` class. Conversely, the new member predicate `getALocalTaintSource` can be called on a `DataFlow::Node` to obtain a `LocalSourceNode` from which taint can be tracked locally to that data-flow node. * The new predicate `parameterNode` can now be used to map from a `Parameter` to a data-flow node. diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll index e802373a527..36db37a0a0f 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll @@ -139,11 +139,6 @@ class Node extends TNode { * Gets a local source node from which data may flow to this node in zero or more local data-flow steps. */ LocalSourceNode getALocalSource() { result.flowsTo(this) } - - /** - * Gets a local source node from which data may flow to this node in zero or more local taint-flow steps. - */ - LocalSourceNode getALocalTaintSource() { result.taintFlowsTo(this) } } /** A data-flow node corresponding to an SSA variable. */ diff --git a/python/ql/src/semmle/python/dataflow/new/internal/LocalSources.qll b/python/ql/src/semmle/python/dataflow/new/internal/LocalSources.qll index 26d731061b4..205188dd5fd 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/LocalSources.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/LocalSources.qll @@ -9,7 +9,6 @@ import python import DataFlowPublic private import DataFlowPrivate -private import TaintTrackingPublic /** * A data flow node that is a source of local flow. This includes things like @@ -28,10 +27,6 @@ class LocalSourceNode extends Node { pragma[inline] predicate flowsTo(Node nodeTo) { Cached::hasLocalSource(nodeTo, this) } - /** Holds if this `LocalSourceNode` can flow to `nodeTo` in one or more local taint steps. */ - pragma[inline] - predicate taintFlowsTo(Node nodeTo) { Cached::hasLocalTaintSource(nodeTo, this) } - /** * Gets a reference (read or write) of attribute `attrName` on this node. */ @@ -82,24 +77,6 @@ private module Cached { ) } - /** - * Holds if `source` is a `LocalSourceNode` that can reach `sink` via local taint steps. - * - * The slightly backwards parametering ordering is to force correct indexing. - */ - cached - predicate hasLocalTaintSource(Node sink, Node source) { - // Declaring `source` to be a `LocalSourceNode` currently causes a redundant check in the - // recursive case, so instead we check it explicitly here. - source = sink and - source instanceof LocalSourceNode - or - exists(Node mid | - hasLocalTaintSource(mid, source) and - localTaintStep(mid, sink) - ) - } - /** * Holds if `base` flows to the base of `ref` and `ref` has attribute name `attr`. */ diff --git a/python/ql/test/2/library-tests/locations/general/Locations.expected b/python/ql/test/2/library-tests/locations/general/Locations.expected index c6473cb2cc2..3c74898d80f 100644 --- a/python/ql/test/2/library-tests/locations/general/Locations.expected +++ b/python/ql/test/2/library-tests/locations/general/Locations.expected @@ -55,7 +55,6 @@ | Dict | 46 | 54 | 46 | 55 | | Dict | 48 | 9 | 48 | 19 | | DictUnpacking | 46 | 52 | 46 | 55 | -| DjangoViewClassHelper | 4 | 1 | 4 | 8 | | Ellipsis | 7 | 7 | 7 | 9 | | Ellipsis | 50 | 14 | 50 | 16 | | ExceptStmt | 32 | 9 | 32 | 31 | diff --git a/python/ql/test/3/library-tests/locations/general/Locations.expected b/python/ql/test/3/library-tests/locations/general/Locations.expected index 70217f5117a..8da184f747e 100644 --- a/python/ql/test/3/library-tests/locations/general/Locations.expected +++ b/python/ql/test/3/library-tests/locations/general/Locations.expected @@ -44,7 +44,6 @@ | Dict | 46 | 54 | 46 | 55 | | Dict | 48 | 9 | 48 | 19 | | DictUnpacking | 46 | 52 | 46 | 55 | -| DjangoViewClassHelper | 4 | 1 | 4 | 8 | | Ellipsis | 7 | 7 | 7 | 9 | | Ellipsis | 50 | 14 | 50 | 16 | | ExceptStmt | 32 | 9 | 32 | 31 | From c96b8301ed8ab2d7d0efd1de562bc5b8227bf094 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 24 Mar 2021 09:58:44 +0100 Subject: [PATCH 319/725] C#: Add change note --- csharp/change-notes/2021-03-24-cil-ssa.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 csharp/change-notes/2021-03-24-cil-ssa.md diff --git a/csharp/change-notes/2021-03-24-cil-ssa.md b/csharp/change-notes/2021-03-24-cil-ssa.md new file mode 100644 index 00000000000..2c971fe39f5 --- /dev/null +++ b/csharp/change-notes/2021-03-24-cil-ssa.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* A static single assignment (SSA) library has been added to the CIL analysis library. The SSA library replaces the existing `DefUse` module, which has been deprecated. From c5c80204d54295fa9fda23a8e3468f7aed7c91da Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 3 Mar 2021 10:27:26 +0100 Subject: [PATCH 320/725] C#: Rework flow summary implementation --- .../code/csharp/dataflow/FlowSummary.qll | 230 +- .../csharp/dataflow/LibraryTypeDataFlow.qll | 252 +- .../dataflow/internal/DataFlowDispatch.qll | 106 +- .../dataflow/internal/DataFlowPrivate.qll | 306 +- .../dataflow/internal/DataFlowPublic.qll | 14 +- .../dataflow/internal/FlowSummaryImpl.qll | 870 +-- .../internal/FlowSummaryImplSpecific.qll | 79 + .../dataflow/internal/FlowSummarySpecific.qll | 178 - .../internal/TaintTrackingPrivate.qll | 8 +- .../csharp/frameworks/EntityFramework.qll | 158 +- .../collections/CollectionFlow.expected | 62 +- .../dataflow/delegates/DelegateFlow.expected | 4 +- .../dataflow/global/GetAnOutNode.expected | 319 +- .../dataflow/library/FlowSummaries.expected | 5420 ++++++++--------- .../dataflow/library/FlowSummaries.ql | 8 +- .../EntityFramework/FlowSummaries.expected | 292 +- .../EntityFramework/FlowSummaries.ql | 9 +- 17 files changed, 4151 insertions(+), 4164 deletions(-) create mode 100644 csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummaryImplSpecific.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummarySpecific.qll diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/FlowSummary.qll b/csharp/ql/src/semmle/code/csharp/dataflow/FlowSummary.qll index 587a6dc0cd0..054131d2c06 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/FlowSummary.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/FlowSummary.qll @@ -1,181 +1,109 @@ -/** - * Provides classes and predicates for definining flow summaries. - */ +/** Provides classes and predicates for definining flow summaries. */ import csharp private import internal.FlowSummaryImpl as Impl -private import internal.FlowSummarySpecific::Private -private import internal.DataFlowPublic as DataFlowPublic +private import internal.DataFlowDispatch + // import all instances below -private import semmle.code.csharp.dataflow.LibraryTypeDataFlow -private import semmle.code.csharp.frameworks.EntityFramework +private module Summaries { + private import semmle.code.csharp.dataflow.LibraryTypeDataFlow + private import semmle.code.csharp.frameworks.EntityFramework +} -class SummarizableCallable = Impl::Public::SummarizableCallable; +class SummaryComponent = Impl::Public::SummaryComponent; -/** An unbound method. */ -class SummarizableMethod extends SummarizableCallable, Method { } +/** Provides predicates for constructing summary components. */ +module SummaryComponent { + import Impl::Public::SummaryComponent -class ContentList = Impl::Public::ContentList; + /** Gets a summary component that represents a qualifier. */ + SummaryComponent qualifier() { result = argument(-1) } -/** Provides predicates for constructing content lists. */ -module ContentList { - import Impl::Public::ContentList + /** Gets a summary component that represents an element in a collection. */ + SummaryComponent element() { result = content(any(DataFlow::ElementContent c)) } - /** Gets the singleton "element content" content list. */ - ContentList element() { result = singleton(any(DataFlowPublic::ElementContent c)) } - - /** Gets a singleton property content list. */ - ContentList property(Property p) { - result = - singleton(any(DataFlowPublic::PropertyContent c | c.getProperty() = p.getUnboundDeclaration())) + /** Gets a summary component for property `p`. */ + SummaryComponent property(Property p) { + result = content(any(DataFlow::PropertyContent c | c.getProperty() = p.getUnboundDeclaration())) } - /** Gets a singleton field content list. */ - ContentList field(Field f) { + /** Gets a summary component for field `f`. */ + SummaryComponent field(Field f) { + result = content(any(DataFlow::FieldContent c | c.getField() = f.getUnboundDeclaration())) + } + + /** Gets a summary component that represents the return value of a call. */ + SummaryComponent return() { result = return(any(NormalReturnKind rk)) } + + /** + * Gets a summary component that represents the return value through the `i`th + * `out` argument of a call. + */ + SummaryComponent outArgument(int i) { + result = return(any(OutReturnKind rk | rk.getPosition() = i)) + } + + /** + * Gets a summary component that represents the return value through the `i`th + * `ref` argument of a call. + */ + SummaryComponent refArgument(int i) { + result = return(any(RefReturnKind rk | rk.getPosition() = i)) + } + + /** Gets a summary component that represents a jump to `c`. */ + SummaryComponent jump(Callable c) { result = - singleton(any(DataFlowPublic::FieldContent c | c.getField() = f.getUnboundDeclaration())) + return(any(JumpReturnKind jrk | + jrk.getTarget() = c.getUnboundDeclaration() and + jrk.getTargetReturnKind() instanceof NormalReturnKind + )) } } -class SummaryInput = Impl::Public::SummaryInput; +class SummaryComponentStack = Impl::Public::SummaryComponentStack; -/** Provides predicates for constructing flow-summary input specifications */ -module SummaryInput { - private import semmle.code.csharp.frameworks.system.Collections +/** Provides predicates for constructing stacks of summary components. */ +module SummaryComponentStack { + import Impl::Public::SummaryComponentStack - /** - * Gets an input specification that specifies the `i`th parameter as - * the input. - */ - SummaryInput parameter(int i) { result = TParameterSummaryInput(i) } + /** Gets a singleton stack representing a qualifier. */ + SummaryComponentStack qualifier() { result = singleton(SummaryComponent::qualifier()) } - private predicate isCollectionType(ValueOrRefType t) { - t.getABaseType*() instanceof SystemCollectionsIEnumerableInterface and - not t instanceof StringType + /** Gets a stack representing an element of `of`. */ + SummaryComponentStack elementOf(SummaryComponentStack of) { + result = push(SummaryComponent::element(), of) } - /** - * Gets an input specification that specifies the `i`th parameter as - * the input. - * - * `inputContents` is either empty or a singleton element content list, - * depending on whether the type of the `i`th parameter of `c` is a - * collection type. - */ - SummaryInput parameter(SummarizableCallable c, int i, ContentList inputContents) { - result = parameter(i) and - exists(Parameter p | - p = c.getParameter(i) and - if isCollectionType(p.getType()) - then inputContents = ContentList::element() - else inputContents = ContentList::empty() - ) + /** Gets a stack representing a propery `p` of `of`. */ + SummaryComponentStack propertyOf(Property p, SummaryComponentStack of) { + result = push(SummaryComponent::property(p), of) } - /** - * Gets an input specification that specifies the implicit `this` parameter - * as the input. - */ - SummaryInput thisParameter() { result = TParameterSummaryInput(-1) } - - /** - * Gets an input specification that specifies output from the delegate at - * parameter `i` as the input. - */ - SummaryInput delegate(int i) { result = TDelegateSummaryInput(i) } - - /** - * Gets an input specification that specifies output from the delegate at - * parameter `i` as the input. - * - * `c` must be a compatible callable, that is, a callable where the `i`th - * parameter is a delegate. - */ - SummaryInput delegate(SummarizableCallable c, int i) { - result = delegate(i) and - hasDelegateArgumentPosition(c, i) - } -} - -class SummaryOutput = Impl::Public::SummaryOutput; - -/** Provides predicates for constructing flow-summary output specifications. */ -module SummaryOutput { - /** - * Gets an output specification that specifies the return value from a call as - * the output. - */ - SummaryOutput return() { result = TReturnSummaryOutput() } - - /** - * Gets an output specification that specifies the `i`th parameter as the - * output. - */ - SummaryOutput parameter(int i) { result = TParameterSummaryOutput(i) } - - /** - * Gets an output specification that specifies the implicit `this` parameter - * as the output. - */ - SummaryOutput thisParameter() { result = TParameterSummaryOutput(-1) } - - /** - * Gets an output specification that specifies parameter `j` of the delegate at - * parameter `i` as the output. - */ - SummaryOutput delegate(int i, int j) { result = TDelegateSummaryOutput(i, j) } - - /** - * Gets an output specification that specifies parameter `j` of the delegate at - * parameter `i` as the output. - * - * `c` must be a compatible callable, that is, a callable where the `i`th - * parameter is a delegate with a parameter at position `j`. - */ - SummaryOutput delegate(SummarizableCallable c, int i, int j) { - result = TDelegateSummaryOutput(i, j) and - hasDelegateArgumentPosition2(c, i, j) + /** Gets a stack representing a field `f` of `of`. */ + SummaryComponentStack fieldOf(Field f, SummaryComponentStack of) { + result = push(SummaryComponent::field(f), of) } + /** Gets a singleton stack representing the return value of a call. */ + SummaryComponentStack return() { result = singleton(SummaryComponent::return()) } + /** - * Gets an output specification that specifies the `output` of `target` as the - * output. That is, data will flow into one callable and out of another callable - * (`target`). - * - * `output` is limited to (this) parameters and ordinary returns. + * Gets a singleton stack representing the return value through the `i`th + * `out` argument of a call. */ - SummaryOutput jump(SummarizableCallable target, SummaryOutput output) { - result = TJumpSummaryOutput(target, toReturnKind(output)) - } + SummaryComponentStack outArgument(int i) { result = singleton(SummaryComponent::outArgument(i)) } + + /** + * Gets a singleton stack representing the return value through the `i`th + * `ref` argument of a call. + */ + SummaryComponentStack refArgument(int i) { result = singleton(SummaryComponent::refArgument(i)) } + + /** Gets a singleton stack representing a jump to `c`. */ + SummaryComponentStack jump(Callable c) { result = singleton(SummaryComponent::jump(c)) } } class SummarizedCallable = Impl::Public::SummarizedCallable; -/** Provides a query predicate for outputting a set of relevant flow summaries. */ -module TestOutput { - /** A flow summary to include in the `summary/3` query predicate. */ - abstract class RelevantSummarizedCallable extends SummarizedCallable { } - - /** A query predicate for outputting flow summaries in QL tests. */ - query predicate summary(string callable, string flow, boolean preservesValue) { - exists( - RelevantSummarizedCallable c, SummaryInput input, ContentList inputContents, - string inputContentsString, SummaryOutput output, ContentList outputContents, - string outputContentsString - | - callable = c.getQualifiedNameWithTypes() and - Impl::Private::summary(c, input, inputContents, output, outputContents, preservesValue) and - ( - if inputContents.length() = 0 - then inputContentsString = "" - else inputContentsString = " [" + inputContents + "]" - ) and - ( - if outputContents.length() = 0 - then outputContentsString = "" - else outputContentsString = " [" + outputContents + "]" - ) and - flow = input + inputContentsString + " -> " + output + outputContentsString - ) - } -} +class RequiredSummaryComponentStack = Impl::Public::RequiredSummaryComponentStack; diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll b/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll index 547d269a24c..5798080a98a 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll @@ -354,86 +354,148 @@ abstract class LibraryTypeDataFlow extends Type { } } -private CallableFlowSource toCallableFlowSource(SummaryInput input) { - result = TCallableFlowSourceQualifier() and - input = SummaryInput::parameter(-1) - or - exists(int i | - result = TCallableFlowSourceArg(i) and - input = SummaryInput::parameter(i) - ) - or - exists(int i | - result = TCallableFlowSourceDelegateArg(i) and - input = SummaryInput::delegate(i) - ) -} - -private CallableFlowSink toCallableFlowSink(SummaryOutput output) { - result = TCallableFlowSinkQualifier() and - output = SummaryOutput::parameter(-1) - or - result = TCallableFlowSinkReturn() and - output = SummaryOutput::return() - or - exists(int i | - result = TCallableFlowSinkArg(i) and - output = SummaryOutput::parameter(i) - ) - or - exists(int i, int j | - result = TCallableFlowSinkDelegateArg(i, j) and - output = SummaryOutput::delegate(i, j) - ) -} - -private AccessPath toAccessPath(ContentList cl) { - cl = ContentList::empty() and - result = TNilAccessPath() - or - exists(Content head, ContentList tail | - cl = ContentList::cons(head, tail) and - result = TConsAccessPath(head, toAccessPath(tail)) - ) -} - -private class FrameworkDataFlowAdaptor extends SummarizedCallable { - private LibraryTypeDataFlow ltdf; - - FrameworkDataFlowAdaptor() { - ltdf.callableFlow(_, _, this, _) or - ltdf.callableFlow(_, _, _, _, this, _) or - ltdf.clearsContent(_, _, this) - } - - override predicate propagatesFlow(SummaryInput input, SummaryOutput output, boolean preservesValue) { - ltdf.callableFlow(toCallableFlowSource(input), toCallableFlowSink(output), this, preservesValue) - } - - override predicate propagatesFlow( - SummaryInput input, ContentList inputContents, SummaryOutput output, ContentList outputContents, - boolean preservesValue - ) { - ltdf.callableFlow(toCallableFlowSource(input), toAccessPath(inputContents), - toCallableFlowSink(output), toAccessPath(outputContents), this, preservesValue) - } - - private AccessPath getAnAccessPath() { - ltdf.callableFlow(_, result, _, _, this, _) +/** + * An internal module for translating old `LibraryTypeDataFlow`-style + * flow summaries into the new style. + */ +private module FrameworkDataFlowAdaptor { + private CallableFlowSource toCallableFlowSource(SummaryComponentStack input) { + result = TCallableFlowSourceQualifier() and + input = SummaryComponentStack::qualifier() or - ltdf.callableFlow(_, _, _, result, _, _) - } - - override predicate requiresContentList(Content head, ContentList tail) { - exists(AccessPath ap | - ap = this.getAnAccessPath().drop(_) and - head = ap.getHead() and - toAccessPath(tail) = ap.getTail() + exists(int i | + result = TCallableFlowSourceArg(i) and + input = SummaryComponentStack::argument(i) + ) + or + exists(int i | result = TCallableFlowSourceDelegateArg(i) | + input = + SummaryComponentStack::push(SummaryComponent::return(), SummaryComponentStack::argument(i)) ) } - override predicate clearsContent(SummaryInput input, Content content) { - ltdf.clearsContent(toCallableFlowSource(input), content, this) + private CallableFlowSink toCallableFlowSink(SummaryComponentStack output) { + result = TCallableFlowSinkQualifier() and + output = SummaryComponentStack::qualifier() + or + result = TCallableFlowSinkReturn() and + output = SummaryComponentStack::return() + or + exists(int i | + result = TCallableFlowSinkArg(i) and + output = SummaryComponentStack::outArgument(i) + ) + or + exists(int i, int j | result = TCallableFlowSinkDelegateArg(i, j) | + output = + SummaryComponentStack::push(SummaryComponent::parameter(j), + SummaryComponentStack::argument(i)) + ) + } + + private class FrameworkDataFlowAdaptor extends SummarizedCallable { + private LibraryTypeDataFlow ltdf; + + FrameworkDataFlowAdaptor() { + ltdf.callableFlow(_, _, this, _) or + ltdf.callableFlow(_, _, _, _, this, _) or + ltdf.clearsContent(_, _, this) + } + + predicate input( + CallableFlowSource source, AccessPath sourceAp, SummaryComponent head, + SummaryComponentStack tail, int i + ) { + ltdf.callableFlow(source, sourceAp, _, _, this, _) and + source = toCallableFlowSource(tail) and + head = SummaryComponent::content(sourceAp.getHead()) and + i = 0 + or + exists(SummaryComponent tailHead, SummaryComponentStack tailTail | + this.input(source, sourceAp, tailHead, tailTail, i - 1) and + head = SummaryComponent::content(sourceAp.drop(i).getHead()) and + tail = SummaryComponentStack::push(tailHead, tailTail) + ) + } + + predicate output( + CallableFlowSink sink, AccessPath sinkAp, SummaryComponent head, SummaryComponentStack tail, + int i + ) { + ltdf.callableFlow(_, _, sink, sinkAp, this, _) and + sink = toCallableFlowSink(tail) and + head = SummaryComponent::content(sinkAp.getHead()) and + i = 0 + or + exists(SummaryComponent tailHead, SummaryComponentStack tailTail | + this.output(sink, sinkAp, tailHead, tailTail, i - 1) and + head = SummaryComponent::content(sinkAp.drop(i).getHead()) and + tail = SummaryComponentStack::push(tailHead, tailTail) + ) + } + + override predicate propagatesFlow( + SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue + ) { + ltdf.callableFlow(toCallableFlowSource(input), toCallableFlowSink(output), this, + preservesValue) + or + exists( + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp + | + ltdf.callableFlow(source, sourceAp, sink, sinkAp, this, preservesValue) and + ( + exists(SummaryComponent head, SummaryComponentStack tail | + this.input(source, sourceAp, head, tail, sourceAp.length() - 1) and + input = SummaryComponentStack::push(head, tail) + ) + or + sourceAp.length() = 0 and + source = toCallableFlowSource(input) + ) and + ( + exists(SummaryComponent head, SummaryComponentStack tail | + this.output(sink, sinkAp, head, tail, sinkAp.length() - 1) and + output = SummaryComponentStack::push(head, tail) + ) + or + sinkAp.length() = 0 and + sink = toCallableFlowSink(output) + ) + ) + } + + override predicate clearsContent(int i, Content content) { + exists(SummaryComponentStack input | + ltdf.clearsContent(toCallableFlowSource(input), content, this) and + input = SummaryComponentStack::singleton(SummaryComponent::argument(i)) + ) + } + } + + private class AdaptorRequiredSummaryComponentStack extends RequiredSummaryComponentStack { + private SummaryComponent head; + + AdaptorRequiredSummaryComponentStack() { + exists(int i | + exists(TCallableFlowSourceDelegateArg(i)) and + head = SummaryComponent::return() and + this = SummaryComponentStack::singleton(SummaryComponent::argument(i)) + ) + or + exists(int i, int j | exists(TCallableFlowSinkDelegateArg(i, j)) | + head = SummaryComponent::parameter(j) and + this = SummaryComponentStack::singleton(SummaryComponent::argument(i)) + ) + or + exists(FrameworkDataFlowAdaptor adaptor | + adaptor.input(_, _, head, this, _) + or + adaptor.output(_, _, head, this, _) + ) + } + + override predicate required(SummaryComponent c) { c = head } } } @@ -2417,20 +2479,38 @@ class StringValuesFlow extends LibraryTypeDataFlow, Struct { } } +private predicate recordConstructorFlow(Constructor c, int i, Property p) { + c = any(Record r).getAMember() and + exists(string name | + c.getParameter(i).getName() = name and + c.getDeclaringType().getAMember(name) = p + ) +} + +private class RecordConstructorFlowRequiredSummaryComponentStack extends RequiredSummaryComponentStack { + private SummaryComponent head; + + RecordConstructorFlowRequiredSummaryComponentStack() { + exists(Property p | + recordConstructorFlow(_, _, p) and + head = SummaryComponent::property(p) and + this = SummaryComponentStack::singleton(SummaryComponent::return()) + ) + } + + override predicate required(SummaryComponent c) { c = head } +} + private class RecordConstructorFlow extends SummarizedCallable { - RecordConstructorFlow() { this = any(Record r).getAMember().(Constructor) } + RecordConstructorFlow() { recordConstructorFlow(this, _, _) } override predicate propagatesFlow( - SummaryInput input, ContentList inputContents, SummaryOutput output, ContentList outputContents, - boolean preservesValue + SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue ) { - exists(int i, Property p, string name | - this.getParameter(i).getName() = name and - this.getDeclaringType().getAMember(name) = p and - input = SummaryInput::parameter(i) and - inputContents = ContentList::empty() and - output = SummaryOutput::return() and - outputContents = ContentList::property(p) and + exists(int i, Property p | + recordConstructorFlow(this, i, p) and + input = SummaryComponentStack::argument(i) and + output = SummaryComponentStack::propertyOf(p, SummaryComponentStack::return()) and preservesValue = true ) } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll index 025175061ae..4eac274b04f 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll @@ -9,6 +9,12 @@ private import semmle.code.csharp.dispatch.Dispatch private import semmle.code.csharp.frameworks.system.Collections private import semmle.code.csharp.frameworks.system.collections.Generic +private predicate summarizedCallable(DataFlowCallable c) { + c instanceof SummarizedCallable + or + FlowSummaryImpl::Private::summaryReturnNode(_, TJumpReturnKind(c, _)) +} + /** * Gets a source declaration of callable `c` that has a body or has * a flow summary. @@ -18,11 +24,8 @@ private import semmle.code.csharp.frameworks.system.collections.Generic */ DotNet::Callable getCallableForDataFlow(DotNet::Callable c) { exists(DotNet::Callable unboundDecl | unboundDecl = c.getUnboundDeclaration() | - result = unboundDecl and - result instanceof SummarizedCallable - or - result = unboundDecl and - FlowSummaryImpl::Private::summary(_, _, _, SummaryOutput::jump(result, _), _, _) + summarizedCallable(unboundDecl) and + result = unboundDecl or result.hasBody() and if unboundDecl.getFile().fromSource() @@ -44,17 +47,6 @@ DotNet::Callable getCallableForDataFlow(DotNet::Callable c) { ) } -/** - * Holds if callable `c` can return `e` as an `out`/`ref` value for parameter `p`. - */ -private predicate callableReturnsOutOrRef(Callable c, Parameter p, Expr e) { - exists(Ssa::ExplicitDefinition def | - def.getADefinition().getSource() = e and - def.isLiveOutRefParameterDefinition(p) and - p = c.getAParameter() - ) -} - /** * Holds if `cfn` corresponds to a call that can reach callable `c` using * additional calls, and `c` is a callable that either reads or writes to @@ -82,18 +74,22 @@ private module Cached { cached newtype TReturnKind = TNormalReturnKind() { Stages::DataFlowStage::forceCachingInSameStage() } or - TOutReturnKind(int i) { - exists(Parameter p | callableReturnsOutOrRef(_, p, _) and p.isOut() | i = p.getPosition()) - } or - TRefReturnKind(int i) { - exists(Parameter p | callableReturnsOutOrRef(_, p, _) and p.isRef() | i = p.getPosition()) - } or + TOutReturnKind(int i) { i = any(Parameter p | p.isOut()).getPosition() } or + TRefReturnKind(int i) { i = any(Parameter p | p.isRef()).getPosition() } or TImplicitCapturedReturnKind(LocalScopeVariable v) { exists(Ssa::ExplicitDefinition def | def.isCapturedVariableDefinitionFlowOut(_, _) | v = def.getSourceVariable().getAssignable() ) } or - TQualifierReturnKind() + TJumpReturnKind(DataFlowCallable target, ReturnKind rk) { + rk instanceof NormalReturnKind and + ( + target instanceof Constructor or + not target.getReturnType() instanceof VoidType + ) + or + exists(target.getParameter(rk.(OutRefReturnKind).getPosition())) + } cached newtype TDataFlowCall = @@ -110,16 +106,8 @@ private module Cached { // No need to include calls that are compiled from source not call.getImplementation().getMethod().compiledFromSource() } or - TSummaryDelegateCall(SummarizedCallable c, int pos) { - exists(SummaryInput input | - FlowSummaryImpl::Private::summary(c, input, _, _, _, _) and - input = SummaryInput::delegate(pos) - ) - or - exists(SummaryOutput output | - FlowSummaryImpl::Private::summary(c, _, _, output, _, _) and - output = SummaryOutput::delegate(pos, _) - ) + TSummaryCall(SummarizedCallable c, Node receiver) { + FlowSummaryImpl::Private::summaryCallbackRange(c, receiver) } /** Gets a viable run-time target for the call `call`. */ @@ -218,12 +206,30 @@ class ImplicitCapturedReturnKind extends ReturnKind, TImplicitCapturedReturnKind override string toString() { result = "captured " + v } } -/** A value returned through the qualifier of a call. */ -class QualifierReturnKind extends ReturnKind, TQualifierReturnKind { - override string toString() { result = "qualifier" } +/** + * A value returned through the output of another callable. + * + * This is currently only used to model flow summaries where data may flow into + * one API entry point and out of another. + */ +class JumpReturnKind extends ReturnKind, TJumpReturnKind { + private DataFlowCallable target; + private ReturnKind rk; + + JumpReturnKind() { this = TJumpReturnKind(target, rk) } + + /** Gets the target of the jump. */ + DataFlowCallable getTarget() { result = target } + + /** Gets the return kind of the target. */ + ReturnKind getTargetReturnKind() { result = rk } + + override string toString() { result = "jump to " + target } } -class DataFlowCallable = DotNet::Callable; +class DataFlowCallable extends DotNet::Callable { + DataFlowCallable() { this.isUnboundDeclaration() } +} /** A call relevant for data flow. */ abstract class DataFlowCall extends TDataFlowCall { @@ -274,7 +280,7 @@ class NonDelegateDataFlowCall extends DataFlowCall, TNonDelegateCall { override DataFlow::ExprNode getNode() { result.getControlFlowNode() = cfn } - override Callable getEnclosingCallable() { result = cfn.getEnclosingCallable() } + override DataFlowCallable getEnclosingCallable() { result = cfn.getEnclosingCallable() } override string toString() { result = cfn.toString() } @@ -302,7 +308,7 @@ class ExplicitDelegateLikeDataFlowCall extends DelegateDataFlowCall, TExplicitDe override DataFlow::ExprNode getNode() { result.getControlFlowNode() = cfn } - override Callable getEnclosingCallable() { result = cfn.getEnclosingCallable() } + override DataFlowCallable getEnclosingCallable() { result = cfn.getEnclosingCallable() } override string toString() { result = cfn.toString() } @@ -320,13 +326,13 @@ class TransitiveCapturedDataFlowCall extends DataFlowCall, TTransitiveCapturedCa TransitiveCapturedDataFlowCall() { this = TTransitiveCapturedCall(cfn, target) } - override Callable getARuntimeTarget() { result = target } + override DataFlowCallable getARuntimeTarget() { result = target } override ControlFlow::Nodes::ElementNode getControlFlowNode() { result = cfn } override DataFlow::ExprNode getNode() { none() } - override Callable getEnclosingCallable() { result = cfn.getEnclosingCallable() } + override DataFlowCallable getEnclosingCallable() { result = cfn.getEnclosingCallable() } override string toString() { result = "[transitive] " + cfn.toString() } @@ -348,7 +354,7 @@ class CilDataFlowCall extends DataFlowCall, TCilCall { override DataFlow::ExprNode getNode() { result.getExpr() = call } - override CIL::Callable getEnclosingCallable() { result = call.getEnclosingCallable() } + override DataFlowCallable getEnclosingCallable() { result = call.getEnclosingCallable() } override string toString() { result = call.toString() } @@ -356,20 +362,20 @@ class CilDataFlowCall extends DataFlowCall, TCilCall { } /** - * A delegate call inside a callable with a flow summary. + * A synthesized call inside a callable with a flow summary. * * For example, in `ints.Select(i => i + 1)` there is a call to the delegate at * parameter position `1` (counting the qualifier as the `0`th argument) inside * the method `Select`. */ -class SummaryDelegateCall extends DelegateDataFlowCall, TSummaryDelegateCall { +class SummaryCall extends DelegateDataFlowCall, TSummaryCall { private SummarizedCallable c; - private int pos; + private Node receiver; - SummaryDelegateCall() { this = TSummaryDelegateCall(c, pos) } + SummaryCall() { this = TSummaryCall(c, receiver) } - /** Gets the parameter node that this delegate call targets. */ - ParameterNode getParameterNode() { result.isParameterOf(c, pos) } + /** Gets the data flow node that this call targets. */ + Node getReceiver() { result = receiver } override DataFlowCallable getARuntimeTarget() { none() // handled by the shared library @@ -379,9 +385,9 @@ class SummaryDelegateCall extends DelegateDataFlowCall, TSummaryDelegateCall { override DataFlow::Node getNode() { none() } - override Callable getEnclosingCallable() { result = c } + override DataFlowCallable getEnclosingCallable() { result = c } - override string toString() { result = "[summary] delegate call, parameter " + pos + " of " + c } + override string toString() { result = "[summary] call to " + receiver + " in " + c } override Location getLocation() { result = c.getLocation() } } 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 af1511d4ac4..3b646973e28 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -18,7 +18,6 @@ private import semmle.code.csharp.frameworks.EntityFramework private import semmle.code.csharp.frameworks.NHibernate private import semmle.code.csharp.frameworks.system.Collections private import semmle.code.csharp.frameworks.system.threading.Tasks -private import semmle.code.csharp.frameworks.system.linq.Expressions abstract class NodeImpl extends Node { /** Do not call: use `getEnclosingCallable()` instead. */ @@ -70,9 +69,6 @@ private class ExprNodeImpl extends ExprNode, NodeImpl { } } -/** A data-flow node used to interpret a flow summary. */ -abstract private class SummaryNodeImpl extends NodeImpl { } - /** Calculation of the relative order in which `this` references are read. */ private module ThisFlow { private class BasicBlock = ControlFlow::BasicBlock; @@ -379,7 +375,7 @@ module LocalFlow { * inter-procedurality or field-sensitivity. */ predicate excludeFromExposedRelations(Node n) { - n instanceof SummaryNodeImpl or + n instanceof SummaryNode or n instanceof ImplicitCapturedArgumentNode } } @@ -455,9 +451,9 @@ private predicate fieldOrPropertyStore(Expr e, Content c, Expr src, Expr q, bool f.isFieldLike() and f instanceof InstanceFieldOrProperty or - exists(ContentList cl | - FlowSummaryImpl::Private::summary(_, _, cl, _, _, _) and - cl.contains(f.getContent()) + exists(SummarizedCallable callable, FlowSummaryImpl::Public::SummaryComponentStack input | + callable.propagatesFlow(input, _, _) and + input.contains(SummaryComponent::content(f.getContent())) ) ) | @@ -611,8 +607,6 @@ private Gvn::GvnType getANonTypeParameterSubTypeRestricted(DataFlowType t) { /** A collection of cached types and predicates to be evaluated in the same stage. */ cached private module Cached { - private import FlowSummarySpecific as FlowSummarySpecific - cached newtype TNode = TExprNode(ControlFlow::Nodes::ElementNode cfn) { @@ -664,32 +658,8 @@ private module Cached { cfn.getElement() = fla.getQualifier() ) } or - TSummaryInternalNode( - SummarizedCallable c, FlowSummaryImpl::Private::SummaryInternalNodeState state - ) { - FlowSummaryImpl::Private::internalNodeRange(c, state) - } or - TSummaryReturnNode(SummarizedCallable c, ReturnKind rk) { - exists(SummaryOutput output | - FlowSummaryImpl::Private::summary(c, _, _, output, _, _) and - rk = FlowSummarySpecific::Private::toReturnKind(output) - ) - } or - TSummaryDelegateOutNode(SummarizedCallable c, int pos) { - exists(SummaryInput input | - FlowSummaryImpl::Private::summary(c, input, _, _, _, _) and - input = SummaryInput::delegate(pos) - ) - } or - TSummaryDelegateArgumentNode(SummarizedCallable c, int delegateIndex, int parameterIndex) { - exists(SummaryOutput output | - FlowSummaryImpl::Private::summary(c, _, _, output, _, _) and - output = SummaryOutput::delegate(delegateIndex, parameterIndex) - ) - } or - TSummaryJumpNode(SummarizedCallable c, SummarizableCallable target, ReturnKind rk) { - FlowSummaryImpl::Private::summary(c, _, _, - FlowSummarySpecific::Private::TJumpSummaryOutput(target, rk), _, _) + TSummaryNode(SummarizedCallable c, FlowSummaryImpl::Private::SummaryNodeState state) { + FlowSummaryImpl::Private::summaryNodeRange(c, state) } or TParamsArgumentNode(ControlFlow::Node callCfn) { callCfn = any(Call c | isParamsArg(c, _, _)).getAControlFlowNode() @@ -707,7 +677,7 @@ private module Cached { or LocalFlow::localFlowCapturedVarStep(nodeFrom, nodeTo) or - FlowSummaryImpl::Private::localStep(nodeFrom, nodeTo, true) + FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom, nodeTo, true) or nodeTo.(ObjectCreationNode).getPreUpdateNode() = nodeFrom.(ObjectInitializerNode) } @@ -727,7 +697,7 @@ private module Cached { or // Simple flow through library code is included in the exposed local // step relation, even though flow is technically inter-procedural - FlowSummaryImpl::Private::throughStep(nodeFrom, nodeTo, true) + FlowSummaryImpl::Private::Steps::summaryThroughStep(nodeFrom, nodeTo, true) } /** @@ -748,7 +718,11 @@ private module Cached { flr.hasNonlocalValue() ) or - succ = pred.(SummaryJumpNode).getAJumpTarget() + exists(JumpReturnKind jrk, DataFlowCall call | + FlowSummaryImpl::Private::summaryReturnNode(pred, jrk) and + viableCallable(call) = jrk.getTarget() and + succ = getAnOutNode(call, jrk.getTargetReturnKind()) + ) } cached @@ -791,7 +765,7 @@ private module Cached { c = getResultContent() ) or - FlowSummaryImpl::Private::storeStep(node1, c, node2) + FlowSummaryImpl::Private::Steps::summaryStoreStep(node1, c, node2) } pragma[nomagic] @@ -855,7 +829,7 @@ private module Cached { ) ) or - FlowSummaryImpl::Private::readStep(node1, c, node2) + FlowSummaryImpl::Private::Steps::summaryReadStep(node1, c, node2) } /** @@ -869,14 +843,10 @@ private module Cached { or fieldOrPropertyStore(_, c, _, n.(ObjectInitializerNode).getInitializer(), false) or - FlowSummaryImpl::Private::storeStep(n, c, _) and + FlowSummaryImpl::Private::Steps::summaryStoresIntoArg(c, n) and not c instanceof ElementContent or - exists(SummaryInput input, DataFlowCall call, int i | - FlowSummaryImpl::Private::clearsContent(input, call, c) and - input = SummaryInput::parameter(i) and - n.(ArgumentNode).argumentOf(call, i) - ) + FlowSummaryImpl::Private::Steps::summaryClearsContent(n, c) or exists(WithExpr we, ObjectInitializer oi, FieldOrProperty f | oi = we.getInitializer() and @@ -938,11 +908,24 @@ private module Cached { } cached - predicate qualifierOutNode(DataFlowCall call, Node n) { - n.(ExprPostUpdateNode).getPreUpdateNode().(ExplicitArgumentNode).argumentOf(call, -1) - or - any(ObjectOrCollectionInitializerConfiguration x) - .hasExprPath(_, n.(ExprNode).getControlFlowNode(), _, call.getControlFlowNode()) + predicate summaryOutNodeCached(DataFlowCall c, Node out, ReturnKind rk) { + FlowSummaryImpl::Private::summaryOutNode(c, out, rk) + } + + cached + predicate summaryArgumentNodeCached(DataFlowCall c, Node arg, int i) { + FlowSummaryImpl::Private::summaryArgumentNode(c, arg, i) + } + + cached + predicate summaryPostUpdateNodeCached(Node post, ParameterNode pre) { + FlowSummaryImpl::Private::summaryPostUpdateNode(post, pre) + } + + cached + predicate summaryReturnNodeCached(Node ret, ReturnKind rk) { + FlowSummaryImpl::Private::summaryReturnNode(ret, rk) and + not rk instanceof JumpReturnKind } cached @@ -968,6 +951,8 @@ private module Cached { not p.fromSource() ) or + n = TInstanceParameterNode(any(Callable c | not c.fromSource())) + or n instanceof YieldReturnNode or n instanceof AsyncReturnNode @@ -976,7 +961,7 @@ private module Cached { or n instanceof MallocNode or - n instanceof SummaryNodeImpl + n instanceof SummaryNode or n instanceof ParamsArgumentNode or @@ -995,7 +980,7 @@ class SsaDefinitionNode extends NodeImpl, TSsaDefinitionNode { /** Gets the underlying SSA definition. */ Ssa::Definition getDefinition() { result = def } - override Callable getEnclosingCallableImpl() { result = def.getEnclosingCallable() } + override DataFlowCallable getEnclosingCallableImpl() { result = def.getEnclosingCallable() } override Type getTypeImpl() { result = def.getSourceVariable().getType() } @@ -1006,9 +991,13 @@ class SsaDefinitionNode extends NodeImpl, TSsaDefinitionNode { override string toStringImpl() { result = def.toString() } } -private module ParameterNodes { - abstract private class ParameterNodeImpl extends ParameterNode, NodeImpl { } +abstract class ParameterNodeImpl extends NodeImpl { + abstract DotNet::Parameter getParameter(); + abstract predicate isParameterOf(DataFlowCallable c, int i); +} + +private module ParameterNodes { /** * The value of an explicit parameter at function entry, viewed as a node in a data * flow graph. @@ -1048,9 +1037,11 @@ private module ParameterNodes { /** Gets the callable containing this implicit instance parameter. */ Callable getCallable() { result = callable } + override DotNet::Parameter getParameter() { none() } + override predicate isParameterOf(DataFlowCallable c, int pos) { callable = c and pos = -1 } - override Callable getEnclosingCallableImpl() { result = callable } + override DataFlowCallable getEnclosingCallableImpl() { result = callable } override Type getTypeImpl() { result = callable.getDeclaringType() } @@ -1114,7 +1105,7 @@ private module ParameterNodes { * } } * ``` */ - class ImplicitCapturedParameterNode extends ParameterNode, SsaDefinitionNode { + class ImplicitCapturedParameterNode extends ParameterNodeImpl, SsaDefinitionNode { override SsaCapturedEntryDefinition def; ImplicitCapturedParameterNode() { def = this.getDefinition() } @@ -1122,6 +1113,8 @@ private module ParameterNodes { /** Gets the captured variable that this implicit parameter models. */ LocalScopeVariable getVariable() { result = def.getVariable() } + override DotNet::Parameter getParameter() { none() } + override predicate isParameterOf(DataFlowCallable c, int i) { i = getParameterPosition(def) and c = this.getEnclosingCallable() @@ -1223,7 +1216,7 @@ private module ArgumentNodes { ) } - override Callable getEnclosingCallableImpl() { result = cfn.getEnclosingCallable() } + override DataFlowCallable getEnclosingCallableImpl() { result = cfn.getEnclosingCallable() } override Type getTypeImpl() { result = v.getType() } @@ -1250,7 +1243,7 @@ private module ArgumentNodes { override ControlFlow::Node getControlFlowNodeImpl() { result = cfn } - override Callable getEnclosingCallableImpl() { result = cfn.getEnclosingCallable() } + override DataFlowCallable getEnclosingCallableImpl() { result = cfn.getEnclosingCallable() } override Type getTypeImpl() { result = cfn.getElement().(Expr).getType() } @@ -1287,7 +1280,7 @@ private module ArgumentNodes { pos = this.getParameter().getPosition() } - override Callable getEnclosingCallableImpl() { result = callCfn.getEnclosingCallable() } + override DataFlowCallable getEnclosingCallableImpl() { result = callCfn.getEnclosingCallable() } override Type getTypeImpl() { result = this.getParameter().getType() } @@ -1298,46 +1291,15 @@ private module ArgumentNodes { override string toStringImpl() { result = "[implicit array creation] " + callCfn } } - /** - * An argument node inside a callable with a flow summary, where the argument is - * passed to a supplied delegate. For example, in `ints.Select(Foo)` there is a - * node that represents the argument of the call to `Foo` inside `Select`. - */ - class SummaryDelegateArgumentNode extends ArgumentNode, SummaryNodeImpl, - TSummaryDelegateArgumentNode { - private SummarizedCallable c; - private int delegateIndex; - private int parameterIndex; + private class SummaryArgumentNode extends SummaryNode, ArgumentNode { + private DataFlowCall c; + private int i; - SummaryDelegateArgumentNode() { - this = TSummaryDelegateArgumentNode(c, delegateIndex, parameterIndex) - } - - override DataFlowCallable getEnclosingCallableImpl() { result = c } - - override DotNet::Type getTypeImpl() { - result = - c.getParameter(delegateIndex) - .getType() - .(SystemLinqExpressions::DelegateExtType) - .getDelegateType() - .getParameter(parameterIndex) - .getType() - } - - override ControlFlow::Node getControlFlowNodeImpl() { none() } - - override Location getLocationImpl() { result = c.getLocation() } - - override string toStringImpl() { - result = - "[summary] argument " + parameterIndex + " of delegate call, parameter " + parameterIndex + - " of " + c - } + SummaryArgumentNode() { summaryArgumentNodeCached(c, this, i) } override predicate argumentOf(DataFlowCall call, int pos) { - call = TSummaryDelegateCall(c, delegateIndex) and - pos = parameterIndex + call = c and + i = pos } } } @@ -1362,8 +1324,9 @@ private module ReturnNodes { ) } - override ReturnKind getKind() { - any(DotNet::Callable c).canReturn(this.getExpr()) and result instanceof NormalReturnKind + override NormalReturnKind getKind() { + any(DotNet::Callable c).canReturn(this.getExpr()) and + exists(result) } } @@ -1394,7 +1357,7 @@ private module ReturnNodes { override NormalReturnKind getKind() { any() } - override Callable getEnclosingCallableImpl() { result = yrs.getEnclosingCallable() } + override DataFlowCallable getEnclosingCallableImpl() { result = yrs.getEnclosingCallable() } override Type getTypeImpl() { result = yrs.getEnclosingCallable().getReturnType() } @@ -1418,7 +1381,7 @@ private module ReturnNodes { override NormalReturnKind getKind() { any() } - override Callable getEnclosingCallableImpl() { result = expr.getEnclosingCallable() } + override DataFlowCallable getEnclosingCallableImpl() { result = expr.getEnclosingCallable() } override Type getTypeImpl() { result = expr.getEnclosingCallable().getReturnType() } @@ -1468,30 +1431,10 @@ private module ReturnNodes { } } - /** A return node for a callable with a flow summary. */ - class SummaryReturnNode extends ReturnNode, SummaryNodeImpl, TSummaryReturnNode { - private SummarizedCallable sc; + private class SummaryReturnNode extends SummaryNode, ReturnNode { private ReturnKind rk; - SummaryReturnNode() { this = TSummaryReturnNode(sc, rk) } - - override Callable getEnclosingCallableImpl() { result = sc } - - override DotNet::Type getTypeImpl() { - rk instanceof NormalReturnKind and - result in [sc.getReturnType(), sc.(Constructor).getDeclaringType()] - or - rk instanceof QualifierReturnKind and - result = sc.getDeclaringType() - or - result = sc.getParameter(rk.(OutRefReturnKind).getPosition()).getType() - } - - override ControlFlow::Node getControlFlowNodeImpl() { none() } - - override Location getLocationImpl() { result = sc.getLocation() } - - override string toStringImpl() { result = "[summary] return of kind " + rk + " inside " + sc } + SummaryReturnNode() { summaryReturnNodeCached(this, rk) } override ReturnKind getKind() { result = rk } } @@ -1549,32 +1492,17 @@ private module OutNodes { ) { exactScope = false and scope = e1 and - isSuccessor = false and - ( + isSuccessor = true and + exists(ObjectOrCollectionInitializer init | init = e1.(ObjectCreation).getInitializer() | // E.g. `new Dictionary{ {0, "a"}, {1, "b"} }` - e1.(CollectionInitializer).getAnElementInitializer() = e2 + e2 = init.(CollectionInitializer).getAnElementInitializer() or // E.g. `new Dictionary() { [0] = "a", [1] = "b" }` - e1.(ObjectInitializer).getAMemberInitializer().getLValue() = e2 + e2 = init.(ObjectInitializer).getAMemberInitializer().getLValue() ) } } - /** - * A data-flow node that contains a value returned by a callable, by writing - * to the qualifier of the call. - */ - private class QualifierOutNode extends OutNode, Node { - private DataFlowCall call; - - QualifierOutNode() { qualifierOutNode(call, this) } - - override DataFlowCall getCall(ReturnKind kind) { - result = call and - kind instanceof QualifierReturnKind - } - } - /** * A data-flow node that reads a value returned implicitly by a callable * using a captured variable. @@ -1620,39 +1548,15 @@ private module OutNodes { } } - /** - * An output node inside a callable with a flow summary, where the output is the - * result of calling a supplied delegate. For example, in `ints.Select(Foo)` there - * is a node that represents the output of calling `Foo` inside `Select`. - */ - private class SummaryDelegateOutNode extends OutNode, SummaryNodeImpl, TSummaryDelegateOutNode { - private SummarizedCallable c; - private int pos; + private class SummaryOutNode extends SummaryNode, OutNode { + private DataFlowCall c; + private ReturnKind rk; - SummaryDelegateOutNode() { this = TSummaryDelegateOutNode(c, pos) } + SummaryOutNode() { summaryOutNodeCached(c, this, rk) } - override Callable getEnclosingCallableImpl() { result = c } - - override DotNet::Type getTypeImpl() { - result = - c.getParameter(pos) - .getType() - .(SystemLinqExpressions::DelegateExtType) - .getDelegateType() - .getReturnType() - } - - override ControlFlow::Node getControlFlowNodeImpl() { none() } - - override Location getLocationImpl() { result = c.getLocation() } - - override string toStringImpl() { - result = "[summary] output from delegate call, parameter " + pos + " of " + c + "]" - } - - override SummaryDelegateCall getCall(ReturnKind kind) { - result = TSummaryDelegateCall(c, pos) and - kind instanceof NormalReturnKind + override DataFlowCall getCall(ReturnKind kind) { + result = c and + kind = rk } } } @@ -1660,15 +1564,17 @@ private module OutNodes { import OutNodes /** A data-flow node used to model flow summaries. */ -private class SummaryInternalNode extends SummaryNodeImpl, TSummaryInternalNode { +private class SummaryNode extends NodeImpl, TSummaryNode { private SummarizedCallable c; - private FlowSummaryImpl::Private::SummaryInternalNodeState state; + private FlowSummaryImpl::Private::SummaryNodeState state; - SummaryInternalNode() { this = TSummaryInternalNode(c, state) } + SummaryNode() { this = TSummaryNode(c, state) } override DataFlowCallable getEnclosingCallableImpl() { result = c } - override DataFlowType getDataFlowType() { result = state.getType() } + override DataFlowType getDataFlowType() { + result = FlowSummaryImpl::Private::summaryNodeType(this) + } override DotNet::Type getTypeImpl() { none() } @@ -1679,28 +1585,6 @@ private class SummaryInternalNode extends SummaryNodeImpl, TSummaryInternalNode override string toStringImpl() { result = "[summary] " + state + " in " + c } } -/** A data-flow node used to model flow summaries with jumps. */ -private class SummaryJumpNode extends SummaryNodeImpl, TSummaryJumpNode { - private SummarizedCallable c; - private SummarizableCallable target; - private ReturnKind rk; - - SummaryJumpNode() { this = TSummaryJumpNode(c, target, rk) } - - /** Gets a jump target of this node. */ - OutNode getAJumpTarget() { target = viableCallable(result.getCall(rk)) } - - override Callable getEnclosingCallableImpl() { result = c } - - override DotNet::Type getTypeImpl() { result = target.getReturnType() } - - override ControlFlow::Node getControlFlowNodeImpl() { none() } - - override Location getLocationImpl() { result = c.getLocation() } - - override string toStringImpl() { result = "[summary] jump to " + target } -} - /** A field or a property. */ class FieldOrProperty extends Assignable, Modifiable { FieldOrProperty() { @@ -1935,7 +1819,7 @@ private module PostUpdateNodes { * Such a node acts as both a post-update node for the `MallocNode`, as well as * a pre-update node for the `ObjectCreationNode`. */ - class ObjectInitializerNode extends PostUpdateNode, NodeImpl, TObjectInitializerNode { + class ObjectInitializerNode extends PostUpdateNode, NodeImpl, ArgumentNode, TObjectInitializerNode { private ObjectCreation oc; private ControlFlow::Nodes::ElementNode cfn; @@ -1949,7 +1833,13 @@ private module PostUpdateNodes { override MallocNode getPreUpdateNode() { result.getControlFlowNode() = cfn } - override Callable getEnclosingCallableImpl() { result = cfn.getEnclosingCallable() } + override predicate argumentOf(DataFlowCall call, int pos) { + pos = -1 and + any(ObjectOrCollectionInitializerConfiguration x) + .hasExprPath(_, cfn, _, call.getControlFlowNode()) + } + + override DataFlowCallable getEnclosingCallableImpl() { result = cfn.getEnclosingCallable() } override DotNet::Type getTypeImpl() { result = oc.getType() } @@ -1967,7 +1857,7 @@ private module PostUpdateNodes { override ExprNode getPreUpdateNode() { cfn = result.getControlFlowNode() } - override Callable getEnclosingCallableImpl() { result = cfn.getEnclosingCallable() } + override DataFlowCallable getEnclosingCallableImpl() { result = cfn.getEnclosingCallable() } override Type getTypeImpl() { result = cfn.getElement().(Expr).getType() } @@ -1977,6 +1867,14 @@ private module PostUpdateNodes { override string toStringImpl() { result = "[post] " + cfn.toString() } } + + private class SummaryPostUpdateNode extends SummaryNode, PostUpdateNode { + private Node pre; + + SummaryPostUpdateNode() { summaryPostUpdateNodeCached(this, pre) } + + override Node getPreUpdateNode() { result = pre } + } } private import PostUpdateNodes @@ -2077,7 +1975,7 @@ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) { call.getControlFlowNode()) ) or - receiver = call.(SummaryDelegateCall).getParameterNode() + receiver = call.(SummaryCall).getReceiver() ) and kind = TMkUnit() } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll index 662276497ab..40853f7316a 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll @@ -117,22 +117,18 @@ class ExprNode extends Node { * flow graph. */ class ParameterNode extends Node { - ParameterNode() { - // charpred needed to avoid making `ParameterNode` abstract - this = TExplicitParameterNode(_) or - this.(SsaDefinitionNode).getDefinition() instanceof - ImplicitCapturedParameterNodeImpl::SsaCapturedEntryDefinition or - this = TInstanceParameterNode(_) - } + private ParameterNodeImpl p; + + ParameterNode() { this = p } /** Gets the parameter corresponding to this node, if any. */ - DotNet::Parameter getParameter() { none() } + DotNet::Parameter getParameter() { result = p.getParameter() } /** * Holds if this node is the parameter of callable `c` at the specified * (zero-based) position. */ - predicate isParameterOf(DataFlowCallable c, int i) { none() } + predicate isParameterOf(DataFlowCallable c, int i) { p.isParameterOf(c, i) } } /** A definition, viewed as a node in a data flow graph. */ diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll index 2a258d04f2e..08a341ce8c0 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll @@ -2,126 +2,157 @@ * Provides classes and predicates for definining flow summaries. * * The definitions in this file are language-independant, and language-specific - * definitions are passed in via the `FlowSummarySpecific` module. + * definitions are passed in via the `DataFlowImplSpecific` and + * `FlowSummaryImplSpecific` modules. */ -private import FlowSummarySpecific::Private +private import FlowSummaryImplSpecific +private import DataFlowImplSpecific::Private +private import DataFlowImplSpecific::Public -/** - * Provides classes and predicates for definining flow summaries. - */ +/** Provides classes and predicates for definining flow summaries. */ module Public { - import FlowSummarySpecific::Public - - private newtype TContentList = - TNilContentList() or - TConsContentList(Content head, ContentList tail) { - tail = TNilContentList() + /** + * A compontent used in a flow summary. + * + * Either a parameter or an argument at a given position, a specific + * content type, or a return kind. + */ + class SummaryComponent extends TSummaryComponent { + /** Gets a textual representation of this summary component. */ + string toString() { + exists(Content c | this = TContantSummaryComponent(c) and result = c.toString()) or - any(SummarizedCallable c).requiresContentList(head, tail) and - tail.length() < accessPathLimit() + exists(int i | this = TParameterSummaryComponent(i) and result = "parameter " + i) + or + exists(int i | this = TArgumentSummaryComponent(i) and result = "argument " + i) + or + exists(ReturnKind rk | this = TReturnSummaryComponent(rk) and result = "return (" + rk + ")") + } + } + + /** Provides predicates for constructing summary components. */ + module SummaryComponent { + /** Gets a summary component for content `c`. */ + SummaryComponent content(Content c) { result = TContantSummaryComponent(c) } + + /** Gets a summary component for parameter `i`. */ + SummaryComponent parameter(int i) { result = TParameterSummaryComponent(i) } + + /** Gets a summary component for argument `i`. */ + SummaryComponent argument(int i) { result = TArgumentSummaryComponent(i) } + + /** Gets a summary component for a return of kind `rk`. */ + SummaryComponent return(ReturnKind rk) { result = TReturnSummaryComponent(rk) } + } + + /** + * A (non-empty) stack of summary components. + * + * A stack is used to represent where data is read from (input) or where it + * is written to (output). For example, an input stack `[Field f, Argument 0]` + * means that data is read from field `f` from the `0`th argument, while an + * output stack `[Field g, Return]` means that data is written to the field + * `g` of the returned object. + */ + class SummaryComponentStack extends TSummaryComponentStack { + /** Gets the head of this stack. */ + SummaryComponent head() { + this = TSingletonSummaryComponentStack(result) or + this = TConsSummaryComponentStack(result, _) } - /** A content list. */ - class ContentList extends TContentList { - /** Gets the head of this content list, if any. */ - Content head() { this = TConsContentList(result, _) } + /** Gets the tail of this stack, if any. */ + SummaryComponentStack tail() { this = TConsSummaryComponentStack(_, result) } - /** Gets the tail of this content list, if any. */ - ContentList tail() { this = TConsContentList(_, result) } - - /** Gets the length of this content list. */ + /** Gets the length of this stack. */ int length() { - this = TNilContentList() and result = 0 + this = TSingletonSummaryComponentStack(_) and result = 1 or result = 1 + this.tail().length() } - /** Gets the content list obtained by dropping the first `i` elements, if any. */ - ContentList drop(int i) { + /** Gets the stack obtained by dropping the first `i` elements, if any. */ + SummaryComponentStack drop(int i) { i = 0 and result = this or result = this.tail().drop(i - 1) } - /** Holds if this content list contains content `c`. */ - predicate contains(Content c) { c = this.drop(_).head() } + /** Holds if this stack contains summary component `c`. */ + predicate contains(SummaryComponent c) { c = this.drop(_).head() } - /** Gets a textual representation of this content list. */ + /** Gets a textual representation of this stack. */ string toString() { - exists(Content head, ContentList tail | + exists(SummaryComponent head, SummaryComponentStack tail | head = this.head() and tail = this.tail() and - if tail.length() = 0 then result = head.toString() else result = head + ", " + tail + result = head + " of " + tail ) or - this = TNilContentList() and - result = "" + exists(SummaryComponent c | + this = TSingletonSummaryComponentStack(c) and + result = c.toString() + ) } } - /** Provides predicates for constructing content lists. */ - module ContentList { - /** Gets the empty content list. */ - ContentList empty() { result = TNilContentList() } + /** Provides predicates for constructing stacks of summary components. */ + module SummaryComponentStack { + /** Gets a singleton stack containing `c`. */ + SummaryComponentStack singleton(SummaryComponent c) { + result = TSingletonSummaryComponentStack(c) + } - /** Gets a singleton content list containing `c`. */ - ContentList singleton(Content c) { result = TConsContentList(c, TNilContentList()) } - - /** Gets the content list obtained by consing `head` onto `tail`. */ - ContentList cons(Content head, ContentList tail) { result = TConsContentList(head, tail) } - } - - /** A callable with flow summaries. */ - abstract class SummarizedCallable extends SummarizableCallable { /** - * Holds if data may flow from `input` to `output` through this callable. + * Gets the stack obtained by push `head` onto `tail`. * - * `preservesValue` indicates whether this is a value-preserving step - * or a taint-step. + * Make sure to override `RequiredSummaryComponentStack::required()` in order + * to ensure that the constructed stack exists. */ - pragma[nomagic] - predicate propagatesFlow(SummaryInput input, SummaryOutput output, boolean preservesValue) { - none() + SummaryComponentStack push(SummaryComponent head, SummaryComponentStack tail) { + result = TConsSummaryComponentStack(head, tail) } + /** Gets a singleton stack for argument `i`. */ + SummaryComponentStack argument(int i) { result = singleton(SummaryComponent::argument(i)) } + + /** Gets a singleton stack representing a return of kind `rk`. */ + SummaryComponentStack return(ReturnKind rk) { result = singleton(SummaryComponent::return(rk)) } + } + + /** + * A class that exists for QL technical reasons only (the IPA type used + * to represent component stacks needs to be bounded). + */ + abstract class RequiredSummaryComponentStack extends SummaryComponentStack { + /** + * Holds if the stack obtained by pushing `head` onto `tail` is required. + */ + abstract predicate required(SummaryComponent c); + } + + /** A callable with a flow summary. */ + abstract class SummarizedCallable extends DataFlowCallable { /** * Holds if data may flow from `input` to `output` through this callable. * - * `inputContents` describes the contents that is popped from the access - * path from the input and `outputContents` describes the contents that - * is pushed onto the resulting access path. - * * `preservesValue` indicates whether this is a value-preserving step * or a taint-step. */ pragma[nomagic] predicate propagatesFlow( - SummaryInput input, ContentList inputContents, SummaryOutput output, - ContentList outputContents, boolean preservesValue + SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue ) { none() } - /** - * Holds if the content list obtained by consing `head` onto `tail` is needed - * for a summary specified by `propagatesFlow()`. - * - * This predicate is needed for QL technical reasons only (the IPA type used - * to represent content lists needs to be bounded). - * - * Only summaries using content lists of length >= 2 need to override this - * predicate. - */ - pragma[nomagic] - predicate requiresContentList(Content head, ContentList tail) { none() } - /** * Holds if values stored inside `content` are cleared on objects passed as - * arguments of type `input` to this callable. + * the `i`th argument to this callable. */ pragma[nomagic] - predicate clearsContent(SummaryInput input, Content content) { none() } + predicate clearsContent(int i, Content content) { none() } } } @@ -131,340 +162,499 @@ module Public { */ module Private { private import Public - private import DataFlowDispatch - private import FlowSummarySpecific::Public + private import DataFlowImplCommon as DataFlowImplCommon + + newtype TSummaryComponent = + TContantSummaryComponent(Content c) or + TParameterSummaryComponent(int i) { parameterPosition(i) } or + TArgumentSummaryComponent(int i) { parameterPosition(i) } or + TReturnSummaryComponent(ReturnKind rk) + + newtype TSummaryComponentStack = + TSingletonSummaryComponentStack(SummaryComponent c) or + TConsSummaryComponentStack(SummaryComponent head, SummaryComponentStack tail) { + tail.(RequiredSummaryComponentStack).required(head) + } - /** - * Holds if data may flow from `input` to `output` when calling `c`. - * - * `inputContents` describes the contents that is popped from the access - * path from the input and `outputContents` describes the contents that - * is pushed onto the resulting access path. - * - * `preservesValue` indicates whether this is a value-preserving step - * or a taint-step. - */ pragma[nomagic] - predicate summary( - SummarizedCallable c, SummaryInput input, ContentList inputContents, SummaryOutput output, - ContentList outputContents, boolean preservesValue + private predicate summary( + SummarizedCallable c, SummaryComponentStack input, SummaryComponentStack output, + boolean preservesValue ) { - c.propagatesFlow(input, output, preservesValue) and - inputContents = ContentList::empty() and - outputContents = ContentList::empty() - or - c.propagatesFlow(input, inputContents, output, outputContents, preservesValue) + c.propagatesFlow(input, output, preservesValue) } - /** Gets the `i`th element in `l`. */ - pragma[noinline] - private Content getContent(ContentList l, int i) { result = l.drop(i).head() } - - private newtype TContentListRev = - TConsNilContentListRev(Content c) or - TConsContentListRev(Content head, ContentListRev tail) { - exists(ContentList l, int i | - tail = reverse(l, i) and - head = getContent(l, i) - ) - } - - /** - * Gets the reversed content list that contains the `i` first elements of `l` - * in reverse order. - */ - private ContentListRev reverse(ContentList l, int i) { - exists(Content head | - result = TConsNilContentListRev(head) and - head = l.head() and - i = 1 - or - exists(ContentListRev tail | - result = TConsContentListRev(head, tail) and - tail = reverse(l, i - 1) and - head = getContent(l, i - 1) - ) - ) - } - - /** A reversed, non-empty content list. */ - private class ContentListRev extends TContentListRev { - /** Gets the head of this reversed content list. */ - Content head() { - this = TConsNilContentListRev(result) or this = TConsContentListRev(result, _) - } - - /** Gets the tail of this reversed content list, if any. */ - ContentListRev tail() { this = TConsContentListRev(_, result) } - - /** Gets the length of this reversed content list. */ - int length() { - this = TConsNilContentListRev(_) and result = 1 - or - result = 1 + this.tail().length() - } - - /** Gets a textual representation of this reversed content list. */ - string toString() { - exists(Content head | - this = TConsNilContentListRev(head) and - result = head.toString() - or - exists(ContentListRev tail | - head = this.head() and - tail = this.tail() and - result = head + ", " + tail - ) - ) - } - } - - private newtype TSummaryInternalNodeState = - TSummaryInternalNodeReadState(SummaryInput input, ContentListRev l) { - exists(ContentList inputContents | - summary(_, input, inputContents, _, _, _) and - l = reverse(inputContents, _) + private newtype TSummaryNodeState = + TSummaryNodeInputState(SummaryComponentStack s) { + exists(SummaryComponentStack input | + summary(_, input, _, _) and + s = input.drop(_) ) } or - TSummaryInternalNodeStoreState(SummaryOutput output, ContentListRev l) { - exists(ContentList outputContents | - summary(_, _, _, output, outputContents, _) and - l = reverse(outputContents, _) + TSummaryNodeOutputState(SummaryComponentStack s) { + exists(SummaryComponentStack output | + summary(_, _, output, _) and + s = output.drop(_) ) } /** * A state used to break up (complex) flow summaries into atomic flow steps. - * For a flow summary with input `input`, input contents `inputContents`, output - * `output`, and output contents `outputContents`, the following states are used: + * For a flow summary * - * - `TSummaryInternalNodeReadState(SummaryInput input, ContentListRev l)`: - * this state represents that the contents in `l` has been read from `input`, - * where `l` is a reversed, non-empty suffix of `inputContents`. - * - `TSummaryInternalNodeStoreState(SummaryOutput output, ContentListRev l)`: - * this state represents that the contents of `l` remains to be stored into - * `output`, where `l` is a reversed, non-empty suffix of `outputContents`. + * ```ql + * propagatesFlow( + * SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue + * ) + * ``` + * + * the following states are used: + * + * - `TSummaryNodeInputState(SummaryComponentStack s)`: + * this state represents that the components in `s` _have been read_ from the + * input. + * - `TSummaryNodeOutputState(SummaryComponentStack s)`: + * this state represents that the components in `s` _remain to be written_ to + * the output. */ - class SummaryInternalNodeState extends TSummaryInternalNodeState { - /** - * Holds if this state represents that the `i` first elements of `inputContents` - * have been read from `input` in `c`. - */ + class SummaryNodeState extends TSummaryNodeState { + /** Holds if this state is a valid input state for `c`. */ pragma[nomagic] - predicate isReadState(SummarizedCallable c, SummaryInput input, ContentList inputContents, int i) { - this = TSummaryInternalNodeReadState(input, reverse(inputContents, i)) and - summary(c, input, inputContents, _, _, _) + predicate isInputState(SummarizedCallable c, SummaryComponentStack s) { + this = TSummaryNodeInputState(s) and + exists(SummaryComponentStack input | + summary(c, input, _, _) and + s = input.drop(_) + ) } - /** - * Holds if this state represents that the `i` first elements of `outputContents` - * remain to be stored into `output` in `c`. - */ + /** Holds if this state is a valid output state for `c`. */ pragma[nomagic] - predicate isStoreState( - SummarizedCallable c, SummaryOutput output, ContentList outputContents, int i - ) { - this = TSummaryInternalNodeStoreState(output, reverse(outputContents, i)) and - summary(c, _, _, output, outputContents, _) - } - - /** Gets the type of a node in this state. */ - DataFlowType getType() { - exists(ContentListRev l | result = getContentType(l.head()) | - this = TSummaryInternalNodeReadState(_, l) - or - this = TSummaryInternalNodeStoreState(_, l) + predicate isOutputState(SummarizedCallable c, SummaryComponentStack s) { + this = TSummaryNodeOutputState(s) and + exists(SummaryComponentStack output | + summary(c, _, output, _) and + s = output.drop(_) ) } /** Gets a textual representation of this state. */ string toString() { - exists(SummaryInput input, ContentListRev l | - this = TSummaryInternalNodeReadState(input, l) and - result = "input: " + input + ", read: " + l + exists(SummaryComponentStack s | + this = TSummaryNodeInputState(s) and + result = "read: " + s ) or - exists(SummaryOutput output, ContentListRev l | - this = TSummaryInternalNodeStoreState(output, l) and - result = "output: " + output + ", to store: " + l + exists(SummaryComponentStack s | + this = TSummaryNodeOutputState(s) and + result = "to write: " + s ) } } /** - * Holds if an internal summary node is needed for the state `state` in summarized + * Holds if `state` represents having read the `i`th argument for `c`. In this case + * we are not synthesizing a data-flow node, but instead assume that a relevant + * parameter node already exists. + */ + private predicate parameterReadState(SummarizedCallable c, SummaryNodeState state, int i) { + state.isInputState(c, SummaryComponentStack::argument(i)) + } + + /** + * Holds if a synthesized summary node is needed for the state `state` in summarized * callable `c`. */ - predicate internalNodeRange(SummarizedCallable c, SummaryInternalNodeState state) { - state.isReadState(c, _, _, _) + predicate summaryNodeRange(SummarizedCallable c, SummaryNodeState state) { + state.isInputState(c, _) and + not parameterReadState(c, state, _) or - state.isStoreState(c, _, _, _) + state.isOutputState(c, _) } pragma[noinline] - private Node internalNodeLastReadState( - SummarizedCallable c, SummaryInput input, ContentList inputContents - ) { - exists(SummaryInternalNodeState state | - state.isReadState(c, input, inputContents, inputContents.length()) and - result = internalNode(c, state) + private Node summaryNodeInputState(SummarizedCallable c, SummaryComponentStack s) { + exists(SummaryNodeState state | state.isInputState(c, s) | + result = summaryNode(c, state) + or + exists(int i | + parameterReadState(c, state, i) and + result.(ParameterNode).isParameterOf(c, i) + ) ) } pragma[noinline] - private Node internalNodeFirstStoreState( - SummarizedCallable c, SummaryOutput output, ContentList outputContents + private Node summaryNodeOutputState(SummarizedCallable c, SummaryComponentStack s) { + exists(SummaryNodeState state | + state.isOutputState(c, s) and + result = summaryNode(c, state) + ) + } + + /** + * Holds if a write targets `post`, which is a post-update node for the `i`th + * parameter of `c`. + */ + private predicate isParameterPostUpdate(Node post, SummarizedCallable c, int i) { + post = summaryNodeOutputState(c, SummaryComponentStack::argument(i)) + } + + /** Holds if a parameter node is required for the `i`th parameter of `c`. */ + predicate summaryParameterNodeRange(SummarizedCallable c, int i) { + parameterReadState(c, _, i) + or + isParameterPostUpdate(_, c, i) + } + + private Node pre(Node post) { + summaryPostUpdateNode(post, result) + or + not summaryPostUpdateNode(post, _) and + result = post + } + + private predicate callbackOutput( + SummarizedCallable c, SummaryComponentStack s, Node receiver, ReturnKind rk ) { - exists(SummaryInternalNodeState state | - state.isStoreState(c, output, outputContents, outputContents.length()) and - result = internalNode(c, state) - ) + any(SummaryNodeState state).isInputState(c, s) and + s.head() = TReturnSummaryComponent(rk) and + receiver = pre(summaryNodeInputState(c, s.drop(1))) + } + + private predicate callbackInput( + SummarizedCallable c, SummaryComponentStack s, Node receiver, int i + ) { + any(SummaryNodeState state).isOutputState(c, s) and + s.head() = TParameterSummaryComponent(i) and + receiver = pre(summaryNodeOutputState(c, s.drop(1))) + } + + /** Holds if a call targeting `receiver` should be synthesized inside `c`. */ + predicate summaryCallbackRange(SummarizedCallable c, Node receiver) { + callbackOutput(c, _, receiver, _) + or + callbackInput(c, _, receiver, _) } /** - * Holds if there is a local step from `pred` to `succ`, which is synthesized - * from a flow summary. + * Gets the type of synthesized summary node `n`. + * + * The type is computed based on the language-specific predicates + * `getContentType()`, `getReturnType()`, `getCallbackParameterType()`, and + * `getCallbackReturnType()`. */ - predicate localStep(Node pred, Node succ, boolean preservesValue) { - exists( - SummarizedCallable c, SummaryInput input, ContentList inputContents, SummaryOutput output, - ContentList outputContents - | - summary(c, input, inputContents, output, outputContents, preservesValue) - | - pred = inputNode(c, input) and + DataFlowType summaryNodeType(Node n) { + exists(Node pre | + summaryPostUpdateNode(n, pre) and + result = getNodeType(pre) + ) + or + exists(SummarizedCallable c, SummaryComponentStack s, SummaryComponent head | head = s.head() | + n = summaryNodeInputState(c, s) and ( - // Simple flow summary without reads or stores - inputContents = ContentList::empty() and - outputContents = ContentList::empty() and - succ = outputNode(c, output) + exists(Content cont | + head = TContantSummaryComponent(cont) and result = getContentType(cont) + ) or - // Flow summary with stores but no reads - inputContents = ContentList::empty() and - succ = internalNodeFirstStoreState(c, output, outputContents) + exists(ReturnKind rk | + head = TReturnSummaryComponent(rk) and + result = getCallbackReturnType(getNodeType(summaryNodeInputState(c, s.drop(1))), rk) + ) ) or - pred = internalNodeLastReadState(c, input, inputContents) and + n = summaryNodeOutputState(c, s) and ( - // Exit step after last read (no stores) - outputContents = ContentList::empty() and - succ = outputNode(c, output) + exists(Content cont | + head = TContantSummaryComponent(cont) and result = getContentType(cont) + ) or - // Internal step for complex flow summaries with both reads and writes - succ = internalNodeFirstStoreState(c, output, outputContents) + s.length() = 1 and + exists(ReturnKind rk | + head = TReturnSummaryComponent(rk) and + result = getReturnType(c, rk) + ) + or + exists(int i | head = TParameterSummaryComponent(i) | + result = getCallbackParameterType(getNodeType(summaryNodeOutputState(c, s.drop(1))), i) + ) ) ) } - /** - * Holds if there is a read step from `pred` to `succ`, which is synthesized - * from a flow summary. - */ - predicate readStep(Node pred, Content c, Node succ) { - exists( - SummarizedCallable sc, SummaryInput input, ContentList inputContents, - SummaryInternalNodeState succState, int i - | - succState.isReadState(sc, input, inputContents, i) and - succ = internalNode(sc, succState) and - c = getContent(inputContents, i - 1) - | - // First read - i = 1 and - pred = inputNode(sc, input) - or - // Subsequent reads - exists(SummaryInternalNodeState predState | - predState.isReadState(sc, input, inputContents, i - 1) and - pred = internalNode(sc, predState) + /** Holds if summary node `out` contains output of kind `rk` from call `c`. */ + predicate summaryOutNode(DataFlowCall c, Node out, ReturnKind rk) { + exists(SummarizedCallable callable, SummaryComponentStack s, Node receiver | + callbackOutput(callable, s, receiver, rk) and + out = summaryNodeInputState(callable, s) and + c = summaryDataFlowCall(receiver) + ) + } + + /** Holds if summary node `arg` is the `i`th argument of call `c`. */ + predicate summaryArgumentNode(DataFlowCall c, Node arg, int i) { + exists(SummarizedCallable callable, SummaryComponentStack s, Node receiver | + callbackInput(callable, s, receiver, i) and + arg = summaryNodeOutputState(callable, s) and + c = summaryDataFlowCall(receiver) + ) + } + + /** Holds if summary node `post` is a post-update node with pre-update node `pre`. */ + predicate summaryPostUpdateNode(Node post, ParameterNode pre) { + exists(SummarizedCallable c, int i | + isParameterPostUpdate(post, c, i) and + pre.isParameterOf(c, i) + ) + } + + /** Holds if summary node `ret` is a return node of kind `rk`. */ + predicate summaryReturnNode(Node ret, ReturnKind rk) { + exists(SummarizedCallable callable, SummaryComponentStack s | + ret = summaryNodeOutputState(callable, s) and + s = TSingletonSummaryComponentStack(TReturnSummaryComponent(rk)) + ) + } + + /** Provides a compilation of flow summaries to atomic data-flow steps. */ + module Steps { + /** + * Holds if there is a local step from `pred` to `succ`, which is synthesized + * from a flow summary. + */ + predicate summaryLocalStep(Node pred, Node succ, boolean preservesValue) { + exists( + SummarizedCallable c, SummaryComponentStack inputContents, + SummaryComponentStack outputContents + | + summary(c, inputContents, outputContents, preservesValue) and + pred = summaryNodeInputState(c, inputContents) and + succ = summaryNodeOutputState(c, outputContents) ) - ) - } + } - /** - * Holds if there is a store step from `pred` to `succ`, which is synthesized - * from a flow summary. - */ - predicate storeStep(Node pred, Content c, Node succ) { - exists( - SummarizedCallable sc, SummaryOutput output, ContentList outputContents, - SummaryInternalNodeState predState, int i - | - predState.isStoreState(sc, output, outputContents, i) and - pred = internalNode(sc, predState) and - c = getContent(outputContents, i - 1) - | - // More stores needed - exists(SummaryInternalNodeState succState | - succState.isStoreState(sc, output, outputContents, i - 1) and - succ = internalNode(sc, succState) + /** + * Holds if there is a read step of content `c` from `pred` to `succ`, which + * is synthesized from a flow summary. + */ + predicate summaryReadStep(Node pred, Content c, Node succ) { + exists(SummarizedCallable sc, SummaryComponentStack s | + pred = summaryNodeInputState(sc, s.drop(1)) and + succ = summaryNodeInputState(sc, s) and + SummaryComponent::content(c) = s.head() ) - or - // Last store - i = 1 and - succ = outputNode(sc, output) - ) - } + } - pragma[nomagic] - private ParameterNode summaryArgParam(ArgumentNode arg, ReturnKind rk, OutNode out) { - exists(DataFlowCall call, int pos, SummarizedCallable callable | - arg.argumentOf(call, pos) and - viableCallable(call) = callable and - result.isParameterOf(callable, pos) and - call = out.getCall(rk) - ) + /** + * Holds if there is a store step of content `c` from `pred` to `succ`, which + * is synthesized from a flow summary. + */ + predicate summaryStoreStep(Node pred, Content c, Node succ) { + exists(SummarizedCallable sc, SummaryComponentStack s | + pred = summaryNodeOutputState(sc, s) and + succ = summaryNodeOutputState(sc, s.drop(1)) and + SummaryComponent::content(c) = s.head() + ) + } + + /** + * Holds if values stored inside content `c` are cleared when passed as + * input of type `input` in `call`. + */ + predicate summaryClearsContent(ArgumentNode arg, Content c) { + exists(DataFlowCall call, int i | + viableCallable(call).(SummarizedCallable).clearsContent(i, c) and + arg.argumentOf(call, i) + ) + } + + pragma[nomagic] + private ParameterNode summaryArgParam( + ArgumentNode arg, DataFlowImplCommon::ReturnKindExt rk, DataFlowImplCommon::OutNodeExt out + ) { + exists(DataFlowCall call, int pos, SummarizedCallable callable | + arg.argumentOf(call, pos) and + viableCallable(call) = callable and + result.isParameterOf(callable, pos) and + out = rk.getAnOutNode(call) + ) + } + + /** + * Holds if `arg` flows to `out` using a simple flow summary, that is, a flow + * summary without reads and stores. + * + * NOTE: This step should not be used in global data-flow/taint-tracking, but may + * be useful to include in the exposed local data-flow/taint-tracking relations. + */ + predicate summaryThroughStep(ArgumentNode arg, Node out, boolean preservesValue) { + exists(DataFlowImplCommon::ReturnKindExt rk, DataFlowImplCommon::ReturnNodeExt ret | + summaryLocalStep(summaryArgParam(arg, rk, out), ret, preservesValue) and + ret.getKind() = rk + ) + } + + /** + * Holds if there is a read(+taint) of `c` from `arg` to `out` using a + * flow summary. + * + * NOTE: This step should not be used in global data-flow/taint-tracking, but may + * be useful to include in the exposed local data-flow/taint-tracking relations. + */ + predicate summaryGetterStep(ArgumentNode arg, Content c, Node out) { + exists(DataFlowImplCommon::ReturnKindExt rk, Node mid, DataFlowImplCommon::ReturnNodeExt ret | + summaryReadStep(summaryArgParam(arg, rk, out), c, mid) and + summaryLocalStep(mid, ret, _) and + ret.getKind() = rk + ) + } + + /** + * Holds if there is a (taint+)store of `arg` into content `c` of `out` using a + * flow summary. + * + * NOTE: This step should not be used in global data-flow/taint-tracking, but may + * be useful to include in the exposed local data-flow/taint-tracking relations. + */ + predicate summarySetterStep(ArgumentNode arg, Content c, Node out) { + exists(DataFlowImplCommon::ReturnKindExt rk, Node mid, DataFlowImplCommon::ReturnNodeExt ret | + summaryLocalStep(summaryArgParam(arg, rk, out), mid, _) and + summaryStoreStep(mid, c, ret) and + ret.getKind() = rk + ) + } + + /** + * Holds if data is written into content `c` of argument `arg` using a flow summary. + * + * Depending on the type of `c`, this predicate may be relevant to include in the + * definition of `clearsContent()`. + */ + predicate summaryStoresIntoArg(Content c, Node arg) { + exists( + DataFlowImplCommon::ParamUpdateReturnKind rk, DataFlowImplCommon::ReturnNodeExt ret, + PostUpdateNode out + | + exists(DataFlowCall call, SummarizedCallable callable | + DataFlowImplCommon::getNodeEnclosingCallable(ret) = callable and + viableCallable(call) = callable and + summaryStoreStep(_, c, ret) and + ret.getKind() = pragma[only_bind_into](rk) and + out = rk.getAnOutNode(call) and + arg = out.getPreUpdateNode() + ) + ) + } } /** - * Holds if `arg` flows to `out` using a simple flow summary, that is, a flow - * summary without reads and stores. - * - * NOTE: This step should not be used in global data-flow/taint-tracking, but may - * be useful to include in the exposed local data-flow/taint-tracking relations. + * Provides a means of translating externally (e.g., CSV) defined flow + * summaries into a `SummarizedCallable`s. */ - predicate throughStep(ArgumentNode arg, OutNode out, boolean preservesValue) { - exists(ReturnKind rk, ReturnNode ret | - localStep(summaryArgParam(arg, rk, out), ret, preservesValue) and - ret.getKind() = rk - ) + module External { + /** + * Provides a means of translating an externally (e.g., CSV) defined flow + * summary into a `SummarizedCallable`. + */ + abstract class ExternalSummaryCompilation extends string { + bindingset[this] + ExternalSummaryCompilation() { any() } + + /** Holds if this flow summary is for callable `c`. */ + abstract predicate callable(DataFlowCallable c, boolean preservesValue); + + /** Holds if the `i`th input component is `c`. */ + abstract predicate input(int i, SummaryComponent c); + + /** Holds if the `i`th output component is `c`. */ + abstract predicate output(int i, SummaryComponent c); + + /** + * Holds if the input components starting from index `i` translate into `suffix`. + */ + final predicate translateInput(int i, SummaryComponentStack suffix) { + exists(SummaryComponent comp | this.input(i, comp) | + i = max(int j | this.input(j, _)) and + suffix = TSingletonSummaryComponentStack(comp) + or + exists(TSummaryComponent head, SummaryComponentStack tail | + this.translateInputCons(i, head, tail) and + suffix = TConsSummaryComponentStack(head, tail) + ) + ) + } + + final predicate translateInputCons(int i, SummaryComponent head, SummaryComponentStack tail) { + this.input(i, head) and + this.translateInput(i + 1, tail) + } + + /** + * Holds if the output components starting from index `i` translate into `suffix`. + */ + predicate translateOutput(int i, SummaryComponentStack suffix) { + exists(SummaryComponent comp | this.output(i, comp) | + i = max(int j | this.output(j, _)) and + suffix = TSingletonSummaryComponentStack(comp) + or + exists(TSummaryComponent head, SummaryComponentStack tail | + this.translateOutputCons(i, head, tail) and + suffix = TConsSummaryComponentStack(head, tail) + ) + ) + } + + predicate translateOutputCons(int i, SummaryComponent head, SummaryComponentStack tail) { + this.output(i, head) and + this.translateOutput(i + 1, tail) + } + } + + private class ExternalRequiredSummaryComponentStack extends RequiredSummaryComponentStack { + private SummaryComponent head; + + ExternalRequiredSummaryComponentStack() { + any(ExternalSummaryCompilation s).translateInputCons(_, head, this) or + any(ExternalSummaryCompilation s).translateOutputCons(_, head, this) + } + + override predicate required(SummaryComponent c) { c = head } + } + + class ExternalSummarizedCallableAdaptor extends SummarizedCallable { + ExternalSummarizedCallableAdaptor() { any(ExternalSummaryCompilation s).callable(this, _) } + + override predicate propagatesFlow( + SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue + ) { + exists(ExternalSummaryCompilation s | + s.callable(this, preservesValue) and + s.translateInput(0, input) and + s.translateOutput(0, output) + ) + } + } } - /** - * Holds if there is a read(+taint) of `c` from `arg` to `out` using a - * flow summary. - * - * NOTE: This step should not be used in global data-flow/taint-tracking, but may - * be useful to include in the exposed local data-flow/taint-tracking relations. - */ - predicate getterStep(ArgumentNode arg, Content c, OutNode out) { - exists(ReturnKind rk, Node mid, ReturnNode ret | - readStep(summaryArgParam(arg, rk, out), c, mid) and - localStep(mid, ret, _) and - ret.getKind() = rk - ) - } + /** Provides a query predicate for outputting a set of relevant flow summaries. */ + module TestOutput { + /** A flow summary to include in the `summary/3` query predicate. */ + abstract class RelevantSummarizedCallable extends SummarizedCallable { + /** Gets the string representation of this callable used by `summary/3`. */ + string getFullString() { result = this.toString() } + } - /** - * Holds if there is a (taint+)store of `arg` into content `c` of `out` using a - * flow summary. - * - * NOTE: This step should not be used in global data-flow/taint-tracking, but may - * be useful to include in the exposed local data-flow/taint-tracking relations. - */ - predicate setterStep(ArgumentNode arg, Content c, OutNode out) { - exists(ReturnKind rk, Node mid, ReturnNode ret | - localStep(summaryArgParam(arg, rk, out), mid, _) and - storeStep(mid, c, ret) and - ret.getKind() = rk - ) - } - - /** - * Holds if values stored inside content `c` are cleared when passed as - * input of type `input` in `call`. - */ - predicate clearsContent(SummaryInput input, DataFlowCall call, Content c) { - viableCallable(call).(SummarizedCallable).clearsContent(input, c) + /** A query predicate for outputting flow summaries in QL tests. */ + query predicate summary(string callable, string flow, boolean preservesValue) { + exists( + RelevantSummarizedCallable c, SummaryComponentStack input, SummaryComponentStack output + | + callable = c.getFullString() and + c.propagatesFlow(input, output, preservesValue) and + flow = input + " -> " + output + ) + } } } + +private import Private diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummaryImplSpecific.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummaryImplSpecific.qll new file mode 100644 index 00000000000..cb38cd18ad4 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummaryImplSpecific.qll @@ -0,0 +1,79 @@ +/** + * Provides C# specific classes and predicates for definining flow summaries. + */ + +private import csharp +private import semmle.code.csharp.frameworks.system.linq.Expressions +private import DataFlowDispatch +private import DataFlowPrivate +private import DataFlowPublic +private import FlowSummaryImpl::Private +private import FlowSummaryImpl::Public +private import semmle.code.csharp.Unification + +/** Holds is `i` is a valid parameter position. */ +predicate parameterPosition(int i) { i in [-1 .. any(Parameter p).getPosition()] } + +/** Gets the synthesized summary data-flow node for the given values. */ +Node summaryNode(SummarizedCallable c, SummaryNodeState state) { result = TSummaryNode(c, state) } + +/** Gets the synthesized data-flow call for `receiver`. */ +SummaryCall summaryDataFlowCall(Node receiver) { receiver = result.getReceiver() } + +/** Gets the type of content `c`. */ +DataFlowType getContentType(Content c) { + exists(Type t | result = Gvn::getGlobalValueNumber(t) | + t = c.(FieldContent).getField().getType() + or + t = c.(PropertyContent).getProperty().getType() + or + c instanceof ElementContent and + t instanceof ObjectType // we don't know what the actual element type is + ) +} + +private DataFlowType getReturnTypeBase(DataFlowCallable c, ReturnKind rk) { + exists(Type t | result = Gvn::getGlobalValueNumber(t) | + rk instanceof NormalReturnKind and + ( + t = c.(Constructor).getDeclaringType() + or + not c instanceof Constructor and + t = c.getReturnType() + ) + or + t = c.getParameter(rk.(OutRefReturnKind).getPosition()).getType() + ) +} + +/** Gets the return type of kind `rk` for callable `c`. */ +bindingset[c] +DataFlowType getReturnType(SummarizedCallable c, ReturnKind rk) { + result = getReturnTypeBase(c, rk) + or + rk = + any(JumpReturnKind jrk | result = getReturnTypeBase(jrk.getTarget(), jrk.getTargetReturnKind())) +} + +/** + * Gets the type of the `i`th parameter in a synthesized call that targets a + * callback of type `t`. + */ +DataFlowType getCallbackParameterType(DataFlowType t, int i) { + exists(SystemLinqExpressions::DelegateExtType dt | + t = Gvn::getGlobalValueNumber(dt) and + result = Gvn::getGlobalValueNumber(dt.getDelegateType().getParameter(i).getType()) + ) +} + +/** + * Gets the return type of kind `rk` in a synthesized call that targets a + * callback of type `t`. + */ +DataFlowType getCallbackReturnType(DataFlowType t, ReturnKind rk) { + rk instanceof NormalReturnKind and + exists(SystemLinqExpressions::DelegateExtType dt | + t = Gvn::getGlobalValueNumber(dt) and + result = Gvn::getGlobalValueNumber(dt.getDelegateType().getReturnType()) + ) +} diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummarySpecific.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummarySpecific.qll deleted file mode 100644 index 2edca6111ed..00000000000 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummarySpecific.qll +++ /dev/null @@ -1,178 +0,0 @@ -/** - * Provides C# specific classes and predicates for definining flow summaries. - */ - -private import csharp -private import semmle.code.csharp.frameworks.system.linq.Expressions -private import DataFlowDispatch - -module Private { - private import Public - private import DataFlowPrivate as DataFlowPrivate - private import DataFlowPublic as DataFlowPublic - private import FlowSummaryImpl as Impl - private import semmle.code.csharp.Unification - - class Content = DataFlowPublic::Content; - - class DataFlowType = DataFlowPrivate::DataFlowType; - - class Node = DataFlowPublic::Node; - - class ParameterNode = DataFlowPublic::ParameterNode; - - class ArgumentNode = DataFlowPrivate::ArgumentNode; - - class ReturnNode = DataFlowPrivate::ReturnNode; - - class OutNode = DataFlowPrivate::OutNode; - - private class NodeImpl = DataFlowPrivate::NodeImpl; - - predicate accessPathLimit = DataFlowPrivate::accessPathLimit/0; - - predicate hasDelegateArgumentPosition(SummarizableCallable c, int i) { - exists(DelegateType dt | - dt = c.getParameter(i).getType().(SystemLinqExpressions::DelegateExtType).getDelegateType() - | - not dt.getReturnType() instanceof VoidType - ) - } - - predicate hasDelegateArgumentPosition2(SummarizableCallable c, int i, int j) { - exists(DelegateType dt | - dt = c.getParameter(i).getType().(SystemLinqExpressions::DelegateExtType).getDelegateType() - | - exists(dt.getParameter(j)) - ) - } - - newtype TSummaryInput = - TParameterSummaryInput(int i) { i in [-1, any(Parameter p).getPosition()] } or - TDelegateSummaryInput(int i) { hasDelegateArgumentPosition(_, i) } - - newtype TSummaryOutput = - TReturnSummaryOutput() or - TParameterSummaryOutput(int i) { - i in [-1, any(SummarizableCallable c).getAParameter().getPosition()] - } or - TDelegateSummaryOutput(int i, int j) { hasDelegateArgumentPosition2(_, i, j) } or - TJumpSummaryOutput(SummarizableCallable target, ReturnKind rk) { - rk instanceof NormalReturnKind and - ( - target instanceof Constructor or - not target.getReturnType() instanceof VoidType - ) - or - rk instanceof QualifierReturnKind and - not target.(Modifiable).isStatic() - or - exists(target.getParameter(rk.(OutRefReturnKind).getPosition())) - } - - /** Gets the return kind that matches `sink`, if any. */ - ReturnKind toReturnKind(SummaryOutput output) { - output = TReturnSummaryOutput() and - result instanceof NormalReturnKind - or - exists(int i | output = TParameterSummaryOutput(i) | - i = -1 and - result instanceof QualifierReturnKind - or - i = result.(OutRefReturnKind).getPosition() - ) - } - - /** Gets the input node for `c` of type `input`. */ - NodeImpl inputNode(SummarizableCallable c, SummaryInput input) { - exists(int i | - input = TParameterSummaryInput(i) and - result.(ParameterNode).isParameterOf(c, i) - ) - or - exists(int i | - input = TDelegateSummaryInput(i) and - result = DataFlowPrivate::TSummaryDelegateOutNode(c, i) - ) - } - - /** Gets the output node for `c` of type `output`. */ - NodeImpl outputNode(SummarizableCallable c, SummaryOutput output) { - result = DataFlowPrivate::TSummaryReturnNode(c, toReturnKind(output)) - or - exists(int i, int j | - output = TDelegateSummaryOutput(i, j) and - result = DataFlowPrivate::TSummaryDelegateArgumentNode(c, i, j) - ) - or - exists(SummarizableCallable target, ReturnKind rk | - output = TJumpSummaryOutput(target, rk) and - result = DataFlowPrivate::TSummaryJumpNode(c, target, rk) - ) - } - - /** Gets the internal summary node for the given values. */ - Node internalNode(SummarizableCallable c, Impl::Private::SummaryInternalNodeState state) { - result = DataFlowPrivate::TSummaryInternalNode(c, state) - } - - /** Gets the type of content `c`. */ - pragma[noinline] - DataFlowType getContentType(Content c) { - exists(Type t | result = Gvn::getGlobalValueNumber(t) | - t = c.(DataFlowPublic::FieldContent).getField().getType() - or - t = c.(DataFlowPublic::PropertyContent).getProperty().getType() - or - c instanceof DataFlowPublic::ElementContent and - t instanceof ObjectType // we don't know what the actual element type is - ) - } -} - -module Public { - private import Private - - /** An unbound callable. */ - class SummarizableCallable extends Callable { - SummarizableCallable() { this.isUnboundDeclaration() } - } - - /** A flow-summary input specification. */ - class SummaryInput extends TSummaryInput { - /** Gets a textual representation of this input specification. */ - final string toString() { - exists(int i | - this = TParameterSummaryInput(i) and - if i = -1 then result = "this parameter" else result = "parameter " + i - or - this = TDelegateSummaryInput(i) and - result = "deleget output from parameter " + i - ) - } - } - - /** A flow-summary output specification. */ - class SummaryOutput extends TSummaryOutput { - /** Gets a textual representation of this flow sink specification. */ - final string toString() { - this = TReturnSummaryOutput() and - result = "return" - or - exists(int i | - this = TParameterSummaryOutput(i) and - if i = -1 then result = "this parameter" else result = "parameter " + i - ) - or - exists(int delegateIndex, int parameterIndex | - this = TDelegateSummaryOutput(delegateIndex, parameterIndex) and - result = "parameter " + parameterIndex + " of delegate parameter " + delegateIndex - ) - or - exists(SummarizableCallable target, ReturnKind rk | - this = TJumpSummaryOutput(target, rk) and - result = "jump to " + target + " (" + rk + ")" - ) - } - } -} diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll index e8922edbf9f..72525d3234a 100755 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll @@ -103,19 +103,19 @@ private module Cached { ( // Simple flow through library code is included in the exposed local // step relation, even though flow is technically inter-procedural - FlowSummaryImpl::Private::throughStep(nodeFrom, nodeTo, false) + FlowSummaryImpl::Private::Steps::summaryThroughStep(nodeFrom, nodeTo, false) or // Taint collection by adding a tainted element exists(DataFlow::ElementContent c | storeStep(nodeFrom, c, nodeTo) or - FlowSummaryImpl::Private::setterStep(nodeFrom, c, nodeTo) + FlowSummaryImpl::Private::Steps::summarySetterStep(nodeFrom, c, nodeTo) ) or exists(DataFlow::Content c | readStep(nodeFrom, c, nodeTo) or - FlowSummaryImpl::Private::getterStep(nodeFrom, c, nodeTo) + FlowSummaryImpl::Private::Steps::summaryGetterStep(nodeFrom, c, nodeTo) | // Taint members c = any(TaintedMember m).(FieldOrProperty).getContent() @@ -142,7 +142,7 @@ private module Cached { // tracking configurations where the source is a collection readStep(nodeFrom, TElementContent(), nodeTo) or - FlowSummaryImpl::Private::localStep(nodeFrom, nodeTo, false) + FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom, nodeTo, false) or nodeTo = nodeFrom.(DataFlow::NonLocalJumpNode).getAJumpSuccessor(false) } diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/EntityFramework.qll b/csharp/ql/src/semmle/code/csharp/frameworks/EntityFramework.qll index 19f598d0ad1..29939efccdb 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/EntityFramework.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/EntityFramework.qll @@ -9,6 +9,7 @@ private import semmle.code.csharp.frameworks.system.data.Entity private import semmle.code.csharp.frameworks.system.collections.Generic private import semmle.code.csharp.frameworks.Sql private import semmle.code.csharp.dataflow.FlowSummary +private import semmle.code.csharp.dataflow.internal.DataFlowPrivate as DataFlowPrivate /** * Definitions relating to the `System.ComponentModel.DataAnnotations` @@ -74,7 +75,7 @@ module EntityFramework { DbSet() { this.getName() = "DbSet<>" } /** Gets a method that adds or updates entities in a DB set. */ - SummarizableMethod getAnAddOrUpdateMethod(boolean range) { + Method getAnAddOrUpdateMethod(boolean range) { exists(string name | result = this.getAMethod(name) | name in ["Add", "AddAsync", "Attach", "Update"] and range = false @@ -88,23 +89,31 @@ module EntityFramework { /** A flow summary for EntityFramework. */ abstract class EFSummarizedCallable extends SummarizedCallable { } + private class DbSetAddOrUpdateRequiredSummaryComponentStack extends RequiredSummaryComponentStack { + private SummaryComponent head; + + DbSetAddOrUpdateRequiredSummaryComponentStack() { + this = SummaryComponentStack::argument([-1, 0]) and + head = SummaryComponent::element() + } + + override predicate required(SummaryComponent c) { c = head } + } + private class DbSetAddOrUpdate extends EFSummarizedCallable { private boolean range; DbSetAddOrUpdate() { this = any(DbSet c).getAnAddOrUpdateMethod(range) } override predicate propagatesFlow( - SummaryInput input, ContentList inputContents, SummaryOutput output, - ContentList outputContents, boolean preservesValue + SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue ) { - input = SummaryInput::parameter(0) and ( if range = true - then inputContents = ContentList::element() - else inputContents = ContentList::empty() + then input = SummaryComponentStack::elementOf(SummaryComponentStack::argument(0)) + else input = SummaryComponentStack::argument(0) ) and - output = SummaryOutput::thisParameter() and - outputContents = ContentList::element() and + output = SummaryComponentStack::elementOf(SummaryComponentStack::argument(-1)) and preservesValue = true } } @@ -165,27 +174,27 @@ module EntityFramework { } private class RawSqlStringSummarizedCallable extends EFSummarizedCallable { - private SummaryInput input_; - private SummaryOutput output_; + private SummaryComponentStack input_; + private SummaryComponentStack output_; private boolean preservesValue_; RawSqlStringSummarizedCallable() { exists(RawSqlStringStruct s | this = s.getAConstructor() and - input_ = SummaryInput::parameter(0) and + input_ = SummaryComponentStack::argument(0) and this.getNumberOfParameters() > 0 and - output_ = SummaryOutput::return() and + output_ = SummaryComponentStack::return() and preservesValue_ = false or this = s.getAConversionTo() and - input_ = SummaryInput::parameter(0) and - output_ = SummaryOutput::return() and + input_ = SummaryComponentStack::argument(0) and + output_ = SummaryComponentStack::return() and preservesValue_ = false ) } override predicate propagatesFlow( - SummaryInput input, SummaryOutput output, boolean preservesValue + SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue ) { input = input_ and output = output_ and @@ -295,15 +304,17 @@ module EntityFramework { * If `t2` is a column type, `c2` will be included in the model (see * https://docs.microsoft.com/en-us/ef/core/modeling/entity-types?tabs=data-annotations). */ - private predicate step(Content c1, Type t1, Content c2, Type t2) { + private predicate step(Content c1, Type t1, Content c2, Type t2, int dist) { exists(Property p1 | p1 = this.getADbSetProperty(t2) and c1.(PropertyContent).getProperty() = p1 and t1 = p1.getType() and - c2 instanceof ElementContent + c2 instanceof ElementContent and + dist = 0 ) or - step(_, _, c1, t1) and + step(_, _, c1, t1, dist - 1) and + dist < DataFlowPrivate::accessPathLimit() - 1 and not isNotMapped(t2) and ( // Navigation property (https://docs.microsoft.com/en-us/ef/ef6/fundamentals/relationships) @@ -350,52 +361,61 @@ module EntityFramework { * } * ``` */ - private Property getAColumnProperty() { + Property getAColumnProperty(int dist) { exists(PropertyContent c, Type t | - this.step(_, _, c, t) and + this.step(_, _, c, t, dist) and c.getProperty() = result and isColumnType(t) ) } + private predicate stepRev(Content c1, Type t1, Content c2, Type t2, int dist) { + step(c1, t1, c2, t2, dist) and + c2.(PropertyContent).getProperty() = getAColumnProperty(dist) + or + stepRev(c2, t2, _, _, dist + 1) and + step(c1, t1, c2, t2, dist) + } + /** Gets a `SaveChanges[Async]` method. */ pragma[nomagic] - SummarizableMethod getASaveChanges() { + Method getASaveChanges() { this.hasMethod(result) and result.getName().matches("SaveChanges%") } - /** Holds if content list `head :: tail` is required. */ - predicate requiresContentList( - Content head, Type headType, ContentList tail, Type tailType, Property last + /** Holds if component stack `head :: tail` is required for the input specification. */ + predicate requiresComponentStackIn( + Content head, Type headType, SummaryComponentStack tail, int dist ) { - exists(PropertyContent p | - last = this.getAColumnProperty() and - p.getProperty() = last and - tail = ContentList::singleton(p) and - this.step(head, headType, p, tailType) - ) + tail = SummaryComponentStack::qualifier() and + this.stepRev(head, headType, _, _, 0) and + dist = -1 or - exists(Content tailHead, ContentList tailTail | - this.requiresContentList(tailHead, tailType, tailTail, _, last) and - tail = ContentList::cons(tailHead, tailTail) and - this.step(head, headType, tailHead, tailType) + exists(Content tailHead, Type tailType, SummaryComponentStack tailTail | + this.requiresComponentStackIn(tailHead, tailType, tailTail, dist - 1) and + tail = SummaryComponentStack::push(SummaryComponent::content(tailHead), tailTail) and + this.stepRev(tailHead, tailType, head, headType, dist) ) } - /** - * Holds if the access path obtained by concatenating `head` onto `tail` - * is a path from `dbSet` (which is a `DbSet` property belonging to - * this DB context) to `last`, which is a property that is mapped directly - * to a column in the underlying DB. - */ - pragma[noinline] - predicate pathFromDbSetToDbProperty( - Property dbSet, PropertyContent head, ContentList tail, Property last + /** Holds if component stack `head :: tail` is required for the output specification. */ + predicate requiresComponentStackOut( + Content head, Type headType, SummaryComponentStack tail, int dist ) { - this.requiresContentList(head, _, tail, _, last) and - head.getProperty() = dbSet and - dbSet = this.getADbSetProperty(_) + exists(Property dbSetProp, PropertyContent c1 | + dbSetProp = this.getADbSetProperty(headType) and + this.stepRev(c1, _, head, headType, 0) and + c1.getProperty() = dbSetProp and + tail = SummaryComponentStack::jump(dbSetProp.getGetter()) and + dist = 0 + ) + or + exists(Content tailHead, SummaryComponentStack tailTail, Type tailType | + this.requiresComponentStackOut(tailHead, tailType, tailTail, dist - 1) and + tail = SummaryComponentStack::push(SummaryComponent::content(tailHead), tailTail) and + this.stepRev(tailHead, tailType, head, headType, dist) + ) } } @@ -404,26 +424,46 @@ module EntityFramework { DbContextSaveChanges() { this = c.getASaveChanges() } - override predicate requiresContentList(Content head, ContentList tail) { - c.requiresContentList(head, _, tail, _, _) + pragma[noinline] + private predicate input(SummaryComponentStack input, Property mapped) { + exists(PropertyContent head, SummaryComponentStack tail | + c.requiresComponentStackIn(head, _, tail, _) and + head.getProperty() = mapped and + mapped = c.getAColumnProperty(_) and + input = SummaryComponentStack::push(SummaryComponent::content(head), tail) + ) + } + + pragma[noinline] + private predicate output(SummaryComponentStack output, Property mapped) { + exists(PropertyContent head, SummaryComponentStack tail | + c.requiresComponentStackOut(head, _, tail, _) and + head.getProperty() = mapped and + mapped = c.getAColumnProperty(_) and + output = SummaryComponentStack::push(SummaryComponent::content(head), tail) + ) } override predicate propagatesFlow( - SummaryInput input, ContentList inputContents, SummaryOutput output, - ContentList outputContents, boolean preservesValue + SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue ) { exists(Property mapped | preservesValue = true and - exists(PropertyContent sourceHead, ContentList sourceTail | - input = SummaryInput::thisParameter() and - c.pathFromDbSetToDbProperty(_, sourceHead, sourceTail, mapped) and - inputContents = ContentList::cons(sourceHead, sourceTail) - ) and - exists(Property dbSetProp | - output = SummaryOutput::jump(dbSetProp.getGetter(), SummaryOutput::return()) and - c.pathFromDbSetToDbProperty(dbSetProp, _, outputContents, mapped) - ) + input(input, mapped) and + output(output, mapped) ) } } + + private class DbContextSaveChangesRequiredSummaryComponentStack extends RequiredSummaryComponentStack { + private Content head; + + DbContextSaveChangesRequiredSummaryComponentStack() { + any(DbContextClass c).requiresComponentStackIn(head, _, this, _) + or + any(DbContextClass c).requiresComponentStackOut(head, _, this, _) + } + + override predicate required(SummaryComponent c) { c = SummaryComponent::content(head) } + } } diff --git a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected index efffa47040c..3295c03ac94 100644 --- a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected @@ -36,10 +36,10 @@ edges | CollectionFlow.cs:74:22:74:25 | access to local variable list [element] : A | CollectionFlow.cs:376:49:376:52 | list [element] : A | | CollectionFlow.cs:75:24:75:27 | access to local variable list [element] : A | CollectionFlow.cs:75:14:75:28 | call to method ListFirst | | CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:90:36:90:36 | access to local variable a : A | -| CollectionFlow.cs:90:34:90:38 | { ..., ... } [element] : A | CollectionFlow.cs:91:14:91:17 | access to local variable list [element] : A | -| CollectionFlow.cs:90:34:90:38 | { ..., ... } [element] : A | CollectionFlow.cs:92:22:92:25 | access to local variable list [element] : A | -| CollectionFlow.cs:90:34:90:38 | { ..., ... } [element] : A | CollectionFlow.cs:93:24:93:27 | access to local variable list [element] : A | -| CollectionFlow.cs:90:36:90:36 | access to local variable a : A | CollectionFlow.cs:90:34:90:38 | { ..., ... } [element] : A | +| CollectionFlow.cs:90:20:90:38 | object creation of type List [element] : A | CollectionFlow.cs:91:14:91:17 | access to local variable list [element] : A | +| CollectionFlow.cs:90:20:90:38 | object creation of type List [element] : A | CollectionFlow.cs:92:22:92:25 | access to local variable list [element] : A | +| CollectionFlow.cs:90:20:90:38 | object creation of type List [element] : A | CollectionFlow.cs:93:24:93:27 | access to local variable list [element] : A | +| CollectionFlow.cs:90:36:90:36 | access to local variable a : A | CollectionFlow.cs:90:20:90:38 | object creation of type List [element] : A | | CollectionFlow.cs:91:14:91:17 | access to local variable list [element] : A | CollectionFlow.cs:91:14:91:20 | access to indexer | | CollectionFlow.cs:92:22:92:25 | access to local variable list [element] : A | CollectionFlow.cs:376:49:376:52 | list [element] : A | | CollectionFlow.cs:93:24:93:27 | access to local variable list [element] : A | CollectionFlow.cs:93:14:93:28 | call to method ListFirst | @@ -64,46 +64,46 @@ edges | CollectionFlow.cs:131:29:131:32 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:131:14:131:33 | call to method DictFirstValue | | CollectionFlow.cs:132:30:132:33 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:132:14:132:34 | call to method DictValuesFirst | | CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:149:52:149:52 | access to local variable a : A | -| CollectionFlow.cs:149:45:149:56 | { ..., ... } [element, property Value] : A | CollectionFlow.cs:150:14:150:17 | access to local variable dict [element, property Value] : A | -| CollectionFlow.cs:149:45:149:56 | { ..., ... } [element, property Value] : A | CollectionFlow.cs:151:23:151:26 | access to local variable dict [element, property Value] : A | -| CollectionFlow.cs:149:45:149:56 | { ..., ... } [element, property Value] : A | CollectionFlow.cs:152:28:152:31 | access to local variable dict [element, property Value] : A | -| CollectionFlow.cs:149:45:149:56 | { ..., ... } [element, property Value] : A | CollectionFlow.cs:153:29:153:32 | access to local variable dict [element, property Value] : A | -| CollectionFlow.cs:149:45:149:56 | { ..., ... } [element, property Value] : A | CollectionFlow.cs:154:30:154:33 | access to local variable dict [element, property Value] : A | -| CollectionFlow.cs:149:52:149:52 | access to local variable a : A | CollectionFlow.cs:149:45:149:56 | { ..., ... } [element, property Value] : A | +| CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary [element, property Value] : A | CollectionFlow.cs:150:14:150:17 | access to local variable dict [element, property Value] : A | +| CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary [element, property Value] : A | CollectionFlow.cs:151:23:151:26 | access to local variable dict [element, property Value] : A | +| CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary [element, property Value] : A | CollectionFlow.cs:152:28:152:31 | access to local variable dict [element, property Value] : A | +| CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary [element, property Value] : A | CollectionFlow.cs:153:29:153:32 | access to local variable dict [element, property Value] : A | +| CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary [element, property Value] : A | CollectionFlow.cs:154:30:154:33 | access to local variable dict [element, property Value] : A | +| CollectionFlow.cs:149:52:149:52 | access to local variable a : A | CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary [element, property Value] : A | | CollectionFlow.cs:150:14:150:17 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:150:14:150:20 | access to indexer | | CollectionFlow.cs:151:23:151:26 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:378:61:378:64 | dict [element, property Value] : A | | CollectionFlow.cs:152:28:152:31 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:152:14:152:32 | call to method DictIndexZero | | CollectionFlow.cs:153:29:153:32 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:153:14:153:33 | call to method DictFirstValue | | CollectionFlow.cs:154:30:154:33 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:154:14:154:34 | call to method DictValuesFirst | | CollectionFlow.cs:169:17:169:23 | object creation of type A : A | CollectionFlow.cs:170:53:170:53 | access to local variable a : A | -| CollectionFlow.cs:170:45:170:55 | { ..., ... } [element, property Value] : A | CollectionFlow.cs:171:14:171:17 | access to local variable dict [element, property Value] : A | -| CollectionFlow.cs:170:45:170:55 | { ..., ... } [element, property Value] : A | CollectionFlow.cs:172:23:172:26 | access to local variable dict [element, property Value] : A | -| CollectionFlow.cs:170:45:170:55 | { ..., ... } [element, property Value] : A | CollectionFlow.cs:173:28:173:31 | access to local variable dict [element, property Value] : A | -| CollectionFlow.cs:170:45:170:55 | { ..., ... } [element, property Value] : A | CollectionFlow.cs:174:29:174:32 | access to local variable dict [element, property Value] : A | -| CollectionFlow.cs:170:45:170:55 | { ..., ... } [element, property Value] : A | CollectionFlow.cs:175:30:175:33 | access to local variable dict [element, property Value] : A | -| CollectionFlow.cs:170:53:170:53 | access to local variable a : A | CollectionFlow.cs:170:45:170:55 | { ..., ... } [element, property Value] : A | +| CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary [element, property Value] : A | CollectionFlow.cs:171:14:171:17 | access to local variable dict [element, property Value] : A | +| CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary [element, property Value] : A | CollectionFlow.cs:172:23:172:26 | access to local variable dict [element, property Value] : A | +| CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary [element, property Value] : A | CollectionFlow.cs:173:28:173:31 | access to local variable dict [element, property Value] : A | +| CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary [element, property Value] : A | CollectionFlow.cs:174:29:174:32 | access to local variable dict [element, property Value] : A | +| CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary [element, property Value] : A | CollectionFlow.cs:175:30:175:33 | access to local variable dict [element, property Value] : A | +| CollectionFlow.cs:170:53:170:53 | access to local variable a : A | CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary [element, property Value] : A | | CollectionFlow.cs:171:14:171:17 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:171:14:171:20 | access to indexer | | CollectionFlow.cs:172:23:172:26 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:378:61:378:64 | dict [element, property Value] : A | | CollectionFlow.cs:173:28:173:31 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:173:14:173:32 | call to method DictIndexZero | | CollectionFlow.cs:174:29:174:32 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:174:14:174:33 | call to method DictFirstValue | | CollectionFlow.cs:175:30:175:33 | access to local variable dict [element, property Value] : A | CollectionFlow.cs:175:14:175:34 | call to method DictValuesFirst | | CollectionFlow.cs:191:17:191:23 | object creation of type A : A | CollectionFlow.cs:192:49:192:49 | access to local variable a : A | -| CollectionFlow.cs:192:45:192:56 | { ..., ... } [element, property Key] : A | CollectionFlow.cs:193:14:193:17 | access to local variable dict [element, property Key] : A | -| CollectionFlow.cs:192:45:192:56 | { ..., ... } [element, property Key] : A | CollectionFlow.cs:194:21:194:24 | access to local variable dict [element, property Key] : A | -| CollectionFlow.cs:192:45:192:56 | { ..., ... } [element, property Key] : A | CollectionFlow.cs:195:28:195:31 | access to local variable dict [element, property Key] : A | -| CollectionFlow.cs:192:45:192:56 | { ..., ... } [element, property Key] : A | CollectionFlow.cs:196:27:196:30 | access to local variable dict [element, property Key] : A | -| CollectionFlow.cs:192:49:192:49 | access to local variable a : A | CollectionFlow.cs:192:45:192:56 | { ..., ... } [element, property Key] : A | +| CollectionFlow.cs:192:20:192:56 | object creation of type Dictionary [element, property Key] : A | CollectionFlow.cs:193:14:193:17 | access to local variable dict [element, property Key] : A | +| CollectionFlow.cs:192:20:192:56 | object creation of type Dictionary [element, property Key] : A | CollectionFlow.cs:194:21:194:24 | access to local variable dict [element, property Key] : A | +| CollectionFlow.cs:192:20:192:56 | object creation of type Dictionary [element, property Key] : A | CollectionFlow.cs:195:28:195:31 | access to local variable dict [element, property Key] : A | +| CollectionFlow.cs:192:20:192:56 | object creation of type Dictionary [element, property Key] : A | CollectionFlow.cs:196:27:196:30 | access to local variable dict [element, property Key] : A | +| CollectionFlow.cs:192:49:192:49 | access to local variable a : A | CollectionFlow.cs:192:20:192:56 | object creation of type Dictionary [element, property Key] : A | | CollectionFlow.cs:193:14:193:17 | access to local variable dict [element, property Key] : A | CollectionFlow.cs:193:14:193:22 | access to property Keys [element] : A | | CollectionFlow.cs:193:14:193:22 | access to property Keys [element] : A | CollectionFlow.cs:193:14:193:30 | call to method First | | CollectionFlow.cs:194:21:194:24 | access to local variable dict [element, property Key] : A | CollectionFlow.cs:380:59:380:62 | dict [element, property Key] : A | | CollectionFlow.cs:195:28:195:31 | access to local variable dict [element, property Key] : A | CollectionFlow.cs:195:14:195:32 | call to method DictKeysFirst | | CollectionFlow.cs:196:27:196:30 | access to local variable dict [element, property Key] : A | CollectionFlow.cs:196:14:196:31 | call to method DictFirstKey | | CollectionFlow.cs:210:17:210:23 | object creation of type A : A | CollectionFlow.cs:211:48:211:48 | access to local variable a : A | -| CollectionFlow.cs:211:45:211:55 | { ..., ... } [element, property Key] : A | CollectionFlow.cs:212:14:212:17 | access to local variable dict [element, property Key] : A | -| CollectionFlow.cs:211:45:211:55 | { ..., ... } [element, property Key] : A | CollectionFlow.cs:213:21:213:24 | access to local variable dict [element, property Key] : A | -| CollectionFlow.cs:211:45:211:55 | { ..., ... } [element, property Key] : A | CollectionFlow.cs:214:28:214:31 | access to local variable dict [element, property Key] : A | -| CollectionFlow.cs:211:45:211:55 | { ..., ... } [element, property Key] : A | CollectionFlow.cs:215:27:215:30 | access to local variable dict [element, property Key] : A | -| CollectionFlow.cs:211:48:211:48 | access to local variable a : A | CollectionFlow.cs:211:45:211:55 | { ..., ... } [element, property Key] : A | +| CollectionFlow.cs:211:20:211:55 | object creation of type Dictionary [element, property Key] : A | CollectionFlow.cs:212:14:212:17 | access to local variable dict [element, property Key] : A | +| CollectionFlow.cs:211:20:211:55 | object creation of type Dictionary [element, property Key] : A | CollectionFlow.cs:213:21:213:24 | access to local variable dict [element, property Key] : A | +| CollectionFlow.cs:211:20:211:55 | object creation of type Dictionary [element, property Key] : A | CollectionFlow.cs:214:28:214:31 | access to local variable dict [element, property Key] : A | +| CollectionFlow.cs:211:20:211:55 | object creation of type Dictionary [element, property Key] : A | CollectionFlow.cs:215:27:215:30 | access to local variable dict [element, property Key] : A | +| CollectionFlow.cs:211:48:211:48 | access to local variable a : A | CollectionFlow.cs:211:20:211:55 | object creation of type Dictionary [element, property Key] : A | | CollectionFlow.cs:212:14:212:17 | access to local variable dict [element, property Key] : A | CollectionFlow.cs:212:14:212:22 | access to property Keys [element] : A | | CollectionFlow.cs:212:14:212:22 | access to property Keys [element] : A | CollectionFlow.cs:212:14:212:30 | call to method First | | CollectionFlow.cs:213:21:213:24 | access to local variable dict [element, property Key] : A | CollectionFlow.cs:380:59:380:62 | dict [element, property Key] : A | @@ -214,7 +214,7 @@ nodes | CollectionFlow.cs:75:14:75:28 | call to method ListFirst | semmle.label | call to method ListFirst | | CollectionFlow.cs:75:24:75:27 | access to local variable list [element] : A | semmle.label | access to local variable list [element] : A | | CollectionFlow.cs:89:17:89:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:90:34:90:38 | { ..., ... } [element] : A | semmle.label | { ..., ... } [element] : A | +| CollectionFlow.cs:90:20:90:38 | object creation of type List [element] : A | semmle.label | object creation of type List [element] : A | | CollectionFlow.cs:90:36:90:36 | access to local variable a : A | semmle.label | access to local variable a : A | | CollectionFlow.cs:91:14:91:17 | access to local variable list [element] : A | semmle.label | access to local variable list [element] : A | | CollectionFlow.cs:91:14:91:20 | access to indexer | semmle.label | access to indexer | @@ -242,7 +242,7 @@ nodes | CollectionFlow.cs:132:14:132:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst | | CollectionFlow.cs:132:30:132:33 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A | | CollectionFlow.cs:148:17:148:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:149:45:149:56 | { ..., ... } [element, property Value] : A | semmle.label | { ..., ... } [element, property Value] : A | +| CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary [element, property Value] : A | semmle.label | object creation of type Dictionary [element, property Value] : A | | CollectionFlow.cs:149:52:149:52 | access to local variable a : A | semmle.label | access to local variable a : A | | CollectionFlow.cs:150:14:150:17 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A | | CollectionFlow.cs:150:14:150:20 | access to indexer | semmle.label | access to indexer | @@ -254,7 +254,7 @@ nodes | CollectionFlow.cs:154:14:154:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst | | CollectionFlow.cs:154:30:154:33 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A | | CollectionFlow.cs:169:17:169:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:170:45:170:55 | { ..., ... } [element, property Value] : A | semmle.label | { ..., ... } [element, property Value] : A | +| CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary [element, property Value] : A | semmle.label | object creation of type Dictionary [element, property Value] : A | | CollectionFlow.cs:170:53:170:53 | access to local variable a : A | semmle.label | access to local variable a : A | | CollectionFlow.cs:171:14:171:17 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A | | CollectionFlow.cs:171:14:171:20 | access to indexer | semmle.label | access to indexer | @@ -266,7 +266,7 @@ nodes | CollectionFlow.cs:175:14:175:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst | | CollectionFlow.cs:175:30:175:33 | access to local variable dict [element, property Value] : A | semmle.label | access to local variable dict [element, property Value] : A | | CollectionFlow.cs:191:17:191:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:192:45:192:56 | { ..., ... } [element, property Key] : A | semmle.label | { ..., ... } [element, property Key] : A | +| CollectionFlow.cs:192:20:192:56 | object creation of type Dictionary [element, property Key] : A | semmle.label | object creation of type Dictionary [element, property Key] : A | | CollectionFlow.cs:192:49:192:49 | access to local variable a : A | semmle.label | access to local variable a : A | | CollectionFlow.cs:193:14:193:17 | access to local variable dict [element, property Key] : A | semmle.label | access to local variable dict [element, property Key] : A | | CollectionFlow.cs:193:14:193:22 | access to property Keys [element] : A | semmle.label | access to property Keys [element] : A | @@ -277,7 +277,7 @@ nodes | CollectionFlow.cs:196:14:196:31 | call to method DictFirstKey | semmle.label | call to method DictFirstKey | | CollectionFlow.cs:196:27:196:30 | access to local variable dict [element, property Key] : A | semmle.label | access to local variable dict [element, property Key] : A | | CollectionFlow.cs:210:17:210:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:211:45:211:55 | { ..., ... } [element, property Key] : A | semmle.label | { ..., ... } [element, property Key] : A | +| CollectionFlow.cs:211:20:211:55 | object creation of type Dictionary [element, property Key] : A | semmle.label | object creation of type Dictionary [element, property Key] : A | | CollectionFlow.cs:211:48:211:48 | access to local variable a : A | semmle.label | access to local variable a : A | | CollectionFlow.cs:212:14:212:17 | access to local variable dict [element, property Key] : A | semmle.label | access to local variable dict [element, property Key] : A | | CollectionFlow.cs:212:14:212:22 | access to property Keys [element] : A | semmle.label | access to property Keys [element] : A | diff --git a/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.expected b/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.expected index 731de330946..f9fbbbab6be 100644 --- a/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.expected @@ -51,5 +51,5 @@ viableLambda | DelegateFlow.cs:125:9:125:25 | function pointer call | file://:0:0:0:0 | (none) | DelegateFlow.cs:7:17:7:18 | M2 | | DelegateFlow.cs:132:9:132:11 | delegate call | DelegateFlow.cs:135:25:135:40 | call to method M19 | DelegateFlow.cs:135:29:135:36 | (...) => ... | | DelegateFlow.cs:132:9:132:11 | delegate call | file://:0:0:0:0 | (none) | DelegateFlow.cs:131:17:131:24 | (...) => ... | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Lazy | DelegateFlow.cs:105:9:105:24 | object creation of type Lazy | DelegateFlow.cs:104:23:104:30 | (...) => ... | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Lazy | DelegateFlow.cs:107:9:107:24 | object creation of type Lazy | DelegateFlow.cs:106:13:106:20 | (...) => ... | +| file://:0:0:0:0 | [summary] call to valueFactory in Lazy | DelegateFlow.cs:105:9:105:24 | object creation of type Lazy | DelegateFlow.cs:104:23:104:30 | (...) => ... | +| file://:0:0:0:0 | [summary] call to valueFactory in Lazy | DelegateFlow.cs:107:9:107:24 | object creation of type Lazy | DelegateFlow.cs:106:13:106:20 | (...) => ... | diff --git a/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected b/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected index 2a5f828159f..ce0ed3c75af 100644 --- a/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected +++ b/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected @@ -25,7 +25,6 @@ | GlobalDataFlow.cs:33:15:33:35 | access to property NonSinkProperty1 | normal | GlobalDataFlow.cs:33:15:33:35 | access to property NonSinkProperty1 | | GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 | normal | GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 | | GlobalDataFlow.cs:37:26:37:58 | call to method GetMethod | normal | GlobalDataFlow.cs:37:26:37:58 | call to method GetMethod | -| GlobalDataFlow.cs:37:26:37:58 | call to method GetMethod | qualifier | GlobalDataFlow.cs:37:26:37:41 | [post] typeof(...) | | GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 | normal | GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 | | GlobalDataFlow.cs:39:9:39:37 | call to method Invoke | normal | GlobalDataFlow.cs:39:9:39:37 | call to method Invoke | | GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 | normal | GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 | @@ -35,14 +34,11 @@ | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 | normal | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 | | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 | normal | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 | | GlobalDataFlow.cs:65:9:65:18 | access to property InProperty | normal | GlobalDataFlow.cs:65:9:65:18 | access to property InProperty | -| GlobalDataFlow.cs:65:9:65:18 | access to property InProperty | qualifier | GlobalDataFlow.cs:65:9:65:18 | [post] this access | | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 | normal | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 | | GlobalDataFlow.cs:68:9:68:21 | access to property NonInProperty | normal | GlobalDataFlow.cs:68:9:68:21 | access to property NonInProperty | -| GlobalDataFlow.cs:68:9:68:21 | access to property NonInProperty | qualifier | GlobalDataFlow.cs:68:9:68:21 | [post] this access | | GlobalDataFlow.cs:71:21:71:46 | call to method Return | normal | GlobalDataFlow.cs:71:21:71:46 | call to method Return | | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 | normal | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 | | GlobalDataFlow.cs:73:29:73:64 | call to method GetMethod | normal | GlobalDataFlow.cs:73:29:73:64 | call to method GetMethod | -| GlobalDataFlow.cs:73:29:73:64 | call to method GetMethod | qualifier | GlobalDataFlow.cs:73:29:73:44 | [post] typeof(...) | | GlobalDataFlow.cs:73:29:73:101 | call to method Invoke | normal | GlobalDataFlow.cs:73:29:73:101 | call to method Invoke | | GlobalDataFlow.cs:76:9:76:46 | call to method ReturnOut | out parameter 1 | GlobalDataFlow.cs:76:30:76:34 | SSA def(sink2) | | GlobalDataFlow.cs:76:9:76:46 | call to method ReturnOut | ref parameter 1 | GlobalDataFlow.cs:76:30:76:34 | SSA def(sink2) | @@ -66,11 +62,11 @@ | GlobalDataFlow.cs:97:9:97:41 | call to method TryParse | ref parameter 1 | GlobalDataFlow.cs:97:35:97:40 | SSA def(sink22) | | GlobalDataFlow.cs:101:24:101:33 | call to method Return | normal | GlobalDataFlow.cs:101:24:101:33 | call to method Return | | GlobalDataFlow.cs:103:28:103:63 | call to method GetMethod | normal | GlobalDataFlow.cs:103:28:103:63 | call to method GetMethod | -| GlobalDataFlow.cs:103:28:103:63 | call to method GetMethod | qualifier | GlobalDataFlow.cs:103:28:103:43 | [post] typeof(...) | | GlobalDataFlow.cs:103:28:103:103 | call to method Invoke | normal | GlobalDataFlow.cs:103:28:103:103 | call to method Invoke | | GlobalDataFlow.cs:105:9:105:49 | call to method ReturnOut | out parameter 1 | GlobalDataFlow.cs:105:27:105:34 | SSA def(nonSink0) | | GlobalDataFlow.cs:105:9:105:49 | call to method ReturnOut | ref parameter 1 | GlobalDataFlow.cs:105:27:105:34 | SSA def(nonSink0) | | GlobalDataFlow.cs:107:9:107:49 | call to method ReturnOut | out parameter 2 | GlobalDataFlow.cs:107:41:107:48 | SSA def(nonSink0) | +| GlobalDataFlow.cs:107:9:107:49 | call to method ReturnOut | ref parameter 2 | GlobalDataFlow.cs:107:41:107:48 | SSA def(nonSink0) | | GlobalDataFlow.cs:109:9:109:49 | call to method ReturnRef | out parameter 1 | GlobalDataFlow.cs:109:27:109:34 | SSA def(nonSink0) | | GlobalDataFlow.cs:109:9:109:49 | call to method ReturnRef | ref parameter 1 | GlobalDataFlow.cs:109:27:109:34 | SSA def(nonSink0) | | GlobalDataFlow.cs:111:9:111:49 | call to method ReturnRef | out parameter 1 | GlobalDataFlow.cs:111:30:111:34 | SSA def(sink1) | @@ -99,41 +95,29 @@ | GlobalDataFlow.cs:148:20:148:40 | call to method ApplyFunc | normal | GlobalDataFlow.cs:148:20:148:40 | call to method ApplyFunc | | GlobalDataFlow.cs:150:20:150:44 | call to method ApplyFunc | normal | GlobalDataFlow.cs:150:20:150:44 | call to method ApplyFunc | | GlobalDataFlow.cs:154:21:154:25 | call to method Out | normal | GlobalDataFlow.cs:154:21:154:25 | call to method Out | -| GlobalDataFlow.cs:154:21:154:25 | call to method Out | qualifier | GlobalDataFlow.cs:154:21:154:25 | [post] this access | | GlobalDataFlow.cs:157:9:157:25 | call to method OutOut | out parameter 0 | GlobalDataFlow.cs:157:20:157:24 | SSA def(sink7) | -| GlobalDataFlow.cs:157:9:157:25 | call to method OutOut | qualifier | GlobalDataFlow.cs:157:9:157:25 | [post] this access | | GlobalDataFlow.cs:157:9:157:25 | call to method OutOut | ref parameter 0 | GlobalDataFlow.cs:157:20:157:24 | SSA def(sink7) | | GlobalDataFlow.cs:160:9:160:25 | call to method OutRef | out parameter 0 | GlobalDataFlow.cs:160:20:160:24 | SSA def(sink8) | -| GlobalDataFlow.cs:160:9:160:25 | call to method OutRef | qualifier | GlobalDataFlow.cs:160:9:160:25 | [post] this access | | GlobalDataFlow.cs:160:9:160:25 | call to method OutRef | ref parameter 0 | GlobalDataFlow.cs:160:20:160:24 | SSA def(sink8) | | GlobalDataFlow.cs:162:22:162:31 | call to method OutYield | normal | GlobalDataFlow.cs:162:22:162:31 | call to method OutYield | -| GlobalDataFlow.cs:162:22:162:31 | call to method OutYield | qualifier | GlobalDataFlow.cs:162:22:162:31 | [post] this access | | GlobalDataFlow.cs:162:22:162:39 | call to method First | normal | GlobalDataFlow.cs:162:22:162:39 | call to method First | | GlobalDataFlow.cs:164:22:164:43 | call to method TaintedParam | normal | GlobalDataFlow.cs:164:22:164:43 | call to method TaintedParam | | GlobalDataFlow.cs:168:20:168:27 | call to method NonOut | normal | GlobalDataFlow.cs:168:20:168:27 | call to method NonOut | -| GlobalDataFlow.cs:168:20:168:27 | call to method NonOut | qualifier | GlobalDataFlow.cs:168:20:168:27 | [post] this access | | GlobalDataFlow.cs:170:9:170:31 | call to method NonOutOut | out parameter 0 | GlobalDataFlow.cs:170:23:170:30 | SSA def(nonSink0) | -| GlobalDataFlow.cs:170:9:170:31 | call to method NonOutOut | qualifier | GlobalDataFlow.cs:170:9:170:31 | [post] this access | | GlobalDataFlow.cs:170:9:170:31 | call to method NonOutOut | ref parameter 0 | GlobalDataFlow.cs:170:23:170:30 | SSA def(nonSink0) | | GlobalDataFlow.cs:172:9:172:31 | call to method NonOutRef | out parameter 0 | GlobalDataFlow.cs:172:23:172:30 | SSA def(nonSink0) | -| GlobalDataFlow.cs:172:9:172:31 | call to method NonOutRef | qualifier | GlobalDataFlow.cs:172:9:172:31 | [post] this access | | GlobalDataFlow.cs:172:9:172:31 | call to method NonOutRef | ref parameter 0 | GlobalDataFlow.cs:172:23:172:30 | SSA def(nonSink0) | | GlobalDataFlow.cs:174:20:174:32 | call to method NonOutYield | normal | GlobalDataFlow.cs:174:20:174:32 | call to method NonOutYield | -| GlobalDataFlow.cs:174:20:174:32 | call to method NonOutYield | qualifier | GlobalDataFlow.cs:174:20:174:32 | [post] this access | | GlobalDataFlow.cs:174:20:174:40 | call to method First | normal | GlobalDataFlow.cs:174:20:174:40 | call to method First | | GlobalDataFlow.cs:176:20:176:44 | call to method NonTaintedParam | normal | GlobalDataFlow.cs:176:20:176:44 | call to method NonTaintedParam | | GlobalDataFlow.cs:181:21:181:26 | delegate call | normal | GlobalDataFlow.cs:181:21:181:26 | delegate call | | GlobalDataFlow.cs:186:20:186:27 | delegate call | normal | GlobalDataFlow.cs:186:20:186:27 | delegate call | | GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy | normal | GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy | | GlobalDataFlow.cs:190:22:190:48 | access to property Value | normal | GlobalDataFlow.cs:190:22:190:48 | access to property Value | -| GlobalDataFlow.cs:190:22:190:48 | access to property Value | qualifier | GlobalDataFlow.cs:190:22:190:42 | [post] object creation of type Lazy | | GlobalDataFlow.cs:194:20:194:43 | object creation of type Lazy | normal | GlobalDataFlow.cs:194:20:194:43 | object creation of type Lazy | | GlobalDataFlow.cs:194:20:194:49 | access to property Value | normal | GlobalDataFlow.cs:194:20:194:49 | access to property Value | -| GlobalDataFlow.cs:194:20:194:49 | access to property Value | qualifier | GlobalDataFlow.cs:194:20:194:43 | [post] object creation of type Lazy | | GlobalDataFlow.cs:198:22:198:32 | access to property OutProperty | normal | GlobalDataFlow.cs:198:22:198:32 | access to property OutProperty | -| GlobalDataFlow.cs:198:22:198:32 | access to property OutProperty | qualifier | GlobalDataFlow.cs:198:22:198:32 | [post] this access | | GlobalDataFlow.cs:202:20:202:33 | access to property NonOutProperty | normal | GlobalDataFlow.cs:202:20:202:33 | access to property NonOutProperty | -| GlobalDataFlow.cs:202:20:202:33 | access to property NonOutProperty | qualifier | GlobalDataFlow.cs:202:20:202:33 | [post] this access | | GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable | normal | GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable | | GlobalDataFlow.cs:209:41:209:77 | call to method AsQueryable | normal | GlobalDataFlow.cs:209:41:209:77 | call to method AsQueryable | | GlobalDataFlow.cs:212:76:212:90 | call to method ReturnCheck2 | normal | GlobalDataFlow.cs:212:76:212:90 | call to method ReturnCheck2 | @@ -156,26 +140,19 @@ | GlobalDataFlow.cs:231:19:231:57 | call to method First | normal | GlobalDataFlow.cs:231:19:231:57 | call to method First | | GlobalDataFlow.cs:238:20:238:49 | call to method Run | normal | GlobalDataFlow.cs:238:20:238:49 | call to method Run | | GlobalDataFlow.cs:239:22:239:32 | access to property Result | normal | GlobalDataFlow.cs:239:22:239:32 | access to property Result | -| GlobalDataFlow.cs:239:22:239:32 | access to property Result | qualifier | GlobalDataFlow.cs:239:22:239:25 | [post] access to local variable task | | GlobalDataFlow.cs:245:16:245:33 | call to method Run | normal | GlobalDataFlow.cs:245:16:245:33 | call to method Run | | GlobalDataFlow.cs:246:24:246:34 | access to property Result | normal | GlobalDataFlow.cs:246:24:246:34 | access to property Result | -| GlobalDataFlow.cs:246:24:246:34 | access to property Result | qualifier | GlobalDataFlow.cs:246:24:246:27 | [post] access to local variable task | | GlobalDataFlow.cs:297:17:297:38 | call to method ApplyFunc | normal | GlobalDataFlow.cs:297:17:297:38 | call to method ApplyFunc | | GlobalDataFlow.cs:386:16:386:19 | delegate call | normal | GlobalDataFlow.cs:386:16:386:19 | delegate call | | GlobalDataFlow.cs:445:9:445:20 | call to method Append | normal | GlobalDataFlow.cs:445:9:445:20 | call to method Append | -| GlobalDataFlow.cs:445:9:445:20 | call to method Append | qualifier | GlobalDataFlow.cs:445:9:445:10 | [post] access to parameter sb | | GlobalDataFlow.cs:450:18:450:36 | object creation of type StringBuilder | normal | GlobalDataFlow.cs:450:18:450:36 | object creation of type StringBuilder | | GlobalDataFlow.cs:452:22:452:34 | call to method ToString | normal | GlobalDataFlow.cs:452:22:452:34 | call to method ToString | -| GlobalDataFlow.cs:452:22:452:34 | call to method ToString | qualifier | GlobalDataFlow.cs:452:22:452:23 | [post] access to local variable sb | | GlobalDataFlow.cs:455:9:455:18 | call to method Clear | normal | GlobalDataFlow.cs:455:9:455:18 | call to method Clear | -| GlobalDataFlow.cs:455:9:455:18 | call to method Clear | qualifier | GlobalDataFlow.cs:455:9:455:10 | [post] access to local variable sb | | GlobalDataFlow.cs:456:23:456:35 | call to method ToString | normal | GlobalDataFlow.cs:456:23:456:35 | call to method ToString | -| GlobalDataFlow.cs:456:23:456:35 | call to method ToString | qualifier | GlobalDataFlow.cs:456:23:456:24 | [post] access to local variable sb | | GlobalDataFlow.cs:462:22:462:65 | call to method Join | normal | GlobalDataFlow.cs:462:22:462:65 | call to method Join | | GlobalDataFlow.cs:465:23:465:65 | call to method Join | normal | GlobalDataFlow.cs:465:23:465:65 | call to method Join | | GlobalDataFlow.cs:471:20:471:49 | call to method Run | normal | GlobalDataFlow.cs:471:20:471:49 | call to method Run | | GlobalDataFlow.cs:472:25:472:50 | call to method ConfigureAwait | normal | GlobalDataFlow.cs:472:25:472:50 | call to method ConfigureAwait | -| GlobalDataFlow.cs:472:25:472:50 | call to method ConfigureAwait | qualifier | GlobalDataFlow.cs:472:25:472:28 | [post] access to local variable task | | GlobalDataFlow.cs:473:23:473:44 | call to method GetAwaiter | normal | GlobalDataFlow.cs:473:23:473:44 | call to method GetAwaiter | | GlobalDataFlow.cs:474:22:474:40 | call to method GetResult | normal | GlobalDataFlow.cs:474:22:474:40 | call to method GetResult | | GlobalDataFlow.cs:498:44:498:47 | delegate call | normal | GlobalDataFlow.cs:498:44:498:47 | delegate call | @@ -184,163 +161,153 @@ | Splitting.cs:20:22:20:30 | call to method Return | normal | Splitting.cs:20:22:20:30 | call to method Return | | Splitting.cs:21:21:21:33 | call to method Return | normal | Splitting.cs:21:21:21:33 | call to method Return | | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element | normal | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element | -| Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element | qualifier | Splitting.cs:30:9:30:9 | [post] [b (line 24): false] access to local variable d | | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element | normal | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element | -| Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element | qualifier | Splitting.cs:30:9:30:9 | [post] [b (line 24): true] access to local variable d | | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | normal | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | qualifier | Splitting.cs:31:17:31:17 | [post] [b (line 24): false] access to local variable d | | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | normal | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | qualifier | Splitting.cs:31:17:31:17 | [post] [b (line 24): true] access to local variable d | | Splitting.cs:32:9:32:16 | [b (line 24): false] dynamic call to method Check | normal | Splitting.cs:32:9:32:16 | [b (line 24): false] dynamic call to method Check | | Splitting.cs:32:9:32:16 | [b (line 24): true] dynamic call to method Check | normal | Splitting.cs:32:9:32:16 | [b (line 24): true] dynamic call to method Check | | Splitting.cs:34:13:34:20 | dynamic call to method Check | normal | Splitting.cs:34:13:34:20 | dynamic call to method Check | -| This.cs:12:9:12:20 | call to method M | qualifier | This.cs:12:9:12:12 | [post] this access | -| This.cs:13:9:13:15 | call to method M | qualifier | This.cs:13:9:13:15 | [post] this access | -| This.cs:15:9:15:21 | call to method M | qualifier | This.cs:15:9:15:12 | [post] this access | -| This.cs:16:9:16:16 | call to method M | qualifier | This.cs:16:9:16:16 | [post] this access | | This.cs:17:9:17:18 | object creation of type This | normal | This.cs:17:9:17:18 | object creation of type This | -| This.cs:26:13:26:24 | call to method M | qualifier | This.cs:26:13:26:16 | [post] this access | -| This.cs:27:13:27:24 | call to method M | qualifier | This.cs:27:13:27:16 | [post] base access | | This.cs:28:13:28:21 | object creation of type Sub | normal | This.cs:28:13:28:21 | object creation of type Sub | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Lazy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Lazy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Lazy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Lazy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Lazy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Lazy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Run | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Run] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Run | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Run] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Run | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Run] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Run | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Run] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | -| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of Aggregate | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of Aggregate] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of Aggregate | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of Aggregate] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of Select | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of Select] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of Select | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of Select] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of Select | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of Select] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of Select | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of Select] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | -| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of Aggregate | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of Aggregate] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of Aggregate | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of Aggregate] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of Aggregate | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of Aggregate] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of Aggregate | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of Aggregate] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of SelectMany | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of SelectMany] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of SelectMany | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of SelectMany] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of SelectMany | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of SelectMany] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of SelectMany | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of SelectMany] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of ToDictionary | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of ToDictionary] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of ToDictionary | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of ToDictionary] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of ToLookup | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of ToLookup] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of ToLookup | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of ToLookup] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of Zip | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of Zip] | -| file://:0:0:0:0 | [summary] delegate call, parameter 2 of Zip | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of Zip] | -| file://:0:0:0:0 | [summary] delegate call, parameter 3 of Aggregate | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 3 of Aggregate] | -| file://:0:0:0:0 | [summary] delegate call, parameter 3 of Aggregate | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 3 of Aggregate] | -| file://:0:0:0:0 | [summary] delegate call, parameter 3 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 3 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 3 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 3 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 3 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 3 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 3 of GroupBy | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 3 of GroupBy] | -| file://:0:0:0:0 | [summary] delegate call, parameter 4 of GroupJoin | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of GroupJoin] | -| file://:0:0:0:0 | [summary] delegate call, parameter 4 of GroupJoin | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of GroupJoin] | -| file://:0:0:0:0 | [summary] delegate call, parameter 4 of GroupJoin | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of GroupJoin] | -| file://:0:0:0:0 | [summary] delegate call, parameter 4 of GroupJoin | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of GroupJoin] | -| file://:0:0:0:0 | [summary] delegate call, parameter 4 of Join | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of Join] | -| file://:0:0:0:0 | [summary] delegate call, parameter 4 of Join | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of Join] | -| file://:0:0:0:0 | [summary] delegate call, parameter 4 of Join | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of Join] | -| file://:0:0:0:0 | [summary] delegate call, parameter 4 of Join | normal | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of Join] | +| file://:0:0:0:0 | [summary] call to collectionSelector in SelectMany | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in SelectMany | +| file://:0:0:0:0 | [summary] call to collectionSelector in SelectMany | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in SelectMany | +| file://:0:0:0:0 | [summary] call to collectionSelector in SelectMany | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in SelectMany | +| file://:0:0:0:0 | [summary] call to collectionSelector in SelectMany | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in SelectMany | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWhenAll | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in ContinueWhenAll | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWhenAll | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in ContinueWhenAll | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWhenAll | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in ContinueWhenAll | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWhenAll | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in ContinueWhenAll | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWhenAll | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in ContinueWhenAll | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWhenAll | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in ContinueWhenAll | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWhenAll | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in ContinueWhenAll | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWhenAll | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in ContinueWhenAll | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWhenAll | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in ContinueWhenAll | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWhenAll | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in ContinueWhenAll | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWhenAll | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in ContinueWhenAll | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWhenAll | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in ContinueWhenAll | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWhenAll | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in ContinueWhenAll | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWhenAll | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in ContinueWhenAll | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWhenAll | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in ContinueWhenAll | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWhenAll | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in ContinueWhenAll | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWhenAny | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in ContinueWhenAny | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWhenAny | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in ContinueWhenAny | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWhenAny | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in ContinueWhenAny | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWhenAny | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in ContinueWhenAny | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWhenAny | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in ContinueWhenAny | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWhenAny | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in ContinueWhenAny | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWhenAny | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in ContinueWhenAny | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWhenAny | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in ContinueWhenAny | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWhenAny | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in ContinueWhenAny | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWhenAny | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in ContinueWhenAny | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWhenAny | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in ContinueWhenAny | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWhenAny | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in ContinueWhenAny | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWhenAny | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in ContinueWhenAny | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWhenAny | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in ContinueWhenAny | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWhenAny | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in ContinueWhenAny | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWhenAny | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in ContinueWhenAny | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWith | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in ContinueWith | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWith | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in ContinueWith | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWith | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in ContinueWith | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWith | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in ContinueWith | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWith | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in ContinueWith | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWith | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in ContinueWith | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWith | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in ContinueWith | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWith | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in ContinueWith | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWith | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in ContinueWith | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWith | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in ContinueWith | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWith | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in ContinueWith | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWith | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in ContinueWith | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWith | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in ContinueWith | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWith | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in ContinueWith | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWith | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in ContinueWith | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWith | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in ContinueWith | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWith | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in ContinueWith | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWith | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in ContinueWith | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWith | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in ContinueWith | +| file://:0:0:0:0 | [summary] call to continuationFunction in ContinueWith | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in ContinueWith | +| file://:0:0:0:0 | [summary] call to elementSelector in GroupBy | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 2 in GroupBy | +| file://:0:0:0:0 | [summary] call to elementSelector in GroupBy | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 2 in GroupBy | +| file://:0:0:0:0 | [summary] call to elementSelector in GroupBy | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 2 in GroupBy | +| file://:0:0:0:0 | [summary] call to elementSelector in GroupBy | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 2 in GroupBy | +| file://:0:0:0:0 | [summary] call to elementSelector in GroupBy | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 2 in GroupBy | +| file://:0:0:0:0 | [summary] call to elementSelector in GroupBy | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 2 in GroupBy | +| file://:0:0:0:0 | [summary] call to elementSelector in ToDictionary | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 2 in ToDictionary | +| file://:0:0:0:0 | [summary] call to elementSelector in ToDictionary | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 2 in ToDictionary | +| file://:0:0:0:0 | [summary] call to elementSelector in ToLookup | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 2 in ToLookup | +| file://:0:0:0:0 | [summary] call to elementSelector in ToLookup | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 2 in ToLookup | +| file://:0:0:0:0 | [summary] call to func in Aggregate | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in Aggregate | +| file://:0:0:0:0 | [summary] call to func in Aggregate | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in Aggregate | +| file://:0:0:0:0 | [summary] call to func in Aggregate | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 2 in Aggregate | +| file://:0:0:0:0 | [summary] call to func in Aggregate | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 2 in Aggregate | +| file://:0:0:0:0 | [summary] call to func in Aggregate | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 2 in Aggregate | +| file://:0:0:0:0 | [summary] call to func in Aggregate | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 2 in Aggregate | +| file://:0:0:0:0 | [summary] call to function in Run | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in Run | +| file://:0:0:0:0 | [summary] call to function in Run | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in Run | +| file://:0:0:0:0 | [summary] call to function in Run | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in Run | +| file://:0:0:0:0 | [summary] call to function in Run | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in Run | +| file://:0:0:0:0 | [summary] call to function in StartNew | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in StartNew | +| file://:0:0:0:0 | [summary] call to function in StartNew | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in StartNew | +| file://:0:0:0:0 | [summary] call to function in StartNew | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in StartNew | +| file://:0:0:0:0 | [summary] call to function in StartNew | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in StartNew | +| file://:0:0:0:0 | [summary] call to function in StartNew | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in StartNew | +| file://:0:0:0:0 | [summary] call to function in StartNew | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in StartNew | +| file://:0:0:0:0 | [summary] call to function in StartNew | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in StartNew | +| file://:0:0:0:0 | [summary] call to function in StartNew | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in StartNew | +| file://:0:0:0:0 | [summary] call to function in StartNew | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in StartNew | +| file://:0:0:0:0 | [summary] call to function in StartNew | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in StartNew | +| file://:0:0:0:0 | [summary] call to function in StartNew | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in StartNew | +| file://:0:0:0:0 | [summary] call to function in StartNew | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in StartNew | +| file://:0:0:0:0 | [summary] call to function in StartNew | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in StartNew | +| file://:0:0:0:0 | [summary] call to function in StartNew | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in StartNew | +| file://:0:0:0:0 | [summary] call to function in StartNew | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in StartNew | +| file://:0:0:0:0 | [summary] call to function in StartNew | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in StartNew | +| file://:0:0:0:0 | [summary] call to function in Task | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in Task | +| file://:0:0:0:0 | [summary] call to function in Task | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in Task | +| file://:0:0:0:0 | [summary] call to function in Task | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in Task | +| file://:0:0:0:0 | [summary] call to function in Task | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in Task | +| file://:0:0:0:0 | [summary] call to function in Task | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in Task | +| file://:0:0:0:0 | [summary] call to function in Task | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in Task | +| file://:0:0:0:0 | [summary] call to function in Task | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in Task | +| file://:0:0:0:0 | [summary] call to function in Task | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in Task | +| file://:0:0:0:0 | [summary] call to keySelector in GroupBy | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in GroupBy | +| file://:0:0:0:0 | [summary] call to keySelector in GroupBy | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in GroupBy | +| file://:0:0:0:0 | [summary] call to keySelector in GroupBy | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in GroupBy | +| file://:0:0:0:0 | [summary] call to keySelector in GroupBy | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in GroupBy | +| file://:0:0:0:0 | [summary] call to keySelector in GroupBy | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in GroupBy | +| file://:0:0:0:0 | [summary] call to keySelector in GroupBy | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in GroupBy | +| file://:0:0:0:0 | [summary] call to keySelector in GroupBy | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in GroupBy | +| file://:0:0:0:0 | [summary] call to keySelector in GroupBy | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in GroupBy | +| file://:0:0:0:0 | [summary] call to keySelector in GroupBy | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in GroupBy | +| file://:0:0:0:0 | [summary] call to resultSelector in Aggregate | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 3 in Aggregate | +| file://:0:0:0:0 | [summary] call to resultSelector in GroupBy | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 2 in GroupBy | +| file://:0:0:0:0 | [summary] call to resultSelector in GroupBy | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 2 in GroupBy | +| file://:0:0:0:0 | [summary] call to resultSelector in GroupBy | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 3 in GroupBy | +| file://:0:0:0:0 | [summary] call to resultSelector in GroupBy | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 3 in GroupBy | +| file://:0:0:0:0 | [summary] call to resultSelector in GroupBy | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 3 in GroupBy | +| file://:0:0:0:0 | [summary] call to resultSelector in GroupBy | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 3 in GroupBy | +| file://:0:0:0:0 | [summary] call to resultSelector in GroupJoin | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 4 in GroupJoin | +| file://:0:0:0:0 | [summary] call to resultSelector in GroupJoin | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 4 in GroupJoin | +| file://:0:0:0:0 | [summary] call to resultSelector in GroupJoin | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 4 in GroupJoin | +| file://:0:0:0:0 | [summary] call to resultSelector in GroupJoin | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 4 in GroupJoin | +| file://:0:0:0:0 | [summary] call to resultSelector in Join | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 4 in Join | +| file://:0:0:0:0 | [summary] call to resultSelector in Join | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 4 in Join | +| file://:0:0:0:0 | [summary] call to resultSelector in Join | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 4 in Join | +| file://:0:0:0:0 | [summary] call to resultSelector in Join | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 4 in Join | +| file://:0:0:0:0 | [summary] call to resultSelector in SelectMany | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 2 in SelectMany | +| file://:0:0:0:0 | [summary] call to resultSelector in SelectMany | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 2 in SelectMany | +| file://:0:0:0:0 | [summary] call to resultSelector in SelectMany | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 2 in SelectMany | +| file://:0:0:0:0 | [summary] call to resultSelector in SelectMany | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 2 in SelectMany | +| file://:0:0:0:0 | [summary] call to resultSelector in Zip | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 2 in Zip | +| file://:0:0:0:0 | [summary] call to resultSelector in Zip | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 2 in Zip | +| file://:0:0:0:0 | [summary] call to selector in Aggregate | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 3 in Aggregate | +| file://:0:0:0:0 | [summary] call to selector in Select | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in Select | +| file://:0:0:0:0 | [summary] call to selector in Select | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in Select | +| file://:0:0:0:0 | [summary] call to selector in Select | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in Select | +| file://:0:0:0:0 | [summary] call to selector in Select | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in Select | +| file://:0:0:0:0 | [summary] call to selector in SelectMany | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in SelectMany | +| file://:0:0:0:0 | [summary] call to selector in SelectMany | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in SelectMany | +| file://:0:0:0:0 | [summary] call to selector in SelectMany | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in SelectMany | +| file://:0:0:0:0 | [summary] call to selector in SelectMany | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 1 in SelectMany | +| file://:0:0:0:0 | [summary] call to valueFactory in Lazy | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in Lazy | +| file://:0:0:0:0 | [summary] call to valueFactory in Lazy | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in Lazy | +| file://:0:0:0:0 | [summary] call to valueFactory in Lazy | normal | file://:0:0:0:0 | [summary] read: return (normal) of argument 0 in Lazy | diff --git a/csharp/ql/test/library-tests/dataflow/library/FlowSummaries.expected b/csharp/ql/test/library-tests/dataflow/library/FlowSummaries.expected index 5a0c76baed0..30b6ee553a1 100644 --- a/csharp/ql/test/library-tests/dataflow/library/FlowSummaries.expected +++ b/csharp/ql/test/library-tests/dataflow/library/FlowSummaries.expected @@ -1,2710 +1,2710 @@ -| MS.Internal.Xml.Linq.ComponentModel.XDeferredAxis<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.().Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 0 -> return [field Item1] | true | -| System.().Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 1 -> return [field Item2] | true | -| System.().Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 2 -> return [field Item3] | true | -| System.().Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 3 -> return [field Item4] | true | -| System.().Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 4 -> return [field Item5] | true | -| System.().Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 5 -> return [field Item6] | true | -| System.().Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 6 -> return [field Item7] | true | -| System.().Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 7 -> return [field Item8] | true | -| System.().Create(T1, T2, T3, T4, T5, T6, T7) | parameter 0 -> return [field Item1] | true | -| System.().Create(T1, T2, T3, T4, T5, T6, T7) | parameter 1 -> return [field Item2] | true | -| System.().Create(T1, T2, T3, T4, T5, T6, T7) | parameter 2 -> return [field Item3] | true | -| System.().Create(T1, T2, T3, T4, T5, T6, T7) | parameter 3 -> return [field Item4] | true | -| System.().Create(T1, T2, T3, T4, T5, T6, T7) | parameter 4 -> return [field Item5] | true | -| System.().Create(T1, T2, T3, T4, T5, T6, T7) | parameter 5 -> return [field Item6] | true | -| System.().Create(T1, T2, T3, T4, T5, T6, T7) | parameter 6 -> return [field Item7] | true | -| System.().Create(T1, T2, T3, T4, T5, T6) | parameter 0 -> return [field Item1] | true | -| System.().Create(T1, T2, T3, T4, T5, T6) | parameter 1 -> return [field Item2] | true | -| System.().Create(T1, T2, T3, T4, T5, T6) | parameter 2 -> return [field Item3] | true | -| System.().Create(T1, T2, T3, T4, T5, T6) | parameter 3 -> return [field Item4] | true | -| System.().Create(T1, T2, T3, T4, T5, T6) | parameter 4 -> return [field Item5] | true | -| System.().Create(T1, T2, T3, T4, T5, T6) | parameter 5 -> return [field Item6] | true | -| System.().Create(T1, T2, T3, T4, T5) | parameter 0 -> return [field Item1] | true | -| System.().Create(T1, T2, T3, T4, T5) | parameter 1 -> return [field Item2] | true | -| System.().Create(T1, T2, T3, T4, T5) | parameter 2 -> return [field Item3] | true | -| System.().Create(T1, T2, T3, T4, T5) | parameter 3 -> return [field Item4] | true | -| System.().Create(T1, T2, T3, T4, T5) | parameter 4 -> return [field Item5] | true | -| System.().Create(T1, T2, T3, T4) | parameter 0 -> return [field Item1] | true | -| System.().Create(T1, T2, T3, T4) | parameter 1 -> return [field Item2] | true | -| System.().Create(T1, T2, T3, T4) | parameter 2 -> return [field Item3] | true | -| System.().Create(T1, T2, T3, T4) | parameter 3 -> return [field Item4] | true | -| System.().Create(T1, T2, T3) | parameter 0 -> return [field Item1] | true | -| System.().Create(T1, T2, T3) | parameter 1 -> return [field Item2] | true | -| System.().Create(T1, T2, T3) | parameter 2 -> return [field Item3] | true | -| System.().Create(T1, T2) | parameter 0 -> return [field Item1] | true | -| System.().Create(T1, T2) | parameter 1 -> return [field Item2] | true | -| System.().Create(T1) | parameter 0 -> return [field Item1] | true | -| System.(T1).ValueTuple(T1) | parameter 0 -> return [field Item1] | true | -| System.(T1).get_Item(int) | this parameter [field Item1] -> return | true | -| System.(T1,T2).ValueTuple(T1, T2) | parameter 0 -> return [field Item1] | true | -| System.(T1,T2).ValueTuple(T1, T2) | parameter 1 -> return [field Item2] | true | -| System.(T1,T2).get_Item(int) | this parameter [field Item1] -> return | true | -| System.(T1,T2).get_Item(int) | this parameter [field Item2] -> return | true | -| System.(T1,T2,T3).ValueTuple(T1, T2, T3) | parameter 0 -> return [field Item1] | true | -| System.(T1,T2,T3).ValueTuple(T1, T2, T3) | parameter 1 -> return [field Item2] | true | -| System.(T1,T2,T3).ValueTuple(T1, T2, T3) | parameter 2 -> return [field Item3] | true | -| System.(T1,T2,T3).get_Item(int) | this parameter [field Item1] -> return | true | -| System.(T1,T2,T3).get_Item(int) | this parameter [field Item2] -> return | true | -| System.(T1,T2,T3).get_Item(int) | this parameter [field Item3] -> return | true | -| System.(T1,T2,T3,T4).ValueTuple(T1, T2, T3, T4) | parameter 0 -> return [field Item1] | true | -| System.(T1,T2,T3,T4).ValueTuple(T1, T2, T3, T4) | parameter 1 -> return [field Item2] | true | -| System.(T1,T2,T3,T4).ValueTuple(T1, T2, T3, T4) | parameter 2 -> return [field Item3] | true | -| System.(T1,T2,T3,T4).ValueTuple(T1, T2, T3, T4) | parameter 3 -> return [field Item4] | true | -| System.(T1,T2,T3,T4).get_Item(int) | this parameter [field Item1] -> return | true | -| System.(T1,T2,T3,T4).get_Item(int) | this parameter [field Item2] -> return | true | -| System.(T1,T2,T3,T4).get_Item(int) | this parameter [field Item3] -> return | true | -| System.(T1,T2,T3,T4).get_Item(int) | this parameter [field Item4] -> return | true | -| System.(T1,T2,T3,T4,T5).ValueTuple(T1, T2, T3, T4, T5) | parameter 0 -> return [field Item1] | true | -| System.(T1,T2,T3,T4,T5).ValueTuple(T1, T2, T3, T4, T5) | parameter 1 -> return [field Item2] | true | -| System.(T1,T2,T3,T4,T5).ValueTuple(T1, T2, T3, T4, T5) | parameter 2 -> return [field Item3] | true | -| System.(T1,T2,T3,T4,T5).ValueTuple(T1, T2, T3, T4, T5) | parameter 3 -> return [field Item4] | true | -| System.(T1,T2,T3,T4,T5).ValueTuple(T1, T2, T3, T4, T5) | parameter 4 -> return [field Item5] | true | -| System.(T1,T2,T3,T4,T5).get_Item(int) | this parameter [field Item1] -> return | true | -| System.(T1,T2,T3,T4,T5).get_Item(int) | this parameter [field Item2] -> return | true | -| System.(T1,T2,T3,T4,T5).get_Item(int) | this parameter [field Item3] -> return | true | -| System.(T1,T2,T3,T4,T5).get_Item(int) | this parameter [field Item4] -> return | true | -| System.(T1,T2,T3,T4,T5).get_Item(int) | this parameter [field Item5] -> return | true | -| System.(T1,T2,T3,T4,T5,T6).ValueTuple(T1, T2, T3, T4, T5, T6) | parameter 0 -> return [field Item1] | true | -| System.(T1,T2,T3,T4,T5,T6).ValueTuple(T1, T2, T3, T4, T5, T6) | parameter 1 -> return [field Item2] | true | -| System.(T1,T2,T3,T4,T5,T6).ValueTuple(T1, T2, T3, T4, T5, T6) | parameter 2 -> return [field Item3] | true | -| System.(T1,T2,T3,T4,T5,T6).ValueTuple(T1, T2, T3, T4, T5, T6) | parameter 3 -> return [field Item4] | true | -| System.(T1,T2,T3,T4,T5,T6).ValueTuple(T1, T2, T3, T4, T5, T6) | parameter 4 -> return [field Item5] | true | -| System.(T1,T2,T3,T4,T5,T6).ValueTuple(T1, T2, T3, T4, T5, T6) | parameter 5 -> return [field Item6] | true | -| System.(T1,T2,T3,T4,T5,T6).get_Item(int) | this parameter [field Item1] -> return | true | -| System.(T1,T2,T3,T4,T5,T6).get_Item(int) | this parameter [field Item2] -> return | true | -| System.(T1,T2,T3,T4,T5,T6).get_Item(int) | this parameter [field Item3] -> return | true | -| System.(T1,T2,T3,T4,T5,T6).get_Item(int) | this parameter [field Item4] -> return | true | -| System.(T1,T2,T3,T4,T5,T6).get_Item(int) | this parameter [field Item5] -> return | true | -| System.(T1,T2,T3,T4,T5,T6).get_Item(int) | this parameter [field Item6] -> return | true | -| System.(T1,T2,T3,T4,T5,T6,T7).ValueTuple(T1, T2, T3, T4, T5, T6, T7) | parameter 0 -> return [field Item1] | true | -| System.(T1,T2,T3,T4,T5,T6,T7).ValueTuple(T1, T2, T3, T4, T5, T6, T7) | parameter 1 -> return [field Item2] | true | -| System.(T1,T2,T3,T4,T5,T6,T7).ValueTuple(T1, T2, T3, T4, T5, T6, T7) | parameter 2 -> return [field Item3] | true | -| System.(T1,T2,T3,T4,T5,T6,T7).ValueTuple(T1, T2, T3, T4, T5, T6, T7) | parameter 3 -> return [field Item4] | true | -| System.(T1,T2,T3,T4,T5,T6,T7).ValueTuple(T1, T2, T3, T4, T5, T6, T7) | parameter 4 -> return [field Item5] | true | -| System.(T1,T2,T3,T4,T5,T6,T7).ValueTuple(T1, T2, T3, T4, T5, T6, T7) | parameter 5 -> return [field Item6] | true | -| System.(T1,T2,T3,T4,T5,T6,T7).ValueTuple(T1, T2, T3, T4, T5, T6, T7) | parameter 6 -> return [field Item7] | true | -| System.(T1,T2,T3,T4,T5,T6,T7).get_Item(int) | this parameter [field Item1] -> return | true | -| System.(T1,T2,T3,T4,T5,T6,T7).get_Item(int) | this parameter [field Item2] -> return | true | -| System.(T1,T2,T3,T4,T5,T6,T7).get_Item(int) | this parameter [field Item3] -> return | true | -| System.(T1,T2,T3,T4,T5,T6,T7).get_Item(int) | this parameter [field Item4] -> return | true | -| System.(T1,T2,T3,T4,T5,T6,T7).get_Item(int) | this parameter [field Item5] -> return | true | -| System.(T1,T2,T3,T4,T5,T6,T7).get_Item(int) | this parameter [field Item6] -> return | true | -| System.(T1,T2,T3,T4,T5,T6,T7).get_Item(int) | this parameter [field Item7] -> return | true | -| System.Array.Add(object) | parameter 0 -> this parameter [element] | true | -| System.Array.AsReadOnly(T[]) | parameter 0 [element] -> return [element] | true | -| System.Array.Clone() | parameter 0 [element] -> return [element] | true | -| System.Array.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Array.CopyTo(Array, long) | this parameter [element] -> parameter 0 [element] | true | -| System.Array.Find(T[], Predicate) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Array.Find(T[], Predicate) | parameter 0 [element] -> return | true | -| System.Array.FindAll(T[], Predicate) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Array.FindAll(T[], Predicate) | parameter 0 [element] -> return | true | -| System.Array.FindLast(T[], Predicate) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Array.FindLast(T[], Predicate) | parameter 0 [element] -> return | true | -| System.Array.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Array.Insert(int, object) | parameter 1 -> this parameter [element] | true | -| System.Array.Reverse(Array) | parameter 0 [element] -> return [element] | true | -| System.Array.Reverse(Array, int, int) | parameter 0 [element] -> return [element] | true | -| System.Array.Reverse(T[]) | parameter 0 [element] -> return [element] | true | -| System.Array.Reverse(T[], int, int) | parameter 0 [element] -> return [element] | true | -| System.Array.get_Item(int) | this parameter [element] -> return | true | -| System.Array.set_Item(int, object) | parameter 1 -> this parameter [element] | true | -| System.Boolean.Parse(string) | parameter 0 -> return | false | -| System.Boolean.TryParse(string, out bool) | parameter 0 -> parameter 1 | false | -| System.Boolean.TryParse(string, out bool) | parameter 0 -> return | false | -| System.Collections.ArrayList.Add(object) | parameter 0 -> this parameter [element] | true | -| System.Collections.ArrayList.AddRange(ICollection) | parameter 0 [element] -> this parameter [element] | true | -| System.Collections.ArrayList.Clone() | parameter 0 [element] -> return [element] | true | -| System.Collections.ArrayList.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.ArrayList.FixedSize(ArrayList) | parameter 0 [element] -> return [element] | true | -| System.Collections.ArrayList.FixedSize(IList) | parameter 0 [element] -> return [element] | true | -| System.Collections.ArrayList.FixedSizeArrayList.Add(object) | parameter 0 -> this parameter [element] | true | -| System.Collections.ArrayList.FixedSizeArrayList.AddRange(ICollection) | parameter 0 [element] -> this parameter [element] | true | -| System.Collections.ArrayList.FixedSizeArrayList.Clone() | parameter 0 [element] -> return [element] | true | -| System.Collections.ArrayList.FixedSizeArrayList.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.ArrayList.FixedSizeArrayList.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.ArrayList.FixedSizeArrayList.GetEnumerator(int, int) | this parameter [element] -> return [property Current] | true | -| System.Collections.ArrayList.FixedSizeArrayList.GetRange(int, int) | parameter 0 [element] -> return [element] | true | -| System.Collections.ArrayList.FixedSizeArrayList.Insert(int, object) | parameter 1 -> this parameter [element] | true | -| System.Collections.ArrayList.FixedSizeArrayList.InsertRange(int, ICollection) | parameter 1 [element] -> this parameter [element] | true | -| System.Collections.ArrayList.FixedSizeArrayList.Reverse(int, int) | parameter 0 [element] -> return [element] | true | -| System.Collections.ArrayList.FixedSizeArrayList.get_Item(int) | this parameter [element] -> return | true | -| System.Collections.ArrayList.FixedSizeArrayList.set_Item(int, object) | parameter 1 -> this parameter [element] | true | -| System.Collections.ArrayList.FixedSizeList.Add(object) | parameter 0 -> this parameter [element] | true | -| System.Collections.ArrayList.FixedSizeList.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.ArrayList.FixedSizeList.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.ArrayList.FixedSizeList.Insert(int, object) | parameter 1 -> this parameter [element] | true | -| System.Collections.ArrayList.FixedSizeList.get_Item(int) | this parameter [element] -> return | true | -| System.Collections.ArrayList.FixedSizeList.set_Item(int, object) | parameter 1 -> this parameter [element] | true | -| System.Collections.ArrayList.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.ArrayList.GetEnumerator(int, int) | this parameter [element] -> return [property Current] | true | -| System.Collections.ArrayList.GetRange(int, int) | parameter 0 [element] -> return [element] | true | -| System.Collections.ArrayList.IListWrapper.Add(object) | parameter 0 -> this parameter [element] | true | -| System.Collections.ArrayList.IListWrapper.AddRange(ICollection) | parameter 0 [element] -> this parameter [element] | true | -| System.Collections.ArrayList.IListWrapper.Clone() | parameter 0 [element] -> return [element] | true | -| System.Collections.ArrayList.IListWrapper.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.ArrayList.IListWrapper.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.ArrayList.IListWrapper.GetEnumerator(int, int) | this parameter [element] -> return [property Current] | true | -| System.Collections.ArrayList.IListWrapper.GetRange(int, int) | parameter 0 [element] -> return [element] | true | -| System.Collections.ArrayList.IListWrapper.Insert(int, object) | parameter 1 -> this parameter [element] | true | -| System.Collections.ArrayList.IListWrapper.InsertRange(int, ICollection) | parameter 1 [element] -> this parameter [element] | true | -| System.Collections.ArrayList.IListWrapper.Reverse(int, int) | parameter 0 [element] -> return [element] | true | -| System.Collections.ArrayList.IListWrapper.get_Item(int) | this parameter [element] -> return | true | -| System.Collections.ArrayList.IListWrapper.set_Item(int, object) | parameter 1 -> this parameter [element] | true | -| System.Collections.ArrayList.Insert(int, object) | parameter 1 -> this parameter [element] | true | -| System.Collections.ArrayList.InsertRange(int, ICollection) | parameter 1 [element] -> this parameter [element] | true | -| System.Collections.ArrayList.Range.Add(object) | parameter 0 -> this parameter [element] | true | -| System.Collections.ArrayList.Range.AddRange(ICollection) | parameter 0 [element] -> this parameter [element] | true | -| System.Collections.ArrayList.Range.Clone() | parameter 0 [element] -> return [element] | true | -| System.Collections.ArrayList.Range.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.ArrayList.Range.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.ArrayList.Range.GetEnumerator(int, int) | this parameter [element] -> return [property Current] | true | -| System.Collections.ArrayList.Range.GetRange(int, int) | parameter 0 [element] -> return [element] | true | -| System.Collections.ArrayList.Range.Insert(int, object) | parameter 1 -> this parameter [element] | true | -| System.Collections.ArrayList.Range.InsertRange(int, ICollection) | parameter 1 [element] -> this parameter [element] | true | -| System.Collections.ArrayList.Range.Reverse(int, int) | parameter 0 [element] -> return [element] | true | -| System.Collections.ArrayList.Range.get_Item(int) | this parameter [element] -> return | true | -| System.Collections.ArrayList.Range.set_Item(int, object) | parameter 1 -> this parameter [element] | true | -| System.Collections.ArrayList.ReadOnlyArrayList.Add(object) | parameter 0 -> this parameter [element] | true | -| System.Collections.ArrayList.ReadOnlyArrayList.AddRange(ICollection) | parameter 0 [element] -> this parameter [element] | true | -| System.Collections.ArrayList.ReadOnlyArrayList.Clone() | parameter 0 [element] -> return [element] | true | -| System.Collections.ArrayList.ReadOnlyArrayList.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.ArrayList.ReadOnlyArrayList.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.ArrayList.ReadOnlyArrayList.GetEnumerator(int, int) | this parameter [element] -> return [property Current] | true | -| System.Collections.ArrayList.ReadOnlyArrayList.GetRange(int, int) | parameter 0 [element] -> return [element] | true | -| System.Collections.ArrayList.ReadOnlyArrayList.Insert(int, object) | parameter 1 -> this parameter [element] | true | -| System.Collections.ArrayList.ReadOnlyArrayList.InsertRange(int, ICollection) | parameter 1 [element] -> this parameter [element] | true | -| System.Collections.ArrayList.ReadOnlyArrayList.Reverse(int, int) | parameter 0 [element] -> return [element] | true | -| System.Collections.ArrayList.ReadOnlyArrayList.get_Item(int) | this parameter [element] -> return | true | -| System.Collections.ArrayList.ReadOnlyArrayList.set_Item(int, object) | parameter 1 -> this parameter [element] | true | -| System.Collections.ArrayList.ReadOnlyList.Add(object) | parameter 0 -> this parameter [element] | true | -| System.Collections.ArrayList.ReadOnlyList.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.ArrayList.ReadOnlyList.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.ArrayList.ReadOnlyList.Insert(int, object) | parameter 1 -> this parameter [element] | true | -| System.Collections.ArrayList.ReadOnlyList.get_Item(int) | this parameter [element] -> return | true | -| System.Collections.ArrayList.ReadOnlyList.set_Item(int, object) | parameter 1 -> this parameter [element] | true | -| System.Collections.ArrayList.Repeat(object, int) | parameter 0 -> return [element] | true | -| System.Collections.ArrayList.Reverse() | parameter 0 [element] -> return [element] | true | -| System.Collections.ArrayList.Reverse(int, int) | parameter 0 [element] -> return [element] | true | -| System.Collections.ArrayList.SyncArrayList.Add(object) | parameter 0 -> this parameter [element] | true | -| System.Collections.ArrayList.SyncArrayList.AddRange(ICollection) | parameter 0 [element] -> this parameter [element] | true | -| System.Collections.ArrayList.SyncArrayList.Clone() | parameter 0 [element] -> return [element] | true | -| System.Collections.ArrayList.SyncArrayList.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.ArrayList.SyncArrayList.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.ArrayList.SyncArrayList.GetEnumerator(int, int) | this parameter [element] -> return [property Current] | true | -| System.Collections.ArrayList.SyncArrayList.GetRange(int, int) | parameter 0 [element] -> return [element] | true | -| System.Collections.ArrayList.SyncArrayList.Insert(int, object) | parameter 1 -> this parameter [element] | true | -| System.Collections.ArrayList.SyncArrayList.InsertRange(int, ICollection) | parameter 1 [element] -> this parameter [element] | true | -| System.Collections.ArrayList.SyncArrayList.Reverse(int, int) | parameter 0 [element] -> return [element] | true | -| System.Collections.ArrayList.SyncArrayList.get_Item(int) | this parameter [element] -> return | true | -| System.Collections.ArrayList.SyncArrayList.set_Item(int, object) | parameter 1 -> this parameter [element] | true | -| System.Collections.ArrayList.SyncIList.Add(object) | parameter 0 -> this parameter [element] | true | -| System.Collections.ArrayList.SyncIList.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.ArrayList.SyncIList.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.ArrayList.SyncIList.Insert(int, object) | parameter 1 -> this parameter [element] | true | -| System.Collections.ArrayList.SyncIList.get_Item(int) | this parameter [element] -> return | true | -| System.Collections.ArrayList.SyncIList.set_Item(int, object) | parameter 1 -> this parameter [element] | true | -| System.Collections.ArrayList.get_Item(int) | this parameter [element] -> return | true | -| System.Collections.ArrayList.set_Item(int, object) | parameter 1 -> this parameter [element] | true | -| System.Collections.BitArray.Clone() | parameter 0 [element] -> return [element] | true | -| System.Collections.BitArray.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.BitArray.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.CollectionBase.Add(object) | parameter 0 -> this parameter [element] | true | -| System.Collections.CollectionBase.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.CollectionBase.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.CollectionBase.Insert(int, object) | parameter 1 -> this parameter [element] | true | -| System.Collections.CollectionBase.get_Item(int) | this parameter [element] -> return | true | -| System.Collections.CollectionBase.set_Item(int, object) | parameter 1 -> this parameter [element] | true | -| System.Collections.Concurrent.BlockingCollection<>.d__68.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Concurrent.BlockingCollection<>.Add(T) | parameter 0 -> this parameter [element] | true | -| System.Collections.Concurrent.BlockingCollection<>.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Concurrent.BlockingCollection<>.CopyTo(T[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Concurrent.BlockingCollection<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Concurrent.ConcurrentBag<>.Add(T) | parameter 0 -> this parameter [element] | true | -| System.Collections.Concurrent.ConcurrentBag<>.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Concurrent.ConcurrentBag<>.CopyTo(T[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Concurrent.ConcurrentBag<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(KeyValuePair) | parameter 0 -> this parameter [element] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(KeyValuePair) | parameter 0 [property Key] -> this parameter [element, property Key] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(KeyValuePair) | parameter 0 [property Value] -> this parameter [element, property Value] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(TKey, TValue) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(TKey, TValue) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(object, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(object, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(IEnumerable>) | parameter 0 [element, property Key] -> return [element, property Key] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(IEnumerable>) | parameter 0 [element, property Value] -> return [element, property Value] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(IEnumerable>, IEqualityComparer) | parameter 0 [element, property Key] -> return [element, property Key] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(IEnumerable>, IEqualityComparer) | parameter 0 [element, property Value] -> return [element, property Value] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(int, IEnumerable>, IEqualityComparer) | parameter 1 [element, property Key] -> return [element, property Key] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(int, IEnumerable>, IEqualityComparer) | parameter 1 [element, property Value] -> return [element, property Value] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.CopyTo(KeyValuePair[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.get_Item(TKey) | this parameter [element, property Value] -> return | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.get_Item(object) | this parameter [element, property Value] -> return | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.get_Keys() | this parameter [element, property Key] -> return [element] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.get_Values() | this parameter [element, property Value] -> return [element] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.set_Item(TKey, TValue) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.set_Item(TKey, TValue) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.set_Item(object, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.Concurrent.ConcurrentDictionary<,>.set_Item(object, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.Concurrent.ConcurrentQueue<>.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Concurrent.ConcurrentQueue<>.CopyTo(T[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Concurrent.ConcurrentQueue<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Concurrent.ConcurrentStack<>.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Concurrent.ConcurrentStack<>.CopyTo(T[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Concurrent.ConcurrentStack<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Concurrent.IProducerConsumerCollection<>.CopyTo(T[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Concurrent.OrderablePartitioner<>.EnumerableDropIndices.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Concurrent.Partitioner.d__7.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Concurrent.Partitioner.d__10.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Concurrent.Partitioner.DynamicPartitionerForArray<>.InternalPartitionEnumerable.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Concurrent.Partitioner.DynamicPartitionerForIEnumerable<>.InternalPartitionEnumerable.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Concurrent.Partitioner.DynamicPartitionerForIList<>.InternalPartitionEnumerable.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.DictionaryBase.Add(object, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.DictionaryBase.Add(object, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.DictionaryBase.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.DictionaryBase.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.DictionaryBase.get_Item(object) | this parameter [element, property Value] -> return | true | -| System.Collections.DictionaryBase.get_Keys() | this parameter [element, property Key] -> return [element] | true | -| System.Collections.DictionaryBase.get_Values() | this parameter [element, property Value] -> return [element] | true | -| System.Collections.DictionaryBase.set_Item(object, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.DictionaryBase.set_Item(object, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.EmptyReadOnlyDictionaryInternal.Add(object, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.EmptyReadOnlyDictionaryInternal.Add(object, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.EmptyReadOnlyDictionaryInternal.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.EmptyReadOnlyDictionaryInternal.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.EmptyReadOnlyDictionaryInternal.get_Item(object) | this parameter [element, property Value] -> return | true | -| System.Collections.EmptyReadOnlyDictionaryInternal.get_Keys() | this parameter [element, property Key] -> return [element] | true | -| System.Collections.EmptyReadOnlyDictionaryInternal.get_Values() | this parameter [element, property Value] -> return [element] | true | -| System.Collections.EmptyReadOnlyDictionaryInternal.set_Item(object, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.EmptyReadOnlyDictionaryInternal.set_Item(object, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.Generic.Dictionary<,>.Add(KeyValuePair) | parameter 0 -> this parameter [element] | true | -| System.Collections.Generic.Dictionary<,>.Add(KeyValuePair) | parameter 0 [property Key] -> this parameter [element, property Key] | true | -| System.Collections.Generic.Dictionary<,>.Add(KeyValuePair) | parameter 0 [property Value] -> this parameter [element, property Value] | true | -| System.Collections.Generic.Dictionary<,>.Add(TKey, TValue) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.Generic.Dictionary<,>.Add(TKey, TValue) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.Generic.Dictionary<,>.Add(object, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.Generic.Dictionary<,>.Add(object, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.Generic.Dictionary<,>.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Generic.Dictionary<,>.CopyTo(KeyValuePair[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Generic.Dictionary<,>.Dictionary(IDictionary) | parameter 0 [element, property Key] -> return [element, property Key] | true | -| System.Collections.Generic.Dictionary<,>.Dictionary(IDictionary) | parameter 0 [element, property Value] -> return [element, property Value] | true | -| System.Collections.Generic.Dictionary<,>.Dictionary(IDictionary, IEqualityComparer) | parameter 0 [element, property Key] -> return [element, property Key] | true | -| System.Collections.Generic.Dictionary<,>.Dictionary(IDictionary, IEqualityComparer) | parameter 0 [element, property Value] -> return [element, property Value] | true | -| System.Collections.Generic.Dictionary<,>.Dictionary(IEnumerable>) | parameter 0 [element, property Key] -> return [element, property Key] | true | -| System.Collections.Generic.Dictionary<,>.Dictionary(IEnumerable>) | parameter 0 [element, property Value] -> return [element, property Value] | true | -| System.Collections.Generic.Dictionary<,>.Dictionary(IEnumerable>, IEqualityComparer) | parameter 0 [element, property Key] -> return [element, property Key] | true | -| System.Collections.Generic.Dictionary<,>.Dictionary(IEnumerable>, IEqualityComparer) | parameter 0 [element, property Value] -> return [element, property Value] | true | -| System.Collections.Generic.Dictionary<,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Generic.Dictionary<,>.KeyCollection.Add(TKey) | parameter 0 -> this parameter [element] | true | -| System.Collections.Generic.Dictionary<,>.KeyCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Generic.Dictionary<,>.KeyCollection.CopyTo(TKey[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Generic.Dictionary<,>.KeyCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Generic.Dictionary<,>.ValueCollection.Add(TValue) | parameter 0 -> this parameter [element] | true | -| System.Collections.Generic.Dictionary<,>.ValueCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Generic.Dictionary<,>.ValueCollection.CopyTo(TValue[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Generic.Dictionary<,>.ValueCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Generic.Dictionary<,>.get_Item(TKey) | this parameter [element, property Value] -> return | true | -| System.Collections.Generic.Dictionary<,>.get_Item(object) | this parameter [element, property Value] -> return | true | -| System.Collections.Generic.Dictionary<,>.get_Keys() | this parameter [element, property Key] -> return [element] | true | -| System.Collections.Generic.Dictionary<,>.get_Values() | this parameter [element, property Value] -> return [element] | true | -| System.Collections.Generic.Dictionary<,>.set_Item(TKey, TValue) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.Generic.Dictionary<,>.set_Item(TKey, TValue) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.Generic.Dictionary<,>.set_Item(object, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.Generic.Dictionary<,>.set_Item(object, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.Generic.HashSet<>.Add(T) | parameter 0 -> this parameter [element] | true | -| System.Collections.Generic.HashSet<>.CopyTo(T[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Generic.HashSet<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Generic.ICollection<>.Add(T) | parameter 0 -> this parameter [element] | true | -| System.Collections.Generic.ICollection<>.CopyTo(T[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Generic.IDictionary<,>.Add(TKey, TValue) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.Generic.IDictionary<,>.Add(TKey, TValue) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.Generic.IDictionary<,>.get_Item(TKey) | this parameter [element, property Value] -> return | true | -| System.Collections.Generic.IDictionary<,>.get_Keys() | this parameter [element, property Key] -> return [element] | true | -| System.Collections.Generic.IDictionary<,>.get_Values() | this parameter [element, property Value] -> return [element] | true | -| System.Collections.Generic.IDictionary<,>.set_Item(TKey, TValue) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.Generic.IDictionary<,>.set_Item(TKey, TValue) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.Generic.IList<>.Insert(int, T) | parameter 1 -> this parameter [element] | true | -| System.Collections.Generic.IList<>.get_Item(int) | this parameter [element] -> return | true | -| System.Collections.Generic.IList<>.set_Item(int, T) | parameter 1 -> this parameter [element] | true | -| System.Collections.Generic.ISet<>.Add(T) | parameter 0 -> this parameter [element] | true | -| System.Collections.Generic.KeyValuePair<,>.KeyValuePair() | parameter 0 -> return [property Key] | true | -| System.Collections.Generic.KeyValuePair<,>.KeyValuePair() | parameter 1 -> return [property Value] | true | -| System.Collections.Generic.KeyValuePair<,>.KeyValuePair(TKey, TValue) | parameter 0 -> return [property Key] | true | -| System.Collections.Generic.KeyValuePair<,>.KeyValuePair(TKey, TValue) | parameter 1 -> return [property Value] | true | -| System.Collections.Generic.LinkedList<>.Add(T) | parameter 0 -> this parameter [element] | true | -| System.Collections.Generic.LinkedList<>.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Generic.LinkedList<>.CopyTo(T[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Generic.LinkedList<>.Find(T) | this parameter [element] -> return | true | -| System.Collections.Generic.LinkedList<>.FindLast(T) | this parameter [element] -> return | true | -| System.Collections.Generic.LinkedList<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Generic.List<>.Add(T) | parameter 0 -> this parameter [element] | true | -| System.Collections.Generic.List<>.Add(object) | parameter 0 -> this parameter [element] | true | -| System.Collections.Generic.List<>.AddRange(IEnumerable) | parameter 0 [element] -> this parameter [element] | true | -| System.Collections.Generic.List<>.AsReadOnly() | parameter 0 [element] -> return [element] | true | -| System.Collections.Generic.List<>.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Generic.List<>.CopyTo(T[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Generic.List<>.Find(Predicate) | this parameter [element] -> parameter 0 of delegate parameter 0 | true | -| System.Collections.Generic.List<>.Find(Predicate) | this parameter [element] -> return | true | -| System.Collections.Generic.List<>.FindAll(Predicate) | this parameter [element] -> parameter 0 of delegate parameter 0 | true | -| System.Collections.Generic.List<>.FindAll(Predicate) | this parameter [element] -> return | true | -| System.Collections.Generic.List<>.FindLast(Predicate) | this parameter [element] -> parameter 0 of delegate parameter 0 | true | -| System.Collections.Generic.List<>.FindLast(Predicate) | this parameter [element] -> return | true | -| System.Collections.Generic.List<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Generic.List<>.GetRange(int, int) | parameter 0 [element] -> return [element] | true | -| System.Collections.Generic.List<>.Insert(int, T) | parameter 1 -> this parameter [element] | true | -| System.Collections.Generic.List<>.Insert(int, object) | parameter 1 -> this parameter [element] | true | -| System.Collections.Generic.List<>.InsertRange(int, IEnumerable) | parameter 1 [element] -> this parameter [element] | true | -| System.Collections.Generic.List<>.Reverse() | parameter 0 [element] -> return [element] | true | -| System.Collections.Generic.List<>.Reverse(int, int) | parameter 0 [element] -> return [element] | true | -| System.Collections.Generic.List<>.get_Item(int) | this parameter [element] -> return | true | -| System.Collections.Generic.List<>.set_Item(int, T) | parameter 1 -> this parameter [element] | true | -| System.Collections.Generic.List<>.set_Item(int, object) | parameter 1 -> this parameter [element] | true | -| System.Collections.Generic.Queue<>.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Generic.Queue<>.CopyTo(T[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Generic.Queue<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Generic.Queue<>.Peek() | this parameter [element] -> return | true | -| System.Collections.Generic.SortedDictionary<,>.Add(KeyValuePair) | parameter 0 -> this parameter [element] | true | -| System.Collections.Generic.SortedDictionary<,>.Add(KeyValuePair) | parameter 0 [property Key] -> this parameter [element, property Key] | true | -| System.Collections.Generic.SortedDictionary<,>.Add(KeyValuePair) | parameter 0 [property Value] -> this parameter [element, property Value] | true | -| System.Collections.Generic.SortedDictionary<,>.Add(TKey, TValue) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.Generic.SortedDictionary<,>.Add(TKey, TValue) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.Generic.SortedDictionary<,>.Add(object, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.Generic.SortedDictionary<,>.Add(object, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.Generic.SortedDictionary<,>.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Generic.SortedDictionary<,>.CopyTo(KeyValuePair[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Generic.SortedDictionary<,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Generic.SortedDictionary<,>.KeyCollection.Add(TKey) | parameter 0 -> this parameter [element] | true | -| System.Collections.Generic.SortedDictionary<,>.KeyCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Generic.SortedDictionary<,>.KeyCollection.CopyTo(TKey[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Generic.SortedDictionary<,>.KeyCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Generic.SortedDictionary<,>.SortedDictionary(IDictionary) | parameter 0 [element, property Key] -> return [element, property Key] | true | -| System.Collections.Generic.SortedDictionary<,>.SortedDictionary(IDictionary) | parameter 0 [element, property Value] -> return [element, property Value] | true | -| System.Collections.Generic.SortedDictionary<,>.SortedDictionary(IDictionary, IComparer) | parameter 0 [element, property Key] -> return [element, property Key] | true | -| System.Collections.Generic.SortedDictionary<,>.SortedDictionary(IDictionary, IComparer) | parameter 0 [element, property Value] -> return [element, property Value] | true | -| System.Collections.Generic.SortedDictionary<,>.ValueCollection.Add(TValue) | parameter 0 -> this parameter [element] | true | -| System.Collections.Generic.SortedDictionary<,>.ValueCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Generic.SortedDictionary<,>.ValueCollection.CopyTo(TValue[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Generic.SortedDictionary<,>.ValueCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Generic.SortedDictionary<,>.get_Item(TKey) | this parameter [element, property Value] -> return | true | -| System.Collections.Generic.SortedDictionary<,>.get_Item(object) | this parameter [element, property Value] -> return | true | -| System.Collections.Generic.SortedDictionary<,>.get_Keys() | this parameter [element, property Key] -> return [element] | true | -| System.Collections.Generic.SortedDictionary<,>.get_Values() | this parameter [element, property Value] -> return [element] | true | -| System.Collections.Generic.SortedDictionary<,>.set_Item(TKey, TValue) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.Generic.SortedDictionary<,>.set_Item(TKey, TValue) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.Generic.SortedDictionary<,>.set_Item(object, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.Generic.SortedDictionary<,>.set_Item(object, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.Generic.SortedList<,>.Add(KeyValuePair) | parameter 0 -> this parameter [element] | true | -| System.Collections.Generic.SortedList<,>.Add(KeyValuePair) | parameter 0 [property Key] -> this parameter [element, property Key] | true | -| System.Collections.Generic.SortedList<,>.Add(KeyValuePair) | parameter 0 [property Value] -> this parameter [element, property Value] | true | -| System.Collections.Generic.SortedList<,>.Add(TKey, TValue) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.Generic.SortedList<,>.Add(TKey, TValue) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.Generic.SortedList<,>.Add(object, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.Generic.SortedList<,>.Add(object, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.Generic.SortedList<,>.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Generic.SortedList<,>.CopyTo(KeyValuePair[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Generic.SortedList<,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Generic.SortedList<,>.KeyList.Add(TKey) | parameter 0 -> this parameter [element] | true | -| System.Collections.Generic.SortedList<,>.KeyList.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Generic.SortedList<,>.KeyList.CopyTo(TKey[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Generic.SortedList<,>.KeyList.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Generic.SortedList<,>.KeyList.Insert(int, TKey) | parameter 1 -> this parameter [element] | true | -| System.Collections.Generic.SortedList<,>.KeyList.get_Item(int) | this parameter [element] -> return | true | -| System.Collections.Generic.SortedList<,>.KeyList.set_Item(int, TKey) | parameter 1 -> this parameter [element] | true | -| System.Collections.Generic.SortedList<,>.SortedList(IDictionary) | parameter 0 [element, property Key] -> return [element, property Key] | true | -| System.Collections.Generic.SortedList<,>.SortedList(IDictionary) | parameter 0 [element, property Value] -> return [element, property Value] | true | -| System.Collections.Generic.SortedList<,>.SortedList(IDictionary, IComparer) | parameter 0 [element, property Key] -> return [element, property Key] | true | -| System.Collections.Generic.SortedList<,>.SortedList(IDictionary, IComparer) | parameter 0 [element, property Value] -> return [element, property Value] | true | -| System.Collections.Generic.SortedList<,>.ValueList.Add(TValue) | parameter 0 -> this parameter [element] | true | -| System.Collections.Generic.SortedList<,>.ValueList.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Generic.SortedList<,>.ValueList.CopyTo(TValue[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Generic.SortedList<,>.ValueList.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Generic.SortedList<,>.ValueList.Insert(int, TValue) | parameter 1 -> this parameter [element] | true | -| System.Collections.Generic.SortedList<,>.ValueList.get_Item(int) | this parameter [element] -> return | true | -| System.Collections.Generic.SortedList<,>.ValueList.set_Item(int, TValue) | parameter 1 -> this parameter [element] | true | -| System.Collections.Generic.SortedList<,>.get_Item(TKey) | this parameter [element, property Value] -> return | true | -| System.Collections.Generic.SortedList<,>.get_Item(object) | this parameter [element, property Value] -> return | true | -| System.Collections.Generic.SortedList<,>.get_Keys() | this parameter [element, property Key] -> return [element] | true | -| System.Collections.Generic.SortedList<,>.get_Values() | this parameter [element, property Value] -> return [element] | true | -| System.Collections.Generic.SortedList<,>.set_Item(TKey, TValue) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.Generic.SortedList<,>.set_Item(TKey, TValue) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.Generic.SortedList<,>.set_Item(object, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.Generic.SortedList<,>.set_Item(object, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.Generic.SortedSet<>.d__84.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Generic.SortedSet<>.Add(T) | parameter 0 -> this parameter [element] | true | -| System.Collections.Generic.SortedSet<>.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Generic.SortedSet<>.CopyTo(T[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Generic.SortedSet<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Generic.SortedSet<>.Reverse() | parameter 0 [element] -> return [element] | true | -| System.Collections.Generic.Stack<>.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Generic.Stack<>.CopyTo(T[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Generic.Stack<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Generic.Stack<>.Peek() | this parameter [element] -> return | true | -| System.Collections.Generic.Stack<>.Pop() | this parameter [element] -> return | true | -| System.Collections.Hashtable.Add(object, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.Hashtable.Add(object, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.Hashtable.Clone() | parameter 0 [element] -> return [element] | true | -| System.Collections.Hashtable.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Hashtable.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Hashtable.Hashtable(IDictionary) | parameter 0 [element, property Key] -> return [element, property Key] | true | -| System.Collections.Hashtable.Hashtable(IDictionary) | parameter 0 [element, property Value] -> return [element, property Value] | true | -| System.Collections.Hashtable.Hashtable(IDictionary, IEqualityComparer) | parameter 0 [element, property Key] -> return [element, property Key] | true | -| System.Collections.Hashtable.Hashtable(IDictionary, IEqualityComparer) | parameter 0 [element, property Value] -> return [element, property Value] | true | -| System.Collections.Hashtable.Hashtable(IDictionary, IHashCodeProvider, IComparer) | parameter 0 [element, property Key] -> return [element, property Key] | true | -| System.Collections.Hashtable.Hashtable(IDictionary, IHashCodeProvider, IComparer) | parameter 0 [element, property Value] -> return [element, property Value] | true | -| System.Collections.Hashtable.Hashtable(IDictionary, float) | parameter 0 [element, property Key] -> return [element, property Key] | true | -| System.Collections.Hashtable.Hashtable(IDictionary, float) | parameter 0 [element, property Value] -> return [element, property Value] | true | -| System.Collections.Hashtable.Hashtable(IDictionary, float, IEqualityComparer) | parameter 0 [element, property Key] -> return [element, property Key] | true | -| System.Collections.Hashtable.Hashtable(IDictionary, float, IEqualityComparer) | parameter 0 [element, property Value] -> return [element, property Value] | true | -| System.Collections.Hashtable.Hashtable(IDictionary, float, IHashCodeProvider, IComparer) | parameter 0 [element, property Key] -> return [element, property Key] | true | -| System.Collections.Hashtable.Hashtable(IDictionary, float, IHashCodeProvider, IComparer) | parameter 0 [element, property Value] -> return [element, property Value] | true | -| System.Collections.Hashtable.KeyCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Hashtable.KeyCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Hashtable.SyncHashtable.Add(object, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.Hashtable.SyncHashtable.Add(object, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.Hashtable.SyncHashtable.Clone() | parameter 0 [element] -> return [element] | true | -| System.Collections.Hashtable.SyncHashtable.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Hashtable.SyncHashtable.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Hashtable.SyncHashtable.get_Item(object) | this parameter [element, property Value] -> return | true | -| System.Collections.Hashtable.SyncHashtable.get_Keys() | this parameter [element, property Key] -> return [element] | true | -| System.Collections.Hashtable.SyncHashtable.get_Values() | this parameter [element, property Value] -> return [element] | true | -| System.Collections.Hashtable.SyncHashtable.set_Item(object, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.Hashtable.SyncHashtable.set_Item(object, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.Hashtable.ValueCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Hashtable.ValueCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Hashtable.get_Item(object) | this parameter [element, property Value] -> return | true | -| System.Collections.Hashtable.get_Keys() | this parameter [element, property Key] -> return [element] | true | -| System.Collections.Hashtable.get_Values() | this parameter [element, property Value] -> return [element] | true | -| System.Collections.Hashtable.set_Item(object, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.Hashtable.set_Item(object, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.ICollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.IDictionary.Add(object, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.IDictionary.Add(object, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.IDictionary.get_Item(object) | this parameter [element, property Value] -> return | true | -| System.Collections.IDictionary.get_Keys() | this parameter [element, property Key] -> return [element] | true | -| System.Collections.IDictionary.get_Values() | this parameter [element, property Value] -> return [element] | true | -| System.Collections.IDictionary.set_Item(object, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.IDictionary.set_Item(object, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.IEnumerable.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.IList.Add(object) | parameter 0 -> this parameter [element] | true | -| System.Collections.IList.Insert(int, object) | parameter 1 -> this parameter [element] | true | -| System.Collections.IList.get_Item(int) | this parameter [element] -> return | true | -| System.Collections.IList.set_Item(int, object) | parameter 1 -> this parameter [element] | true | -| System.Collections.ListDictionaryInternal.Add(object, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.ListDictionaryInternal.Add(object, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.ListDictionaryInternal.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.ListDictionaryInternal.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.ListDictionaryInternal.NodeKeyValueCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.ListDictionaryInternal.NodeKeyValueCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.ListDictionaryInternal.get_Item(object) | this parameter [element, property Value] -> return | true | -| System.Collections.ListDictionaryInternal.get_Keys() | this parameter [element, property Key] -> return [element] | true | -| System.Collections.ListDictionaryInternal.get_Values() | this parameter [element, property Value] -> return [element] | true | -| System.Collections.ListDictionaryInternal.set_Item(object, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.ListDictionaryInternal.set_Item(object, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.ObjectModel.Collection<>.Add(T) | parameter 0 -> this parameter [element] | true | -| System.Collections.ObjectModel.Collection<>.Add(object) | parameter 0 -> this parameter [element] | true | -| System.Collections.ObjectModel.Collection<>.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.ObjectModel.Collection<>.CopyTo(T[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.ObjectModel.Collection<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.ObjectModel.Collection<>.Insert(int, T) | parameter 1 -> this parameter [element] | true | -| System.Collections.ObjectModel.Collection<>.Insert(int, object) | parameter 1 -> this parameter [element] | true | -| System.Collections.ObjectModel.Collection<>.get_Item(int) | this parameter [element] -> return | true | -| System.Collections.ObjectModel.Collection<>.set_Item(int, T) | parameter 1 -> this parameter [element] | true | -| System.Collections.ObjectModel.Collection<>.set_Item(int, object) | parameter 1 -> this parameter [element] | true | -| System.Collections.ObjectModel.KeyedCollection<,>.get_Item(TKey) | this parameter [element] -> return | true | -| System.Collections.ObjectModel.ReadOnlyCollection<>.Add(T) | parameter 0 -> this parameter [element] | true | -| System.Collections.ObjectModel.ReadOnlyCollection<>.Add(object) | parameter 0 -> this parameter [element] | true | -| System.Collections.ObjectModel.ReadOnlyCollection<>.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.ObjectModel.ReadOnlyCollection<>.CopyTo(T[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.ObjectModel.ReadOnlyCollection<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.ObjectModel.ReadOnlyCollection<>.Insert(int, T) | parameter 1 -> this parameter [element] | true | -| System.Collections.ObjectModel.ReadOnlyCollection<>.Insert(int, object) | parameter 1 -> this parameter [element] | true | -| System.Collections.ObjectModel.ReadOnlyCollection<>.get_Item(int) | this parameter [element] -> return | true | -| System.Collections.ObjectModel.ReadOnlyCollection<>.set_Item(int, T) | parameter 1 -> this parameter [element] | true | -| System.Collections.ObjectModel.ReadOnlyCollection<>.set_Item(int, object) | parameter 1 -> this parameter [element] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(KeyValuePair) | parameter 0 -> this parameter [element] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(KeyValuePair) | parameter 0 [property Key] -> this parameter [element, property Key] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(KeyValuePair) | parameter 0 [property Value] -> this parameter [element, property Value] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(TKey, TValue) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(TKey, TValue) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(object, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(object, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.CopyTo(KeyValuePair[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.KeyCollection.Add(TKey) | parameter 0 -> this parameter [element] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.KeyCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.KeyCollection.CopyTo(TKey[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.KeyCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ReadOnlyDictionary(IDictionary) | parameter 0 [element, property Key] -> return [element, property Key] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ReadOnlyDictionary(IDictionary) | parameter 0 [element, property Value] -> return [element, property Value] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ValueCollection.Add(TValue) | parameter 0 -> this parameter [element] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ValueCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ValueCollection.CopyTo(TValue[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ValueCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.get_Item(TKey) | this parameter [element, property Value] -> return | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.get_Item(object) | this parameter [element, property Value] -> return | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.get_Keys() | this parameter [element, property Key] -> return [element] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.get_Values() | this parameter [element, property Value] -> return [element] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.set_Item(TKey, TValue) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.set_Item(TKey, TValue) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.set_Item(object, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.set_Item(object, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.Queue.Clone() | parameter 0 [element] -> return [element] | true | -| System.Collections.Queue.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Queue.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Queue.Peek() | this parameter [element] -> return | true | -| System.Collections.Queue.SynchronizedQueue.Clone() | parameter 0 [element] -> return [element] | true | -| System.Collections.Queue.SynchronizedQueue.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Queue.SynchronizedQueue.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Queue.SynchronizedQueue.Peek() | this parameter [element] -> return | true | -| System.Collections.ReadOnlyCollectionBase.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.ReadOnlyCollectionBase.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.SortedList.Add(object, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.SortedList.Add(object, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.SortedList.Clone() | parameter 0 [element] -> return [element] | true | -| System.Collections.SortedList.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.SortedList.GetByIndex(int) | this parameter [element, property Value] -> return | true | -| System.Collections.SortedList.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.SortedList.GetValueList() | this parameter [element, property Value] -> return [element] | true | -| System.Collections.SortedList.KeyList.Add(object) | parameter 0 -> this parameter [element] | true | -| System.Collections.SortedList.KeyList.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.SortedList.KeyList.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.SortedList.KeyList.Insert(int, object) | parameter 1 -> this parameter [element] | true | -| System.Collections.SortedList.KeyList.get_Item(int) | this parameter [element] -> return | true | -| System.Collections.SortedList.KeyList.set_Item(int, object) | parameter 1 -> this parameter [element] | true | -| System.Collections.SortedList.SortedList(IDictionary) | parameter 0 [element, property Key] -> return [element, property Key] | true | -| System.Collections.SortedList.SortedList(IDictionary) | parameter 0 [element, property Value] -> return [element, property Value] | true | -| System.Collections.SortedList.SortedList(IDictionary, IComparer) | parameter 0 [element, property Key] -> return [element, property Key] | true | -| System.Collections.SortedList.SortedList(IDictionary, IComparer) | parameter 0 [element, property Value] -> return [element, property Value] | true | -| System.Collections.SortedList.SyncSortedList.Add(object, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.SortedList.SyncSortedList.Add(object, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.SortedList.SyncSortedList.Clone() | parameter 0 [element] -> return [element] | true | -| System.Collections.SortedList.SyncSortedList.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.SortedList.SyncSortedList.GetByIndex(int) | this parameter [element, property Value] -> return | true | -| System.Collections.SortedList.SyncSortedList.GetValueList() | this parameter [element, property Value] -> return [element] | true | -| System.Collections.SortedList.SyncSortedList.get_Item(object) | this parameter [element, property Value] -> return | true | -| System.Collections.SortedList.SyncSortedList.set_Item(object, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.SortedList.SyncSortedList.set_Item(object, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.SortedList.ValueList.Add(object) | parameter 0 -> this parameter [element] | true | -| System.Collections.SortedList.ValueList.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.SortedList.ValueList.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.SortedList.ValueList.Insert(int, object) | parameter 1 -> this parameter [element] | true | -| System.Collections.SortedList.ValueList.get_Item(int) | this parameter [element] -> return | true | -| System.Collections.SortedList.ValueList.set_Item(int, object) | parameter 1 -> this parameter [element] | true | -| System.Collections.SortedList.get_Item(object) | this parameter [element, property Value] -> return | true | -| System.Collections.SortedList.get_Keys() | this parameter [element, property Key] -> return [element] | true | -| System.Collections.SortedList.get_Values() | this parameter [element, property Value] -> return [element] | true | -| System.Collections.SortedList.set_Item(object, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.SortedList.set_Item(object, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.Specialized.HybridDictionary.Add(object, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.Specialized.HybridDictionary.Add(object, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.Specialized.HybridDictionary.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Specialized.HybridDictionary.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Specialized.HybridDictionary.get_Item(object) | this parameter [element, property Value] -> return | true | -| System.Collections.Specialized.HybridDictionary.get_Keys() | this parameter [element, property Key] -> return [element] | true | -| System.Collections.Specialized.HybridDictionary.get_Values() | this parameter [element, property Value] -> return [element] | true | -| System.Collections.Specialized.HybridDictionary.set_Item(object, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.Specialized.HybridDictionary.set_Item(object, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.Specialized.IOrderedDictionary.get_Item(int) | this parameter [element, property Value] -> return | true | -| System.Collections.Specialized.IOrderedDictionary.set_Item(int, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.Specialized.IOrderedDictionary.set_Item(int, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.Specialized.ListDictionary.Add(object, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.Specialized.ListDictionary.Add(object, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.Specialized.ListDictionary.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Specialized.ListDictionary.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Specialized.ListDictionary.NodeKeyValueCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Specialized.ListDictionary.NodeKeyValueCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Specialized.ListDictionary.get_Item(object) | this parameter [element, property Value] -> return | true | -| System.Collections.Specialized.ListDictionary.get_Keys() | this parameter [element, property Key] -> return [element] | true | -| System.Collections.Specialized.ListDictionary.get_Values() | this parameter [element, property Value] -> return [element] | true | -| System.Collections.Specialized.ListDictionary.set_Item(object, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.Specialized.ListDictionary.set_Item(object, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.Specialized.NameObjectCollectionBase.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Specialized.NameObjectCollectionBase.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Specialized.NameObjectCollectionBase.KeysCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Specialized.NameObjectCollectionBase.KeysCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Specialized.NameValueCollection.Add(NameValueCollection) | parameter 0 -> this parameter [element] | true | -| System.Collections.Specialized.NameValueCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Specialized.OrderedDictionary.Add(object, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.Specialized.OrderedDictionary.Add(object, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.Specialized.OrderedDictionary.AsReadOnly() | parameter 0 [element] -> return [element] | true | -| System.Collections.Specialized.OrderedDictionary.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Specialized.OrderedDictionary.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Specialized.OrderedDictionary.OrderedDictionaryKeyValueCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Specialized.OrderedDictionary.OrderedDictionaryKeyValueCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Specialized.OrderedDictionary.get_Item(int) | this parameter [element, property Value] -> return | true | -| System.Collections.Specialized.OrderedDictionary.get_Item(object) | this parameter [element, property Value] -> return | true | -| System.Collections.Specialized.OrderedDictionary.get_Keys() | this parameter [element, property Key] -> return [element] | true | -| System.Collections.Specialized.OrderedDictionary.get_Values() | this parameter [element, property Value] -> return [element] | true | -| System.Collections.Specialized.OrderedDictionary.set_Item(int, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.Specialized.OrderedDictionary.set_Item(int, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.Specialized.OrderedDictionary.set_Item(object, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.Collections.Specialized.OrderedDictionary.set_Item(object, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.Collections.Specialized.ReadOnlyList.Add(object) | parameter 0 -> this parameter [element] | true | -| System.Collections.Specialized.ReadOnlyList.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Specialized.ReadOnlyList.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Specialized.ReadOnlyList.Insert(int, object) | parameter 1 -> this parameter [element] | true | -| System.Collections.Specialized.ReadOnlyList.get_Item(int) | this parameter [element] -> return | true | -| System.Collections.Specialized.ReadOnlyList.set_Item(int, object) | parameter 1 -> this parameter [element] | true | -| System.Collections.Specialized.StringCollection.Add(object) | parameter 0 -> this parameter [element] | true | -| System.Collections.Specialized.StringCollection.Add(string) | parameter 0 -> this parameter [element] | true | -| System.Collections.Specialized.StringCollection.AddRange(String[]) | parameter 0 [element] -> this parameter [element] | true | -| System.Collections.Specialized.StringCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Specialized.StringCollection.CopyTo(String[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Specialized.StringCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Specialized.StringCollection.Insert(int, object) | parameter 1 -> this parameter [element] | true | -| System.Collections.Specialized.StringCollection.Insert(int, string) | parameter 1 -> this parameter [element] | true | -| System.Collections.Specialized.StringCollection.get_Item(int) | this parameter [element] -> return | true | -| System.Collections.Specialized.StringCollection.set_Item(int, object) | parameter 1 -> this parameter [element] | true | -| System.Collections.Specialized.StringCollection.set_Item(int, string) | parameter 1 -> this parameter [element] | true | -| System.Collections.Specialized.StringDictionary.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Stack.Clone() | parameter 0 [element] -> return [element] | true | -| System.Collections.Stack.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Stack.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Stack.Peek() | this parameter [element] -> return | true | -| System.Collections.Stack.Pop() | this parameter [element] -> return | true | -| System.Collections.Stack.SyncStack.Clone() | parameter 0 [element] -> return [element] | true | -| System.Collections.Stack.SyncStack.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Collections.Stack.SyncStack.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Collections.Stack.SyncStack.Peek() | this parameter [element] -> return | true | -| System.Collections.Stack.SyncStack.Pop() | this parameter [element] -> return | true | -| System.ComponentModel.AttributeCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.ComponentModel.AttributeCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.ComponentModel.BindingList<>.Find(PropertyDescriptor, object) | this parameter [element] -> return | true | -| System.ComponentModel.Design.DesignerCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.ComponentModel.Design.DesignerCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.Add(object) | parameter 0 -> this parameter [element] | true | -| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.Insert(int, object) | parameter 1 -> this parameter [element] | true | -| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.get_Item(int) | this parameter [element] -> return | true | -| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.get_Item(string) | this parameter [element] -> return | true | -| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.set_Item(int, object) | parameter 1 -> this parameter [element] | true | -| System.ComponentModel.Design.DesignerVerbCollection.Add(DesignerVerb) | parameter 0 -> this parameter [element] | true | -| System.ComponentModel.Design.DesignerVerbCollection.AddRange(DesignerVerbCollection) | parameter 0 [element] -> this parameter [element] | true | -| System.ComponentModel.Design.DesignerVerbCollection.AddRange(DesignerVerb[]) | parameter 0 [element] -> this parameter [element] | true | -| System.ComponentModel.Design.DesignerVerbCollection.CopyTo(DesignerVerb[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.ComponentModel.Design.DesignerVerbCollection.Insert(int, DesignerVerb) | parameter 1 -> this parameter [element] | true | -| System.ComponentModel.Design.DesignerVerbCollection.get_Item(int) | this parameter [element] -> return | true | -| System.ComponentModel.Design.DesignerVerbCollection.set_Item(int, DesignerVerb) | parameter 1 -> this parameter [element] | true | -| System.ComponentModel.EventDescriptorCollection.Add(EventDescriptor) | parameter 0 -> this parameter [element] | true | -| System.ComponentModel.EventDescriptorCollection.Add(object) | parameter 0 -> this parameter [element] | true | -| System.ComponentModel.EventDescriptorCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.ComponentModel.EventDescriptorCollection.Find(string, bool) | this parameter [element] -> return | true | -| System.ComponentModel.EventDescriptorCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.ComponentModel.EventDescriptorCollection.Insert(int, EventDescriptor) | parameter 1 -> this parameter [element] | true | -| System.ComponentModel.EventDescriptorCollection.Insert(int, object) | parameter 1 -> this parameter [element] | true | -| System.ComponentModel.EventDescriptorCollection.get_Item(int) | this parameter [element] -> return | true | -| System.ComponentModel.EventDescriptorCollection.get_Item(string) | this parameter [element] -> return | true | -| System.ComponentModel.EventDescriptorCollection.set_Item(int, object) | parameter 1 -> this parameter [element] | true | -| System.ComponentModel.IBindingList.Find(PropertyDescriptor, object) | this parameter [element] -> return | true | -| System.ComponentModel.ListSortDescriptionCollection.Add(object) | parameter 0 -> this parameter [element] | true | -| System.ComponentModel.ListSortDescriptionCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.ComponentModel.ListSortDescriptionCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.ComponentModel.ListSortDescriptionCollection.Insert(int, object) | parameter 1 -> this parameter [element] | true | -| System.ComponentModel.ListSortDescriptionCollection.get_Item(int) | this parameter [element] -> return | true | -| System.ComponentModel.ListSortDescriptionCollection.set_Item(int, ListSortDescription) | parameter 1 -> this parameter [element] | true | -| System.ComponentModel.ListSortDescriptionCollection.set_Item(int, object) | parameter 1 -> this parameter [element] | true | -| System.ComponentModel.PropertyDescriptorCollection.Add(PropertyDescriptor) | parameter 0 -> this parameter [element] | true | -| System.ComponentModel.PropertyDescriptorCollection.Add(PropertyDescriptor) | parameter 0 [property Key] -> this parameter [element, property Key] | true | -| System.ComponentModel.PropertyDescriptorCollection.Add(PropertyDescriptor) | parameter 0 [property Value] -> this parameter [element, property Value] | true | -| System.ComponentModel.PropertyDescriptorCollection.Add(object) | parameter 0 -> this parameter [element] | true | -| System.ComponentModel.PropertyDescriptorCollection.Add(object) | parameter 0 [property Key] -> this parameter [element, property Key] | true | -| System.ComponentModel.PropertyDescriptorCollection.Add(object) | parameter 0 [property Value] -> this parameter [element, property Value] | true | -| System.ComponentModel.PropertyDescriptorCollection.Add(object, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.ComponentModel.PropertyDescriptorCollection.Add(object, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.ComponentModel.PropertyDescriptorCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.ComponentModel.PropertyDescriptorCollection.Find(string, bool) | this parameter [element] -> return | true | -| System.ComponentModel.PropertyDescriptorCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.ComponentModel.PropertyDescriptorCollection.Insert(int, PropertyDescriptor) | parameter 1 -> this parameter [element] | true | -| System.ComponentModel.PropertyDescriptorCollection.Insert(int, object) | parameter 1 -> this parameter [element] | true | -| System.ComponentModel.PropertyDescriptorCollection.PropertyDescriptorCollection(PropertyDescriptor[]) | parameter 0 [element, property Key] -> return [element, property Key] | true | -| System.ComponentModel.PropertyDescriptorCollection.PropertyDescriptorCollection(PropertyDescriptor[]) | parameter 0 [element, property Value] -> return [element, property Value] | true | -| System.ComponentModel.PropertyDescriptorCollection.PropertyDescriptorCollection(PropertyDescriptor[], bool) | parameter 0 [element, property Key] -> return [element, property Key] | true | -| System.ComponentModel.PropertyDescriptorCollection.PropertyDescriptorCollection(PropertyDescriptor[], bool) | parameter 0 [element, property Value] -> return [element, property Value] | true | -| System.ComponentModel.PropertyDescriptorCollection.get_Item(int) | this parameter [element, property Value] -> return | true | -| System.ComponentModel.PropertyDescriptorCollection.get_Item(int) | this parameter [element] -> return | true | -| System.ComponentModel.PropertyDescriptorCollection.get_Item(object) | this parameter [element, property Value] -> return | true | -| System.ComponentModel.PropertyDescriptorCollection.get_Item(object) | this parameter [element] -> return | true | -| System.ComponentModel.PropertyDescriptorCollection.get_Item(string) | this parameter [element, property Value] -> return | true | -| System.ComponentModel.PropertyDescriptorCollection.get_Item(string) | this parameter [element] -> return | true | -| System.ComponentModel.PropertyDescriptorCollection.get_Keys() | this parameter [element, property Key] -> return [element] | true | -| System.ComponentModel.PropertyDescriptorCollection.get_Values() | this parameter [element, property Value] -> return [element] | true | -| System.ComponentModel.PropertyDescriptorCollection.set_Item(int, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.ComponentModel.PropertyDescriptorCollection.set_Item(int, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.ComponentModel.PropertyDescriptorCollection.set_Item(int, object) | parameter 1 -> this parameter [element] | true | -| System.ComponentModel.PropertyDescriptorCollection.set_Item(object, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.ComponentModel.PropertyDescriptorCollection.set_Item(object, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.ComponentModel.PropertyDescriptorCollection.set_Item(object, object) | parameter 1 -> this parameter [element] | true | -| System.ComponentModel.TypeConverter.StandardValuesCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.ComponentModel.TypeConverter.StandardValuesCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.ConsolePal.UnixConsoleStream.Read(Byte[], int, int) | this parameter -> parameter 0 | false | -| System.ConsolePal.UnixConsoleStream.Write(Byte[], int, int) | parameter 0 -> this parameter | false | -| System.Convert.ChangeType(object, Type) | parameter 0 -> return | false | -| System.Convert.ChangeType(object, Type, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ChangeType(object, TypeCode) | parameter 0 -> return | false | -| System.Convert.ChangeType(object, TypeCode, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.FromBase64CharArray(Char[], int, int) | parameter 0 -> return | false | -| System.Convert.FromBase64String(string) | parameter 0 -> return | false | -| System.Convert.FromHexString(ReadOnlySpan) | parameter 0 -> return | false | -| System.Convert.FromHexString(string) | parameter 0 -> return | false | -| System.Convert.GetTypeCode(object) | parameter 0 -> return | false | -| System.Convert.IsDBNull(object) | parameter 0 -> return | false | -| System.Convert.ToBase64CharArray(Byte[], int, int, Char[], int) | parameter 0 -> return | false | -| System.Convert.ToBase64CharArray(Byte[], int, int, Char[], int, Base64FormattingOptions) | parameter 0 -> return | false | -| System.Convert.ToBase64String(Byte[]) | parameter 0 -> return | false | -| System.Convert.ToBase64String(Byte[], Base64FormattingOptions) | parameter 0 -> return | false | -| System.Convert.ToBase64String(Byte[], int, int) | parameter 0 -> return | false | -| System.Convert.ToBase64String(Byte[], int, int, Base64FormattingOptions) | parameter 0 -> return | false | -| System.Convert.ToBase64String(ReadOnlySpan, Base64FormattingOptions) | parameter 0 -> return | false | -| System.Convert.ToBoolean(DateTime) | parameter 0 -> return | false | -| System.Convert.ToBoolean(bool) | parameter 0 -> return | false | -| System.Convert.ToBoolean(byte) | parameter 0 -> return | false | -| System.Convert.ToBoolean(char) | parameter 0 -> return | false | -| System.Convert.ToBoolean(decimal) | parameter 0 -> return | false | -| System.Convert.ToBoolean(double) | parameter 0 -> return | false | -| System.Convert.ToBoolean(float) | parameter 0 -> return | false | -| System.Convert.ToBoolean(int) | parameter 0 -> return | false | -| System.Convert.ToBoolean(long) | parameter 0 -> return | false | -| System.Convert.ToBoolean(object) | parameter 0 -> return | false | -| System.Convert.ToBoolean(object, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToBoolean(sbyte) | parameter 0 -> return | false | -| System.Convert.ToBoolean(short) | parameter 0 -> return | false | -| System.Convert.ToBoolean(string) | parameter 0 -> return | false | -| System.Convert.ToBoolean(string, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToBoolean(uint) | parameter 0 -> return | false | -| System.Convert.ToBoolean(ulong) | parameter 0 -> return | false | -| System.Convert.ToBoolean(ushort) | parameter 0 -> return | false | -| System.Convert.ToByte(DateTime) | parameter 0 -> return | false | -| System.Convert.ToByte(bool) | parameter 0 -> return | false | -| System.Convert.ToByte(byte) | parameter 0 -> return | false | -| System.Convert.ToByte(char) | parameter 0 -> return | false | -| System.Convert.ToByte(decimal) | parameter 0 -> return | false | -| System.Convert.ToByte(double) | parameter 0 -> return | false | -| System.Convert.ToByte(float) | parameter 0 -> return | false | -| System.Convert.ToByte(int) | parameter 0 -> return | false | -| System.Convert.ToByte(long) | parameter 0 -> return | false | -| System.Convert.ToByte(object) | parameter 0 -> return | false | -| System.Convert.ToByte(object, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToByte(sbyte) | parameter 0 -> return | false | -| System.Convert.ToByte(short) | parameter 0 -> return | false | -| System.Convert.ToByte(string) | parameter 0 -> return | false | -| System.Convert.ToByte(string, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToByte(string, int) | parameter 0 -> return | false | -| System.Convert.ToByte(uint) | parameter 0 -> return | false | -| System.Convert.ToByte(ulong) | parameter 0 -> return | false | -| System.Convert.ToByte(ushort) | parameter 0 -> return | false | -| System.Convert.ToChar(DateTime) | parameter 0 -> return | false | -| System.Convert.ToChar(bool) | parameter 0 -> return | false | -| System.Convert.ToChar(byte) | parameter 0 -> return | false | -| System.Convert.ToChar(char) | parameter 0 -> return | false | -| System.Convert.ToChar(decimal) | parameter 0 -> return | false | -| System.Convert.ToChar(double) | parameter 0 -> return | false | -| System.Convert.ToChar(float) | parameter 0 -> return | false | -| System.Convert.ToChar(int) | parameter 0 -> return | false | -| System.Convert.ToChar(long) | parameter 0 -> return | false | -| System.Convert.ToChar(object) | parameter 0 -> return | false | -| System.Convert.ToChar(object, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToChar(sbyte) | parameter 0 -> return | false | -| System.Convert.ToChar(short) | parameter 0 -> return | false | -| System.Convert.ToChar(string) | parameter 0 -> return | false | -| System.Convert.ToChar(string, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToChar(uint) | parameter 0 -> return | false | -| System.Convert.ToChar(ulong) | parameter 0 -> return | false | -| System.Convert.ToChar(ushort) | parameter 0 -> return | false | -| System.Convert.ToDateTime(DateTime) | parameter 0 -> return | false | -| System.Convert.ToDateTime(bool) | parameter 0 -> return | false | -| System.Convert.ToDateTime(byte) | parameter 0 -> return | false | -| System.Convert.ToDateTime(char) | parameter 0 -> return | false | -| System.Convert.ToDateTime(decimal) | parameter 0 -> return | false | -| System.Convert.ToDateTime(double) | parameter 0 -> return | false | -| System.Convert.ToDateTime(float) | parameter 0 -> return | false | -| System.Convert.ToDateTime(int) | parameter 0 -> return | false | -| System.Convert.ToDateTime(long) | parameter 0 -> return | false | -| System.Convert.ToDateTime(object) | parameter 0 -> return | false | -| System.Convert.ToDateTime(object, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToDateTime(sbyte) | parameter 0 -> return | false | -| System.Convert.ToDateTime(short) | parameter 0 -> return | false | -| System.Convert.ToDateTime(string) | parameter 0 -> return | false | -| System.Convert.ToDateTime(string, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToDateTime(uint) | parameter 0 -> return | false | -| System.Convert.ToDateTime(ulong) | parameter 0 -> return | false | -| System.Convert.ToDateTime(ushort) | parameter 0 -> return | false | -| System.Convert.ToDecimal(DateTime) | parameter 0 -> return | false | -| System.Convert.ToDecimal(bool) | parameter 0 -> return | false | -| System.Convert.ToDecimal(byte) | parameter 0 -> return | false | -| System.Convert.ToDecimal(char) | parameter 0 -> return | false | -| System.Convert.ToDecimal(decimal) | parameter 0 -> return | false | -| System.Convert.ToDecimal(double) | parameter 0 -> return | false | -| System.Convert.ToDecimal(float) | parameter 0 -> return | false | -| System.Convert.ToDecimal(int) | parameter 0 -> return | false | -| System.Convert.ToDecimal(long) | parameter 0 -> return | false | -| System.Convert.ToDecimal(object) | parameter 0 -> return | false | -| System.Convert.ToDecimal(object, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToDecimal(sbyte) | parameter 0 -> return | false | -| System.Convert.ToDecimal(short) | parameter 0 -> return | false | -| System.Convert.ToDecimal(string) | parameter 0 -> return | false | -| System.Convert.ToDecimal(string, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToDecimal(uint) | parameter 0 -> return | false | -| System.Convert.ToDecimal(ulong) | parameter 0 -> return | false | -| System.Convert.ToDecimal(ushort) | parameter 0 -> return | false | -| System.Convert.ToDouble(DateTime) | parameter 0 -> return | false | -| System.Convert.ToDouble(bool) | parameter 0 -> return | false | -| System.Convert.ToDouble(byte) | parameter 0 -> return | false | -| System.Convert.ToDouble(char) | parameter 0 -> return | false | -| System.Convert.ToDouble(decimal) | parameter 0 -> return | false | -| System.Convert.ToDouble(double) | parameter 0 -> return | false | -| System.Convert.ToDouble(float) | parameter 0 -> return | false | -| System.Convert.ToDouble(int) | parameter 0 -> return | false | -| System.Convert.ToDouble(long) | parameter 0 -> return | false | -| System.Convert.ToDouble(object) | parameter 0 -> return | false | -| System.Convert.ToDouble(object, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToDouble(sbyte) | parameter 0 -> return | false | -| System.Convert.ToDouble(short) | parameter 0 -> return | false | -| System.Convert.ToDouble(string) | parameter 0 -> return | false | -| System.Convert.ToDouble(string, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToDouble(uint) | parameter 0 -> return | false | -| System.Convert.ToDouble(ulong) | parameter 0 -> return | false | -| System.Convert.ToDouble(ushort) | parameter 0 -> return | false | -| System.Convert.ToHexString(Byte[]) | parameter 0 -> return | false | -| System.Convert.ToHexString(Byte[], int, int) | parameter 0 -> return | false | -| System.Convert.ToHexString(ReadOnlySpan) | parameter 0 -> return | false | -| System.Convert.ToInt16(DateTime) | parameter 0 -> return | false | -| System.Convert.ToInt16(bool) | parameter 0 -> return | false | -| System.Convert.ToInt16(byte) | parameter 0 -> return | false | -| System.Convert.ToInt16(char) | parameter 0 -> return | false | -| System.Convert.ToInt16(decimal) | parameter 0 -> return | false | -| System.Convert.ToInt16(double) | parameter 0 -> return | false | -| System.Convert.ToInt16(float) | parameter 0 -> return | false | -| System.Convert.ToInt16(int) | parameter 0 -> return | false | -| System.Convert.ToInt16(long) | parameter 0 -> return | false | -| System.Convert.ToInt16(object) | parameter 0 -> return | false | -| System.Convert.ToInt16(object, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToInt16(sbyte) | parameter 0 -> return | false | -| System.Convert.ToInt16(short) | parameter 0 -> return | false | -| System.Convert.ToInt16(string) | parameter 0 -> return | false | -| System.Convert.ToInt16(string, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToInt16(string, int) | parameter 0 -> return | false | -| System.Convert.ToInt16(uint) | parameter 0 -> return | false | -| System.Convert.ToInt16(ulong) | parameter 0 -> return | false | -| System.Convert.ToInt16(ushort) | parameter 0 -> return | false | -| System.Convert.ToInt32(DateTime) | parameter 0 -> return | false | -| System.Convert.ToInt32(bool) | parameter 0 -> return | false | -| System.Convert.ToInt32(byte) | parameter 0 -> return | false | -| System.Convert.ToInt32(char) | parameter 0 -> return | false | -| System.Convert.ToInt32(decimal) | parameter 0 -> return | false | -| System.Convert.ToInt32(double) | parameter 0 -> return | false | -| System.Convert.ToInt32(float) | parameter 0 -> return | false | -| System.Convert.ToInt32(int) | parameter 0 -> return | false | -| System.Convert.ToInt32(long) | parameter 0 -> return | false | -| System.Convert.ToInt32(object) | parameter 0 -> return | false | -| System.Convert.ToInt32(object, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToInt32(sbyte) | parameter 0 -> return | false | -| System.Convert.ToInt32(short) | parameter 0 -> return | false | -| System.Convert.ToInt32(string) | parameter 0 -> return | false | -| System.Convert.ToInt32(string, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToInt32(string, int) | parameter 0 -> return | false | -| System.Convert.ToInt32(uint) | parameter 0 -> return | false | -| System.Convert.ToInt32(ulong) | parameter 0 -> return | false | -| System.Convert.ToInt32(ushort) | parameter 0 -> return | false | -| System.Convert.ToInt64(DateTime) | parameter 0 -> return | false | -| System.Convert.ToInt64(bool) | parameter 0 -> return | false | -| System.Convert.ToInt64(byte) | parameter 0 -> return | false | -| System.Convert.ToInt64(char) | parameter 0 -> return | false | -| System.Convert.ToInt64(decimal) | parameter 0 -> return | false | -| System.Convert.ToInt64(double) | parameter 0 -> return | false | -| System.Convert.ToInt64(float) | parameter 0 -> return | false | -| System.Convert.ToInt64(int) | parameter 0 -> return | false | -| System.Convert.ToInt64(long) | parameter 0 -> return | false | -| System.Convert.ToInt64(object) | parameter 0 -> return | false | -| System.Convert.ToInt64(object, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToInt64(sbyte) | parameter 0 -> return | false | -| System.Convert.ToInt64(short) | parameter 0 -> return | false | -| System.Convert.ToInt64(string) | parameter 0 -> return | false | -| System.Convert.ToInt64(string, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToInt64(string, int) | parameter 0 -> return | false | -| System.Convert.ToInt64(uint) | parameter 0 -> return | false | -| System.Convert.ToInt64(ulong) | parameter 0 -> return | false | -| System.Convert.ToInt64(ushort) | parameter 0 -> return | false | -| System.Convert.ToSByte(DateTime) | parameter 0 -> return | false | -| System.Convert.ToSByte(bool) | parameter 0 -> return | false | -| System.Convert.ToSByte(byte) | parameter 0 -> return | false | -| System.Convert.ToSByte(char) | parameter 0 -> return | false | -| System.Convert.ToSByte(decimal) | parameter 0 -> return | false | -| System.Convert.ToSByte(double) | parameter 0 -> return | false | -| System.Convert.ToSByte(float) | parameter 0 -> return | false | -| System.Convert.ToSByte(int) | parameter 0 -> return | false | -| System.Convert.ToSByte(long) | parameter 0 -> return | false | -| System.Convert.ToSByte(object) | parameter 0 -> return | false | -| System.Convert.ToSByte(object, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToSByte(sbyte) | parameter 0 -> return | false | -| System.Convert.ToSByte(short) | parameter 0 -> return | false | -| System.Convert.ToSByte(string) | parameter 0 -> return | false | -| System.Convert.ToSByte(string, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToSByte(string, int) | parameter 0 -> return | false | -| System.Convert.ToSByte(uint) | parameter 0 -> return | false | -| System.Convert.ToSByte(ulong) | parameter 0 -> return | false | -| System.Convert.ToSByte(ushort) | parameter 0 -> return | false | -| System.Convert.ToSingle(DateTime) | parameter 0 -> return | false | -| System.Convert.ToSingle(bool) | parameter 0 -> return | false | -| System.Convert.ToSingle(byte) | parameter 0 -> return | false | -| System.Convert.ToSingle(char) | parameter 0 -> return | false | -| System.Convert.ToSingle(decimal) | parameter 0 -> return | false | -| System.Convert.ToSingle(double) | parameter 0 -> return | false | -| System.Convert.ToSingle(float) | parameter 0 -> return | false | -| System.Convert.ToSingle(int) | parameter 0 -> return | false | -| System.Convert.ToSingle(long) | parameter 0 -> return | false | -| System.Convert.ToSingle(object) | parameter 0 -> return | false | -| System.Convert.ToSingle(object, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToSingle(sbyte) | parameter 0 -> return | false | -| System.Convert.ToSingle(short) | parameter 0 -> return | false | -| System.Convert.ToSingle(string) | parameter 0 -> return | false | -| System.Convert.ToSingle(string, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToSingle(uint) | parameter 0 -> return | false | -| System.Convert.ToSingle(ulong) | parameter 0 -> return | false | -| System.Convert.ToSingle(ushort) | parameter 0 -> return | false | -| System.Convert.ToString(DateTime) | parameter 0 -> return | false | -| System.Convert.ToString(DateTime, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToString(bool) | parameter 0 -> return | false | -| System.Convert.ToString(bool, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToString(byte) | parameter 0 -> return | false | -| System.Convert.ToString(byte, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToString(byte, int) | parameter 0 -> return | false | -| System.Convert.ToString(char) | parameter 0 -> return | false | -| System.Convert.ToString(char, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToString(decimal) | parameter 0 -> return | false | -| System.Convert.ToString(decimal, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToString(double) | parameter 0 -> return | false | -| System.Convert.ToString(double, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToString(float) | parameter 0 -> return | false | -| System.Convert.ToString(float, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToString(int) | parameter 0 -> return | false | -| System.Convert.ToString(int, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToString(int, int) | parameter 0 -> return | false | -| System.Convert.ToString(long) | parameter 0 -> return | false | -| System.Convert.ToString(long, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToString(long, int) | parameter 0 -> return | false | -| System.Convert.ToString(object) | parameter 0 -> return | false | -| System.Convert.ToString(object, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToString(sbyte) | parameter 0 -> return | false | -| System.Convert.ToString(sbyte, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToString(short) | parameter 0 -> return | false | -| System.Convert.ToString(short, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToString(short, int) | parameter 0 -> return | false | -| System.Convert.ToString(string) | parameter 0 -> return | false | -| System.Convert.ToString(string, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToString(uint) | parameter 0 -> return | false | -| System.Convert.ToString(uint, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToString(ulong) | parameter 0 -> return | false | -| System.Convert.ToString(ulong, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToString(ushort) | parameter 0 -> return | false | -| System.Convert.ToString(ushort, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToUInt16(DateTime) | parameter 0 -> return | false | -| System.Convert.ToUInt16(bool) | parameter 0 -> return | false | -| System.Convert.ToUInt16(byte) | parameter 0 -> return | false | -| System.Convert.ToUInt16(char) | parameter 0 -> return | false | -| System.Convert.ToUInt16(decimal) | parameter 0 -> return | false | -| System.Convert.ToUInt16(double) | parameter 0 -> return | false | -| System.Convert.ToUInt16(float) | parameter 0 -> return | false | -| System.Convert.ToUInt16(int) | parameter 0 -> return | false | -| System.Convert.ToUInt16(long) | parameter 0 -> return | false | -| System.Convert.ToUInt16(object) | parameter 0 -> return | false | -| System.Convert.ToUInt16(object, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToUInt16(sbyte) | parameter 0 -> return | false | -| System.Convert.ToUInt16(short) | parameter 0 -> return | false | -| System.Convert.ToUInt16(string) | parameter 0 -> return | false | -| System.Convert.ToUInt16(string, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToUInt16(string, int) | parameter 0 -> return | false | -| System.Convert.ToUInt16(uint) | parameter 0 -> return | false | -| System.Convert.ToUInt16(ulong) | parameter 0 -> return | false | -| System.Convert.ToUInt16(ushort) | parameter 0 -> return | false | -| System.Convert.ToUInt32(DateTime) | parameter 0 -> return | false | -| System.Convert.ToUInt32(bool) | parameter 0 -> return | false | -| System.Convert.ToUInt32(byte) | parameter 0 -> return | false | -| System.Convert.ToUInt32(char) | parameter 0 -> return | false | -| System.Convert.ToUInt32(decimal) | parameter 0 -> return | false | -| System.Convert.ToUInt32(double) | parameter 0 -> return | false | -| System.Convert.ToUInt32(float) | parameter 0 -> return | false | -| System.Convert.ToUInt32(int) | parameter 0 -> return | false | -| System.Convert.ToUInt32(long) | parameter 0 -> return | false | -| System.Convert.ToUInt32(object) | parameter 0 -> return | false | -| System.Convert.ToUInt32(object, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToUInt32(sbyte) | parameter 0 -> return | false | -| System.Convert.ToUInt32(short) | parameter 0 -> return | false | -| System.Convert.ToUInt32(string) | parameter 0 -> return | false | -| System.Convert.ToUInt32(string, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToUInt32(string, int) | parameter 0 -> return | false | -| System.Convert.ToUInt32(uint) | parameter 0 -> return | false | -| System.Convert.ToUInt32(ulong) | parameter 0 -> return | false | -| System.Convert.ToUInt32(ushort) | parameter 0 -> return | false | -| System.Convert.ToUInt64(DateTime) | parameter 0 -> return | false | -| System.Convert.ToUInt64(bool) | parameter 0 -> return | false | -| System.Convert.ToUInt64(byte) | parameter 0 -> return | false | -| System.Convert.ToUInt64(char) | parameter 0 -> return | false | -| System.Convert.ToUInt64(decimal) | parameter 0 -> return | false | -| System.Convert.ToUInt64(double) | parameter 0 -> return | false | -| System.Convert.ToUInt64(float) | parameter 0 -> return | false | -| System.Convert.ToUInt64(int) | parameter 0 -> return | false | -| System.Convert.ToUInt64(long) | parameter 0 -> return | false | -| System.Convert.ToUInt64(object) | parameter 0 -> return | false | -| System.Convert.ToUInt64(object, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToUInt64(sbyte) | parameter 0 -> return | false | -| System.Convert.ToUInt64(short) | parameter 0 -> return | false | -| System.Convert.ToUInt64(string) | parameter 0 -> return | false | -| System.Convert.ToUInt64(string, IFormatProvider) | parameter 0 -> return | false | -| System.Convert.ToUInt64(string, int) | parameter 0 -> return | false | -| System.Convert.ToUInt64(uint) | parameter 0 -> return | false | -| System.Convert.ToUInt64(ulong) | parameter 0 -> return | false | -| System.Convert.ToUInt64(ushort) | parameter 0 -> return | false | -| System.Convert.TryFromBase64Chars(ReadOnlySpan, Span, out int) | parameter 0 -> return | false | -| System.Convert.TryFromBase64String(string, Span, out int) | parameter 0 -> return | false | -| System.Convert.TryToBase64Chars(ReadOnlySpan, Span, out int, Base64FormattingOptions) | parameter 0 -> return | false | -| System.Diagnostics.Tracing.CounterPayload.d__51.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Diagnostics.Tracing.CounterPayload.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Diagnostics.Tracing.EventPayload.Add(KeyValuePair) | parameter 0 -> this parameter [element] | true | -| System.Diagnostics.Tracing.EventPayload.Add(KeyValuePair) | parameter 0 [property Key] -> this parameter [element, property Key] | true | -| System.Diagnostics.Tracing.EventPayload.Add(KeyValuePair) | parameter 0 [property Value] -> this parameter [element, property Value] | true | -| System.Diagnostics.Tracing.EventPayload.Add(string, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.Diagnostics.Tracing.EventPayload.Add(string, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.Diagnostics.Tracing.EventPayload.CopyTo(KeyValuePair[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Diagnostics.Tracing.EventPayload.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Diagnostics.Tracing.EventPayload.get_Item(string) | this parameter [element, property Value] -> return | true | -| System.Diagnostics.Tracing.EventPayload.get_Keys() | this parameter [element, property Key] -> return [element] | true | -| System.Diagnostics.Tracing.EventPayload.get_Values() | this parameter [element, property Value] -> return [element] | true | -| System.Diagnostics.Tracing.EventPayload.set_Item(string, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.Diagnostics.Tracing.EventPayload.set_Item(string, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.Diagnostics.Tracing.IncrementingCounterPayload.d__39.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Diagnostics.Tracing.IncrementingCounterPayload.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Dynamic.ExpandoObject.Add(KeyValuePair) | parameter 0 -> this parameter [element] | true | -| System.Dynamic.ExpandoObject.Add(KeyValuePair) | parameter 0 [property Key] -> this parameter [element, property Key] | true | -| System.Dynamic.ExpandoObject.Add(KeyValuePair) | parameter 0 [property Value] -> this parameter [element, property Value] | true | -| System.Dynamic.ExpandoObject.Add(string, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.Dynamic.ExpandoObject.Add(string, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.Dynamic.ExpandoObject.CopyTo(KeyValuePair[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Dynamic.ExpandoObject.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Dynamic.ExpandoObject.KeyCollection.Add(string) | parameter 0 -> this parameter [element] | true | -| System.Dynamic.ExpandoObject.KeyCollection.CopyTo(String[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Dynamic.ExpandoObject.KeyCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Dynamic.ExpandoObject.MetaExpando.d__6.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Dynamic.ExpandoObject.ValueCollection.Add(object) | parameter 0 -> this parameter [element] | true | -| System.Dynamic.ExpandoObject.ValueCollection.CopyTo(Object[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Dynamic.ExpandoObject.ValueCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Dynamic.ExpandoObject.get_Item(string) | this parameter [element, property Value] -> return | true | -| System.Dynamic.ExpandoObject.get_Keys() | this parameter [element, property Key] -> return [element] | true | -| System.Dynamic.ExpandoObject.get_Values() | this parameter [element, property Value] -> return [element] | true | -| System.Dynamic.ExpandoObject.set_Item(string, object) | parameter 0 -> this parameter [element, property Key] | true | -| System.Dynamic.ExpandoObject.set_Item(string, object) | parameter 1 -> this parameter [element, property Value] | true | -| System.Dynamic.Utils.ListProvider<>.Add(T) | parameter 0 -> this parameter [element] | true | -| System.Dynamic.Utils.ListProvider<>.CopyTo(T[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Dynamic.Utils.ListProvider<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Dynamic.Utils.ListProvider<>.Insert(int, T) | parameter 1 -> this parameter [element] | true | -| System.Dynamic.Utils.ListProvider<>.get_Item(int) | this parameter [element] -> return | true | -| System.Dynamic.Utils.ListProvider<>.set_Item(int, T) | parameter 1 -> this parameter [element] | true | -| System.IO.BufferedStream.BeginRead(Byte[], int, int, AsyncCallback, object) | this parameter -> parameter 0 | false | -| System.IO.BufferedStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | parameter 0 -> this parameter | false | -| System.IO.BufferedStream.CopyTo(Stream, int) | this parameter -> parameter 0 | false | -| System.IO.BufferedStream.CopyToAsync(Stream, int, CancellationToken) | this parameter -> parameter 0 | false | -| System.IO.BufferedStream.Read(Byte[], int, int) | this parameter -> parameter 0 | false | -| System.IO.BufferedStream.ReadAsync(Byte[], int, int, CancellationToken) | this parameter -> parameter 0 | false | -| System.IO.BufferedStream.Write(Byte[], int, int) | parameter 0 -> this parameter | false | -| System.IO.BufferedStream.WriteAsync(Byte[], int, int, CancellationToken) | parameter 0 -> this parameter | false | -| System.IO.Compression.CheckSumAndSizeWriteStream.Read(Byte[], int, int) | this parameter -> parameter 0 | false | -| System.IO.Compression.CheckSumAndSizeWriteStream.Write(Byte[], int, int) | parameter 0 -> this parameter | false | -| System.IO.Compression.DeflateManagedStream.BeginRead(Byte[], int, int, AsyncCallback, object) | this parameter -> parameter 0 | false | -| System.IO.Compression.DeflateManagedStream.Read(Byte[], int, int) | this parameter -> parameter 0 | false | -| System.IO.Compression.DeflateManagedStream.ReadAsync(Byte[], int, int, CancellationToken) | this parameter -> parameter 0 | false | -| System.IO.Compression.DeflateManagedStream.Write(Byte[], int, int) | parameter 0 -> this parameter | false | -| System.IO.Compression.DeflateStream.BeginRead(Byte[], int, int, AsyncCallback, object) | this parameter -> parameter 0 | false | -| System.IO.Compression.DeflateStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | parameter 0 -> this parameter | false | -| System.IO.Compression.DeflateStream.CopyTo(Stream, int) | this parameter -> parameter 0 | false | -| System.IO.Compression.DeflateStream.CopyToAsync(Stream, int, CancellationToken) | this parameter -> parameter 0 | false | -| System.IO.Compression.DeflateStream.CopyToStream.Read(Byte[], int, int) | this parameter -> parameter 0 | false | -| System.IO.Compression.DeflateStream.CopyToStream.Write(Byte[], int, int) | parameter 0 -> this parameter | false | -| System.IO.Compression.DeflateStream.CopyToStream.WriteAsync(Byte[], int, int, CancellationToken) | parameter 0 -> this parameter | false | -| System.IO.Compression.DeflateStream.DeflateStream(Stream, CompressionLevel) | parameter 0 -> return | false | -| System.IO.Compression.DeflateStream.DeflateStream(Stream, CompressionLevel, bool) | parameter 0 -> return | false | -| System.IO.Compression.DeflateStream.DeflateStream(Stream, CompressionMode) | parameter 0 -> return | false | -| System.IO.Compression.DeflateStream.DeflateStream(Stream, CompressionMode, bool) | parameter 0 -> return | false | -| System.IO.Compression.DeflateStream.Read(Byte[], int, int) | this parameter -> parameter 0 | false | -| System.IO.Compression.DeflateStream.ReadAsync(Byte[], int, int, CancellationToken) | this parameter -> parameter 0 | false | -| System.IO.Compression.DeflateStream.Write(Byte[], int, int) | parameter 0 -> this parameter | false | -| System.IO.Compression.DeflateStream.WriteAsync(Byte[], int, int, CancellationToken) | parameter 0 -> this parameter | false | -| System.IO.Compression.GZipStream.BeginRead(Byte[], int, int, AsyncCallback, object) | this parameter -> parameter 0 | false | -| System.IO.Compression.GZipStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | parameter 0 -> this parameter | false | -| System.IO.Compression.GZipStream.CopyTo(Stream, int) | this parameter -> parameter 0 | false | -| System.IO.Compression.GZipStream.CopyToAsync(Stream, int, CancellationToken) | this parameter -> parameter 0 | false | -| System.IO.Compression.GZipStream.Read(Byte[], int, int) | this parameter -> parameter 0 | false | -| System.IO.Compression.GZipStream.ReadAsync(Byte[], int, int, CancellationToken) | this parameter -> parameter 0 | false | -| System.IO.Compression.GZipStream.Write(Byte[], int, int) | parameter 0 -> this parameter | false | -| System.IO.Compression.GZipStream.WriteAsync(Byte[], int, int, CancellationToken) | parameter 0 -> this parameter | false | -| System.IO.Compression.PositionPreservingWriteOnlyStreamWrapper.BeginWrite(Byte[], int, int, AsyncCallback, object) | parameter 0 -> this parameter | false | -| System.IO.Compression.PositionPreservingWriteOnlyStreamWrapper.Read(Byte[], int, int) | this parameter -> parameter 0 | false | -| System.IO.Compression.PositionPreservingWriteOnlyStreamWrapper.Write(Byte[], int, int) | parameter 0 -> this parameter | false | -| System.IO.Compression.PositionPreservingWriteOnlyStreamWrapper.WriteAsync(Byte[], int, int, CancellationToken) | parameter 0 -> this parameter | false | -| System.IO.Compression.SubReadStream.Read(Byte[], int, int) | this parameter -> parameter 0 | false | -| System.IO.Compression.SubReadStream.Write(Byte[], int, int) | parameter 0 -> this parameter | false | -| System.IO.Compression.WrappedStream.Read(Byte[], int, int) | this parameter -> parameter 0 | false | -| System.IO.Compression.WrappedStream.Write(Byte[], int, int) | parameter 0 -> this parameter | false | -| System.IO.Compression.ZipArchiveEntry.DirectToArchiveWriterStream.Read(Byte[], int, int) | this parameter -> parameter 0 | false | -| System.IO.Compression.ZipArchiveEntry.DirectToArchiveWriterStream.Write(Byte[], int, int) | parameter 0 -> this parameter | false | -| System.IO.FileStream.BeginRead(Byte[], int, int, AsyncCallback, object) | this parameter -> parameter 0 | false | -| System.IO.FileStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | parameter 0 -> this parameter | false | -| System.IO.FileStream.CopyToAsync(Stream, int, CancellationToken) | this parameter -> parameter 0 | false | -| System.IO.FileStream.Read(Byte[], int, int) | this parameter -> parameter 0 | false | -| System.IO.FileStream.ReadAsync(Byte[], int, int, CancellationToken) | this parameter -> parameter 0 | false | -| System.IO.FileStream.Write(Byte[], int, int) | parameter 0 -> this parameter | false | -| System.IO.FileStream.WriteAsync(Byte[], int, int, CancellationToken) | parameter 0 -> this parameter | false | -| System.IO.MemoryStream.CopyTo(Stream, int) | this parameter -> parameter 0 | false | -| System.IO.MemoryStream.CopyToAsync(Stream, int, CancellationToken) | this parameter -> parameter 0 | false | -| System.IO.MemoryStream.MemoryStream(Byte[]) | parameter 0 -> return | false | -| System.IO.MemoryStream.MemoryStream(Byte[], bool) | parameter 0 -> return | false | -| System.IO.MemoryStream.MemoryStream(Byte[], int, int) | parameter 0 -> return | false | -| System.IO.MemoryStream.MemoryStream(Byte[], int, int, bool) | parameter 0 -> return | false | -| System.IO.MemoryStream.MemoryStream(Byte[], int, int, bool, bool) | parameter 0 -> return | false | -| System.IO.MemoryStream.Read(Byte[], int, int) | this parameter -> parameter 0 | false | -| System.IO.MemoryStream.ReadAsync(Byte[], int, int, CancellationToken) | this parameter -> parameter 0 | false | -| System.IO.MemoryStream.ToArray() | this parameter -> return | false | -| System.IO.MemoryStream.Write(Byte[], int, int) | parameter 0 -> this parameter | false | -| System.IO.MemoryStream.WriteAsync(Byte[], int, int, CancellationToken) | parameter 0 -> this parameter | false | -| System.IO.Path.Combine(params String[]) | parameter 0 [element] -> return | false | -| System.IO.Path.Combine(string, string) | parameter 0 -> return | false | -| System.IO.Path.Combine(string, string) | parameter 1 -> return | false | -| System.IO.Path.Combine(string, string, string) | parameter 0 -> return | false | -| System.IO.Path.Combine(string, string, string) | parameter 1 -> return | false | -| System.IO.Path.Combine(string, string, string) | parameter 2 -> return | false | -| System.IO.Path.Combine(string, string, string, string) | parameter 0 -> return | false | -| System.IO.Path.Combine(string, string, string, string) | parameter 1 -> return | false | -| System.IO.Path.Combine(string, string, string, string) | parameter 2 -> return | false | -| System.IO.Path.Combine(string, string, string, string) | parameter 3 -> return | false | -| System.IO.Path.GetDirectoryName(ReadOnlySpan) | parameter 0 -> return | false | -| System.IO.Path.GetDirectoryName(string) | parameter 0 -> return | false | -| System.IO.Path.GetExtension(ReadOnlySpan) | parameter 0 -> return | false | -| System.IO.Path.GetExtension(string) | parameter 0 -> return | false | -| System.IO.Path.GetFileName(ReadOnlySpan) | parameter 0 -> return | false | -| System.IO.Path.GetFileName(string) | parameter 0 -> return | false | -| System.IO.Path.GetFileNameWithoutExtension(ReadOnlySpan) | parameter 0 -> return | false | -| System.IO.Path.GetFileNameWithoutExtension(string) | parameter 0 -> return | false | -| System.IO.Path.GetFullPath(string) | parameter 0 -> return | false | -| System.IO.Path.GetFullPath(string, string) | parameter 0 -> return | false | -| System.IO.Path.GetPathRoot(ReadOnlySpan) | parameter 0 -> return | false | -| System.IO.Path.GetPathRoot(string) | parameter 0 -> return | false | -| System.IO.Path.GetRelativePath(string, string) | parameter 1 -> return | false | -| System.IO.Pipes.PipeStream.BeginRead(Byte[], int, int, AsyncCallback, object) | this parameter -> parameter 0 | false | -| System.IO.Pipes.PipeStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | parameter 0 -> this parameter | false | -| System.IO.Pipes.PipeStream.Read(Byte[], int, int) | this parameter -> parameter 0 | false | -| System.IO.Pipes.PipeStream.ReadAsync(Byte[], int, int, CancellationToken) | this parameter -> parameter 0 | false | -| System.IO.Pipes.PipeStream.Write(Byte[], int, int) | parameter 0 -> this parameter | false | -| System.IO.Pipes.PipeStream.WriteAsync(Byte[], int, int, CancellationToken) | parameter 0 -> this parameter | false | -| System.IO.Stream.BeginRead(Byte[], int, int, AsyncCallback, object) | this parameter -> parameter 0 | false | -| System.IO.Stream.BeginWrite(Byte[], int, int, AsyncCallback, object) | parameter 0 -> this parameter | false | -| System.IO.Stream.CopyTo(Stream) | this parameter -> parameter 0 | false | -| System.IO.Stream.CopyTo(Stream, int) | this parameter -> parameter 0 | false | -| System.IO.Stream.CopyToAsync(Stream) | this parameter -> parameter 0 | false | -| System.IO.Stream.CopyToAsync(Stream, CancellationToken) | this parameter -> parameter 0 | false | -| System.IO.Stream.CopyToAsync(Stream, int) | this parameter -> parameter 0 | false | -| System.IO.Stream.CopyToAsync(Stream, int, CancellationToken) | this parameter -> parameter 0 | false | -| System.IO.Stream.NullStream.BeginRead(Byte[], int, int, AsyncCallback, object) | this parameter -> parameter 0 | false | -| System.IO.Stream.NullStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | parameter 0 -> this parameter | false | -| System.IO.Stream.NullStream.CopyTo(Stream, int) | this parameter -> parameter 0 | false | -| System.IO.Stream.NullStream.CopyToAsync(Stream, int, CancellationToken) | this parameter -> parameter 0 | false | -| System.IO.Stream.NullStream.Read(Byte[], int, int) | this parameter -> parameter 0 | false | -| System.IO.Stream.NullStream.ReadAsync(Byte[], int, int, CancellationToken) | this parameter -> parameter 0 | false | -| System.IO.Stream.NullStream.Write(Byte[], int, int) | parameter 0 -> this parameter | false | -| System.IO.Stream.NullStream.WriteAsync(Byte[], int, int, CancellationToken) | parameter 0 -> this parameter | false | -| System.IO.Stream.Read(Byte[], int, int) | this parameter -> parameter 0 | false | -| System.IO.Stream.ReadAsync(Byte[], int, int) | this parameter -> parameter 0 | false | -| System.IO.Stream.ReadAsync(Byte[], int, int, CancellationToken) | this parameter -> parameter 0 | false | -| System.IO.Stream.SyncStream.BeginRead(Byte[], int, int, AsyncCallback, object) | this parameter -> parameter 0 | false | -| System.IO.Stream.SyncStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | parameter 0 -> this parameter | false | -| System.IO.Stream.SyncStream.Read(Byte[], int, int) | this parameter -> parameter 0 | false | -| System.IO.Stream.SyncStream.Write(Byte[], int, int) | parameter 0 -> this parameter | false | -| System.IO.Stream.Write(Byte[], int, int) | parameter 0 -> this parameter | false | -| System.IO.Stream.WriteAsync(Byte[], int, int) | parameter 0 -> this parameter | false | -| System.IO.Stream.WriteAsync(Byte[], int, int, CancellationToken) | parameter 0 -> this parameter | false | -| System.IO.StringReader.Read() | this parameter -> return | false | -| System.IO.StringReader.Read(Char[], int, int) | this parameter -> return | false | -| System.IO.StringReader.Read(Span) | this parameter -> return | false | -| System.IO.StringReader.ReadAsync(Char[], int, int) | this parameter -> return | false | -| System.IO.StringReader.ReadAsync(Memory, CancellationToken) | this parameter -> return | false | -| System.IO.StringReader.ReadBlock(Span) | this parameter -> return | false | -| System.IO.StringReader.ReadBlockAsync(Char[], int, int) | this parameter -> return | false | -| System.IO.StringReader.ReadBlockAsync(Memory, CancellationToken) | this parameter -> return | false | -| System.IO.StringReader.ReadLine() | this parameter -> return | false | -| System.IO.StringReader.ReadLineAsync() | this parameter -> return | false | -| System.IO.StringReader.ReadToEnd() | this parameter -> return | false | -| System.IO.StringReader.ReadToEndAsync() | this parameter -> return | false | -| System.IO.StringReader.StringReader(string) | parameter 0 -> return | false | -| System.IO.TextReader.Read() | this parameter -> return | false | -| System.IO.TextReader.Read(Char[], int, int) | this parameter -> return | false | -| System.IO.TextReader.Read(Span) | this parameter -> return | false | -| System.IO.TextReader.ReadAsync(Char[], int, int) | this parameter -> return | false | -| System.IO.TextReader.ReadAsync(Memory, CancellationToken) | this parameter -> return | false | -| System.IO.TextReader.ReadAsyncInternal(Memory, CancellationToken) | this parameter -> return | false | -| System.IO.TextReader.ReadBlock(Char[], int, int) | this parameter -> return | false | -| System.IO.TextReader.ReadBlock(Span) | this parameter -> return | false | -| System.IO.TextReader.ReadBlockAsync(Char[], int, int) | this parameter -> return | false | -| System.IO.TextReader.ReadBlockAsync(Memory, CancellationToken) | this parameter -> return | false | -| System.IO.TextReader.ReadLine() | this parameter -> return | false | -| System.IO.TextReader.ReadLineAsync() | this parameter -> return | false | -| System.IO.TextReader.ReadToEnd() | this parameter -> return | false | -| System.IO.TextReader.ReadToEndAsync() | this parameter -> return | false | -| System.IO.UnmanagedMemoryStream.Read(Byte[], int, int) | this parameter -> parameter 0 | false | -| System.IO.UnmanagedMemoryStream.ReadAsync(Byte[], int, int, CancellationToken) | this parameter -> parameter 0 | false | -| System.IO.UnmanagedMemoryStream.Write(Byte[], int, int) | parameter 0 -> this parameter | false | -| System.IO.UnmanagedMemoryStream.WriteAsync(Byte[], int, int, CancellationToken) | parameter 0 -> this parameter | false | -| System.IO.UnmanagedMemoryStreamWrapper.CopyToAsync(Stream, int, CancellationToken) | this parameter -> parameter 0 | false | -| System.IO.UnmanagedMemoryStreamWrapper.Read(Byte[], int, int) | this parameter -> parameter 0 | false | -| System.IO.UnmanagedMemoryStreamWrapper.ReadAsync(Byte[], int, int, CancellationToken) | this parameter -> parameter 0 | false | -| System.IO.UnmanagedMemoryStreamWrapper.ToArray() | this parameter -> return | false | -| System.IO.UnmanagedMemoryStreamWrapper.Write(Byte[], int, int) | parameter 0 -> this parameter | false | -| System.IO.UnmanagedMemoryStreamWrapper.WriteAsync(Byte[], int, int, CancellationToken) | parameter 0 -> this parameter | false | -| System.Int32.Parse(string) | parameter 0 -> return | false | -| System.Int32.Parse(string, IFormatProvider) | parameter 0 -> return | false | -| System.Int32.Parse(string, NumberStyles) | parameter 0 -> return | false | -| System.Int32.Parse(string, NumberStyles, IFormatProvider) | parameter 0 -> return | false | -| System.Int32.TryParse(string, NumberStyles, IFormatProvider, out int) | parameter 0 -> parameter 3 | false | -| System.Int32.TryParse(string, NumberStyles, IFormatProvider, out int) | parameter 0 -> return | false | -| System.Int32.TryParse(string, out int) | parameter 0 -> parameter 1 | false | -| System.Int32.TryParse(string, out int) | parameter 0 -> return | false | -| System.Lazy<>.Lazy(Func) | deleget output from parameter 0 -> return [property Value] | true | -| System.Lazy<>.Lazy(Func, LazyThreadSafetyMode) | deleget output from parameter 0 -> return [property Value] | true | -| System.Lazy<>.Lazy(Func, bool) | deleget output from parameter 0 -> return [property Value] | true | -| System.Lazy<>.get_Value() | this parameter -> return | false | -| System.Linq.EmptyPartition<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Enumerable.d__64<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Enumerable.d__81<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Enumerable.d__98<,,,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Enumerable.d__101<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Enumerable.d__105<,,,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Enumerable.d__62<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Enumerable.d__174<,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Enumerable.d__177<,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Enumerable.d__179<,,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Enumerable.d__181<,,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Enumerable.d__194<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Enumerable.d__190<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Enumerable.d__192<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Enumerable.d__221<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Enumerable.d__217<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Enumerable.d__219<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Enumerable.d__240<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Enumerable.d__243<,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Enumerable.d__244<,,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func, Func) | deleget output from parameter 2 -> parameter 0 of delegate parameter 3 | true | -| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func, Func) | deleget output from parameter 3 -> return | true | -| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func, Func) | parameter 0 [element] -> parameter 1 of delegate parameter 2 | true | -| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func, Func) | parameter 1 -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func) | deleget output from parameter 2 -> return | true | -| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func) | parameter 0 [element] -> parameter 1 of delegate parameter 2 | true | -| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func) | parameter 1 -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.Aggregate(IEnumerable, Func) | deleget output from parameter 1 -> return | true | -| System.Linq.Enumerable.Aggregate(IEnumerable, Func) | parameter 0 [element] -> parameter 1 of delegate parameter 1 | true | -| System.Linq.Enumerable.All(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Any(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.AsEnumerable(IEnumerable) | parameter 0 [element] -> return [element] | true | -| System.Linq.Enumerable.Average(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Average(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Average(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Average(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Average(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Average(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Average(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Average(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Average(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Average(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Cast(IEnumerable) | parameter 0 [element] -> return [element] | true | -| System.Linq.Enumerable.Concat(IEnumerable, IEnumerable) | parameter 0 [element] -> return [element] | true | -| System.Linq.Enumerable.Concat(IEnumerable, IEnumerable) | parameter 1 [element] -> return [element] | true | -| System.Linq.Enumerable.Count(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.DefaultIfEmpty(IEnumerable) | parameter 0 [element] -> return | true | -| System.Linq.Enumerable.DefaultIfEmpty(IEnumerable, TSource) | parameter 0 [element] -> return | true | -| System.Linq.Enumerable.DefaultIfEmpty(IEnumerable, TSource) | parameter 1 -> return | true | -| System.Linq.Enumerable.Distinct(IEnumerable) | parameter 0 [element] -> return [element] | true | -| System.Linq.Enumerable.Distinct(IEnumerable, IEqualityComparer) | parameter 0 [element] -> return [element] | true | -| System.Linq.Enumerable.ElementAt(IEnumerable, int) | parameter 0 [element] -> return | true | -| System.Linq.Enumerable.ElementAtOrDefault(IEnumerable, int) | parameter 0 [element] -> return | true | -| System.Linq.Enumerable.Except(IEnumerable, IEnumerable) | parameter 0 [element] -> return | true | -| System.Linq.Enumerable.Except(IEnumerable, IEnumerable, IEqualityComparer) | parameter 0 [element] -> return | true | -| System.Linq.Enumerable.First(IEnumerable) | parameter 0 [element] -> return | true | -| System.Linq.Enumerable.First(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.First(IEnumerable, Func) | parameter 0 [element] -> return | true | -| System.Linq.Enumerable.FirstOrDefault(IEnumerable) | parameter 0 [element] -> return | true | -| System.Linq.Enumerable.FirstOrDefault(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.FirstOrDefault(IEnumerable, Func) | parameter 0 [element] -> return | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | deleget output from parameter 1 -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | deleget output from parameter 2 -> parameter 1 of delegate parameter 3 [element] | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | deleget output from parameter 3 -> return [element] | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | deleget output from parameter 1 -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | deleget output from parameter 2 -> parameter 1 of delegate parameter 3 [element] | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | deleget output from parameter 3 -> return [element] | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func) | deleget output from parameter 2 -> return [element] | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, IEqualityComparer) | deleget output from parameter 1 -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>) | deleget output from parameter 1 -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>) | deleget output from parameter 2 -> return [element] | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>) | parameter 0 -> parameter 1 of delegate parameter 2 | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>, IEqualityComparer) | deleget output from parameter 1 -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.GroupBy(IEnumerable, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | deleget output from parameter 4 -> return [element] | true | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | parameter 0 [element] -> parameter 0 of delegate parameter 4 | true | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | parameter 1 [element] -> parameter 0 of delegate parameter 3 | true | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | parameter 1 [element] -> parameter 1 of delegate parameter 4 | true | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | deleget output from parameter 4 -> return [element] | true | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 4 | true | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | parameter 1 [element] -> parameter 0 of delegate parameter 3 | true | -| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | parameter 1 [element] -> parameter 1 of delegate parameter 4 | true | -| System.Linq.Enumerable.Intersect(IEnumerable, IEnumerable) | parameter 0 [element] -> return [element] | true | -| System.Linq.Enumerable.Intersect(IEnumerable, IEnumerable) | parameter 1 [element] -> return [element] | true | -| System.Linq.Enumerable.Intersect(IEnumerable, IEnumerable, IEqualityComparer) | parameter 0 [element] -> return [element] | true | -| System.Linq.Enumerable.Intersect(IEnumerable, IEnumerable, IEqualityComparer) | parameter 1 [element] -> return [element] | true | -| System.Linq.Enumerable.Iterator<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | deleget output from parameter 4 -> return [element] | true | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 4 | true | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | parameter 1 [element] -> parameter 0 of delegate parameter 3 | true | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | parameter 1 [element] -> parameter 1 of delegate parameter 4 | true | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | deleget output from parameter 4 -> return [element] | true | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 4 | true | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | parameter 1 [element] -> parameter 0 of delegate parameter 3 | true | -| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | parameter 1 [element] -> parameter 1 of delegate parameter 4 | true | -| System.Linq.Enumerable.Last(IEnumerable) | parameter 0 [element] -> return | true | -| System.Linq.Enumerable.Last(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Last(IEnumerable, Func) | parameter 0 [element] -> return | true | -| System.Linq.Enumerable.LastOrDefault(IEnumerable) | parameter 0 [element] -> return | true | -| System.Linq.Enumerable.LastOrDefault(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.LastOrDefault(IEnumerable, Func) | parameter 0 [element] -> return | true | -| System.Linq.Enumerable.LongCount(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Max(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Max(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Max(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Max(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Max(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Max(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Max(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Max(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Max(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Max(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Max(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Min(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Min(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Min(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Min(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Min(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Min(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Min(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Min(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Min(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Min(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Min(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.OfType(IEnumerable) | parameter 0 [element] -> return [element] | true | -| System.Linq.Enumerable.OrderBy(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.OrderBy(IEnumerable, Func) | parameter 0 [element] -> return [element] | true | -| System.Linq.Enumerable.OrderBy(IEnumerable, Func, IComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.OrderBy(IEnumerable, Func, IComparer) | parameter 0 [element] -> return [element] | true | -| System.Linq.Enumerable.OrderByDescending(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.OrderByDescending(IEnumerable, Func) | parameter 0 [element] -> return [element] | true | -| System.Linq.Enumerable.OrderByDescending(IEnumerable, Func, IComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.OrderByDescending(IEnumerable, Func, IComparer) | parameter 0 [element] -> return [element] | true | -| System.Linq.Enumerable.Reverse(IEnumerable) | parameter 0 [element] -> return [element] | true | -| System.Linq.Enumerable.Select(IEnumerable, Func) | deleget output from parameter 1 -> return [element] | true | -| System.Linq.Enumerable.Select(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Select(IEnumerable, Func) | deleget output from parameter 1 -> return [element] | true | -| System.Linq.Enumerable.Select(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | deleget output from parameter 1 [element] -> parameter 1 of delegate parameter 2 | true | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | deleget output from parameter 2 -> return [element] | true | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | deleget output from parameter 1 [element] -> parameter 1 of delegate parameter 2 | true | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | deleget output from parameter 2 -> return [element] | true | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>) | deleget output from parameter 1 -> return [element] | true | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>) | deleget output from parameter 1 -> return [element] | true | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Single(IEnumerable) | parameter 0 [element] -> return | true | -| System.Linq.Enumerable.Single(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Single(IEnumerable, Func) | parameter 0 [element] -> return | true | -| System.Linq.Enumerable.SingleOrDefault(IEnumerable) | parameter 0 [element] -> return | true | -| System.Linq.Enumerable.SingleOrDefault(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.SingleOrDefault(IEnumerable, Func) | parameter 0 [element] -> return | true | -| System.Linq.Enumerable.Skip(IEnumerable, int) | parameter 0 [element] -> return [element] | true | -| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | parameter 0 [element] -> return [element] | true | -| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | parameter 0 [element] -> return [element] | true | -| System.Linq.Enumerable.Sum(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Sum(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Sum(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Sum(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Sum(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Sum(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Sum(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Sum(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Sum(IEnumerable, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Sum(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Take(IEnumerable, int) | parameter 0 [element] -> return [element] | true | -| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | parameter 0 [element] -> return [element] | true | -| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | parameter 0 [element] -> return [element] | true | -| System.Linq.Enumerable.ThenBy(IOrderedEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.ThenBy(IOrderedEnumerable, Func) | parameter 0 [element] -> return [element] | true | -| System.Linq.Enumerable.ThenBy(IOrderedEnumerable, Func, IComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.ThenBy(IOrderedEnumerable, Func, IComparer) | parameter 0 [element] -> return [element] | true | -| System.Linq.Enumerable.ThenByDescending(IOrderedEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.ThenByDescending(IOrderedEnumerable, Func) | parameter 0 [element] -> return [element] | true | -| System.Linq.Enumerable.ThenByDescending(IOrderedEnumerable, Func, IComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.ThenByDescending(IOrderedEnumerable, Func, IComparer) | parameter 0 [element] -> return [element] | true | -| System.Linq.Enumerable.ToArray(IEnumerable) | parameter 0 [element] -> return [element] | true | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func) | deleget output from parameter 2 -> return [element] | true | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func, IEqualityComparer) | deleget output from parameter 2 -> return [element] | true | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func) | parameter 0 [element] -> return [element] | true | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, IEqualityComparer) | parameter 0 [element] -> return [element] | true | -| System.Linq.Enumerable.ToList(IEnumerable) | parameter 0 [element] -> return [element] | true | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func) | deleget output from parameter 2 -> return [element] | true | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func, IEqualityComparer) | deleget output from parameter 2 -> return [element] | true | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func) | parameter 0 [element] -> return [element] | true | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.ToLookup(IEnumerable, Func, IEqualityComparer) | parameter 0 [element] -> return [element] | true | -| System.Linq.Enumerable.Union(IEnumerable, IEnumerable) | parameter 0 [element] -> return [element] | true | -| System.Linq.Enumerable.Union(IEnumerable, IEnumerable) | parameter 1 [element] -> return [element] | true | -| System.Linq.Enumerable.Union(IEnumerable, IEnumerable, IEqualityComparer) | parameter 0 [element] -> return [element] | true | -| System.Linq.Enumerable.Union(IEnumerable, IEnumerable, IEqualityComparer) | parameter 1 [element] -> return [element] | true | -| System.Linq.Enumerable.Where(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Where(IEnumerable, Func) | parameter 0 [element] -> return [element] | true | -| System.Linq.Enumerable.Where(IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Enumerable.Where(IEnumerable, Func) | parameter 0 [element] -> return [element] | true | -| System.Linq.Enumerable.Zip(IEnumerable, IEnumerable, Func) | deleget output from parameter 2 -> return [element] | true | -| System.Linq.Enumerable.Zip(IEnumerable, IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Enumerable.Zip(IEnumerable, IEnumerable, Func) | parameter 1 [element] -> parameter 1 of delegate parameter 2 | true | -| System.Linq.EnumerableQuery<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Expressions.BlockExpressionList.Add(Expression) | parameter 0 -> this parameter [element] | true | -| System.Linq.Expressions.BlockExpressionList.CopyTo(Expression[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Linq.Expressions.BlockExpressionList.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Expressions.BlockExpressionList.Insert(int, Expression) | parameter 1 -> this parameter [element] | true | -| System.Linq.Expressions.BlockExpressionList.get_Item(int) | this parameter [element] -> return | true | -| System.Linq.Expressions.BlockExpressionList.set_Item(int, Expression) | parameter 1 -> this parameter [element] | true | -| System.Linq.Expressions.Compiler.CompilerScope.d__32.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Expressions.Compiler.ParameterList.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Expressions.Interpreter.InterpretedFrame.d__29.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.GroupedEnumerable<,,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.GroupedEnumerable<,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.GroupedResultEnumerable<,,,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.GroupedResultEnumerable<,,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Grouping<,>.Add(TElement) | parameter 0 -> this parameter [element] | true | -| System.Linq.Grouping<,>.CopyTo(TElement[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Linq.Grouping<,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Grouping<,>.Insert(int, TElement) | parameter 1 -> this parameter [element] | true | -| System.Linq.Grouping<,>.get_Item(int) | this parameter [element] -> return | true | -| System.Linq.Grouping<,>.set_Item(int, TElement) | parameter 1 -> this parameter [element] | true | -| System.Linq.Lookup<,>.d__19<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Lookup<,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.OrderedEnumerable<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.OrderedPartition<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Parallel.CancellableEnumerable.d__0<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Parallel.EnumerableWrapperWeakToStrong.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Parallel.ExceptionAggregator.d__0<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Parallel.ExceptionAggregator.d__1<,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Parallel.GroupByGrouping<,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Parallel.ListChunk<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Parallel.Lookup<,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Parallel.MergeExecutor<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Parallel.OrderedGroupByGrouping<,,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Parallel.ParallelEnumerableWrapper.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Parallel.PartitionerQueryOperator<>.d__5.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Parallel.QueryResults<>.Add(T) | parameter 0 -> this parameter [element] | true | -| System.Linq.Parallel.QueryResults<>.CopyTo(T[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Linq.Parallel.QueryResults<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Parallel.QueryResults<>.Insert(int, T) | parameter 1 -> this parameter [element] | true | -| System.Linq.Parallel.QueryResults<>.get_Item(int) | this parameter [element] -> return | true | -| System.Linq.Parallel.QueryResults<>.set_Item(int, T) | parameter 1 -> this parameter [element] | true | -| System.Linq.Parallel.RangeEnumerable.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Parallel.ZipQueryOperator<,,>.d__9.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func, Func) | deleget output from parameter 2 -> parameter 0 of delegate parameter 3 | true | -| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func, Func) | deleget output from parameter 3 -> return | true | -| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func, Func) | parameter 0 [element] -> parameter 1 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func, Func) | parameter 1 -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func) | deleget output from parameter 2 -> return | true | -| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func) | parameter 0 [element] -> parameter 1 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func) | parameter 1 -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, Func) | deleget output from parameter 1 -> return | true | -| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, Func) | parameter 0 [element] -> parameter 1 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.All(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Any(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.AsEnumerable(ParallelQuery) | parameter 0 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Cast(ParallelQuery) | parameter 0 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.Concat(ParallelQuery, IEnumerable) | parameter 0 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.Concat(ParallelQuery, IEnumerable) | parameter 1 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.Concat(ParallelQuery, ParallelQuery) | parameter 0 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.Concat(ParallelQuery, ParallelQuery) | parameter 1 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.Count(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.DefaultIfEmpty(ParallelQuery) | parameter 0 [element] -> return | true | -| System.Linq.ParallelEnumerable.DefaultIfEmpty(ParallelQuery, TSource) | parameter 0 [element] -> return | true | -| System.Linq.ParallelEnumerable.DefaultIfEmpty(ParallelQuery, TSource) | parameter 1 -> return | true | -| System.Linq.ParallelEnumerable.Distinct(ParallelQuery) | parameter 0 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.Distinct(ParallelQuery, IEqualityComparer) | parameter 0 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.ElementAt(ParallelQuery, int) | parameter 0 [element] -> return | true | -| System.Linq.ParallelEnumerable.ElementAtOrDefault(ParallelQuery, int) | parameter 0 [element] -> return | true | -| System.Linq.ParallelEnumerable.Except(ParallelQuery, IEnumerable) | parameter 0 [element] -> return | true | -| System.Linq.ParallelEnumerable.Except(ParallelQuery, IEnumerable, IEqualityComparer) | parameter 0 [element] -> return | true | -| System.Linq.ParallelEnumerable.Except(ParallelQuery, ParallelQuery) | parameter 0 [element] -> return | true | -| System.Linq.ParallelEnumerable.Except(ParallelQuery, ParallelQuery, IEqualityComparer) | parameter 0 [element] -> return | true | -| System.Linq.ParallelEnumerable.First(ParallelQuery) | parameter 0 [element] -> return | true | -| System.Linq.ParallelEnumerable.First(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.First(ParallelQuery, Func) | parameter 0 [element] -> return | true | -| System.Linq.ParallelEnumerable.FirstOrDefault(ParallelQuery) | parameter 0 [element] -> return | true | -| System.Linq.ParallelEnumerable.FirstOrDefault(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.FirstOrDefault(ParallelQuery, Func) | parameter 0 [element] -> return | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | deleget output from parameter 1 -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | deleget output from parameter 2 -> parameter 1 of delegate parameter 3 [element] | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | deleget output from parameter 3 -> return [element] | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | deleget output from parameter 1 -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | deleget output from parameter 2 -> parameter 1 of delegate parameter 3 [element] | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | deleget output from parameter 3 -> return [element] | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func) | deleget output from parameter 2 -> return [element] | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, IEqualityComparer) | deleget output from parameter 1 -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>) | deleget output from parameter 1 -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>) | deleget output from parameter 2 -> return [element] | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>) | parameter 0 -> parameter 1 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>, IEqualityComparer) | deleget output from parameter 1 -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | deleget output from parameter 4 -> return [element] | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | parameter 0 [element] -> parameter 0 of delegate parameter 4 | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | parameter 1 [element] -> parameter 0 of delegate parameter 3 | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | parameter 1 [element] -> parameter 1 of delegate parameter 4 | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | deleget output from parameter 4 -> return [element] | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 4 | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | parameter 1 [element] -> parameter 0 of delegate parameter 3 | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | parameter 1 [element] -> parameter 1 of delegate parameter 4 | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | deleget output from parameter 4 -> return [element] | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | parameter 0 [element] -> parameter 0 of delegate parameter 4 | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | parameter 1 [element] -> parameter 0 of delegate parameter 3 | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | parameter 1 [element] -> parameter 1 of delegate parameter 4 | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | deleget output from parameter 4 -> return [element] | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 4 | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | parameter 1 [element] -> parameter 0 of delegate parameter 3 | true | -| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | parameter 1 [element] -> parameter 1 of delegate parameter 4 | true | -| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, IEnumerable) | parameter 0 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, IEnumerable) | parameter 1 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, IEnumerable, IEqualityComparer) | parameter 0 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, IEnumerable, IEqualityComparer) | parameter 1 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, ParallelQuery) | parameter 0 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, ParallelQuery) | parameter 1 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, ParallelQuery, IEqualityComparer) | parameter 0 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, ParallelQuery, IEqualityComparer) | parameter 1 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | deleget output from parameter 4 -> return [element] | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 4 | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | parameter 1 [element] -> parameter 0 of delegate parameter 3 | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | parameter 1 [element] -> parameter 1 of delegate parameter 4 | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | deleget output from parameter 4 -> return [element] | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 4 | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | parameter 1 [element] -> parameter 0 of delegate parameter 3 | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | parameter 1 [element] -> parameter 1 of delegate parameter 4 | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | deleget output from parameter 4 -> return [element] | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 4 | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | parameter 1 [element] -> parameter 0 of delegate parameter 3 | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | parameter 1 [element] -> parameter 1 of delegate parameter 4 | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | deleget output from parameter 4 -> return [element] | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 4 | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | parameter 1 [element] -> parameter 0 of delegate parameter 3 | true | -| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | parameter 1 [element] -> parameter 1 of delegate parameter 4 | true | -| System.Linq.ParallelEnumerable.Last(ParallelQuery) | parameter 0 [element] -> return | true | -| System.Linq.ParallelEnumerable.Last(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Last(ParallelQuery, Func) | parameter 0 [element] -> return | true | -| System.Linq.ParallelEnumerable.LastOrDefault(ParallelQuery) | parameter 0 [element] -> return | true | -| System.Linq.ParallelEnumerable.LastOrDefault(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.LastOrDefault(ParallelQuery, Func) | parameter 0 [element] -> return | true | -| System.Linq.ParallelEnumerable.LongCount(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.OfType(ParallelQuery) | parameter 0 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.OrderBy(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.OrderBy(ParallelQuery, Func) | parameter 0 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.OrderBy(ParallelQuery, Func, IComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.OrderBy(ParallelQuery, Func, IComparer) | parameter 0 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.OrderByDescending(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.OrderByDescending(ParallelQuery, Func) | parameter 0 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.OrderByDescending(ParallelQuery, Func, IComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.OrderByDescending(ParallelQuery, Func, IComparer) | parameter 0 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.Reverse(ParallelQuery) | parameter 0 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.Select(ParallelQuery, Func) | deleget output from parameter 1 -> return [element] | true | -| System.Linq.ParallelEnumerable.Select(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Select(ParallelQuery, Func) | deleget output from parameter 1 -> return [element] | true | -| System.Linq.ParallelEnumerable.Select(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | deleget output from parameter 1 [element] -> parameter 1 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | deleget output from parameter 2 -> return [element] | true | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | deleget output from parameter 1 [element] -> parameter 1 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | deleget output from parameter 2 -> return [element] | true | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>) | deleget output from parameter 1 -> return [element] | true | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>) | deleget output from parameter 1 -> return [element] | true | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Single(ParallelQuery) | parameter 0 [element] -> return | true | -| System.Linq.ParallelEnumerable.Single(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Single(ParallelQuery, Func) | parameter 0 [element] -> return | true | -| System.Linq.ParallelEnumerable.SingleOrDefault(ParallelQuery) | parameter 0 [element] -> return | true | -| System.Linq.ParallelEnumerable.SingleOrDefault(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.SingleOrDefault(ParallelQuery, Func) | parameter 0 [element] -> return | true | -| System.Linq.ParallelEnumerable.Skip(ParallelQuery, int) | parameter 0 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | parameter 0 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | parameter 0 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Take(ParallelQuery, int) | parameter 0 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | parameter 0 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | parameter 0 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.ThenBy(OrderedParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.ThenBy(OrderedParallelQuery, Func) | parameter 0 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.ThenBy(OrderedParallelQuery, Func, IComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.ThenBy(OrderedParallelQuery, Func, IComparer) | parameter 0 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.ThenByDescending(OrderedParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.ThenByDescending(OrderedParallelQuery, Func) | parameter 0 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.ThenByDescending(OrderedParallelQuery, Func, IComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.ThenByDescending(OrderedParallelQuery, Func, IComparer) | parameter 0 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.ToArray(ParallelQuery) | parameter 0 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func) | deleget output from parameter 2 -> return [element] | true | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func, IEqualityComparer) | deleget output from parameter 2 -> return [element] | true | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func) | parameter 0 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, IEqualityComparer) | parameter 0 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.ToList(ParallelQuery) | parameter 0 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func) | deleget output from parameter 2 -> return [element] | true | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func, IEqualityComparer) | deleget output from parameter 2 -> return [element] | true | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func) | parameter 0 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, IEqualityComparer) | parameter 0 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.Union(ParallelQuery, IEnumerable) | parameter 0 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.Union(ParallelQuery, IEnumerable) | parameter 1 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.Union(ParallelQuery, IEnumerable, IEqualityComparer) | parameter 0 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.Union(ParallelQuery, IEnumerable, IEqualityComparer) | parameter 1 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.Union(ParallelQuery, ParallelQuery) | parameter 0 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.Union(ParallelQuery, ParallelQuery) | parameter 1 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.Union(ParallelQuery, ParallelQuery, IEqualityComparer) | parameter 0 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.Union(ParallelQuery, ParallelQuery, IEqualityComparer) | parameter 1 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | parameter 0 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | parameter 0 [element] -> return [element] | true | -| System.Linq.ParallelEnumerable.Zip(ParallelQuery, IEnumerable, Func) | deleget output from parameter 2 -> return [element] | true | -| System.Linq.ParallelEnumerable.Zip(ParallelQuery, IEnumerable, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.Zip(ParallelQuery, IEnumerable, Func) | parameter 1 [element] -> parameter 1 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.Zip(ParallelQuery, ParallelQuery, Func) | deleget output from parameter 2 -> return [element] | true | -| System.Linq.ParallelEnumerable.Zip(ParallelQuery, ParallelQuery, Func) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.ParallelEnumerable.Zip(ParallelQuery, ParallelQuery, Func) | parameter 1 [element] -> parameter 1 of delegate parameter 2 | true | -| System.Linq.ParallelQuery.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>, Expression>) | deleget output from parameter 2 -> parameter 0 of delegate parameter 3 | true | -| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>, Expression>) | deleget output from parameter 3 -> return | true | -| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>, Expression>) | parameter 0 [element] -> parameter 1 of delegate parameter 2 | true | -| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>, Expression>) | parameter 1 -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>) | deleget output from parameter 2 -> return | true | -| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>) | parameter 0 [element] -> parameter 1 of delegate parameter 2 | true | -| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>) | parameter 1 -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Queryable.Aggregate(IQueryable, Expression>) | deleget output from parameter 1 -> return | true | -| System.Linq.Queryable.Aggregate(IQueryable, Expression>) | parameter 0 [element] -> parameter 1 of delegate parameter 1 | true | -| System.Linq.Queryable.All(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Any(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.AsQueryable(IEnumerable) | parameter 0 [element] -> return [element] | true | -| System.Linq.Queryable.AsQueryable(IEnumerable) | parameter 0 [element] -> return [element] | true | -| System.Linq.Queryable.Average(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Average(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Average(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Average(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Average(IQueryable, Expression>>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Average(IQueryable, Expression>>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Average(IQueryable, Expression>>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Average(IQueryable, Expression>>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Average(IQueryable, Expression>>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Average(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Cast(IQueryable) | parameter 0 [element] -> return [element] | true | -| System.Linq.Queryable.Concat(IQueryable, IEnumerable) | parameter 0 [element] -> return [element] | true | -| System.Linq.Queryable.Concat(IQueryable, IEnumerable) | parameter 1 [element] -> return [element] | true | -| System.Linq.Queryable.Count(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.DefaultIfEmpty(IQueryable) | parameter 0 [element] -> return | true | -| System.Linq.Queryable.DefaultIfEmpty(IQueryable, TSource) | parameter 0 [element] -> return | true | -| System.Linq.Queryable.DefaultIfEmpty(IQueryable, TSource) | parameter 1 -> return | true | -| System.Linq.Queryable.Distinct(IQueryable) | parameter 0 [element] -> return [element] | true | -| System.Linq.Queryable.Distinct(IQueryable, IEqualityComparer) | parameter 0 [element] -> return [element] | true | -| System.Linq.Queryable.ElementAt(IQueryable, int) | parameter 0 [element] -> return | true | -| System.Linq.Queryable.ElementAtOrDefault(IQueryable, int) | parameter 0 [element] -> return | true | -| System.Linq.Queryable.Except(IQueryable, IEnumerable) | parameter 0 [element] -> return | true | -| System.Linq.Queryable.Except(IQueryable, IEnumerable, IEqualityComparer) | parameter 0 [element] -> return | true | -| System.Linq.Queryable.First(IQueryable) | parameter 0 [element] -> return | true | -| System.Linq.Queryable.First(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.First(IQueryable, Expression>) | parameter 0 [element] -> return | true | -| System.Linq.Queryable.FirstOrDefault(IQueryable) | parameter 0 [element] -> return | true | -| System.Linq.Queryable.FirstOrDefault(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.FirstOrDefault(IQueryable, Expression>) | parameter 0 [element] -> return | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | deleget output from parameter 1 -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | deleget output from parameter 2 -> parameter 1 of delegate parameter 3 [element] | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | deleget output from parameter 3 -> return [element] | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | deleget output from parameter 1 -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | deleget output from parameter 2 -> parameter 1 of delegate parameter 3 [element] | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | deleget output from parameter 3 -> return [element] | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>) | deleget output from parameter 2 -> return [element] | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, IEqualityComparer) | deleget output from parameter 1 -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>) | deleget output from parameter 2 -> return [element] | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>, IEqualityComparer) | deleget output from parameter 1 -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | deleget output from parameter 4 -> return [element] | true | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | parameter 0 [element] -> parameter 0 of delegate parameter 4 | true | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | parameter 1 [element] -> parameter 0 of delegate parameter 3 | true | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | parameter 1 [element] -> parameter 1 of delegate parameter 4 | true | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | deleget output from parameter 4 -> return [element] | true | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 4 | true | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | parameter 1 [element] -> parameter 0 of delegate parameter 3 | true | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | parameter 1 [element] -> parameter 1 of delegate parameter 4 | true | -| System.Linq.Queryable.Intersect(IQueryable, IEnumerable) | parameter 0 [element] -> return [element] | true | -| System.Linq.Queryable.Intersect(IQueryable, IEnumerable) | parameter 1 [element] -> return [element] | true | -| System.Linq.Queryable.Intersect(IQueryable, IEnumerable, IEqualityComparer) | parameter 0 [element] -> return [element] | true | -| System.Linq.Queryable.Intersect(IQueryable, IEnumerable, IEqualityComparer) | parameter 1 [element] -> return [element] | true | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | deleget output from parameter 4 -> return [element] | true | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 4 | true | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | parameter 1 [element] -> parameter 0 of delegate parameter 3 | true | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | parameter 1 [element] -> parameter 1 of delegate parameter 4 | true | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | deleget output from parameter 4 -> return [element] | true | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 4 | true | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | parameter 1 [element] -> parameter 0 of delegate parameter 3 | true | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | parameter 1 [element] -> parameter 1 of delegate parameter 4 | true | -| System.Linq.Queryable.Last(IQueryable) | parameter 0 [element] -> return | true | -| System.Linq.Queryable.Last(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Last(IQueryable, Expression>) | parameter 0 [element] -> return | true | -| System.Linq.Queryable.LastOrDefault(IQueryable) | parameter 0 [element] -> return | true | -| System.Linq.Queryable.LastOrDefault(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.LastOrDefault(IQueryable, Expression>) | parameter 0 [element] -> return | true | -| System.Linq.Queryable.LongCount(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Max(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Min(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.OfType(IQueryable) | parameter 0 [element] -> return [element] | true | -| System.Linq.Queryable.OrderBy(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.OrderBy(IQueryable, Expression>) | parameter 0 [element] -> return [element] | true | -| System.Linq.Queryable.OrderBy(IQueryable, Expression>, IComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.OrderBy(IQueryable, Expression>, IComparer) | parameter 0 [element] -> return [element] | true | -| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>) | parameter 0 [element] -> return [element] | true | -| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>, IComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>, IComparer) | parameter 0 [element] -> return [element] | true | -| System.Linq.Queryable.Reverse(IQueryable) | parameter 0 [element] -> return [element] | true | -| System.Linq.Queryable.Select(IQueryable, Expression>) | deleget output from parameter 1 -> return [element] | true | -| System.Linq.Queryable.Select(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Select(IQueryable, Expression>) | deleget output from parameter 1 -> return [element] | true | -| System.Linq.Queryable.Select(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | deleget output from parameter 1 [element] -> parameter 1 of delegate parameter 2 | true | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | deleget output from parameter 2 -> return [element] | true | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | deleget output from parameter 1 [element] -> parameter 1 of delegate parameter 2 | true | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | deleget output from parameter 2 -> return [element] | true | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | deleget output from parameter 1 -> return [element] | true | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | deleget output from parameter 1 -> return [element] | true | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Single(IQueryable) | parameter 0 [element] -> return | true | -| System.Linq.Queryable.Single(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Single(IQueryable, Expression>) | parameter 0 [element] -> return | true | -| System.Linq.Queryable.SingleOrDefault(IQueryable) | parameter 0 [element] -> return | true | -| System.Linq.Queryable.SingleOrDefault(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.SingleOrDefault(IQueryable, Expression>) | parameter 0 [element] -> return | true | -| System.Linq.Queryable.Skip(IQueryable, int) | parameter 0 [element] -> return [element] | true | -| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | parameter 0 [element] -> return [element] | true | -| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | parameter 0 [element] -> return [element] | true | -| System.Linq.Queryable.Sum(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Sum(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Sum(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Sum(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Sum(IQueryable, Expression>>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Sum(IQueryable, Expression>>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Sum(IQueryable, Expression>>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Sum(IQueryable, Expression>>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Sum(IQueryable, Expression>>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Sum(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Take(IQueryable, int) | parameter 0 [element] -> return [element] | true | -| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | parameter 0 [element] -> return [element] | true | -| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | parameter 0 [element] -> return [element] | true | -| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>) | parameter 0 [element] -> return [element] | true | -| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>, IComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>, IComparer) | parameter 0 [element] -> return [element] | true | -| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>) | parameter 0 [element] -> return [element] | true | -| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>, IComparer) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>, IComparer) | parameter 0 [element] -> return [element] | true | -| System.Linq.Queryable.Union(IQueryable, IEnumerable) | parameter 0 [element] -> return [element] | true | -| System.Linq.Queryable.Union(IQueryable, IEnumerable) | parameter 1 [element] -> return [element] | true | -| System.Linq.Queryable.Union(IQueryable, IEnumerable, IEqualityComparer) | parameter 0 [element] -> return [element] | true | -| System.Linq.Queryable.Union(IQueryable, IEnumerable, IEqualityComparer) | parameter 1 [element] -> return [element] | true | -| System.Linq.Queryable.Where(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Where(IQueryable, Expression>) | parameter 0 [element] -> return [element] | true | -| System.Linq.Queryable.Where(IQueryable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 1 | true | -| System.Linq.Queryable.Where(IQueryable, Expression>) | parameter 0 [element] -> return [element] | true | -| System.Linq.Queryable.Zip(IQueryable, IEnumerable, Expression>) | deleget output from parameter 2 -> return [element] | true | -| System.Linq.Queryable.Zip(IQueryable, IEnumerable, Expression>) | parameter 0 [element] -> parameter 0 of delegate parameter 2 | true | -| System.Linq.Queryable.Zip(IQueryable, IEnumerable, Expression>) | parameter 1 [element] -> parameter 1 of delegate parameter 2 | true | -| System.Net.Cookie.get_Value() | this parameter -> return | false | -| System.Net.CookieCollection.Add(Cookie) | parameter 0 -> this parameter [element] | true | -| System.Net.CookieCollection.Add(CookieCollection) | parameter 0 -> this parameter [element] | true | -| System.Net.CookieCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Net.CookieCollection.CopyTo(Cookie[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Net.CookieCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Net.CredentialCache.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Net.HttpListenerPrefixCollection.Add(string) | parameter 0 -> this parameter [element] | true | -| System.Net.HttpListenerPrefixCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Net.HttpListenerPrefixCollection.CopyTo(String[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Net.HttpListenerPrefixCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Net.HttpRequestStream.BeginRead(Byte[], int, int, AsyncCallback, object) | this parameter -> parameter 0 | false | -| System.Net.HttpRequestStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | parameter 0 -> this parameter | false | -| System.Net.HttpRequestStream.Read(Byte[], int, int) | this parameter -> parameter 0 | false | -| System.Net.HttpRequestStream.Write(Byte[], int, int) | parameter 0 -> this parameter | false | -| System.Net.HttpResponseStream.BeginRead(Byte[], int, int, AsyncCallback, object) | this parameter -> parameter 0 | false | -| System.Net.HttpResponseStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | parameter 0 -> this parameter | false | -| System.Net.HttpResponseStream.Read(Byte[], int, int) | this parameter -> parameter 0 | false | -| System.Net.HttpResponseStream.Write(Byte[], int, int) | parameter 0 -> this parameter | false | -| System.Net.NetworkInformation.IPAddressCollection.Add(IPAddress) | parameter 0 -> this parameter [element] | true | -| System.Net.NetworkInformation.IPAddressCollection.CopyTo(IPAddress[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Net.NetworkInformation.IPAddressCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Net.Security.CipherSuitesPolicy.d__6.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Net.Security.NegotiateStream.BeginRead(Byte[], int, int, AsyncCallback, object) | this parameter -> parameter 0 | false | -| System.Net.Security.NegotiateStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | parameter 0 -> this parameter | false | -| System.Net.Security.NegotiateStream.Read(Byte[], int, int) | this parameter -> parameter 0 | false | -| System.Net.Security.NegotiateStream.ReadAsync(Byte[], int, int, CancellationToken) | this parameter -> parameter 0 | false | -| System.Net.Security.NegotiateStream.Write(Byte[], int, int) | parameter 0 -> this parameter | false | -| System.Net.Security.NegotiateStream.WriteAsync(Byte[], int, int, CancellationToken) | parameter 0 -> this parameter | false | -| System.Net.Security.SslStream.BeginRead(Byte[], int, int, AsyncCallback, object) | this parameter -> parameter 0 | false | -| System.Net.Security.SslStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | parameter 0 -> this parameter | false | -| System.Net.Security.SslStream.Read(Byte[], int, int) | this parameter -> parameter 0 | false | -| System.Net.Security.SslStream.ReadAsync(Byte[], int, int, CancellationToken) | this parameter -> parameter 0 | false | -| System.Net.Security.SslStream.Write(Byte[], int, int) | parameter 0 -> this parameter | false | -| System.Net.Security.SslStream.WriteAsync(Byte[], int, int, CancellationToken) | parameter 0 -> this parameter | false | -| System.Net.WebUtility.HtmlEncode(string) | parameter 0 -> return | false | -| System.Net.WebUtility.HtmlEncode(string, TextWriter) | parameter 0 -> return | false | -| System.Net.WebUtility.UrlEncode(string) | parameter 0 -> return | false | -| System.Nullable<>.GetValueOrDefault() | this parameter [property Value] -> return | true | -| System.Nullable<>.GetValueOrDefault(T) | parameter 0 -> return | true | -| System.Nullable<>.GetValueOrDefault(T) | this parameter [property Value] -> return | true | -| System.Nullable<>.Nullable(T) | parameter 0 -> return [property Value] | true | -| System.Nullable<>.get_HasValue() | this parameter [property Value] -> return | false | -| System.Nullable<>.get_Value() | this parameter -> return | false | -| System.Reflection.TypeInfo.d__10.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Reflection.TypeInfo.d__22.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Resources.ResourceFallbackManager.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Resources.ResourceReader.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Resources.ResourceSet.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Resources.RuntimeResourceSet.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Runtime.CompilerServices.ConditionalWeakTable<,>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Runtime.CompilerServices.ConfiguredTaskAwaitable<>.ConfiguredTaskAwaiter.GetResult() | this parameter [field m_task, property Result] -> return | true | -| System.Runtime.CompilerServices.ConfiguredTaskAwaitable<>.GetAwaiter() | this parameter [field m_configuredTaskAwaiter] -> return | true | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Add(T) | parameter 0 -> this parameter [element] | true | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Add(object) | parameter 0 -> this parameter [element] | true | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.CopyTo(T[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Insert(int, T) | parameter 1 -> this parameter [element] | true | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Insert(int, object) | parameter 1 -> this parameter [element] | true | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Reverse() | parameter 0 [element] -> return [element] | true | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Reverse(int, int) | parameter 0 [element] -> return [element] | true | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.get_Item(int) | this parameter [element] -> return | true | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.set_Item(int, T) | parameter 1 -> this parameter [element] | true | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.set_Item(int, object) | parameter 1 -> this parameter [element] | true | -| System.Runtime.CompilerServices.TaskAwaiter<>.GetResult() | this parameter [field m_task, property Result] -> return | true | -| System.Runtime.InteropServices.MemoryMarshal.d__15<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Runtime.Loader.AssemblyLoadContext.d__83.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Runtime.Loader.AssemblyLoadContext.d__53.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Runtime.Loader.LibraryNameVariation.d__5.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Security.Cryptography.CryptoStream.BeginRead(Byte[], int, int, AsyncCallback, object) | this parameter -> parameter 0 | false | -| System.Security.Cryptography.CryptoStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | parameter 0 -> this parameter | false | -| System.Security.Cryptography.CryptoStream.Read(Byte[], int, int) | this parameter -> parameter 0 | false | -| System.Security.Cryptography.CryptoStream.ReadAsync(Byte[], int, int, CancellationToken) | this parameter -> parameter 0 | false | -| System.Security.Cryptography.CryptoStream.Write(Byte[], int, int) | parameter 0 -> this parameter | false | -| System.Security.Cryptography.CryptoStream.WriteAsync(Byte[], int, int, CancellationToken) | parameter 0 -> this parameter | false | -| System.Security.PermissionSet.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Security.PermissionSet.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.String.Clone() | this parameter -> return | true | -| System.String.Concat(IEnumerable) | parameter 0 [element] -> return | false | -| System.String.Concat(ReadOnlySpan, ReadOnlySpan) | parameter 0 -> return | false | -| System.String.Concat(ReadOnlySpan, ReadOnlySpan) | parameter 1 -> return | false | -| System.String.Concat(ReadOnlySpan, ReadOnlySpan, ReadOnlySpan) | parameter 0 -> return | false | -| System.String.Concat(ReadOnlySpan, ReadOnlySpan, ReadOnlySpan) | parameter 1 -> return | false | -| System.String.Concat(ReadOnlySpan, ReadOnlySpan, ReadOnlySpan) | parameter 2 -> return | false | -| System.String.Concat(ReadOnlySpan, ReadOnlySpan, ReadOnlySpan, ReadOnlySpan) | parameter 0 -> return | false | -| System.String.Concat(ReadOnlySpan, ReadOnlySpan, ReadOnlySpan, ReadOnlySpan) | parameter 1 -> return | false | -| System.String.Concat(ReadOnlySpan, ReadOnlySpan, ReadOnlySpan, ReadOnlySpan) | parameter 2 -> return | false | -| System.String.Concat(ReadOnlySpan, ReadOnlySpan, ReadOnlySpan, ReadOnlySpan) | parameter 3 -> return | false | -| System.String.Concat(object) | parameter 0 -> return | false | -| System.String.Concat(object, object) | parameter 0 -> return | false | -| System.String.Concat(object, object) | parameter 1 -> return | false | -| System.String.Concat(object, object, object) | parameter 0 -> return | false | -| System.String.Concat(object, object, object) | parameter 1 -> return | false | -| System.String.Concat(object, object, object) | parameter 2 -> return | false | -| System.String.Concat(params Object[]) | parameter 0 [element] -> return | false | -| System.String.Concat(params String[]) | parameter 0 [element] -> return | false | -| System.String.Concat(string, string) | parameter 0 -> return | false | -| System.String.Concat(string, string) | parameter 1 -> return | false | -| System.String.Concat(string, string, string) | parameter 0 -> return | false | -| System.String.Concat(string, string, string) | parameter 1 -> return | false | -| System.String.Concat(string, string, string) | parameter 2 -> return | false | -| System.String.Concat(string, string, string, string) | parameter 0 -> return | false | -| System.String.Concat(string, string, string, string) | parameter 1 -> return | false | -| System.String.Concat(string, string, string, string) | parameter 2 -> return | false | -| System.String.Concat(string, string, string, string) | parameter 3 -> return | false | -| System.String.Concat(IEnumerable) | parameter 0 [element] -> return | false | -| System.String.Copy(string) | parameter 0 -> return | true | -| System.String.Format(IFormatProvider, string, object) | parameter 1 -> return | false | -| System.String.Format(IFormatProvider, string, object) | parameter 2 -> return | false | -| System.String.Format(IFormatProvider, string, object, object) | parameter 1 -> return | false | -| System.String.Format(IFormatProvider, string, object, object) | parameter 2 -> return | false | -| System.String.Format(IFormatProvider, string, object, object) | parameter 3 -> return | false | -| System.String.Format(IFormatProvider, string, object, object, object) | parameter 1 -> return | false | -| System.String.Format(IFormatProvider, string, object, object, object) | parameter 2 -> return | false | -| System.String.Format(IFormatProvider, string, object, object, object) | parameter 3 -> return | false | -| System.String.Format(IFormatProvider, string, object, object, object) | parameter 4 -> return | false | -| System.String.Format(IFormatProvider, string, params Object[]) | parameter 1 -> return | false | -| System.String.Format(IFormatProvider, string, params Object[]) | parameter 2 [element] -> return | false | -| System.String.Format(string, object) | parameter 0 -> return | false | -| System.String.Format(string, object) | parameter 1 -> return | false | -| System.String.Format(string, object, object) | parameter 0 -> return | false | -| System.String.Format(string, object, object) | parameter 1 -> return | false | -| System.String.Format(string, object, object) | parameter 2 -> return | false | -| System.String.Format(string, object, object, object) | parameter 0 -> return | false | -| System.String.Format(string, object, object, object) | parameter 1 -> return | false | -| System.String.Format(string, object, object, object) | parameter 2 -> return | false | -| System.String.Format(string, object, object, object) | parameter 3 -> return | false | -| System.String.Format(string, params Object[]) | parameter 0 -> return | false | -| System.String.Format(string, params Object[]) | parameter 1 [element] -> return | false | -| System.String.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.String.Insert(int, string) | parameter 1 -> return | false | -| System.String.Insert(int, string) | this parameter -> return | false | -| System.String.Join(char, String[], int, int) | parameter 0 -> return | false | -| System.String.Join(char, String[], int, int) | parameter 1 [element] -> return | false | -| System.String.Join(char, params Object[]) | parameter 0 -> return | false | -| System.String.Join(char, params Object[]) | parameter 1 [element] -> return | false | -| System.String.Join(char, params String[]) | parameter 0 -> return | false | -| System.String.Join(char, params String[]) | parameter 1 [element] -> return | false | -| System.String.Join(string, IEnumerable) | parameter 0 -> return | false | -| System.String.Join(string, IEnumerable) | parameter 1 [element] -> return | false | -| System.String.Join(string, String[], int, int) | parameter 0 -> return | false | -| System.String.Join(string, String[], int, int) | parameter 1 [element] -> return | false | -| System.String.Join(string, params Object[]) | parameter 0 -> return | false | -| System.String.Join(string, params Object[]) | parameter 1 [element] -> return | false | -| System.String.Join(string, params String[]) | parameter 0 -> return | false | -| System.String.Join(string, params String[]) | parameter 1 [element] -> return | false | -| System.String.Join(char, IEnumerable) | parameter 0 -> return | false | -| System.String.Join(char, IEnumerable) | parameter 1 [element] -> return | false | -| System.String.Join(string, IEnumerable) | parameter 0 -> return | false | -| System.String.Join(string, IEnumerable) | parameter 1 [element] -> return | false | -| System.String.Normalize() | this parameter -> return | false | -| System.String.Normalize(NormalizationForm) | this parameter -> return | false | -| System.String.PadLeft(int) | this parameter -> return | false | -| System.String.PadLeft(int, char) | this parameter -> return | false | -| System.String.PadRight(int) | this parameter -> return | false | -| System.String.PadRight(int, char) | this parameter -> return | false | -| System.String.Remove(int) | this parameter -> return | false | -| System.String.Remove(int, int) | this parameter -> return | false | -| System.String.Replace(char, char) | parameter 1 -> return | false | -| System.String.Replace(char, char) | this parameter -> return | false | -| System.String.Replace(string, string) | parameter 1 -> return | false | -| System.String.Replace(string, string) | this parameter -> return | false | -| System.String.Split(Char[], StringSplitOptions) | this parameter -> return [element] | false | -| System.String.Split(Char[], int) | this parameter -> return [element] | false | -| System.String.Split(Char[], int, StringSplitOptions) | this parameter -> return [element] | false | -| System.String.Split(String[], StringSplitOptions) | this parameter -> return [element] | false | -| System.String.Split(String[], int, StringSplitOptions) | this parameter -> return [element] | false | -| System.String.Split(char, StringSplitOptions) | this parameter -> return [element] | false | -| System.String.Split(char, int, StringSplitOptions) | this parameter -> return [element] | false | -| System.String.Split(params Char[]) | this parameter -> return [element] | false | -| System.String.Split(string, StringSplitOptions) | this parameter -> return [element] | false | -| System.String.Split(string, int, StringSplitOptions) | this parameter -> return [element] | false | -| System.String.String(Char[]) | parameter 0 [element] -> return | false | -| System.String.String(Char[], int, int) | parameter 0 [element] -> return | false | -| System.String.Substring(int) | this parameter -> return | false | -| System.String.Substring(int, int) | this parameter -> return | false | -| System.String.ToLower() | this parameter -> return | false | -| System.String.ToLower(CultureInfo) | this parameter -> return | false | -| System.String.ToLowerInvariant() | this parameter -> return | false | -| System.String.ToString() | this parameter -> return | true | -| System.String.ToString(IFormatProvider) | this parameter -> return | true | -| System.String.ToUpper() | this parameter -> return | false | -| System.String.ToUpper(CultureInfo) | this parameter -> return | false | -| System.String.ToUpperInvariant() | this parameter -> return | false | -| System.String.Trim() | this parameter -> return | false | -| System.String.Trim(char) | this parameter -> return | false | -| System.String.Trim(params Char[]) | this parameter -> return | false | -| System.String.TrimEnd() | this parameter -> return | false | -| System.String.TrimEnd(char) | this parameter -> return | false | -| System.String.TrimEnd(params Char[]) | this parameter -> return | false | -| System.String.TrimStart() | this parameter -> return | false | -| System.String.TrimStart(char) | this parameter -> return | false | -| System.String.TrimStart(params Char[]) | this parameter -> return | false | -| System.Text.Encoding.GetBytes(Char[]) | parameter 0 [element] -> return | false | -| System.Text.Encoding.GetBytes(Char[], int, int) | parameter 0 [element] -> return | false | -| System.Text.Encoding.GetBytes(Char[], int, int, Byte[], int) | parameter 0 [element] -> return | false | -| System.Text.Encoding.GetBytes(ReadOnlySpan, Span) | parameter 0 -> return | false | -| System.Text.Encoding.GetBytes(char*, int, byte*, int) | parameter 0 -> return | false | -| System.Text.Encoding.GetBytes(char*, int, byte*, int, EncoderNLS) | parameter 0 -> return | false | -| System.Text.Encoding.GetBytes(string) | parameter 0 -> return | false | -| System.Text.Encoding.GetBytes(string, int, int) | parameter 0 -> return | false | -| System.Text.Encoding.GetBytes(string, int, int, Byte[], int) | parameter 0 -> return | false | -| System.Text.Encoding.GetChars(Byte[]) | parameter 0 [element] -> return | false | -| System.Text.Encoding.GetChars(Byte[], int, int) | parameter 0 [element] -> return | false | -| System.Text.Encoding.GetChars(Byte[], int, int, Char[], int) | parameter 0 [element] -> return | false | -| System.Text.Encoding.GetChars(ReadOnlySpan, Span) | parameter 0 [element] -> return | false | -| System.Text.Encoding.GetChars(byte*, int, char*, int) | parameter 0 [element] -> return | false | -| System.Text.Encoding.GetChars(byte*, int, char*, int, DecoderNLS) | parameter 0 [element] -> return | false | -| System.Text.Encoding.GetString(Byte[]) | parameter 0 [element] -> return | false | -| System.Text.Encoding.GetString(Byte[], int, int) | parameter 0 [element] -> return | false | -| System.Text.Encoding.GetString(ReadOnlySpan) | parameter 0 [element] -> return | false | -| System.Text.Encoding.GetString(byte*, int) | parameter 0 [element] -> return | false | -| System.Text.RegularExpressions.CaptureCollection.Add(Capture) | parameter 0 -> this parameter [element] | true | -| System.Text.RegularExpressions.CaptureCollection.Add(object) | parameter 0 -> this parameter [element] | true | -| System.Text.RegularExpressions.CaptureCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Text.RegularExpressions.CaptureCollection.CopyTo(Capture[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Text.RegularExpressions.CaptureCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Text.RegularExpressions.CaptureCollection.Insert(int, Capture) | parameter 1 -> this parameter [element] | true | -| System.Text.RegularExpressions.CaptureCollection.Insert(int, object) | parameter 1 -> this parameter [element] | true | -| System.Text.RegularExpressions.CaptureCollection.get_Item(int) | this parameter [element] -> return | true | -| System.Text.RegularExpressions.CaptureCollection.set_Item(int, Capture) | parameter 1 -> this parameter [element] | true | -| System.Text.RegularExpressions.CaptureCollection.set_Item(int, object) | parameter 1 -> this parameter [element] | true | -| System.Text.RegularExpressions.GroupCollection.d__49.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Text.RegularExpressions.GroupCollection.d__51.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Text.RegularExpressions.GroupCollection.Add(Group) | parameter 0 -> this parameter [element] | true | -| System.Text.RegularExpressions.GroupCollection.Add(object) | parameter 0 -> this parameter [element] | true | -| System.Text.RegularExpressions.GroupCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Text.RegularExpressions.GroupCollection.CopyTo(Group[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Text.RegularExpressions.GroupCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Text.RegularExpressions.GroupCollection.Insert(int, Group) | parameter 1 -> this parameter [element] | true | -| System.Text.RegularExpressions.GroupCollection.Insert(int, object) | parameter 1 -> this parameter [element] | true | -| System.Text.RegularExpressions.GroupCollection.get_Item(int) | this parameter [element] -> return | true | -| System.Text.RegularExpressions.GroupCollection.get_Item(string) | this parameter [element] -> return | true | -| System.Text.RegularExpressions.GroupCollection.set_Item(int, Group) | parameter 1 -> this parameter [element] | true | -| System.Text.RegularExpressions.GroupCollection.set_Item(int, object) | parameter 1 -> this parameter [element] | true | -| System.Text.RegularExpressions.MatchCollection.Add(Match) | parameter 0 -> this parameter [element] | true | -| System.Text.RegularExpressions.MatchCollection.Add(object) | parameter 0 -> this parameter [element] | true | -| System.Text.RegularExpressions.MatchCollection.CopyTo(Array, int) | this parameter [element] -> parameter 0 [element] | true | -| System.Text.RegularExpressions.MatchCollection.CopyTo(Match[], int) | this parameter [element] -> parameter 0 [element] | true | -| System.Text.RegularExpressions.MatchCollection.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Text.RegularExpressions.MatchCollection.Insert(int, Match) | parameter 1 -> this parameter [element] | true | -| System.Text.RegularExpressions.MatchCollection.Insert(int, object) | parameter 1 -> this parameter [element] | true | -| System.Text.RegularExpressions.MatchCollection.get_Item(int) | this parameter [element] -> return | true | -| System.Text.RegularExpressions.MatchCollection.set_Item(int, Match) | parameter 1 -> this parameter [element] | true | -| System.Text.RegularExpressions.MatchCollection.set_Item(int, object) | parameter 1 -> this parameter [element] | true | -| System.Text.StringBuilder.Append(object) | parameter 0 -> return [element] | true | -| System.Text.StringBuilder.Append(object) | parameter 0 -> this parameter [element] | true | -| System.Text.StringBuilder.Append(string) | parameter 0 -> return [element] | true | -| System.Text.StringBuilder.Append(string) | parameter 0 -> this parameter [element] | true | -| System.Text.StringBuilder.Append(string, int, int) | parameter 0 -> return [element] | true | -| System.Text.StringBuilder.Append(string, int, int) | parameter 0 -> this parameter [element] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object) | parameter 1 -> return [element] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object) | parameter 1 -> this parameter [element] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object) | parameter 2 -> return [element] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object) | parameter 2 -> this parameter [element] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | parameter 1 -> return [element] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | parameter 1 -> this parameter [element] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | parameter 2 -> return [element] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | parameter 2 -> this parameter [element] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | parameter 3 -> return [element] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | parameter 3 -> this parameter [element] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | parameter 1 -> return [element] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | parameter 1 -> this parameter [element] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | parameter 2 -> return [element] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | parameter 2 -> this parameter [element] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | parameter 3 -> return [element] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | parameter 3 -> this parameter [element] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | parameter 4 -> return [element] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | parameter 4 -> this parameter [element] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, params Object[]) | parameter 1 -> return [element] | true | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, params Object[]) | parameter 1 -> this parameter [element] | true | -| System.Text.StringBuilder.AppendFormat(string, object) | parameter 0 -> return [element] | true | -| System.Text.StringBuilder.AppendFormat(string, object) | parameter 0 -> this parameter [element] | true | -| System.Text.StringBuilder.AppendFormat(string, object) | parameter 1 -> return [element] | true | -| System.Text.StringBuilder.AppendFormat(string, object) | parameter 1 -> this parameter [element] | true | -| System.Text.StringBuilder.AppendFormat(string, object, object) | parameter 0 -> return [element] | true | -| System.Text.StringBuilder.AppendFormat(string, object, object) | parameter 0 -> this parameter [element] | true | -| System.Text.StringBuilder.AppendFormat(string, object, object) | parameter 1 -> return [element] | true | -| System.Text.StringBuilder.AppendFormat(string, object, object) | parameter 1 -> this parameter [element] | true | -| System.Text.StringBuilder.AppendFormat(string, object, object) | parameter 2 -> return [element] | true | -| System.Text.StringBuilder.AppendFormat(string, object, object) | parameter 2 -> this parameter [element] | true | -| System.Text.StringBuilder.AppendFormat(string, object, object, object) | parameter 0 -> return [element] | true | -| System.Text.StringBuilder.AppendFormat(string, object, object, object) | parameter 0 -> this parameter [element] | true | -| System.Text.StringBuilder.AppendFormat(string, object, object, object) | parameter 1 -> return [element] | true | -| System.Text.StringBuilder.AppendFormat(string, object, object, object) | parameter 1 -> this parameter [element] | true | -| System.Text.StringBuilder.AppendFormat(string, object, object, object) | parameter 2 -> return [element] | true | -| System.Text.StringBuilder.AppendFormat(string, object, object, object) | parameter 2 -> this parameter [element] | true | -| System.Text.StringBuilder.AppendFormat(string, object, object, object) | parameter 3 -> return [element] | true | -| System.Text.StringBuilder.AppendFormat(string, object, object, object) | parameter 3 -> this parameter [element] | true | -| System.Text.StringBuilder.AppendFormat(string, params Object[]) | parameter 0 -> return [element] | true | -| System.Text.StringBuilder.AppendFormat(string, params Object[]) | parameter 0 -> this parameter [element] | true | -| System.Text.StringBuilder.AppendLine(string) | parameter 0 -> return [element] | true | -| System.Text.StringBuilder.AppendLine(string) | parameter 0 -> this parameter [element] | true | -| System.Text.StringBuilder.StringBuilder(string) | parameter 0 -> return [element] | true | -| System.Text.StringBuilder.StringBuilder(string, int) | parameter 0 -> return [element] | true | -| System.Text.StringBuilder.StringBuilder(string, int, int, int) | parameter 0 -> return [element] | true | -| System.Text.StringBuilder.ToString() | this parameter [element] -> return | false | -| System.Text.StringBuilder.ToString(int, int) | this parameter [element] -> return | false | -| System.Text.TranscodingStream.BeginRead(Byte[], int, int, AsyncCallback, object) | this parameter -> parameter 0 | false | -| System.Text.TranscodingStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | parameter 0 -> this parameter | false | -| System.Text.TranscodingStream.Read(Byte[], int, int) | this parameter -> parameter 0 | false | -| System.Text.TranscodingStream.ReadAsync(Byte[], int, int, CancellationToken) | this parameter -> parameter 0 | false | -| System.Text.TranscodingStream.Write(Byte[], int, int) | parameter 0 -> this parameter | false | -| System.Text.TranscodingStream.WriteAsync(Byte[], int, int, CancellationToken) | parameter 0 -> this parameter | false | -| System.Threading.Tasks.SingleProducerSingleConsumerQueue<>.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Threading.Tasks.Task.ContinueWith(Action, object) | parameter 1 -> parameter 1 of delegate parameter 0 | true | -| System.Threading.Tasks.Task.ContinueWith(Action, object, CancellationToken) | parameter 1 -> parameter 1 of delegate parameter 0 | true | -| System.Threading.Tasks.Task.ContinueWith(Action, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | parameter 1 -> parameter 1 of delegate parameter 0 | true | -| System.Threading.Tasks.Task.ContinueWith(Action, object, TaskContinuationOptions) | parameter 1 -> parameter 1 of delegate parameter 0 | true | -| System.Threading.Tasks.Task.ContinueWith(Action, object, TaskScheduler) | parameter 1 -> parameter 1 of delegate parameter 0 | true | -| System.Threading.Tasks.Task.ContinueWith(Func, object) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.Task.ContinueWith(Func, object) | parameter 1 -> parameter 1 of delegate parameter 0 | true | -| System.Threading.Tasks.Task.ContinueWith(Func, object, CancellationToken) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.Task.ContinueWith(Func, object, CancellationToken) | parameter 1 -> parameter 1 of delegate parameter 0 | true | -| System.Threading.Tasks.Task.ContinueWith(Func, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.Task.ContinueWith(Func, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | parameter 1 -> parameter 1 of delegate parameter 0 | true | -| System.Threading.Tasks.Task.ContinueWith(Func, object, TaskContinuationOptions) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.Task.ContinueWith(Func, object, TaskContinuationOptions) | parameter 1 -> parameter 1 of delegate parameter 0 | true | -| System.Threading.Tasks.Task.ContinueWith(Func, object, TaskScheduler) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.Task.ContinueWith(Func, object, TaskScheduler) | parameter 1 -> parameter 1 of delegate parameter 0 | true | -| System.Threading.Tasks.Task.ContinueWith(Func) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.Task.ContinueWith(Func, CancellationToken) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.Task.ContinueWith(Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.Task.ContinueWith(Func, TaskContinuationOptions) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.Task.ContinueWith(Func, TaskScheduler) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.Task.FromResult(TResult) | parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.Task.Run(Func) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.Task.Run(Func, CancellationToken) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.Task.Run(Func>) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.Task.Run(Func>, CancellationToken) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.Task.Task(Action, object) | parameter 1 -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task.Task(Action, object, CancellationToken) | parameter 1 -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task.Task(Action, object, CancellationToken, TaskCreationOptions) | parameter 1 -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task.Task(Action, object, TaskCreationOptions) | parameter 1 -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task.WhenAll(IEnumerable>) | parameter 0 [element, property Result] -> return [property Result, element] | true | -| System.Threading.Tasks.Task.WhenAll(params Task[]) | parameter 0 [element, property Result] -> return [property Result, element] | true | -| System.Threading.Tasks.Task.WhenAny(IEnumerable>) | parameter 0 [element, property Result] -> return [property Result, element] | true | -| System.Threading.Tasks.Task.WhenAny(Task, Task) | parameter 0 [element, property Result] -> return [property Result, element] | true | -| System.Threading.Tasks.Task.WhenAny(Task, Task) | parameter 1 [element, property Result] -> return [property Result, element] | true | -| System.Threading.Tasks.Task.WhenAny(params Task[]) | parameter 0 [element, property Result] -> return [property Result, element] | true | -| System.Threading.Tasks.Task<>.ConfigureAwait(bool) | this parameter -> return [field m_configuredTaskAwaiter, field m_task] | true | -| System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object) | parameter 1 -> parameter 1 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object) | this parameter -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object, CancellationToken) | parameter 1 -> parameter 1 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object, CancellationToken) | this parameter -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | parameter 1 -> parameter 1 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | this parameter -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object, TaskContinuationOptions) | parameter 1 -> parameter 1 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object, TaskContinuationOptions) | this parameter -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object, TaskScheduler) | parameter 1 -> parameter 1 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object, TaskScheduler) | this parameter -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Action>) | this parameter -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Action>, CancellationToken) | this parameter -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Action>, CancellationToken, TaskContinuationOptions, TaskScheduler) | this parameter -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Action>, TaskContinuationOptions) | this parameter -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Action>, TaskScheduler) | this parameter -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object) | parameter 1 -> parameter 1 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object) | this parameter -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, CancellationToken) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, CancellationToken) | parameter 1 -> parameter 1 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, CancellationToken) | this parameter -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | parameter 1 -> parameter 1 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | this parameter -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, TaskContinuationOptions) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, TaskContinuationOptions) | parameter 1 -> parameter 1 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, TaskContinuationOptions) | this parameter -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, TaskScheduler) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, TaskScheduler) | parameter 1 -> parameter 1 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, TaskScheduler) | this parameter -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>) | this parameter -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, CancellationToken) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, CancellationToken) | this parameter -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | this parameter -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, TaskContinuationOptions) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, TaskContinuationOptions) | this parameter -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, TaskScheduler) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, TaskScheduler) | this parameter -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.GetAwaiter() | this parameter -> return [field m_task] | true | -| System.Threading.Tasks.Task<>.Task(Func, object) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.Task<>.Task(Func, object) | parameter 1 -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.Task(Func, object, CancellationToken) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.Task<>.Task(Func, object, CancellationToken) | parameter 1 -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.Task(Func, object, CancellationToken, TaskCreationOptions) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.Task<>.Task(Func, object, CancellationToken, TaskCreationOptions) | parameter 1 -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.Task(Func, object, TaskCreationOptions) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.Task<>.Task(Func, object, TaskCreationOptions) | parameter 1 -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.Task<>.Task(Func) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.Task<>.Task(Func, CancellationToken) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.Task<>.Task(Func, CancellationToken, TaskCreationOptions) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.Task<>.Task(Func, TaskCreationOptions) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.Task<>.get_Result() | this parameter -> return | false | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func) | deleget output from parameter 1 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, CancellationToken) | deleget output from parameter 1 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, CancellationToken) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | deleget output from parameter 1 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, TaskContinuationOptions) | deleget output from parameter 1 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, TaskContinuationOptions) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Action) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Action, CancellationToken) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Action, CancellationToken, TaskContinuationOptions, TaskScheduler) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Action, TaskContinuationOptions) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func) | deleget output from parameter 1 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, CancellationToken) | deleget output from parameter 1 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | deleget output from parameter 1 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, TaskContinuationOptions) | deleget output from parameter 1 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>) | deleget output from parameter 1 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>, CancellationToken) | deleget output from parameter 1 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>, CancellationToken) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | deleget output from parameter 1 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>, TaskContinuationOptions) | deleget output from parameter 1 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>, TaskContinuationOptions) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Action>) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Action>, CancellationToken) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Action>, CancellationToken, TaskContinuationOptions, TaskScheduler) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Action>, TaskContinuationOptions) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func) | deleget output from parameter 1 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, CancellationToken) | deleget output from parameter 1 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | deleget output from parameter 1 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TaskContinuationOptions) | deleget output from parameter 1 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory.StartNew(Action, object) | parameter 1 -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.TaskFactory.StartNew(Action, object, CancellationToken) | parameter 1 -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.TaskFactory.StartNew(Action, object, CancellationToken, TaskCreationOptions, TaskScheduler) | parameter 1 -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.TaskFactory.StartNew(Action, object, TaskCreationOptions) | parameter 1 -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.TaskFactory.StartNew(Func, object) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory.StartNew(Func, object) | parameter 1 -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.TaskFactory.StartNew(Func, object, CancellationToken) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory.StartNew(Func, object, CancellationToken) | parameter 1 -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.TaskFactory.StartNew(Func, object, CancellationToken, TaskCreationOptions, TaskScheduler) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory.StartNew(Func, object, CancellationToken, TaskCreationOptions, TaskScheduler) | parameter 1 -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.TaskFactory.StartNew(Func, object, TaskCreationOptions) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory.StartNew(Func, object, TaskCreationOptions) | parameter 1 -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.TaskFactory.StartNew(Func) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory.StartNew(Func, CancellationToken) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory.StartNew(Func, CancellationToken, TaskCreationOptions, TaskScheduler) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory.StartNew(Func, TaskCreationOptions) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func) | deleget output from parameter 1 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, CancellationToken) | deleget output from parameter 1 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | deleget output from parameter 1 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, TaskContinuationOptions) | deleget output from parameter 1 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func) | deleget output from parameter 1 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, CancellationToken) | deleget output from parameter 1 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, CancellationToken) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | deleget output from parameter 1 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, TaskContinuationOptions) | deleget output from parameter 1 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, TaskContinuationOptions) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func) | deleget output from parameter 1 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, CancellationToken) | deleget output from parameter 1 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | deleget output from parameter 1 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TaskContinuationOptions) | deleget output from parameter 1 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>) | deleget output from parameter 1 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>, CancellationToken) | deleget output from parameter 1 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>, CancellationToken) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | deleget output from parameter 1 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>, TaskContinuationOptions) | deleget output from parameter 1 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>, TaskContinuationOptions) | parameter 0 -> parameter 0 of delegate parameter 1 | true | -| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object) | parameter 1 -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, CancellationToken) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, CancellationToken) | parameter 1 -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, CancellationToken, TaskCreationOptions, TaskScheduler) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, CancellationToken, TaskCreationOptions, TaskScheduler) | parameter 1 -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, TaskCreationOptions) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, TaskCreationOptions) | parameter 1 -> parameter 0 of delegate parameter 0 | true | -| System.Threading.Tasks.TaskFactory<>.StartNew(Func) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory<>.StartNew(Func, CancellationToken) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory<>.StartNew(Func, CancellationToken, TaskCreationOptions, TaskScheduler) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.TaskFactory<>.StartNew(Func, TaskCreationOptions) | deleget output from parameter 0 -> return [property Result] | true | -| System.Threading.Tasks.ThreadPoolTaskScheduler.d__6.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Threading.ThreadPool.d__52.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Threading.ThreadPool.d__51.GetEnumerator() | this parameter [element] -> return [property Current] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 0 -> return [property Item1] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 1 -> return [property Item2] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 2 -> return [property Item3] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 3 -> return [property Item4] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 4 -> return [property Item5] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 5 -> return [property Item6] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 6 -> return [property Item7] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7) | parameter 0 -> return [property Item1] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7) | parameter 1 -> return [property Item2] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7) | parameter 2 -> return [property Item3] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7) | parameter 3 -> return [property Item4] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7) | parameter 4 -> return [property Item5] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7) | parameter 5 -> return [property Item6] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7) | parameter 6 -> return [property Item7] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6) | parameter 0 -> return [property Item1] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6) | parameter 1 -> return [property Item2] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6) | parameter 2 -> return [property Item3] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6) | parameter 3 -> return [property Item4] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6) | parameter 4 -> return [property Item5] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5, T6) | parameter 5 -> return [property Item6] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5) | parameter 0 -> return [property Item1] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5) | parameter 1 -> return [property Item2] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5) | parameter 2 -> return [property Item3] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5) | parameter 3 -> return [property Item4] | true | -| System.Tuple.Create(T1, T2, T3, T4, T5) | parameter 4 -> return [property Item5] | true | -| System.Tuple.Create(T1, T2, T3, T4) | parameter 0 -> return [property Item1] | true | -| System.Tuple.Create(T1, T2, T3, T4) | parameter 1 -> return [property Item2] | true | -| System.Tuple.Create(T1, T2, T3, T4) | parameter 2 -> return [property Item3] | true | -| System.Tuple.Create(T1, T2, T3, T4) | parameter 3 -> return [property Item4] | true | -| System.Tuple.Create(T1, T2, T3) | parameter 0 -> return [property Item1] | true | -| System.Tuple.Create(T1, T2, T3) | parameter 1 -> return [property Item2] | true | -| System.Tuple.Create(T1, T2, T3) | parameter 2 -> return [property Item3] | true | -| System.Tuple.Create(T1, T2) | parameter 0 -> return [property Item1] | true | -| System.Tuple.Create(T1, T2) | parameter 1 -> return [property Item2] | true | -| System.Tuple.Create(T1) | parameter 0 -> return [property Item1] | true | -| System.Tuple<,,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 0 -> return [property Item1] | true | -| System.Tuple<,,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 1 -> return [property Item2] | true | -| System.Tuple<,,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 2 -> return [property Item3] | true | -| System.Tuple<,,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 3 -> return [property Item4] | true | -| System.Tuple<,,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 4 -> return [property Item5] | true | -| System.Tuple<,,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 5 -> return [property Item6] | true | -| System.Tuple<,,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 6 -> return [property Item7] | true | -| System.Tuple<,,,,,,,>.get_Item(int) | this parameter [property Item1] -> return | true | -| System.Tuple<,,,,,,,>.get_Item(int) | this parameter [property Item2] -> return | true | -| System.Tuple<,,,,,,,>.get_Item(int) | this parameter [property Item3] -> return | true | -| System.Tuple<,,,,,,,>.get_Item(int) | this parameter [property Item4] -> return | true | -| System.Tuple<,,,,,,,>.get_Item(int) | this parameter [property Item5] -> return | true | -| System.Tuple<,,,,,,,>.get_Item(int) | this parameter [property Item6] -> return | true | -| System.Tuple<,,,,,,,>.get_Item(int) | this parameter [property Item7] -> return | true | -| System.Tuple<,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7) | parameter 0 -> return [property Item1] | true | -| System.Tuple<,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7) | parameter 1 -> return [property Item2] | true | -| System.Tuple<,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7) | parameter 2 -> return [property Item3] | true | -| System.Tuple<,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7) | parameter 3 -> return [property Item4] | true | -| System.Tuple<,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7) | parameter 4 -> return [property Item5] | true | -| System.Tuple<,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7) | parameter 5 -> return [property Item6] | true | -| System.Tuple<,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7) | parameter 6 -> return [property Item7] | true | -| System.Tuple<,,,,,,>.get_Item(int) | this parameter [property Item1] -> return | true | -| System.Tuple<,,,,,,>.get_Item(int) | this parameter [property Item2] -> return | true | -| System.Tuple<,,,,,,>.get_Item(int) | this parameter [property Item3] -> return | true | -| System.Tuple<,,,,,,>.get_Item(int) | this parameter [property Item4] -> return | true | -| System.Tuple<,,,,,,>.get_Item(int) | this parameter [property Item5] -> return | true | -| System.Tuple<,,,,,,>.get_Item(int) | this parameter [property Item6] -> return | true | -| System.Tuple<,,,,,,>.get_Item(int) | this parameter [property Item7] -> return | true | -| System.Tuple<,,,,,>.Tuple(T1, T2, T3, T4, T5, T6) | parameter 0 -> return [property Item1] | true | -| System.Tuple<,,,,,>.Tuple(T1, T2, T3, T4, T5, T6) | parameter 1 -> return [property Item2] | true | -| System.Tuple<,,,,,>.Tuple(T1, T2, T3, T4, T5, T6) | parameter 2 -> return [property Item3] | true | -| System.Tuple<,,,,,>.Tuple(T1, T2, T3, T4, T5, T6) | parameter 3 -> return [property Item4] | true | -| System.Tuple<,,,,,>.Tuple(T1, T2, T3, T4, T5, T6) | parameter 4 -> return [property Item5] | true | -| System.Tuple<,,,,,>.Tuple(T1, T2, T3, T4, T5, T6) | parameter 5 -> return [property Item6] | true | -| System.Tuple<,,,,,>.get_Item(int) | this parameter [property Item1] -> return | true | -| System.Tuple<,,,,,>.get_Item(int) | this parameter [property Item2] -> return | true | -| System.Tuple<,,,,,>.get_Item(int) | this parameter [property Item3] -> return | true | -| System.Tuple<,,,,,>.get_Item(int) | this parameter [property Item4] -> return | true | -| System.Tuple<,,,,,>.get_Item(int) | this parameter [property Item5] -> return | true | -| System.Tuple<,,,,,>.get_Item(int) | this parameter [property Item6] -> return | true | -| System.Tuple<,,,,>.Tuple(T1, T2, T3, T4, T5) | parameter 0 -> return [property Item1] | true | -| System.Tuple<,,,,>.Tuple(T1, T2, T3, T4, T5) | parameter 1 -> return [property Item2] | true | -| System.Tuple<,,,,>.Tuple(T1, T2, T3, T4, T5) | parameter 2 -> return [property Item3] | true | -| System.Tuple<,,,,>.Tuple(T1, T2, T3, T4, T5) | parameter 3 -> return [property Item4] | true | -| System.Tuple<,,,,>.Tuple(T1, T2, T3, T4, T5) | parameter 4 -> return [property Item5] | true | -| System.Tuple<,,,,>.get_Item(int) | this parameter [property Item1] -> return | true | -| System.Tuple<,,,,>.get_Item(int) | this parameter [property Item2] -> return | true | -| System.Tuple<,,,,>.get_Item(int) | this parameter [property Item3] -> return | true | -| System.Tuple<,,,,>.get_Item(int) | this parameter [property Item4] -> return | true | -| System.Tuple<,,,,>.get_Item(int) | this parameter [property Item5] -> return | true | -| System.Tuple<,,,>.Tuple(T1, T2, T3, T4) | parameter 0 -> return [property Item1] | true | -| System.Tuple<,,,>.Tuple(T1, T2, T3, T4) | parameter 1 -> return [property Item2] | true | -| System.Tuple<,,,>.Tuple(T1, T2, T3, T4) | parameter 2 -> return [property Item3] | true | -| System.Tuple<,,,>.Tuple(T1, T2, T3, T4) | parameter 3 -> return [property Item4] | true | -| System.Tuple<,,,>.get_Item(int) | this parameter [property Item1] -> return | true | -| System.Tuple<,,,>.get_Item(int) | this parameter [property Item2] -> return | true | -| System.Tuple<,,,>.get_Item(int) | this parameter [property Item3] -> return | true | -| System.Tuple<,,,>.get_Item(int) | this parameter [property Item4] -> return | true | -| System.Tuple<,,>.Tuple(T1, T2, T3) | parameter 0 -> return [property Item1] | true | -| System.Tuple<,,>.Tuple(T1, T2, T3) | parameter 1 -> return [property Item2] | true | -| System.Tuple<,,>.Tuple(T1, T2, T3) | parameter 2 -> return [property Item3] | true | -| System.Tuple<,,>.get_Item(int) | this parameter [property Item1] -> return | true | -| System.Tuple<,,>.get_Item(int) | this parameter [property Item2] -> return | true | -| System.Tuple<,,>.get_Item(int) | this parameter [property Item3] -> return | true | -| System.Tuple<,>.Tuple(T1, T2) | parameter 0 -> return [property Item1] | true | -| System.Tuple<,>.Tuple(T1, T2) | parameter 1 -> return [property Item2] | true | -| System.Tuple<,>.get_Item(int) | this parameter [property Item1] -> return | true | -| System.Tuple<,>.get_Item(int) | this parameter [property Item2] -> return | true | -| System.Tuple<>.Tuple(T1) | parameter 0 -> return [property Item1] | true | -| System.Tuple<>.get_Item(int) | this parameter [property Item1] -> return | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20, out T21) | parameter 0 [property Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20, out T21) | parameter 0 [property Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20, out T21) | parameter 0 [property Item3] -> parameter 3 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20, out T21) | parameter 0 [property Item4] -> parameter 4 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20, out T21) | parameter 0 [property Item5] -> parameter 5 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20, out T21) | parameter 0 [property Item6] -> parameter 6 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20, out T21) | parameter 0 [property Item7] -> parameter 7 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20) | parameter 0 [property Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20) | parameter 0 [property Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20) | parameter 0 [property Item3] -> parameter 3 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20) | parameter 0 [property Item4] -> parameter 4 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20) | parameter 0 [property Item5] -> parameter 5 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20) | parameter 0 [property Item6] -> parameter 6 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20) | parameter 0 [property Item7] -> parameter 7 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19) | parameter 0 [property Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19) | parameter 0 [property Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19) | parameter 0 [property Item3] -> parameter 3 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19) | parameter 0 [property Item4] -> parameter 4 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19) | parameter 0 [property Item5] -> parameter 5 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19) | parameter 0 [property Item6] -> parameter 6 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19) | parameter 0 [property Item7] -> parameter 7 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18) | parameter 0 [property Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18) | parameter 0 [property Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18) | parameter 0 [property Item3] -> parameter 3 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18) | parameter 0 [property Item4] -> parameter 4 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18) | parameter 0 [property Item5] -> parameter 5 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18) | parameter 0 [property Item6] -> parameter 6 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18) | parameter 0 [property Item7] -> parameter 7 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17) | parameter 0 [property Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17) | parameter 0 [property Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17) | parameter 0 [property Item3] -> parameter 3 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17) | parameter 0 [property Item4] -> parameter 4 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17) | parameter 0 [property Item5] -> parameter 5 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17) | parameter 0 [property Item6] -> parameter 6 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17) | parameter 0 [property Item7] -> parameter 7 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16) | parameter 0 [property Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16) | parameter 0 [property Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16) | parameter 0 [property Item3] -> parameter 3 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16) | parameter 0 [property Item4] -> parameter 4 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16) | parameter 0 [property Item5] -> parameter 5 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16) | parameter 0 [property Item6] -> parameter 6 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16) | parameter 0 [property Item7] -> parameter 7 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15) | parameter 0 [property Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15) | parameter 0 [property Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15) | parameter 0 [property Item3] -> parameter 3 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15) | parameter 0 [property Item4] -> parameter 4 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15) | parameter 0 [property Item5] -> parameter 5 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15) | parameter 0 [property Item6] -> parameter 6 | true | -| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15) | parameter 0 [property Item7] -> parameter 7 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14) | parameter 0 [property Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14) | parameter 0 [property Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14) | parameter 0 [property Item3] -> parameter 3 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14) | parameter 0 [property Item4] -> parameter 4 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14) | parameter 0 [property Item5] -> parameter 5 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14) | parameter 0 [property Item6] -> parameter 6 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14) | parameter 0 [property Item7] -> parameter 7 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13) | parameter 0 [property Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13) | parameter 0 [property Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13) | parameter 0 [property Item3] -> parameter 3 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13) | parameter 0 [property Item4] -> parameter 4 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13) | parameter 0 [property Item5] -> parameter 5 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13) | parameter 0 [property Item6] -> parameter 6 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13) | parameter 0 [property Item7] -> parameter 7 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12) | parameter 0 [property Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12) | parameter 0 [property Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12) | parameter 0 [property Item3] -> parameter 3 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12) | parameter 0 [property Item4] -> parameter 4 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12) | parameter 0 [property Item5] -> parameter 5 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12) | parameter 0 [property Item6] -> parameter 6 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12) | parameter 0 [property Item7] -> parameter 7 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11) | parameter 0 [property Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11) | parameter 0 [property Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11) | parameter 0 [property Item3] -> parameter 3 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11) | parameter 0 [property Item4] -> parameter 4 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11) | parameter 0 [property Item5] -> parameter 5 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11) | parameter 0 [property Item6] -> parameter 6 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11) | parameter 0 [property Item7] -> parameter 7 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10) | parameter 0 [property Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10) | parameter 0 [property Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10) | parameter 0 [property Item3] -> parameter 3 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10) | parameter 0 [property Item4] -> parameter 4 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10) | parameter 0 [property Item5] -> parameter 5 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10) | parameter 0 [property Item6] -> parameter 6 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10) | parameter 0 [property Item7] -> parameter 7 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9) | parameter 0 [property Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9) | parameter 0 [property Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9) | parameter 0 [property Item3] -> parameter 3 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9) | parameter 0 [property Item4] -> parameter 4 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9) | parameter 0 [property Item5] -> parameter 5 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9) | parameter 0 [property Item6] -> parameter 6 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9) | parameter 0 [property Item7] -> parameter 7 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8) | parameter 0 [property Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8) | parameter 0 [property Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8) | parameter 0 [property Item3] -> parameter 3 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8) | parameter 0 [property Item4] -> parameter 4 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8) | parameter 0 [property Item5] -> parameter 5 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8) | parameter 0 [property Item6] -> parameter 6 | true | -| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8) | parameter 0 [property Item7] -> parameter 7 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6, out T7) | parameter 0 [property Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6, out T7) | parameter 0 [property Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6, out T7) | parameter 0 [property Item3] -> parameter 3 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6, out T7) | parameter 0 [property Item4] -> parameter 4 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6, out T7) | parameter 0 [property Item5] -> parameter 5 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6, out T7) | parameter 0 [property Item6] -> parameter 6 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6, out T7) | parameter 0 [property Item7] -> parameter 7 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6) | parameter 0 [property Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6) | parameter 0 [property Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6) | parameter 0 [property Item3] -> parameter 3 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6) | parameter 0 [property Item4] -> parameter 4 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6) | parameter 0 [property Item5] -> parameter 5 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6) | parameter 0 [property Item6] -> parameter 6 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5) | parameter 0 [property Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5) | parameter 0 [property Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5) | parameter 0 [property Item3] -> parameter 3 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5) | parameter 0 [property Item4] -> parameter 4 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5) | parameter 0 [property Item5] -> parameter 5 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4) | parameter 0 [property Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4) | parameter 0 [property Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4) | parameter 0 [property Item3] -> parameter 3 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4) | parameter 0 [property Item4] -> parameter 4 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3) | parameter 0 [property Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3) | parameter 0 [property Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3) | parameter 0 [property Item3] -> parameter 3 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2) | parameter 0 [property Item1] -> parameter 1 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2) | parameter 0 [property Item2] -> parameter 2 | true | -| System.TupleExtensions.Deconstruct(Tuple, out T1) | parameter 0 [property Item1] -> parameter 1 | true | -| System.Uri.ToString() | this parameter -> return | false | -| System.Uri.Uri(string) | parameter 0 -> return | false | -| System.Uri.Uri(string, UriKind) | parameter 0 -> return | false | -| System.Uri.Uri(string, bool) | parameter 0 -> return | false | -| System.Uri.get_OriginalString() | this parameter -> return | false | -| System.Uri.get_PathAndQuery() | this parameter -> return | false | -| System.Uri.get_Query() | this parameter -> return | false | -| System.ValueTuple<,,,,,,,>.ValueTuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 0 -> return [field Item1] | true | -| System.ValueTuple<,,,,,,,>.ValueTuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 1 -> return [field Item2] | true | -| System.ValueTuple<,,,,,,,>.ValueTuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 2 -> return [field Item3] | true | -| System.ValueTuple<,,,,,,,>.ValueTuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 3 -> return [field Item4] | true | -| System.ValueTuple<,,,,,,,>.ValueTuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 4 -> return [field Item5] | true | -| System.ValueTuple<,,,,,,,>.ValueTuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 5 -> return [field Item6] | true | -| System.ValueTuple<,,,,,,,>.ValueTuple(T1, T2, T3, T4, T5, T6, T7, TRest) | parameter 6 -> return [field Item7] | true | -| System.ValueTuple<,,,,,,,>.get_Item(int) | this parameter [field Item1] -> return | true | -| System.ValueTuple<,,,,,,,>.get_Item(int) | this parameter [field Item2] -> return | true | -| System.ValueTuple<,,,,,,,>.get_Item(int) | this parameter [field Item3] -> return | true | -| System.ValueTuple<,,,,,,,>.get_Item(int) | this parameter [field Item4] -> return | true | -| System.ValueTuple<,,,,,,,>.get_Item(int) | this parameter [field Item5] -> return | true | -| System.ValueTuple<,,,,,,,>.get_Item(int) | this parameter [field Item6] -> return | true | -| System.ValueTuple<,,,,,,,>.get_Item(int) | this parameter [field Item7] -> return | true | -| System.Web.HttpCookie.get_Value() | this parameter -> return | false | -| System.Web.HttpCookie.get_Values() | this parameter -> return | false | -| System.Web.HttpServerUtility.UrlEncode(string) | parameter 0 -> return | false | -| System.Web.HttpUtility.HtmlAttributeEncode(string) | parameter 0 -> return | false | -| System.Web.HttpUtility.HtmlEncode(object) | parameter 0 -> return | false | -| System.Web.HttpUtility.HtmlEncode(string) | parameter 0 -> return | false | -| System.Web.HttpUtility.UrlEncode(string) | parameter 0 -> return | false | -| System.Web.UI.WebControls.TextBox.get_Text() | this parameter -> return | false | +| MS.Internal.Xml.Linq.ComponentModel.XDeferredAxis<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.().Create(T1, T2, T3, T4, T5, T6, T7, T8) | argument 0 -> field Item1 of return (normal) | true | +| System.().Create(T1, T2, T3, T4, T5, T6, T7, T8) | argument 1 -> field Item2 of return (normal) | true | +| System.().Create(T1, T2, T3, T4, T5, T6, T7, T8) | argument 2 -> field Item3 of return (normal) | true | +| System.().Create(T1, T2, T3, T4, T5, T6, T7, T8) | argument 3 -> field Item4 of return (normal) | true | +| System.().Create(T1, T2, T3, T4, T5, T6, T7, T8) | argument 4 -> field Item5 of return (normal) | true | +| System.().Create(T1, T2, T3, T4, T5, T6, T7, T8) | argument 5 -> field Item6 of return (normal) | true | +| System.().Create(T1, T2, T3, T4, T5, T6, T7, T8) | argument 6 -> field Item7 of return (normal) | true | +| System.().Create(T1, T2, T3, T4, T5, T6, T7, T8) | argument 7 -> field Item8 of return (normal) | true | +| System.().Create(T1, T2, T3, T4, T5, T6, T7) | argument 0 -> field Item1 of return (normal) | true | +| System.().Create(T1, T2, T3, T4, T5, T6, T7) | argument 1 -> field Item2 of return (normal) | true | +| System.().Create(T1, T2, T3, T4, T5, T6, T7) | argument 2 -> field Item3 of return (normal) | true | +| System.().Create(T1, T2, T3, T4, T5, T6, T7) | argument 3 -> field Item4 of return (normal) | true | +| System.().Create(T1, T2, T3, T4, T5, T6, T7) | argument 4 -> field Item5 of return (normal) | true | +| System.().Create(T1, T2, T3, T4, T5, T6, T7) | argument 5 -> field Item6 of return (normal) | true | +| System.().Create(T1, T2, T3, T4, T5, T6, T7) | argument 6 -> field Item7 of return (normal) | true | +| System.().Create(T1, T2, T3, T4, T5, T6) | argument 0 -> field Item1 of return (normal) | true | +| System.().Create(T1, T2, T3, T4, T5, T6) | argument 1 -> field Item2 of return (normal) | true | +| System.().Create(T1, T2, T3, T4, T5, T6) | argument 2 -> field Item3 of return (normal) | true | +| System.().Create(T1, T2, T3, T4, T5, T6) | argument 3 -> field Item4 of return (normal) | true | +| System.().Create(T1, T2, T3, T4, T5, T6) | argument 4 -> field Item5 of return (normal) | true | +| System.().Create(T1, T2, T3, T4, T5, T6) | argument 5 -> field Item6 of return (normal) | true | +| System.().Create(T1, T2, T3, T4, T5) | argument 0 -> field Item1 of return (normal) | true | +| System.().Create(T1, T2, T3, T4, T5) | argument 1 -> field Item2 of return (normal) | true | +| System.().Create(T1, T2, T3, T4, T5) | argument 2 -> field Item3 of return (normal) | true | +| System.().Create(T1, T2, T3, T4, T5) | argument 3 -> field Item4 of return (normal) | true | +| System.().Create(T1, T2, T3, T4, T5) | argument 4 -> field Item5 of return (normal) | true | +| System.().Create(T1, T2, T3, T4) | argument 0 -> field Item1 of return (normal) | true | +| System.().Create(T1, T2, T3, T4) | argument 1 -> field Item2 of return (normal) | true | +| System.().Create(T1, T2, T3, T4) | argument 2 -> field Item3 of return (normal) | true | +| System.().Create(T1, T2, T3, T4) | argument 3 -> field Item4 of return (normal) | true | +| System.().Create(T1, T2, T3) | argument 0 -> field Item1 of return (normal) | true | +| System.().Create(T1, T2, T3) | argument 1 -> field Item2 of return (normal) | true | +| System.().Create(T1, T2, T3) | argument 2 -> field Item3 of return (normal) | true | +| System.().Create(T1, T2) | argument 0 -> field Item1 of return (normal) | true | +| System.().Create(T1, T2) | argument 1 -> field Item2 of return (normal) | true | +| System.().Create(T1) | argument 0 -> field Item1 of return (normal) | true | +| System.(T1).ValueTuple(T1) | argument 0 -> field Item1 of return (normal) | true | +| System.(T1).get_Item(int) | field Item1 of argument -1 -> return (normal) | true | +| System.(T1,T2).ValueTuple(T1, T2) | argument 0 -> field Item1 of return (normal) | true | +| System.(T1,T2).ValueTuple(T1, T2) | argument 1 -> field Item2 of return (normal) | true | +| System.(T1,T2).get_Item(int) | field Item1 of argument -1 -> return (normal) | true | +| System.(T1,T2).get_Item(int) | field Item2 of argument -1 -> return (normal) | true | +| System.(T1,T2,T3).ValueTuple(T1, T2, T3) | argument 0 -> field Item1 of return (normal) | true | +| System.(T1,T2,T3).ValueTuple(T1, T2, T3) | argument 1 -> field Item2 of return (normal) | true | +| System.(T1,T2,T3).ValueTuple(T1, T2, T3) | argument 2 -> field Item3 of return (normal) | true | +| System.(T1,T2,T3).get_Item(int) | field Item1 of argument -1 -> return (normal) | true | +| System.(T1,T2,T3).get_Item(int) | field Item2 of argument -1 -> return (normal) | true | +| System.(T1,T2,T3).get_Item(int) | field Item3 of argument -1 -> return (normal) | true | +| System.(T1,T2,T3,T4).ValueTuple(T1, T2, T3, T4) | argument 0 -> field Item1 of return (normal) | true | +| System.(T1,T2,T3,T4).ValueTuple(T1, T2, T3, T4) | argument 1 -> field Item2 of return (normal) | true | +| System.(T1,T2,T3,T4).ValueTuple(T1, T2, T3, T4) | argument 2 -> field Item3 of return (normal) | true | +| System.(T1,T2,T3,T4).ValueTuple(T1, T2, T3, T4) | argument 3 -> field Item4 of return (normal) | true | +| System.(T1,T2,T3,T4).get_Item(int) | field Item1 of argument -1 -> return (normal) | true | +| System.(T1,T2,T3,T4).get_Item(int) | field Item2 of argument -1 -> return (normal) | true | +| System.(T1,T2,T3,T4).get_Item(int) | field Item3 of argument -1 -> return (normal) | true | +| System.(T1,T2,T3,T4).get_Item(int) | field Item4 of argument -1 -> return (normal) | true | +| System.(T1,T2,T3,T4,T5).ValueTuple(T1, T2, T3, T4, T5) | argument 0 -> field Item1 of return (normal) | true | +| System.(T1,T2,T3,T4,T5).ValueTuple(T1, T2, T3, T4, T5) | argument 1 -> field Item2 of return (normal) | true | +| System.(T1,T2,T3,T4,T5).ValueTuple(T1, T2, T3, T4, T5) | argument 2 -> field Item3 of return (normal) | true | +| System.(T1,T2,T3,T4,T5).ValueTuple(T1, T2, T3, T4, T5) | argument 3 -> field Item4 of return (normal) | true | +| System.(T1,T2,T3,T4,T5).ValueTuple(T1, T2, T3, T4, T5) | argument 4 -> field Item5 of return (normal) | true | +| System.(T1,T2,T3,T4,T5).get_Item(int) | field Item1 of argument -1 -> return (normal) | true | +| System.(T1,T2,T3,T4,T5).get_Item(int) | field Item2 of argument -1 -> return (normal) | true | +| System.(T1,T2,T3,T4,T5).get_Item(int) | field Item3 of argument -1 -> return (normal) | true | +| System.(T1,T2,T3,T4,T5).get_Item(int) | field Item4 of argument -1 -> return (normal) | true | +| System.(T1,T2,T3,T4,T5).get_Item(int) | field Item5 of argument -1 -> return (normal) | true | +| System.(T1,T2,T3,T4,T5,T6).ValueTuple(T1, T2, T3, T4, T5, T6) | argument 0 -> field Item1 of return (normal) | true | +| System.(T1,T2,T3,T4,T5,T6).ValueTuple(T1, T2, T3, T4, T5, T6) | argument 1 -> field Item2 of return (normal) | true | +| System.(T1,T2,T3,T4,T5,T6).ValueTuple(T1, T2, T3, T4, T5, T6) | argument 2 -> field Item3 of return (normal) | true | +| System.(T1,T2,T3,T4,T5,T6).ValueTuple(T1, T2, T3, T4, T5, T6) | argument 3 -> field Item4 of return (normal) | true | +| System.(T1,T2,T3,T4,T5,T6).ValueTuple(T1, T2, T3, T4, T5, T6) | argument 4 -> field Item5 of return (normal) | true | +| System.(T1,T2,T3,T4,T5,T6).ValueTuple(T1, T2, T3, T4, T5, T6) | argument 5 -> field Item6 of return (normal) | true | +| System.(T1,T2,T3,T4,T5,T6).get_Item(int) | field Item1 of argument -1 -> return (normal) | true | +| System.(T1,T2,T3,T4,T5,T6).get_Item(int) | field Item2 of argument -1 -> return (normal) | true | +| System.(T1,T2,T3,T4,T5,T6).get_Item(int) | field Item3 of argument -1 -> return (normal) | true | +| System.(T1,T2,T3,T4,T5,T6).get_Item(int) | field Item4 of argument -1 -> return (normal) | true | +| System.(T1,T2,T3,T4,T5,T6).get_Item(int) | field Item5 of argument -1 -> return (normal) | true | +| System.(T1,T2,T3,T4,T5,T6).get_Item(int) | field Item6 of argument -1 -> return (normal) | true | +| System.(T1,T2,T3,T4,T5,T6,T7).ValueTuple(T1, T2, T3, T4, T5, T6, T7) | argument 0 -> field Item1 of return (normal) | true | +| System.(T1,T2,T3,T4,T5,T6,T7).ValueTuple(T1, T2, T3, T4, T5, T6, T7) | argument 1 -> field Item2 of return (normal) | true | +| System.(T1,T2,T3,T4,T5,T6,T7).ValueTuple(T1, T2, T3, T4, T5, T6, T7) | argument 2 -> field Item3 of return (normal) | true | +| System.(T1,T2,T3,T4,T5,T6,T7).ValueTuple(T1, T2, T3, T4, T5, T6, T7) | argument 3 -> field Item4 of return (normal) | true | +| System.(T1,T2,T3,T4,T5,T6,T7).ValueTuple(T1, T2, T3, T4, T5, T6, T7) | argument 4 -> field Item5 of return (normal) | true | +| System.(T1,T2,T3,T4,T5,T6,T7).ValueTuple(T1, T2, T3, T4, T5, T6, T7) | argument 5 -> field Item6 of return (normal) | true | +| System.(T1,T2,T3,T4,T5,T6,T7).ValueTuple(T1, T2, T3, T4, T5, T6, T7) | argument 6 -> field Item7 of return (normal) | true | +| System.(T1,T2,T3,T4,T5,T6,T7).get_Item(int) | field Item1 of argument -1 -> return (normal) | true | +| System.(T1,T2,T3,T4,T5,T6,T7).get_Item(int) | field Item2 of argument -1 -> return (normal) | true | +| System.(T1,T2,T3,T4,T5,T6,T7).get_Item(int) | field Item3 of argument -1 -> return (normal) | true | +| System.(T1,T2,T3,T4,T5,T6,T7).get_Item(int) | field Item4 of argument -1 -> return (normal) | true | +| System.(T1,T2,T3,T4,T5,T6,T7).get_Item(int) | field Item5 of argument -1 -> return (normal) | true | +| System.(T1,T2,T3,T4,T5,T6,T7).get_Item(int) | field Item6 of argument -1 -> return (normal) | true | +| System.(T1,T2,T3,T4,T5,T6,T7).get_Item(int) | field Item7 of argument -1 -> return (normal) | true | +| System.Array.Add(object) | argument 0 -> element of argument -1 | true | +| System.Array.AsReadOnly(T[]) | element of argument 0 -> element of return (normal) | true | +| System.Array.Clone() | element of argument 0 -> element of return (normal) | true | +| System.Array.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Array.CopyTo(Array, long) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Array.Find(T[], Predicate) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Array.Find(T[], Predicate) | element of argument 0 -> return (normal) | true | +| System.Array.FindAll(T[], Predicate) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Array.FindAll(T[], Predicate) | element of argument 0 -> return (normal) | true | +| System.Array.FindLast(T[], Predicate) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Array.FindLast(T[], Predicate) | element of argument 0 -> return (normal) | true | +| System.Array.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Array.Insert(int, object) | argument 1 -> element of argument -1 | true | +| System.Array.Reverse(Array) | element of argument 0 -> element of return (normal) | true | +| System.Array.Reverse(Array, int, int) | element of argument 0 -> element of return (normal) | true | +| System.Array.Reverse(T[]) | element of argument 0 -> element of return (normal) | true | +| System.Array.Reverse(T[], int, int) | element of argument 0 -> element of return (normal) | true | +| System.Array.get_Item(int) | element of argument -1 -> return (normal) | true | +| System.Array.set_Item(int, object) | argument 1 -> element of argument -1 | true | +| System.Boolean.Parse(string) | argument 0 -> return (normal) | false | +| System.Boolean.TryParse(string, out bool) | argument 0 -> return (normal) | false | +| System.Boolean.TryParse(string, out bool) | argument 0 -> return (out parameter 1) | false | +| System.Collections.ArrayList.Add(object) | argument 0 -> element of argument -1 | true | +| System.Collections.ArrayList.AddRange(ICollection) | element of argument 0 -> element of argument -1 | true | +| System.Collections.ArrayList.Clone() | element of argument 0 -> element of return (normal) | true | +| System.Collections.ArrayList.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.ArrayList.FixedSize(ArrayList) | element of argument 0 -> element of return (normal) | true | +| System.Collections.ArrayList.FixedSize(IList) | element of argument 0 -> element of return (normal) | true | +| System.Collections.ArrayList.FixedSizeArrayList.Add(object) | argument 0 -> element of argument -1 | true | +| System.Collections.ArrayList.FixedSizeArrayList.AddRange(ICollection) | element of argument 0 -> element of argument -1 | true | +| System.Collections.ArrayList.FixedSizeArrayList.Clone() | element of argument 0 -> element of return (normal) | true | +| System.Collections.ArrayList.FixedSizeArrayList.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.ArrayList.FixedSizeArrayList.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.ArrayList.FixedSizeArrayList.GetEnumerator(int, int) | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.ArrayList.FixedSizeArrayList.GetRange(int, int) | element of argument 0 -> element of return (normal) | true | +| System.Collections.ArrayList.FixedSizeArrayList.Insert(int, object) | argument 1 -> element of argument -1 | true | +| System.Collections.ArrayList.FixedSizeArrayList.InsertRange(int, ICollection) | element of argument 1 -> element of argument -1 | true | +| System.Collections.ArrayList.FixedSizeArrayList.Reverse(int, int) | element of argument 0 -> element of return (normal) | true | +| System.Collections.ArrayList.FixedSizeArrayList.get_Item(int) | element of argument -1 -> return (normal) | true | +| System.Collections.ArrayList.FixedSizeArrayList.set_Item(int, object) | argument 1 -> element of argument -1 | true | +| System.Collections.ArrayList.FixedSizeList.Add(object) | argument 0 -> element of argument -1 | true | +| System.Collections.ArrayList.FixedSizeList.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.ArrayList.FixedSizeList.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.ArrayList.FixedSizeList.Insert(int, object) | argument 1 -> element of argument -1 | true | +| System.Collections.ArrayList.FixedSizeList.get_Item(int) | element of argument -1 -> return (normal) | true | +| System.Collections.ArrayList.FixedSizeList.set_Item(int, object) | argument 1 -> element of argument -1 | true | +| System.Collections.ArrayList.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.ArrayList.GetEnumerator(int, int) | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.ArrayList.GetRange(int, int) | element of argument 0 -> element of return (normal) | true | +| System.Collections.ArrayList.IListWrapper.Add(object) | argument 0 -> element of argument -1 | true | +| System.Collections.ArrayList.IListWrapper.AddRange(ICollection) | element of argument 0 -> element of argument -1 | true | +| System.Collections.ArrayList.IListWrapper.Clone() | element of argument 0 -> element of return (normal) | true | +| System.Collections.ArrayList.IListWrapper.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.ArrayList.IListWrapper.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.ArrayList.IListWrapper.GetEnumerator(int, int) | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.ArrayList.IListWrapper.GetRange(int, int) | element of argument 0 -> element of return (normal) | true | +| System.Collections.ArrayList.IListWrapper.Insert(int, object) | argument 1 -> element of argument -1 | true | +| System.Collections.ArrayList.IListWrapper.InsertRange(int, ICollection) | element of argument 1 -> element of argument -1 | true | +| System.Collections.ArrayList.IListWrapper.Reverse(int, int) | element of argument 0 -> element of return (normal) | true | +| System.Collections.ArrayList.IListWrapper.get_Item(int) | element of argument -1 -> return (normal) | true | +| System.Collections.ArrayList.IListWrapper.set_Item(int, object) | argument 1 -> element of argument -1 | true | +| System.Collections.ArrayList.Insert(int, object) | argument 1 -> element of argument -1 | true | +| System.Collections.ArrayList.InsertRange(int, ICollection) | element of argument 1 -> element of argument -1 | true | +| System.Collections.ArrayList.Range.Add(object) | argument 0 -> element of argument -1 | true | +| System.Collections.ArrayList.Range.AddRange(ICollection) | element of argument 0 -> element of argument -1 | true | +| System.Collections.ArrayList.Range.Clone() | element of argument 0 -> element of return (normal) | true | +| System.Collections.ArrayList.Range.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.ArrayList.Range.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.ArrayList.Range.GetEnumerator(int, int) | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.ArrayList.Range.GetRange(int, int) | element of argument 0 -> element of return (normal) | true | +| System.Collections.ArrayList.Range.Insert(int, object) | argument 1 -> element of argument -1 | true | +| System.Collections.ArrayList.Range.InsertRange(int, ICollection) | element of argument 1 -> element of argument -1 | true | +| System.Collections.ArrayList.Range.Reverse(int, int) | element of argument 0 -> element of return (normal) | true | +| System.Collections.ArrayList.Range.get_Item(int) | element of argument -1 -> return (normal) | true | +| System.Collections.ArrayList.Range.set_Item(int, object) | argument 1 -> element of argument -1 | true | +| System.Collections.ArrayList.ReadOnlyArrayList.Add(object) | argument 0 -> element of argument -1 | true | +| System.Collections.ArrayList.ReadOnlyArrayList.AddRange(ICollection) | element of argument 0 -> element of argument -1 | true | +| System.Collections.ArrayList.ReadOnlyArrayList.Clone() | element of argument 0 -> element of return (normal) | true | +| System.Collections.ArrayList.ReadOnlyArrayList.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.ArrayList.ReadOnlyArrayList.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.ArrayList.ReadOnlyArrayList.GetEnumerator(int, int) | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.ArrayList.ReadOnlyArrayList.GetRange(int, int) | element of argument 0 -> element of return (normal) | true | +| System.Collections.ArrayList.ReadOnlyArrayList.Insert(int, object) | argument 1 -> element of argument -1 | true | +| System.Collections.ArrayList.ReadOnlyArrayList.InsertRange(int, ICollection) | element of argument 1 -> element of argument -1 | true | +| System.Collections.ArrayList.ReadOnlyArrayList.Reverse(int, int) | element of argument 0 -> element of return (normal) | true | +| System.Collections.ArrayList.ReadOnlyArrayList.get_Item(int) | element of argument -1 -> return (normal) | true | +| System.Collections.ArrayList.ReadOnlyArrayList.set_Item(int, object) | argument 1 -> element of argument -1 | true | +| System.Collections.ArrayList.ReadOnlyList.Add(object) | argument 0 -> element of argument -1 | true | +| System.Collections.ArrayList.ReadOnlyList.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.ArrayList.ReadOnlyList.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.ArrayList.ReadOnlyList.Insert(int, object) | argument 1 -> element of argument -1 | true | +| System.Collections.ArrayList.ReadOnlyList.get_Item(int) | element of argument -1 -> return (normal) | true | +| System.Collections.ArrayList.ReadOnlyList.set_Item(int, object) | argument 1 -> element of argument -1 | true | +| System.Collections.ArrayList.Repeat(object, int) | argument 0 -> element of return (normal) | true | +| System.Collections.ArrayList.Reverse() | element of argument 0 -> element of return (normal) | true | +| System.Collections.ArrayList.Reverse(int, int) | element of argument 0 -> element of return (normal) | true | +| System.Collections.ArrayList.SyncArrayList.Add(object) | argument 0 -> element of argument -1 | true | +| System.Collections.ArrayList.SyncArrayList.AddRange(ICollection) | element of argument 0 -> element of argument -1 | true | +| System.Collections.ArrayList.SyncArrayList.Clone() | element of argument 0 -> element of return (normal) | true | +| System.Collections.ArrayList.SyncArrayList.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.ArrayList.SyncArrayList.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.ArrayList.SyncArrayList.GetEnumerator(int, int) | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.ArrayList.SyncArrayList.GetRange(int, int) | element of argument 0 -> element of return (normal) | true | +| System.Collections.ArrayList.SyncArrayList.Insert(int, object) | argument 1 -> element of argument -1 | true | +| System.Collections.ArrayList.SyncArrayList.InsertRange(int, ICollection) | element of argument 1 -> element of argument -1 | true | +| System.Collections.ArrayList.SyncArrayList.Reverse(int, int) | element of argument 0 -> element of return (normal) | true | +| System.Collections.ArrayList.SyncArrayList.get_Item(int) | element of argument -1 -> return (normal) | true | +| System.Collections.ArrayList.SyncArrayList.set_Item(int, object) | argument 1 -> element of argument -1 | true | +| System.Collections.ArrayList.SyncIList.Add(object) | argument 0 -> element of argument -1 | true | +| System.Collections.ArrayList.SyncIList.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.ArrayList.SyncIList.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.ArrayList.SyncIList.Insert(int, object) | argument 1 -> element of argument -1 | true | +| System.Collections.ArrayList.SyncIList.get_Item(int) | element of argument -1 -> return (normal) | true | +| System.Collections.ArrayList.SyncIList.set_Item(int, object) | argument 1 -> element of argument -1 | true | +| System.Collections.ArrayList.get_Item(int) | element of argument -1 -> return (normal) | true | +| System.Collections.ArrayList.set_Item(int, object) | argument 1 -> element of argument -1 | true | +| System.Collections.BitArray.Clone() | element of argument 0 -> element of return (normal) | true | +| System.Collections.BitArray.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.BitArray.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.CollectionBase.Add(object) | argument 0 -> element of argument -1 | true | +| System.Collections.CollectionBase.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.CollectionBase.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.CollectionBase.Insert(int, object) | argument 1 -> element of argument -1 | true | +| System.Collections.CollectionBase.get_Item(int) | element of argument -1 -> return (normal) | true | +| System.Collections.CollectionBase.set_Item(int, object) | argument 1 -> element of argument -1 | true | +| System.Collections.Concurrent.BlockingCollection<>.d__68.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Concurrent.BlockingCollection<>.Add(T) | argument 0 -> element of argument -1 | true | +| System.Collections.Concurrent.BlockingCollection<>.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Concurrent.BlockingCollection<>.CopyTo(T[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Concurrent.BlockingCollection<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Concurrent.ConcurrentBag<>.Add(T) | argument 0 -> element of argument -1 | true | +| System.Collections.Concurrent.ConcurrentBag<>.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Concurrent.ConcurrentBag<>.CopyTo(T[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Concurrent.ConcurrentBag<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(KeyValuePair) | argument 0 -> element of argument -1 | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(KeyValuePair) | property Key of argument 0 -> property Key of element of argument -1 | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(KeyValuePair) | property Value of argument 0 -> property Value of element of argument -1 | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(TKey, TValue) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(TKey, TValue) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(object, object) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(object, object) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(IEnumerable>) | property Key of element of argument 0 -> property Key of element of return (normal) | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(IEnumerable>) | property Value of element of argument 0 -> property Value of element of return (normal) | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(IEnumerable>, IEqualityComparer) | property Key of element of argument 0 -> property Key of element of return (normal) | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(IEnumerable>, IEqualityComparer) | property Value of element of argument 0 -> property Value of element of return (normal) | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(int, IEnumerable>, IEqualityComparer) | property Key of element of argument 1 -> property Key of element of return (normal) | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(int, IEnumerable>, IEqualityComparer) | property Value of element of argument 1 -> property Value of element of return (normal) | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.CopyTo(KeyValuePair[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.get_Item(TKey) | property Value of element of argument -1 -> return (normal) | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.get_Item(object) | property Value of element of argument -1 -> return (normal) | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.get_Keys() | property Key of element of argument -1 -> element of return (normal) | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.get_Values() | property Value of element of argument -1 -> element of return (normal) | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.set_Item(TKey, TValue) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.set_Item(TKey, TValue) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.set_Item(object, object) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.set_Item(object, object) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.Concurrent.ConcurrentQueue<>.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Concurrent.ConcurrentQueue<>.CopyTo(T[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Concurrent.ConcurrentQueue<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Concurrent.ConcurrentStack<>.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Concurrent.ConcurrentStack<>.CopyTo(T[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Concurrent.ConcurrentStack<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Concurrent.IProducerConsumerCollection<>.CopyTo(T[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Concurrent.OrderablePartitioner<>.EnumerableDropIndices.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Concurrent.Partitioner.d__7.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Concurrent.Partitioner.d__10.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Concurrent.Partitioner.DynamicPartitionerForArray<>.InternalPartitionEnumerable.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Concurrent.Partitioner.DynamicPartitionerForIEnumerable<>.InternalPartitionEnumerable.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Concurrent.Partitioner.DynamicPartitionerForIList<>.InternalPartitionEnumerable.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.DictionaryBase.Add(object, object) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.DictionaryBase.Add(object, object) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.DictionaryBase.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.DictionaryBase.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.DictionaryBase.get_Item(object) | property Value of element of argument -1 -> return (normal) | true | +| System.Collections.DictionaryBase.get_Keys() | property Key of element of argument -1 -> element of return (normal) | true | +| System.Collections.DictionaryBase.get_Values() | property Value of element of argument -1 -> element of return (normal) | true | +| System.Collections.DictionaryBase.set_Item(object, object) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.DictionaryBase.set_Item(object, object) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.EmptyReadOnlyDictionaryInternal.Add(object, object) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.EmptyReadOnlyDictionaryInternal.Add(object, object) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.EmptyReadOnlyDictionaryInternal.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.EmptyReadOnlyDictionaryInternal.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.EmptyReadOnlyDictionaryInternal.get_Item(object) | property Value of element of argument -1 -> return (normal) | true | +| System.Collections.EmptyReadOnlyDictionaryInternal.get_Keys() | property Key of element of argument -1 -> element of return (normal) | true | +| System.Collections.EmptyReadOnlyDictionaryInternal.get_Values() | property Value of element of argument -1 -> element of return (normal) | true | +| System.Collections.EmptyReadOnlyDictionaryInternal.set_Item(object, object) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.EmptyReadOnlyDictionaryInternal.set_Item(object, object) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.Generic.Dictionary<,>.Add(KeyValuePair) | argument 0 -> element of argument -1 | true | +| System.Collections.Generic.Dictionary<,>.Add(KeyValuePair) | property Key of argument 0 -> property Key of element of argument -1 | true | +| System.Collections.Generic.Dictionary<,>.Add(KeyValuePair) | property Value of argument 0 -> property Value of element of argument -1 | true | +| System.Collections.Generic.Dictionary<,>.Add(TKey, TValue) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.Generic.Dictionary<,>.Add(TKey, TValue) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.Generic.Dictionary<,>.Add(object, object) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.Generic.Dictionary<,>.Add(object, object) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.Generic.Dictionary<,>.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Generic.Dictionary<,>.CopyTo(KeyValuePair[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IDictionary) | property Key of element of argument 0 -> property Key of element of return (normal) | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IDictionary) | property Value of element of argument 0 -> property Value of element of return (normal) | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IDictionary, IEqualityComparer) | property Key of element of argument 0 -> property Key of element of return (normal) | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IDictionary, IEqualityComparer) | property Value of element of argument 0 -> property Value of element of return (normal) | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IEnumerable>) | property Key of element of argument 0 -> property Key of element of return (normal) | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IEnumerable>) | property Value of element of argument 0 -> property Value of element of return (normal) | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IEnumerable>, IEqualityComparer) | property Key of element of argument 0 -> property Key of element of return (normal) | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IEnumerable>, IEqualityComparer) | property Value of element of argument 0 -> property Value of element of return (normal) | true | +| System.Collections.Generic.Dictionary<,>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Generic.Dictionary<,>.KeyCollection.Add(TKey) | argument 0 -> element of argument -1 | true | +| System.Collections.Generic.Dictionary<,>.KeyCollection.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Generic.Dictionary<,>.KeyCollection.CopyTo(TKey[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Generic.Dictionary<,>.KeyCollection.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Generic.Dictionary<,>.ValueCollection.Add(TValue) | argument 0 -> element of argument -1 | true | +| System.Collections.Generic.Dictionary<,>.ValueCollection.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Generic.Dictionary<,>.ValueCollection.CopyTo(TValue[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Generic.Dictionary<,>.ValueCollection.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Generic.Dictionary<,>.get_Item(TKey) | property Value of element of argument -1 -> return (normal) | true | +| System.Collections.Generic.Dictionary<,>.get_Item(object) | property Value of element of argument -1 -> return (normal) | true | +| System.Collections.Generic.Dictionary<,>.get_Keys() | property Key of element of argument -1 -> element of return (normal) | true | +| System.Collections.Generic.Dictionary<,>.get_Values() | property Value of element of argument -1 -> element of return (normal) | true | +| System.Collections.Generic.Dictionary<,>.set_Item(TKey, TValue) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.Generic.Dictionary<,>.set_Item(TKey, TValue) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.Generic.Dictionary<,>.set_Item(object, object) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.Generic.Dictionary<,>.set_Item(object, object) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.Generic.HashSet<>.Add(T) | argument 0 -> element of argument -1 | true | +| System.Collections.Generic.HashSet<>.CopyTo(T[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Generic.HashSet<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Generic.ICollection<>.Add(T) | argument 0 -> element of argument -1 | true | +| System.Collections.Generic.ICollection<>.CopyTo(T[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Generic.IDictionary<,>.Add(TKey, TValue) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.Generic.IDictionary<,>.Add(TKey, TValue) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.Generic.IDictionary<,>.get_Item(TKey) | property Value of element of argument -1 -> return (normal) | true | +| System.Collections.Generic.IDictionary<,>.get_Keys() | property Key of element of argument -1 -> element of return (normal) | true | +| System.Collections.Generic.IDictionary<,>.get_Values() | property Value of element of argument -1 -> element of return (normal) | true | +| System.Collections.Generic.IDictionary<,>.set_Item(TKey, TValue) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.Generic.IDictionary<,>.set_Item(TKey, TValue) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.Generic.IList<>.Insert(int, T) | argument 1 -> element of argument -1 | true | +| System.Collections.Generic.IList<>.get_Item(int) | element of argument -1 -> return (normal) | true | +| System.Collections.Generic.IList<>.set_Item(int, T) | argument 1 -> element of argument -1 | true | +| System.Collections.Generic.ISet<>.Add(T) | argument 0 -> element of argument -1 | true | +| System.Collections.Generic.KeyValuePair<,>.KeyValuePair() | argument 0 -> property Key of return (normal) | true | +| System.Collections.Generic.KeyValuePair<,>.KeyValuePair() | argument 1 -> property Value of return (normal) | true | +| System.Collections.Generic.KeyValuePair<,>.KeyValuePair(TKey, TValue) | argument 0 -> property Key of return (normal) | true | +| System.Collections.Generic.KeyValuePair<,>.KeyValuePair(TKey, TValue) | argument 1 -> property Value of return (normal) | true | +| System.Collections.Generic.LinkedList<>.Add(T) | argument 0 -> element of argument -1 | true | +| System.Collections.Generic.LinkedList<>.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Generic.LinkedList<>.CopyTo(T[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Generic.LinkedList<>.Find(T) | element of argument -1 -> return (normal) | true | +| System.Collections.Generic.LinkedList<>.FindLast(T) | element of argument -1 -> return (normal) | true | +| System.Collections.Generic.LinkedList<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Generic.List<>.Add(T) | argument 0 -> element of argument -1 | true | +| System.Collections.Generic.List<>.Add(object) | argument 0 -> element of argument -1 | true | +| System.Collections.Generic.List<>.AddRange(IEnumerable) | element of argument 0 -> element of argument -1 | true | +| System.Collections.Generic.List<>.AsReadOnly() | element of argument 0 -> element of return (normal) | true | +| System.Collections.Generic.List<>.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Generic.List<>.CopyTo(T[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Generic.List<>.Find(Predicate) | element of argument -1 -> parameter 0 of argument 0 | true | +| System.Collections.Generic.List<>.Find(Predicate) | element of argument -1 -> return (normal) | true | +| System.Collections.Generic.List<>.FindAll(Predicate) | element of argument -1 -> parameter 0 of argument 0 | true | +| System.Collections.Generic.List<>.FindAll(Predicate) | element of argument -1 -> return (normal) | true | +| System.Collections.Generic.List<>.FindLast(Predicate) | element of argument -1 -> parameter 0 of argument 0 | true | +| System.Collections.Generic.List<>.FindLast(Predicate) | element of argument -1 -> return (normal) | true | +| System.Collections.Generic.List<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Generic.List<>.GetRange(int, int) | element of argument 0 -> element of return (normal) | true | +| System.Collections.Generic.List<>.Insert(int, T) | argument 1 -> element of argument -1 | true | +| System.Collections.Generic.List<>.Insert(int, object) | argument 1 -> element of argument -1 | true | +| System.Collections.Generic.List<>.InsertRange(int, IEnumerable) | element of argument 1 -> element of argument -1 | true | +| System.Collections.Generic.List<>.Reverse() | element of argument 0 -> element of return (normal) | true | +| System.Collections.Generic.List<>.Reverse(int, int) | element of argument 0 -> element of return (normal) | true | +| System.Collections.Generic.List<>.get_Item(int) | element of argument -1 -> return (normal) | true | +| System.Collections.Generic.List<>.set_Item(int, T) | argument 1 -> element of argument -1 | true | +| System.Collections.Generic.List<>.set_Item(int, object) | argument 1 -> element of argument -1 | true | +| System.Collections.Generic.Queue<>.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Generic.Queue<>.CopyTo(T[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Generic.Queue<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Generic.Queue<>.Peek() | element of argument -1 -> return (normal) | true | +| System.Collections.Generic.SortedDictionary<,>.Add(KeyValuePair) | argument 0 -> element of argument -1 | true | +| System.Collections.Generic.SortedDictionary<,>.Add(KeyValuePair) | property Key of argument 0 -> property Key of element of argument -1 | true | +| System.Collections.Generic.SortedDictionary<,>.Add(KeyValuePair) | property Value of argument 0 -> property Value of element of argument -1 | true | +| System.Collections.Generic.SortedDictionary<,>.Add(TKey, TValue) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.Generic.SortedDictionary<,>.Add(TKey, TValue) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.Generic.SortedDictionary<,>.Add(object, object) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.Generic.SortedDictionary<,>.Add(object, object) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.Generic.SortedDictionary<,>.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Generic.SortedDictionary<,>.CopyTo(KeyValuePair[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Generic.SortedDictionary<,>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Generic.SortedDictionary<,>.KeyCollection.Add(TKey) | argument 0 -> element of argument -1 | true | +| System.Collections.Generic.SortedDictionary<,>.KeyCollection.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Generic.SortedDictionary<,>.KeyCollection.CopyTo(TKey[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Generic.SortedDictionary<,>.KeyCollection.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Generic.SortedDictionary<,>.SortedDictionary(IDictionary) | property Key of element of argument 0 -> property Key of element of return (normal) | true | +| System.Collections.Generic.SortedDictionary<,>.SortedDictionary(IDictionary) | property Value of element of argument 0 -> property Value of element of return (normal) | true | +| System.Collections.Generic.SortedDictionary<,>.SortedDictionary(IDictionary, IComparer) | property Key of element of argument 0 -> property Key of element of return (normal) | true | +| System.Collections.Generic.SortedDictionary<,>.SortedDictionary(IDictionary, IComparer) | property Value of element of argument 0 -> property Value of element of return (normal) | true | +| System.Collections.Generic.SortedDictionary<,>.ValueCollection.Add(TValue) | argument 0 -> element of argument -1 | true | +| System.Collections.Generic.SortedDictionary<,>.ValueCollection.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Generic.SortedDictionary<,>.ValueCollection.CopyTo(TValue[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Generic.SortedDictionary<,>.ValueCollection.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Generic.SortedDictionary<,>.get_Item(TKey) | property Value of element of argument -1 -> return (normal) | true | +| System.Collections.Generic.SortedDictionary<,>.get_Item(object) | property Value of element of argument -1 -> return (normal) | true | +| System.Collections.Generic.SortedDictionary<,>.get_Keys() | property Key of element of argument -1 -> element of return (normal) | true | +| System.Collections.Generic.SortedDictionary<,>.get_Values() | property Value of element of argument -1 -> element of return (normal) | true | +| System.Collections.Generic.SortedDictionary<,>.set_Item(TKey, TValue) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.Generic.SortedDictionary<,>.set_Item(TKey, TValue) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.Generic.SortedDictionary<,>.set_Item(object, object) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.Generic.SortedDictionary<,>.set_Item(object, object) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.Generic.SortedList<,>.Add(KeyValuePair) | argument 0 -> element of argument -1 | true | +| System.Collections.Generic.SortedList<,>.Add(KeyValuePair) | property Key of argument 0 -> property Key of element of argument -1 | true | +| System.Collections.Generic.SortedList<,>.Add(KeyValuePair) | property Value of argument 0 -> property Value of element of argument -1 | true | +| System.Collections.Generic.SortedList<,>.Add(TKey, TValue) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.Generic.SortedList<,>.Add(TKey, TValue) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.Generic.SortedList<,>.Add(object, object) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.Generic.SortedList<,>.Add(object, object) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.Generic.SortedList<,>.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Generic.SortedList<,>.CopyTo(KeyValuePair[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Generic.SortedList<,>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Generic.SortedList<,>.KeyList.Add(TKey) | argument 0 -> element of argument -1 | true | +| System.Collections.Generic.SortedList<,>.KeyList.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Generic.SortedList<,>.KeyList.CopyTo(TKey[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Generic.SortedList<,>.KeyList.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Generic.SortedList<,>.KeyList.Insert(int, TKey) | argument 1 -> element of argument -1 | true | +| System.Collections.Generic.SortedList<,>.KeyList.get_Item(int) | element of argument -1 -> return (normal) | true | +| System.Collections.Generic.SortedList<,>.KeyList.set_Item(int, TKey) | argument 1 -> element of argument -1 | true | +| System.Collections.Generic.SortedList<,>.SortedList(IDictionary) | property Key of element of argument 0 -> property Key of element of return (normal) | true | +| System.Collections.Generic.SortedList<,>.SortedList(IDictionary) | property Value of element of argument 0 -> property Value of element of return (normal) | true | +| System.Collections.Generic.SortedList<,>.SortedList(IDictionary, IComparer) | property Key of element of argument 0 -> property Key of element of return (normal) | true | +| System.Collections.Generic.SortedList<,>.SortedList(IDictionary, IComparer) | property Value of element of argument 0 -> property Value of element of return (normal) | true | +| System.Collections.Generic.SortedList<,>.ValueList.Add(TValue) | argument 0 -> element of argument -1 | true | +| System.Collections.Generic.SortedList<,>.ValueList.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Generic.SortedList<,>.ValueList.CopyTo(TValue[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Generic.SortedList<,>.ValueList.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Generic.SortedList<,>.ValueList.Insert(int, TValue) | argument 1 -> element of argument -1 | true | +| System.Collections.Generic.SortedList<,>.ValueList.get_Item(int) | element of argument -1 -> return (normal) | true | +| System.Collections.Generic.SortedList<,>.ValueList.set_Item(int, TValue) | argument 1 -> element of argument -1 | true | +| System.Collections.Generic.SortedList<,>.get_Item(TKey) | property Value of element of argument -1 -> return (normal) | true | +| System.Collections.Generic.SortedList<,>.get_Item(object) | property Value of element of argument -1 -> return (normal) | true | +| System.Collections.Generic.SortedList<,>.get_Keys() | property Key of element of argument -1 -> element of return (normal) | true | +| System.Collections.Generic.SortedList<,>.get_Values() | property Value of element of argument -1 -> element of return (normal) | true | +| System.Collections.Generic.SortedList<,>.set_Item(TKey, TValue) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.Generic.SortedList<,>.set_Item(TKey, TValue) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.Generic.SortedList<,>.set_Item(object, object) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.Generic.SortedList<,>.set_Item(object, object) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.Generic.SortedSet<>.d__84.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Generic.SortedSet<>.Add(T) | argument 0 -> element of argument -1 | true | +| System.Collections.Generic.SortedSet<>.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Generic.SortedSet<>.CopyTo(T[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Generic.SortedSet<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Generic.SortedSet<>.Reverse() | element of argument 0 -> element of return (normal) | true | +| System.Collections.Generic.Stack<>.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Generic.Stack<>.CopyTo(T[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Generic.Stack<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Generic.Stack<>.Peek() | element of argument -1 -> return (normal) | true | +| System.Collections.Generic.Stack<>.Pop() | element of argument -1 -> return (normal) | true | +| System.Collections.Hashtable.Add(object, object) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.Hashtable.Add(object, object) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.Hashtable.Clone() | element of argument 0 -> element of return (normal) | true | +| System.Collections.Hashtable.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Hashtable.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Hashtable.Hashtable(IDictionary) | property Key of element of argument 0 -> property Key of element of return (normal) | true | +| System.Collections.Hashtable.Hashtable(IDictionary) | property Value of element of argument 0 -> property Value of element of return (normal) | true | +| System.Collections.Hashtable.Hashtable(IDictionary, IEqualityComparer) | property Key of element of argument 0 -> property Key of element of return (normal) | true | +| System.Collections.Hashtable.Hashtable(IDictionary, IEqualityComparer) | property Value of element of argument 0 -> property Value of element of return (normal) | true | +| System.Collections.Hashtable.Hashtable(IDictionary, IHashCodeProvider, IComparer) | property Key of element of argument 0 -> property Key of element of return (normal) | true | +| System.Collections.Hashtable.Hashtable(IDictionary, IHashCodeProvider, IComparer) | property Value of element of argument 0 -> property Value of element of return (normal) | true | +| System.Collections.Hashtable.Hashtable(IDictionary, float) | property Key of element of argument 0 -> property Key of element of return (normal) | true | +| System.Collections.Hashtable.Hashtable(IDictionary, float) | property Value of element of argument 0 -> property Value of element of return (normal) | true | +| System.Collections.Hashtable.Hashtable(IDictionary, float, IEqualityComparer) | property Key of element of argument 0 -> property Key of element of return (normal) | true | +| System.Collections.Hashtable.Hashtable(IDictionary, float, IEqualityComparer) | property Value of element of argument 0 -> property Value of element of return (normal) | true | +| System.Collections.Hashtable.Hashtable(IDictionary, float, IHashCodeProvider, IComparer) | property Key of element of argument 0 -> property Key of element of return (normal) | true | +| System.Collections.Hashtable.Hashtable(IDictionary, float, IHashCodeProvider, IComparer) | property Value of element of argument 0 -> property Value of element of return (normal) | true | +| System.Collections.Hashtable.KeyCollection.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Hashtable.KeyCollection.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Hashtable.SyncHashtable.Add(object, object) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.Hashtable.SyncHashtable.Add(object, object) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.Hashtable.SyncHashtable.Clone() | element of argument 0 -> element of return (normal) | true | +| System.Collections.Hashtable.SyncHashtable.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Hashtable.SyncHashtable.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Hashtable.SyncHashtable.get_Item(object) | property Value of element of argument -1 -> return (normal) | true | +| System.Collections.Hashtable.SyncHashtable.get_Keys() | property Key of element of argument -1 -> element of return (normal) | true | +| System.Collections.Hashtable.SyncHashtable.get_Values() | property Value of element of argument -1 -> element of return (normal) | true | +| System.Collections.Hashtable.SyncHashtable.set_Item(object, object) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.Hashtable.SyncHashtable.set_Item(object, object) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.Hashtable.ValueCollection.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Hashtable.ValueCollection.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Hashtable.get_Item(object) | property Value of element of argument -1 -> return (normal) | true | +| System.Collections.Hashtable.get_Keys() | property Key of element of argument -1 -> element of return (normal) | true | +| System.Collections.Hashtable.get_Values() | property Value of element of argument -1 -> element of return (normal) | true | +| System.Collections.Hashtable.set_Item(object, object) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.Hashtable.set_Item(object, object) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.ICollection.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.IDictionary.Add(object, object) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.IDictionary.Add(object, object) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.IDictionary.get_Item(object) | property Value of element of argument -1 -> return (normal) | true | +| System.Collections.IDictionary.get_Keys() | property Key of element of argument -1 -> element of return (normal) | true | +| System.Collections.IDictionary.get_Values() | property Value of element of argument -1 -> element of return (normal) | true | +| System.Collections.IDictionary.set_Item(object, object) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.IDictionary.set_Item(object, object) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.IEnumerable.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.IList.Add(object) | argument 0 -> element of argument -1 | true | +| System.Collections.IList.Insert(int, object) | argument 1 -> element of argument -1 | true | +| System.Collections.IList.get_Item(int) | element of argument -1 -> return (normal) | true | +| System.Collections.IList.set_Item(int, object) | argument 1 -> element of argument -1 | true | +| System.Collections.ListDictionaryInternal.Add(object, object) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.ListDictionaryInternal.Add(object, object) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.ListDictionaryInternal.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.ListDictionaryInternal.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.ListDictionaryInternal.NodeKeyValueCollection.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.ListDictionaryInternal.NodeKeyValueCollection.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.ListDictionaryInternal.get_Item(object) | property Value of element of argument -1 -> return (normal) | true | +| System.Collections.ListDictionaryInternal.get_Keys() | property Key of element of argument -1 -> element of return (normal) | true | +| System.Collections.ListDictionaryInternal.get_Values() | property Value of element of argument -1 -> element of return (normal) | true | +| System.Collections.ListDictionaryInternal.set_Item(object, object) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.ListDictionaryInternal.set_Item(object, object) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.ObjectModel.Collection<>.Add(T) | argument 0 -> element of argument -1 | true | +| System.Collections.ObjectModel.Collection<>.Add(object) | argument 0 -> element of argument -1 | true | +| System.Collections.ObjectModel.Collection<>.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.ObjectModel.Collection<>.CopyTo(T[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.ObjectModel.Collection<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.ObjectModel.Collection<>.Insert(int, T) | argument 1 -> element of argument -1 | true | +| System.Collections.ObjectModel.Collection<>.Insert(int, object) | argument 1 -> element of argument -1 | true | +| System.Collections.ObjectModel.Collection<>.get_Item(int) | element of argument -1 -> return (normal) | true | +| System.Collections.ObjectModel.Collection<>.set_Item(int, T) | argument 1 -> element of argument -1 | true | +| System.Collections.ObjectModel.Collection<>.set_Item(int, object) | argument 1 -> element of argument -1 | true | +| System.Collections.ObjectModel.KeyedCollection<,>.get_Item(TKey) | element of argument -1 -> return (normal) | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.Add(T) | argument 0 -> element of argument -1 | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.Add(object) | argument 0 -> element of argument -1 | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.CopyTo(T[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.Insert(int, T) | argument 1 -> element of argument -1 | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.Insert(int, object) | argument 1 -> element of argument -1 | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.get_Item(int) | element of argument -1 -> return (normal) | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.set_Item(int, T) | argument 1 -> element of argument -1 | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.set_Item(int, object) | argument 1 -> element of argument -1 | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(KeyValuePair) | argument 0 -> element of argument -1 | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(KeyValuePair) | property Key of argument 0 -> property Key of element of argument -1 | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(KeyValuePair) | property Value of argument 0 -> property Value of element of argument -1 | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(TKey, TValue) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(TKey, TValue) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(object, object) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(object, object) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.CopyTo(KeyValuePair[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.KeyCollection.Add(TKey) | argument 0 -> element of argument -1 | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.KeyCollection.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.KeyCollection.CopyTo(TKey[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.KeyCollection.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ReadOnlyDictionary(IDictionary) | property Key of element of argument 0 -> property Key of element of return (normal) | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ReadOnlyDictionary(IDictionary) | property Value of element of argument 0 -> property Value of element of return (normal) | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ValueCollection.Add(TValue) | argument 0 -> element of argument -1 | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ValueCollection.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ValueCollection.CopyTo(TValue[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ValueCollection.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.get_Item(TKey) | property Value of element of argument -1 -> return (normal) | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.get_Item(object) | property Value of element of argument -1 -> return (normal) | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.get_Keys() | property Key of element of argument -1 -> element of return (normal) | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.get_Values() | property Value of element of argument -1 -> element of return (normal) | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.set_Item(TKey, TValue) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.set_Item(TKey, TValue) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.set_Item(object, object) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.set_Item(object, object) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.Queue.Clone() | element of argument 0 -> element of return (normal) | true | +| System.Collections.Queue.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Queue.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Queue.Peek() | element of argument -1 -> return (normal) | true | +| System.Collections.Queue.SynchronizedQueue.Clone() | element of argument 0 -> element of return (normal) | true | +| System.Collections.Queue.SynchronizedQueue.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Queue.SynchronizedQueue.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Queue.SynchronizedQueue.Peek() | element of argument -1 -> return (normal) | true | +| System.Collections.ReadOnlyCollectionBase.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.ReadOnlyCollectionBase.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.SortedList.Add(object, object) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.SortedList.Add(object, object) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.SortedList.Clone() | element of argument 0 -> element of return (normal) | true | +| System.Collections.SortedList.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.SortedList.GetByIndex(int) | property Value of element of argument -1 -> return (normal) | true | +| System.Collections.SortedList.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.SortedList.GetValueList() | property Value of element of argument -1 -> element of return (normal) | true | +| System.Collections.SortedList.KeyList.Add(object) | argument 0 -> element of argument -1 | true | +| System.Collections.SortedList.KeyList.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.SortedList.KeyList.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.SortedList.KeyList.Insert(int, object) | argument 1 -> element of argument -1 | true | +| System.Collections.SortedList.KeyList.get_Item(int) | element of argument -1 -> return (normal) | true | +| System.Collections.SortedList.KeyList.set_Item(int, object) | argument 1 -> element of argument -1 | true | +| System.Collections.SortedList.SortedList(IDictionary) | property Key of element of argument 0 -> property Key of element of return (normal) | true | +| System.Collections.SortedList.SortedList(IDictionary) | property Value of element of argument 0 -> property Value of element of return (normal) | true | +| System.Collections.SortedList.SortedList(IDictionary, IComparer) | property Key of element of argument 0 -> property Key of element of return (normal) | true | +| System.Collections.SortedList.SortedList(IDictionary, IComparer) | property Value of element of argument 0 -> property Value of element of return (normal) | true | +| System.Collections.SortedList.SyncSortedList.Add(object, object) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.SortedList.SyncSortedList.Add(object, object) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.SortedList.SyncSortedList.Clone() | element of argument 0 -> element of return (normal) | true | +| System.Collections.SortedList.SyncSortedList.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.SortedList.SyncSortedList.GetByIndex(int) | property Value of element of argument -1 -> return (normal) | true | +| System.Collections.SortedList.SyncSortedList.GetValueList() | property Value of element of argument -1 -> element of return (normal) | true | +| System.Collections.SortedList.SyncSortedList.get_Item(object) | property Value of element of argument -1 -> return (normal) | true | +| System.Collections.SortedList.SyncSortedList.set_Item(object, object) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.SortedList.SyncSortedList.set_Item(object, object) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.SortedList.ValueList.Add(object) | argument 0 -> element of argument -1 | true | +| System.Collections.SortedList.ValueList.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.SortedList.ValueList.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.SortedList.ValueList.Insert(int, object) | argument 1 -> element of argument -1 | true | +| System.Collections.SortedList.ValueList.get_Item(int) | element of argument -1 -> return (normal) | true | +| System.Collections.SortedList.ValueList.set_Item(int, object) | argument 1 -> element of argument -1 | true | +| System.Collections.SortedList.get_Item(object) | property Value of element of argument -1 -> return (normal) | true | +| System.Collections.SortedList.get_Keys() | property Key of element of argument -1 -> element of return (normal) | true | +| System.Collections.SortedList.get_Values() | property Value of element of argument -1 -> element of return (normal) | true | +| System.Collections.SortedList.set_Item(object, object) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.SortedList.set_Item(object, object) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.Specialized.HybridDictionary.Add(object, object) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.Specialized.HybridDictionary.Add(object, object) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.Specialized.HybridDictionary.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Specialized.HybridDictionary.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Specialized.HybridDictionary.get_Item(object) | property Value of element of argument -1 -> return (normal) | true | +| System.Collections.Specialized.HybridDictionary.get_Keys() | property Key of element of argument -1 -> element of return (normal) | true | +| System.Collections.Specialized.HybridDictionary.get_Values() | property Value of element of argument -1 -> element of return (normal) | true | +| System.Collections.Specialized.HybridDictionary.set_Item(object, object) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.Specialized.HybridDictionary.set_Item(object, object) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.Specialized.IOrderedDictionary.get_Item(int) | property Value of element of argument -1 -> return (normal) | true | +| System.Collections.Specialized.IOrderedDictionary.set_Item(int, object) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.Specialized.IOrderedDictionary.set_Item(int, object) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.Specialized.ListDictionary.Add(object, object) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.Specialized.ListDictionary.Add(object, object) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.Specialized.ListDictionary.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Specialized.ListDictionary.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Specialized.ListDictionary.NodeKeyValueCollection.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Specialized.ListDictionary.NodeKeyValueCollection.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Specialized.ListDictionary.get_Item(object) | property Value of element of argument -1 -> return (normal) | true | +| System.Collections.Specialized.ListDictionary.get_Keys() | property Key of element of argument -1 -> element of return (normal) | true | +| System.Collections.Specialized.ListDictionary.get_Values() | property Value of element of argument -1 -> element of return (normal) | true | +| System.Collections.Specialized.ListDictionary.set_Item(object, object) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.Specialized.ListDictionary.set_Item(object, object) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.Specialized.NameObjectCollectionBase.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Specialized.NameObjectCollectionBase.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Specialized.NameObjectCollectionBase.KeysCollection.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Specialized.NameObjectCollectionBase.KeysCollection.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Specialized.NameValueCollection.Add(NameValueCollection) | argument 0 -> element of argument -1 | true | +| System.Collections.Specialized.NameValueCollection.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Specialized.OrderedDictionary.Add(object, object) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.Specialized.OrderedDictionary.Add(object, object) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.Specialized.OrderedDictionary.AsReadOnly() | element of argument 0 -> element of return (normal) | true | +| System.Collections.Specialized.OrderedDictionary.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Specialized.OrderedDictionary.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Specialized.OrderedDictionary.OrderedDictionaryKeyValueCollection.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Specialized.OrderedDictionary.OrderedDictionaryKeyValueCollection.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Specialized.OrderedDictionary.get_Item(int) | property Value of element of argument -1 -> return (normal) | true | +| System.Collections.Specialized.OrderedDictionary.get_Item(object) | property Value of element of argument -1 -> return (normal) | true | +| System.Collections.Specialized.OrderedDictionary.get_Keys() | property Key of element of argument -1 -> element of return (normal) | true | +| System.Collections.Specialized.OrderedDictionary.get_Values() | property Value of element of argument -1 -> element of return (normal) | true | +| System.Collections.Specialized.OrderedDictionary.set_Item(int, object) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.Specialized.OrderedDictionary.set_Item(int, object) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.Specialized.OrderedDictionary.set_Item(object, object) | argument 0 -> property Key of element of argument -1 | true | +| System.Collections.Specialized.OrderedDictionary.set_Item(object, object) | argument 1 -> property Value of element of argument -1 | true | +| System.Collections.Specialized.ReadOnlyList.Add(object) | argument 0 -> element of argument -1 | true | +| System.Collections.Specialized.ReadOnlyList.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Specialized.ReadOnlyList.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Specialized.ReadOnlyList.Insert(int, object) | argument 1 -> element of argument -1 | true | +| System.Collections.Specialized.ReadOnlyList.get_Item(int) | element of argument -1 -> return (normal) | true | +| System.Collections.Specialized.ReadOnlyList.set_Item(int, object) | argument 1 -> element of argument -1 | true | +| System.Collections.Specialized.StringCollection.Add(object) | argument 0 -> element of argument -1 | true | +| System.Collections.Specialized.StringCollection.Add(string) | argument 0 -> element of argument -1 | true | +| System.Collections.Specialized.StringCollection.AddRange(String[]) | element of argument 0 -> element of argument -1 | true | +| System.Collections.Specialized.StringCollection.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Specialized.StringCollection.CopyTo(String[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Specialized.StringCollection.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Specialized.StringCollection.Insert(int, object) | argument 1 -> element of argument -1 | true | +| System.Collections.Specialized.StringCollection.Insert(int, string) | argument 1 -> element of argument -1 | true | +| System.Collections.Specialized.StringCollection.get_Item(int) | element of argument -1 -> return (normal) | true | +| System.Collections.Specialized.StringCollection.set_Item(int, object) | argument 1 -> element of argument -1 | true | +| System.Collections.Specialized.StringCollection.set_Item(int, string) | argument 1 -> element of argument -1 | true | +| System.Collections.Specialized.StringDictionary.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Stack.Clone() | element of argument 0 -> element of return (normal) | true | +| System.Collections.Stack.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Stack.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Stack.Peek() | element of argument -1 -> return (normal) | true | +| System.Collections.Stack.Pop() | element of argument -1 -> return (normal) | true | +| System.Collections.Stack.SyncStack.Clone() | element of argument 0 -> element of return (normal) | true | +| System.Collections.Stack.SyncStack.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Collections.Stack.SyncStack.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Collections.Stack.SyncStack.Peek() | element of argument -1 -> return (normal) | true | +| System.Collections.Stack.SyncStack.Pop() | element of argument -1 -> return (normal) | true | +| System.ComponentModel.AttributeCollection.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.ComponentModel.AttributeCollection.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.ComponentModel.BindingList<>.Find(PropertyDescriptor, object) | element of argument -1 -> return (normal) | true | +| System.ComponentModel.Design.DesignerCollection.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.ComponentModel.Design.DesignerCollection.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.Add(object) | argument 0 -> element of argument -1 | true | +| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.Insert(int, object) | argument 1 -> element of argument -1 | true | +| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.get_Item(int) | element of argument -1 -> return (normal) | true | +| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.get_Item(string) | element of argument -1 -> return (normal) | true | +| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.set_Item(int, object) | argument 1 -> element of argument -1 | true | +| System.ComponentModel.Design.DesignerVerbCollection.Add(DesignerVerb) | argument 0 -> element of argument -1 | true | +| System.ComponentModel.Design.DesignerVerbCollection.AddRange(DesignerVerbCollection) | element of argument 0 -> element of argument -1 | true | +| System.ComponentModel.Design.DesignerVerbCollection.AddRange(DesignerVerb[]) | element of argument 0 -> element of argument -1 | true | +| System.ComponentModel.Design.DesignerVerbCollection.CopyTo(DesignerVerb[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.ComponentModel.Design.DesignerVerbCollection.Insert(int, DesignerVerb) | argument 1 -> element of argument -1 | true | +| System.ComponentModel.Design.DesignerVerbCollection.get_Item(int) | element of argument -1 -> return (normal) | true | +| System.ComponentModel.Design.DesignerVerbCollection.set_Item(int, DesignerVerb) | argument 1 -> element of argument -1 | true | +| System.ComponentModel.EventDescriptorCollection.Add(EventDescriptor) | argument 0 -> element of argument -1 | true | +| System.ComponentModel.EventDescriptorCollection.Add(object) | argument 0 -> element of argument -1 | true | +| System.ComponentModel.EventDescriptorCollection.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.ComponentModel.EventDescriptorCollection.Find(string, bool) | element of argument -1 -> return (normal) | true | +| System.ComponentModel.EventDescriptorCollection.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.ComponentModel.EventDescriptorCollection.Insert(int, EventDescriptor) | argument 1 -> element of argument -1 | true | +| System.ComponentModel.EventDescriptorCollection.Insert(int, object) | argument 1 -> element of argument -1 | true | +| System.ComponentModel.EventDescriptorCollection.get_Item(int) | element of argument -1 -> return (normal) | true | +| System.ComponentModel.EventDescriptorCollection.get_Item(string) | element of argument -1 -> return (normal) | true | +| System.ComponentModel.EventDescriptorCollection.set_Item(int, object) | argument 1 -> element of argument -1 | true | +| System.ComponentModel.IBindingList.Find(PropertyDescriptor, object) | element of argument -1 -> return (normal) | true | +| System.ComponentModel.ListSortDescriptionCollection.Add(object) | argument 0 -> element of argument -1 | true | +| System.ComponentModel.ListSortDescriptionCollection.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.ComponentModel.ListSortDescriptionCollection.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.ComponentModel.ListSortDescriptionCollection.Insert(int, object) | argument 1 -> element of argument -1 | true | +| System.ComponentModel.ListSortDescriptionCollection.get_Item(int) | element of argument -1 -> return (normal) | true | +| System.ComponentModel.ListSortDescriptionCollection.set_Item(int, ListSortDescription) | argument 1 -> element of argument -1 | true | +| System.ComponentModel.ListSortDescriptionCollection.set_Item(int, object) | argument 1 -> element of argument -1 | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(PropertyDescriptor) | argument 0 -> element of argument -1 | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(PropertyDescriptor) | property Key of argument 0 -> property Key of element of argument -1 | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(PropertyDescriptor) | property Value of argument 0 -> property Value of element of argument -1 | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(object) | argument 0 -> element of argument -1 | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(object) | property Key of argument 0 -> property Key of element of argument -1 | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(object) | property Value of argument 0 -> property Value of element of argument -1 | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(object, object) | argument 0 -> property Key of element of argument -1 | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(object, object) | argument 1 -> property Value of element of argument -1 | true | +| System.ComponentModel.PropertyDescriptorCollection.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.ComponentModel.PropertyDescriptorCollection.Find(string, bool) | element of argument -1 -> return (normal) | true | +| System.ComponentModel.PropertyDescriptorCollection.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.ComponentModel.PropertyDescriptorCollection.Insert(int, PropertyDescriptor) | argument 1 -> element of argument -1 | true | +| System.ComponentModel.PropertyDescriptorCollection.Insert(int, object) | argument 1 -> element of argument -1 | true | +| System.ComponentModel.PropertyDescriptorCollection.PropertyDescriptorCollection(PropertyDescriptor[]) | property Key of element of argument 0 -> property Key of element of return (normal) | true | +| System.ComponentModel.PropertyDescriptorCollection.PropertyDescriptorCollection(PropertyDescriptor[]) | property Value of element of argument 0 -> property Value of element of return (normal) | true | +| System.ComponentModel.PropertyDescriptorCollection.PropertyDescriptorCollection(PropertyDescriptor[], bool) | property Key of element of argument 0 -> property Key of element of return (normal) | true | +| System.ComponentModel.PropertyDescriptorCollection.PropertyDescriptorCollection(PropertyDescriptor[], bool) | property Value of element of argument 0 -> property Value of element of return (normal) | true | +| System.ComponentModel.PropertyDescriptorCollection.get_Item(int) | element of argument -1 -> return (normal) | true | +| System.ComponentModel.PropertyDescriptorCollection.get_Item(int) | property Value of element of argument -1 -> return (normal) | true | +| System.ComponentModel.PropertyDescriptorCollection.get_Item(object) | element of argument -1 -> return (normal) | true | +| System.ComponentModel.PropertyDescriptorCollection.get_Item(object) | property Value of element of argument -1 -> return (normal) | true | +| System.ComponentModel.PropertyDescriptorCollection.get_Item(string) | element of argument -1 -> return (normal) | true | +| System.ComponentModel.PropertyDescriptorCollection.get_Item(string) | property Value of element of argument -1 -> return (normal) | true | +| System.ComponentModel.PropertyDescriptorCollection.get_Keys() | property Key of element of argument -1 -> element of return (normal) | true | +| System.ComponentModel.PropertyDescriptorCollection.get_Values() | property Value of element of argument -1 -> element of return (normal) | true | +| System.ComponentModel.PropertyDescriptorCollection.set_Item(int, object) | argument 0 -> property Key of element of argument -1 | true | +| System.ComponentModel.PropertyDescriptorCollection.set_Item(int, object) | argument 1 -> element of argument -1 | true | +| System.ComponentModel.PropertyDescriptorCollection.set_Item(int, object) | argument 1 -> property Value of element of argument -1 | true | +| System.ComponentModel.PropertyDescriptorCollection.set_Item(object, object) | argument 0 -> property Key of element of argument -1 | true | +| System.ComponentModel.PropertyDescriptorCollection.set_Item(object, object) | argument 1 -> element of argument -1 | true | +| System.ComponentModel.PropertyDescriptorCollection.set_Item(object, object) | argument 1 -> property Value of element of argument -1 | true | +| System.ComponentModel.TypeConverter.StandardValuesCollection.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.ComponentModel.TypeConverter.StandardValuesCollection.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.ConsolePal.UnixConsoleStream.Read(Byte[], int, int) | argument -1 -> return (out parameter 0) | false | +| System.ConsolePal.UnixConsoleStream.Write(Byte[], int, int) | argument 0 -> argument -1 | false | +| System.Convert.ChangeType(object, Type) | argument 0 -> return (normal) | false | +| System.Convert.ChangeType(object, Type, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ChangeType(object, TypeCode) | argument 0 -> return (normal) | false | +| System.Convert.ChangeType(object, TypeCode, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.FromBase64CharArray(Char[], int, int) | argument 0 -> return (normal) | false | +| System.Convert.FromBase64String(string) | argument 0 -> return (normal) | false | +| System.Convert.FromHexString(ReadOnlySpan) | argument 0 -> return (normal) | false | +| System.Convert.FromHexString(string) | argument 0 -> return (normal) | false | +| System.Convert.GetTypeCode(object) | argument 0 -> return (normal) | false | +| System.Convert.IsDBNull(object) | argument 0 -> return (normal) | false | +| System.Convert.ToBase64CharArray(Byte[], int, int, Char[], int) | argument 0 -> return (normal) | false | +| System.Convert.ToBase64CharArray(Byte[], int, int, Char[], int, Base64FormattingOptions) | argument 0 -> return (normal) | false | +| System.Convert.ToBase64String(Byte[]) | argument 0 -> return (normal) | false | +| System.Convert.ToBase64String(Byte[], Base64FormattingOptions) | argument 0 -> return (normal) | false | +| System.Convert.ToBase64String(Byte[], int, int) | argument 0 -> return (normal) | false | +| System.Convert.ToBase64String(Byte[], int, int, Base64FormattingOptions) | argument 0 -> return (normal) | false | +| System.Convert.ToBase64String(ReadOnlySpan, Base64FormattingOptions) | argument 0 -> return (normal) | false | +| System.Convert.ToBoolean(DateTime) | argument 0 -> return (normal) | false | +| System.Convert.ToBoolean(bool) | argument 0 -> return (normal) | false | +| System.Convert.ToBoolean(byte) | argument 0 -> return (normal) | false | +| System.Convert.ToBoolean(char) | argument 0 -> return (normal) | false | +| System.Convert.ToBoolean(decimal) | argument 0 -> return (normal) | false | +| System.Convert.ToBoolean(double) | argument 0 -> return (normal) | false | +| System.Convert.ToBoolean(float) | argument 0 -> return (normal) | false | +| System.Convert.ToBoolean(int) | argument 0 -> return (normal) | false | +| System.Convert.ToBoolean(long) | argument 0 -> return (normal) | false | +| System.Convert.ToBoolean(object) | argument 0 -> return (normal) | false | +| System.Convert.ToBoolean(object, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToBoolean(sbyte) | argument 0 -> return (normal) | false | +| System.Convert.ToBoolean(short) | argument 0 -> return (normal) | false | +| System.Convert.ToBoolean(string) | argument 0 -> return (normal) | false | +| System.Convert.ToBoolean(string, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToBoolean(uint) | argument 0 -> return (normal) | false | +| System.Convert.ToBoolean(ulong) | argument 0 -> return (normal) | false | +| System.Convert.ToBoolean(ushort) | argument 0 -> return (normal) | false | +| System.Convert.ToByte(DateTime) | argument 0 -> return (normal) | false | +| System.Convert.ToByte(bool) | argument 0 -> return (normal) | false | +| System.Convert.ToByte(byte) | argument 0 -> return (normal) | false | +| System.Convert.ToByte(char) | argument 0 -> return (normal) | false | +| System.Convert.ToByte(decimal) | argument 0 -> return (normal) | false | +| System.Convert.ToByte(double) | argument 0 -> return (normal) | false | +| System.Convert.ToByte(float) | argument 0 -> return (normal) | false | +| System.Convert.ToByte(int) | argument 0 -> return (normal) | false | +| System.Convert.ToByte(long) | argument 0 -> return (normal) | false | +| System.Convert.ToByte(object) | argument 0 -> return (normal) | false | +| System.Convert.ToByte(object, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToByte(sbyte) | argument 0 -> return (normal) | false | +| System.Convert.ToByte(short) | argument 0 -> return (normal) | false | +| System.Convert.ToByte(string) | argument 0 -> return (normal) | false | +| System.Convert.ToByte(string, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToByte(string, int) | argument 0 -> return (normal) | false | +| System.Convert.ToByte(uint) | argument 0 -> return (normal) | false | +| System.Convert.ToByte(ulong) | argument 0 -> return (normal) | false | +| System.Convert.ToByte(ushort) | argument 0 -> return (normal) | false | +| System.Convert.ToChar(DateTime) | argument 0 -> return (normal) | false | +| System.Convert.ToChar(bool) | argument 0 -> return (normal) | false | +| System.Convert.ToChar(byte) | argument 0 -> return (normal) | false | +| System.Convert.ToChar(char) | argument 0 -> return (normal) | false | +| System.Convert.ToChar(decimal) | argument 0 -> return (normal) | false | +| System.Convert.ToChar(double) | argument 0 -> return (normal) | false | +| System.Convert.ToChar(float) | argument 0 -> return (normal) | false | +| System.Convert.ToChar(int) | argument 0 -> return (normal) | false | +| System.Convert.ToChar(long) | argument 0 -> return (normal) | false | +| System.Convert.ToChar(object) | argument 0 -> return (normal) | false | +| System.Convert.ToChar(object, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToChar(sbyte) | argument 0 -> return (normal) | false | +| System.Convert.ToChar(short) | argument 0 -> return (normal) | false | +| System.Convert.ToChar(string) | argument 0 -> return (normal) | false | +| System.Convert.ToChar(string, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToChar(uint) | argument 0 -> return (normal) | false | +| System.Convert.ToChar(ulong) | argument 0 -> return (normal) | false | +| System.Convert.ToChar(ushort) | argument 0 -> return (normal) | false | +| System.Convert.ToDateTime(DateTime) | argument 0 -> return (normal) | false | +| System.Convert.ToDateTime(bool) | argument 0 -> return (normal) | false | +| System.Convert.ToDateTime(byte) | argument 0 -> return (normal) | false | +| System.Convert.ToDateTime(char) | argument 0 -> return (normal) | false | +| System.Convert.ToDateTime(decimal) | argument 0 -> return (normal) | false | +| System.Convert.ToDateTime(double) | argument 0 -> return (normal) | false | +| System.Convert.ToDateTime(float) | argument 0 -> return (normal) | false | +| System.Convert.ToDateTime(int) | argument 0 -> return (normal) | false | +| System.Convert.ToDateTime(long) | argument 0 -> return (normal) | false | +| System.Convert.ToDateTime(object) | argument 0 -> return (normal) | false | +| System.Convert.ToDateTime(object, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToDateTime(sbyte) | argument 0 -> return (normal) | false | +| System.Convert.ToDateTime(short) | argument 0 -> return (normal) | false | +| System.Convert.ToDateTime(string) | argument 0 -> return (normal) | false | +| System.Convert.ToDateTime(string, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToDateTime(uint) | argument 0 -> return (normal) | false | +| System.Convert.ToDateTime(ulong) | argument 0 -> return (normal) | false | +| System.Convert.ToDateTime(ushort) | argument 0 -> return (normal) | false | +| System.Convert.ToDecimal(DateTime) | argument 0 -> return (normal) | false | +| System.Convert.ToDecimal(bool) | argument 0 -> return (normal) | false | +| System.Convert.ToDecimal(byte) | argument 0 -> return (normal) | false | +| System.Convert.ToDecimal(char) | argument 0 -> return (normal) | false | +| System.Convert.ToDecimal(decimal) | argument 0 -> return (normal) | false | +| System.Convert.ToDecimal(double) | argument 0 -> return (normal) | false | +| System.Convert.ToDecimal(float) | argument 0 -> return (normal) | false | +| System.Convert.ToDecimal(int) | argument 0 -> return (normal) | false | +| System.Convert.ToDecimal(long) | argument 0 -> return (normal) | false | +| System.Convert.ToDecimal(object) | argument 0 -> return (normal) | false | +| System.Convert.ToDecimal(object, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToDecimal(sbyte) | argument 0 -> return (normal) | false | +| System.Convert.ToDecimal(short) | argument 0 -> return (normal) | false | +| System.Convert.ToDecimal(string) | argument 0 -> return (normal) | false | +| System.Convert.ToDecimal(string, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToDecimal(uint) | argument 0 -> return (normal) | false | +| System.Convert.ToDecimal(ulong) | argument 0 -> return (normal) | false | +| System.Convert.ToDecimal(ushort) | argument 0 -> return (normal) | false | +| System.Convert.ToDouble(DateTime) | argument 0 -> return (normal) | false | +| System.Convert.ToDouble(bool) | argument 0 -> return (normal) | false | +| System.Convert.ToDouble(byte) | argument 0 -> return (normal) | false | +| System.Convert.ToDouble(char) | argument 0 -> return (normal) | false | +| System.Convert.ToDouble(decimal) | argument 0 -> return (normal) | false | +| System.Convert.ToDouble(double) | argument 0 -> return (normal) | false | +| System.Convert.ToDouble(float) | argument 0 -> return (normal) | false | +| System.Convert.ToDouble(int) | argument 0 -> return (normal) | false | +| System.Convert.ToDouble(long) | argument 0 -> return (normal) | false | +| System.Convert.ToDouble(object) | argument 0 -> return (normal) | false | +| System.Convert.ToDouble(object, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToDouble(sbyte) | argument 0 -> return (normal) | false | +| System.Convert.ToDouble(short) | argument 0 -> return (normal) | false | +| System.Convert.ToDouble(string) | argument 0 -> return (normal) | false | +| System.Convert.ToDouble(string, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToDouble(uint) | argument 0 -> return (normal) | false | +| System.Convert.ToDouble(ulong) | argument 0 -> return (normal) | false | +| System.Convert.ToDouble(ushort) | argument 0 -> return (normal) | false | +| System.Convert.ToHexString(Byte[]) | argument 0 -> return (normal) | false | +| System.Convert.ToHexString(Byte[], int, int) | argument 0 -> return (normal) | false | +| System.Convert.ToHexString(ReadOnlySpan) | argument 0 -> return (normal) | false | +| System.Convert.ToInt16(DateTime) | argument 0 -> return (normal) | false | +| System.Convert.ToInt16(bool) | argument 0 -> return (normal) | false | +| System.Convert.ToInt16(byte) | argument 0 -> return (normal) | false | +| System.Convert.ToInt16(char) | argument 0 -> return (normal) | false | +| System.Convert.ToInt16(decimal) | argument 0 -> return (normal) | false | +| System.Convert.ToInt16(double) | argument 0 -> return (normal) | false | +| System.Convert.ToInt16(float) | argument 0 -> return (normal) | false | +| System.Convert.ToInt16(int) | argument 0 -> return (normal) | false | +| System.Convert.ToInt16(long) | argument 0 -> return (normal) | false | +| System.Convert.ToInt16(object) | argument 0 -> return (normal) | false | +| System.Convert.ToInt16(object, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToInt16(sbyte) | argument 0 -> return (normal) | false | +| System.Convert.ToInt16(short) | argument 0 -> return (normal) | false | +| System.Convert.ToInt16(string) | argument 0 -> return (normal) | false | +| System.Convert.ToInt16(string, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToInt16(string, int) | argument 0 -> return (normal) | false | +| System.Convert.ToInt16(uint) | argument 0 -> return (normal) | false | +| System.Convert.ToInt16(ulong) | argument 0 -> return (normal) | false | +| System.Convert.ToInt16(ushort) | argument 0 -> return (normal) | false | +| System.Convert.ToInt32(DateTime) | argument 0 -> return (normal) | false | +| System.Convert.ToInt32(bool) | argument 0 -> return (normal) | false | +| System.Convert.ToInt32(byte) | argument 0 -> return (normal) | false | +| System.Convert.ToInt32(char) | argument 0 -> return (normal) | false | +| System.Convert.ToInt32(decimal) | argument 0 -> return (normal) | false | +| System.Convert.ToInt32(double) | argument 0 -> return (normal) | false | +| System.Convert.ToInt32(float) | argument 0 -> return (normal) | false | +| System.Convert.ToInt32(int) | argument 0 -> return (normal) | false | +| System.Convert.ToInt32(long) | argument 0 -> return (normal) | false | +| System.Convert.ToInt32(object) | argument 0 -> return (normal) | false | +| System.Convert.ToInt32(object, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToInt32(sbyte) | argument 0 -> return (normal) | false | +| System.Convert.ToInt32(short) | argument 0 -> return (normal) | false | +| System.Convert.ToInt32(string) | argument 0 -> return (normal) | false | +| System.Convert.ToInt32(string, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToInt32(string, int) | argument 0 -> return (normal) | false | +| System.Convert.ToInt32(uint) | argument 0 -> return (normal) | false | +| System.Convert.ToInt32(ulong) | argument 0 -> return (normal) | false | +| System.Convert.ToInt32(ushort) | argument 0 -> return (normal) | false | +| System.Convert.ToInt64(DateTime) | argument 0 -> return (normal) | false | +| System.Convert.ToInt64(bool) | argument 0 -> return (normal) | false | +| System.Convert.ToInt64(byte) | argument 0 -> return (normal) | false | +| System.Convert.ToInt64(char) | argument 0 -> return (normal) | false | +| System.Convert.ToInt64(decimal) | argument 0 -> return (normal) | false | +| System.Convert.ToInt64(double) | argument 0 -> return (normal) | false | +| System.Convert.ToInt64(float) | argument 0 -> return (normal) | false | +| System.Convert.ToInt64(int) | argument 0 -> return (normal) | false | +| System.Convert.ToInt64(long) | argument 0 -> return (normal) | false | +| System.Convert.ToInt64(object) | argument 0 -> return (normal) | false | +| System.Convert.ToInt64(object, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToInt64(sbyte) | argument 0 -> return (normal) | false | +| System.Convert.ToInt64(short) | argument 0 -> return (normal) | false | +| System.Convert.ToInt64(string) | argument 0 -> return (normal) | false | +| System.Convert.ToInt64(string, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToInt64(string, int) | argument 0 -> return (normal) | false | +| System.Convert.ToInt64(uint) | argument 0 -> return (normal) | false | +| System.Convert.ToInt64(ulong) | argument 0 -> return (normal) | false | +| System.Convert.ToInt64(ushort) | argument 0 -> return (normal) | false | +| System.Convert.ToSByte(DateTime) | argument 0 -> return (normal) | false | +| System.Convert.ToSByte(bool) | argument 0 -> return (normal) | false | +| System.Convert.ToSByte(byte) | argument 0 -> return (normal) | false | +| System.Convert.ToSByte(char) | argument 0 -> return (normal) | false | +| System.Convert.ToSByte(decimal) | argument 0 -> return (normal) | false | +| System.Convert.ToSByte(double) | argument 0 -> return (normal) | false | +| System.Convert.ToSByte(float) | argument 0 -> return (normal) | false | +| System.Convert.ToSByte(int) | argument 0 -> return (normal) | false | +| System.Convert.ToSByte(long) | argument 0 -> return (normal) | false | +| System.Convert.ToSByte(object) | argument 0 -> return (normal) | false | +| System.Convert.ToSByte(object, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToSByte(sbyte) | argument 0 -> return (normal) | false | +| System.Convert.ToSByte(short) | argument 0 -> return (normal) | false | +| System.Convert.ToSByte(string) | argument 0 -> return (normal) | false | +| System.Convert.ToSByte(string, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToSByte(string, int) | argument 0 -> return (normal) | false | +| System.Convert.ToSByte(uint) | argument 0 -> return (normal) | false | +| System.Convert.ToSByte(ulong) | argument 0 -> return (normal) | false | +| System.Convert.ToSByte(ushort) | argument 0 -> return (normal) | false | +| System.Convert.ToSingle(DateTime) | argument 0 -> return (normal) | false | +| System.Convert.ToSingle(bool) | argument 0 -> return (normal) | false | +| System.Convert.ToSingle(byte) | argument 0 -> return (normal) | false | +| System.Convert.ToSingle(char) | argument 0 -> return (normal) | false | +| System.Convert.ToSingle(decimal) | argument 0 -> return (normal) | false | +| System.Convert.ToSingle(double) | argument 0 -> return (normal) | false | +| System.Convert.ToSingle(float) | argument 0 -> return (normal) | false | +| System.Convert.ToSingle(int) | argument 0 -> return (normal) | false | +| System.Convert.ToSingle(long) | argument 0 -> return (normal) | false | +| System.Convert.ToSingle(object) | argument 0 -> return (normal) | false | +| System.Convert.ToSingle(object, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToSingle(sbyte) | argument 0 -> return (normal) | false | +| System.Convert.ToSingle(short) | argument 0 -> return (normal) | false | +| System.Convert.ToSingle(string) | argument 0 -> return (normal) | false | +| System.Convert.ToSingle(string, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToSingle(uint) | argument 0 -> return (normal) | false | +| System.Convert.ToSingle(ulong) | argument 0 -> return (normal) | false | +| System.Convert.ToSingle(ushort) | argument 0 -> return (normal) | false | +| System.Convert.ToString(DateTime) | argument 0 -> return (normal) | false | +| System.Convert.ToString(DateTime, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToString(bool) | argument 0 -> return (normal) | false | +| System.Convert.ToString(bool, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToString(byte) | argument 0 -> return (normal) | false | +| System.Convert.ToString(byte, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToString(byte, int) | argument 0 -> return (normal) | false | +| System.Convert.ToString(char) | argument 0 -> return (normal) | false | +| System.Convert.ToString(char, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToString(decimal) | argument 0 -> return (normal) | false | +| System.Convert.ToString(decimal, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToString(double) | argument 0 -> return (normal) | false | +| System.Convert.ToString(double, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToString(float) | argument 0 -> return (normal) | false | +| System.Convert.ToString(float, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToString(int) | argument 0 -> return (normal) | false | +| System.Convert.ToString(int, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToString(int, int) | argument 0 -> return (normal) | false | +| System.Convert.ToString(long) | argument 0 -> return (normal) | false | +| System.Convert.ToString(long, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToString(long, int) | argument 0 -> return (normal) | false | +| System.Convert.ToString(object) | argument 0 -> return (normal) | false | +| System.Convert.ToString(object, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToString(sbyte) | argument 0 -> return (normal) | false | +| System.Convert.ToString(sbyte, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToString(short) | argument 0 -> return (normal) | false | +| System.Convert.ToString(short, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToString(short, int) | argument 0 -> return (normal) | false | +| System.Convert.ToString(string) | argument 0 -> return (normal) | false | +| System.Convert.ToString(string, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToString(uint) | argument 0 -> return (normal) | false | +| System.Convert.ToString(uint, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToString(ulong) | argument 0 -> return (normal) | false | +| System.Convert.ToString(ulong, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToString(ushort) | argument 0 -> return (normal) | false | +| System.Convert.ToString(ushort, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt16(DateTime) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt16(bool) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt16(byte) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt16(char) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt16(decimal) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt16(double) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt16(float) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt16(int) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt16(long) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt16(object) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt16(object, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt16(sbyte) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt16(short) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt16(string) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt16(string, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt16(string, int) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt16(uint) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt16(ulong) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt16(ushort) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt32(DateTime) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt32(bool) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt32(byte) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt32(char) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt32(decimal) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt32(double) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt32(float) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt32(int) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt32(long) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt32(object) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt32(object, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt32(sbyte) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt32(short) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt32(string) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt32(string, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt32(string, int) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt32(uint) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt32(ulong) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt32(ushort) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt64(DateTime) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt64(bool) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt64(byte) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt64(char) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt64(decimal) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt64(double) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt64(float) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt64(int) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt64(long) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt64(object) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt64(object, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt64(sbyte) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt64(short) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt64(string) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt64(string, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt64(string, int) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt64(uint) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt64(ulong) | argument 0 -> return (normal) | false | +| System.Convert.ToUInt64(ushort) | argument 0 -> return (normal) | false | +| System.Convert.TryFromBase64Chars(ReadOnlySpan, Span, out int) | argument 0 -> return (normal) | false | +| System.Convert.TryFromBase64String(string, Span, out int) | argument 0 -> return (normal) | false | +| System.Convert.TryToBase64Chars(ReadOnlySpan, Span, out int, Base64FormattingOptions) | argument 0 -> return (normal) | false | +| System.Diagnostics.Tracing.CounterPayload.d__51.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Diagnostics.Tracing.CounterPayload.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Diagnostics.Tracing.EventPayload.Add(KeyValuePair) | argument 0 -> element of argument -1 | true | +| System.Diagnostics.Tracing.EventPayload.Add(KeyValuePair) | property Key of argument 0 -> property Key of element of argument -1 | true | +| System.Diagnostics.Tracing.EventPayload.Add(KeyValuePair) | property Value of argument 0 -> property Value of element of argument -1 | true | +| System.Diagnostics.Tracing.EventPayload.Add(string, object) | argument 0 -> property Key of element of argument -1 | true | +| System.Diagnostics.Tracing.EventPayload.Add(string, object) | argument 1 -> property Value of element of argument -1 | true | +| System.Diagnostics.Tracing.EventPayload.CopyTo(KeyValuePair[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Diagnostics.Tracing.EventPayload.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Diagnostics.Tracing.EventPayload.get_Item(string) | property Value of element of argument -1 -> return (normal) | true | +| System.Diagnostics.Tracing.EventPayload.get_Keys() | property Key of element of argument -1 -> element of return (normal) | true | +| System.Diagnostics.Tracing.EventPayload.get_Values() | property Value of element of argument -1 -> element of return (normal) | true | +| System.Diagnostics.Tracing.EventPayload.set_Item(string, object) | argument 0 -> property Key of element of argument -1 | true | +| System.Diagnostics.Tracing.EventPayload.set_Item(string, object) | argument 1 -> property Value of element of argument -1 | true | +| System.Diagnostics.Tracing.IncrementingCounterPayload.d__39.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Diagnostics.Tracing.IncrementingCounterPayload.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Dynamic.ExpandoObject.Add(KeyValuePair) | argument 0 -> element of argument -1 | true | +| System.Dynamic.ExpandoObject.Add(KeyValuePair) | property Key of argument 0 -> property Key of element of argument -1 | true | +| System.Dynamic.ExpandoObject.Add(KeyValuePair) | property Value of argument 0 -> property Value of element of argument -1 | true | +| System.Dynamic.ExpandoObject.Add(string, object) | argument 0 -> property Key of element of argument -1 | true | +| System.Dynamic.ExpandoObject.Add(string, object) | argument 1 -> property Value of element of argument -1 | true | +| System.Dynamic.ExpandoObject.CopyTo(KeyValuePair[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Dynamic.ExpandoObject.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Dynamic.ExpandoObject.KeyCollection.Add(string) | argument 0 -> element of argument -1 | true | +| System.Dynamic.ExpandoObject.KeyCollection.CopyTo(String[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Dynamic.ExpandoObject.KeyCollection.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Dynamic.ExpandoObject.MetaExpando.d__6.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Dynamic.ExpandoObject.ValueCollection.Add(object) | argument 0 -> element of argument -1 | true | +| System.Dynamic.ExpandoObject.ValueCollection.CopyTo(Object[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Dynamic.ExpandoObject.ValueCollection.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Dynamic.ExpandoObject.get_Item(string) | property Value of element of argument -1 -> return (normal) | true | +| System.Dynamic.ExpandoObject.get_Keys() | property Key of element of argument -1 -> element of return (normal) | true | +| System.Dynamic.ExpandoObject.get_Values() | property Value of element of argument -1 -> element of return (normal) | true | +| System.Dynamic.ExpandoObject.set_Item(string, object) | argument 0 -> property Key of element of argument -1 | true | +| System.Dynamic.ExpandoObject.set_Item(string, object) | argument 1 -> property Value of element of argument -1 | true | +| System.Dynamic.Utils.ListProvider<>.Add(T) | argument 0 -> element of argument -1 | true | +| System.Dynamic.Utils.ListProvider<>.CopyTo(T[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Dynamic.Utils.ListProvider<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Dynamic.Utils.ListProvider<>.Insert(int, T) | argument 1 -> element of argument -1 | true | +| System.Dynamic.Utils.ListProvider<>.get_Item(int) | element of argument -1 -> return (normal) | true | +| System.Dynamic.Utils.ListProvider<>.set_Item(int, T) | argument 1 -> element of argument -1 | true | +| System.IO.BufferedStream.BeginRead(Byte[], int, int, AsyncCallback, object) | argument -1 -> return (out parameter 0) | false | +| System.IO.BufferedStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | argument 0 -> argument -1 | false | +| System.IO.BufferedStream.CopyTo(Stream, int) | argument -1 -> return (out parameter 0) | false | +| System.IO.BufferedStream.CopyToAsync(Stream, int, CancellationToken) | argument -1 -> return (out parameter 0) | false | +| System.IO.BufferedStream.Read(Byte[], int, int) | argument -1 -> return (out parameter 0) | false | +| System.IO.BufferedStream.ReadAsync(Byte[], int, int, CancellationToken) | argument -1 -> return (out parameter 0) | false | +| System.IO.BufferedStream.Write(Byte[], int, int) | argument 0 -> argument -1 | false | +| System.IO.BufferedStream.WriteAsync(Byte[], int, int, CancellationToken) | argument 0 -> argument -1 | false | +| System.IO.Compression.CheckSumAndSizeWriteStream.Read(Byte[], int, int) | argument -1 -> return (out parameter 0) | false | +| System.IO.Compression.CheckSumAndSizeWriteStream.Write(Byte[], int, int) | argument 0 -> argument -1 | false | +| System.IO.Compression.DeflateManagedStream.BeginRead(Byte[], int, int, AsyncCallback, object) | argument -1 -> return (out parameter 0) | false | +| System.IO.Compression.DeflateManagedStream.Read(Byte[], int, int) | argument -1 -> return (out parameter 0) | false | +| System.IO.Compression.DeflateManagedStream.ReadAsync(Byte[], int, int, CancellationToken) | argument -1 -> return (out parameter 0) | false | +| System.IO.Compression.DeflateManagedStream.Write(Byte[], int, int) | argument 0 -> argument -1 | false | +| System.IO.Compression.DeflateStream.BeginRead(Byte[], int, int, AsyncCallback, object) | argument -1 -> return (out parameter 0) | false | +| System.IO.Compression.DeflateStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | argument 0 -> argument -1 | false | +| System.IO.Compression.DeflateStream.CopyTo(Stream, int) | argument -1 -> return (out parameter 0) | false | +| System.IO.Compression.DeflateStream.CopyToAsync(Stream, int, CancellationToken) | argument -1 -> return (out parameter 0) | false | +| System.IO.Compression.DeflateStream.CopyToStream.Read(Byte[], int, int) | argument -1 -> return (out parameter 0) | false | +| System.IO.Compression.DeflateStream.CopyToStream.Write(Byte[], int, int) | argument 0 -> argument -1 | false | +| System.IO.Compression.DeflateStream.CopyToStream.WriteAsync(Byte[], int, int, CancellationToken) | argument 0 -> argument -1 | false | +| System.IO.Compression.DeflateStream.DeflateStream(Stream, CompressionLevel) | argument 0 -> return (normal) | false | +| System.IO.Compression.DeflateStream.DeflateStream(Stream, CompressionLevel, bool) | argument 0 -> return (normal) | false | +| System.IO.Compression.DeflateStream.DeflateStream(Stream, CompressionMode) | argument 0 -> return (normal) | false | +| System.IO.Compression.DeflateStream.DeflateStream(Stream, CompressionMode, bool) | argument 0 -> return (normal) | false | +| System.IO.Compression.DeflateStream.Read(Byte[], int, int) | argument -1 -> return (out parameter 0) | false | +| System.IO.Compression.DeflateStream.ReadAsync(Byte[], int, int, CancellationToken) | argument -1 -> return (out parameter 0) | false | +| System.IO.Compression.DeflateStream.Write(Byte[], int, int) | argument 0 -> argument -1 | false | +| System.IO.Compression.DeflateStream.WriteAsync(Byte[], int, int, CancellationToken) | argument 0 -> argument -1 | false | +| System.IO.Compression.GZipStream.BeginRead(Byte[], int, int, AsyncCallback, object) | argument -1 -> return (out parameter 0) | false | +| System.IO.Compression.GZipStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | argument 0 -> argument -1 | false | +| System.IO.Compression.GZipStream.CopyTo(Stream, int) | argument -1 -> return (out parameter 0) | false | +| System.IO.Compression.GZipStream.CopyToAsync(Stream, int, CancellationToken) | argument -1 -> return (out parameter 0) | false | +| System.IO.Compression.GZipStream.Read(Byte[], int, int) | argument -1 -> return (out parameter 0) | false | +| System.IO.Compression.GZipStream.ReadAsync(Byte[], int, int, CancellationToken) | argument -1 -> return (out parameter 0) | false | +| System.IO.Compression.GZipStream.Write(Byte[], int, int) | argument 0 -> argument -1 | false | +| System.IO.Compression.GZipStream.WriteAsync(Byte[], int, int, CancellationToken) | argument 0 -> argument -1 | false | +| System.IO.Compression.PositionPreservingWriteOnlyStreamWrapper.BeginWrite(Byte[], int, int, AsyncCallback, object) | argument 0 -> argument -1 | false | +| System.IO.Compression.PositionPreservingWriteOnlyStreamWrapper.Read(Byte[], int, int) | argument -1 -> return (out parameter 0) | false | +| System.IO.Compression.PositionPreservingWriteOnlyStreamWrapper.Write(Byte[], int, int) | argument 0 -> argument -1 | false | +| System.IO.Compression.PositionPreservingWriteOnlyStreamWrapper.WriteAsync(Byte[], int, int, CancellationToken) | argument 0 -> argument -1 | false | +| System.IO.Compression.SubReadStream.Read(Byte[], int, int) | argument -1 -> return (out parameter 0) | false | +| System.IO.Compression.SubReadStream.Write(Byte[], int, int) | argument 0 -> argument -1 | false | +| System.IO.Compression.WrappedStream.Read(Byte[], int, int) | argument -1 -> return (out parameter 0) | false | +| System.IO.Compression.WrappedStream.Write(Byte[], int, int) | argument 0 -> argument -1 | false | +| System.IO.Compression.ZipArchiveEntry.DirectToArchiveWriterStream.Read(Byte[], int, int) | argument -1 -> return (out parameter 0) | false | +| System.IO.Compression.ZipArchiveEntry.DirectToArchiveWriterStream.Write(Byte[], int, int) | argument 0 -> argument -1 | false | +| System.IO.FileStream.BeginRead(Byte[], int, int, AsyncCallback, object) | argument -1 -> return (out parameter 0) | false | +| System.IO.FileStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | argument 0 -> argument -1 | false | +| System.IO.FileStream.CopyToAsync(Stream, int, CancellationToken) | argument -1 -> return (out parameter 0) | false | +| System.IO.FileStream.Read(Byte[], int, int) | argument -1 -> return (out parameter 0) | false | +| System.IO.FileStream.ReadAsync(Byte[], int, int, CancellationToken) | argument -1 -> return (out parameter 0) | false | +| System.IO.FileStream.Write(Byte[], int, int) | argument 0 -> argument -1 | false | +| System.IO.FileStream.WriteAsync(Byte[], int, int, CancellationToken) | argument 0 -> argument -1 | false | +| System.IO.MemoryStream.CopyTo(Stream, int) | argument -1 -> return (out parameter 0) | false | +| System.IO.MemoryStream.CopyToAsync(Stream, int, CancellationToken) | argument -1 -> return (out parameter 0) | false | +| System.IO.MemoryStream.MemoryStream(Byte[]) | argument 0 -> return (normal) | false | +| System.IO.MemoryStream.MemoryStream(Byte[], bool) | argument 0 -> return (normal) | false | +| System.IO.MemoryStream.MemoryStream(Byte[], int, int) | argument 0 -> return (normal) | false | +| System.IO.MemoryStream.MemoryStream(Byte[], int, int, bool) | argument 0 -> return (normal) | false | +| System.IO.MemoryStream.MemoryStream(Byte[], int, int, bool, bool) | argument 0 -> return (normal) | false | +| System.IO.MemoryStream.Read(Byte[], int, int) | argument -1 -> return (out parameter 0) | false | +| System.IO.MemoryStream.ReadAsync(Byte[], int, int, CancellationToken) | argument -1 -> return (out parameter 0) | false | +| System.IO.MemoryStream.ToArray() | argument -1 -> return (normal) | false | +| System.IO.MemoryStream.Write(Byte[], int, int) | argument 0 -> argument -1 | false | +| System.IO.MemoryStream.WriteAsync(Byte[], int, int, CancellationToken) | argument 0 -> argument -1 | false | +| System.IO.Path.Combine(params String[]) | element of argument 0 -> return (normal) | false | +| System.IO.Path.Combine(string, string) | argument 0 -> return (normal) | false | +| System.IO.Path.Combine(string, string) | argument 1 -> return (normal) | false | +| System.IO.Path.Combine(string, string, string) | argument 0 -> return (normal) | false | +| System.IO.Path.Combine(string, string, string) | argument 1 -> return (normal) | false | +| System.IO.Path.Combine(string, string, string) | argument 2 -> return (normal) | false | +| System.IO.Path.Combine(string, string, string, string) | argument 0 -> return (normal) | false | +| System.IO.Path.Combine(string, string, string, string) | argument 1 -> return (normal) | false | +| System.IO.Path.Combine(string, string, string, string) | argument 2 -> return (normal) | false | +| System.IO.Path.Combine(string, string, string, string) | argument 3 -> return (normal) | false | +| System.IO.Path.GetDirectoryName(ReadOnlySpan) | argument 0 -> return (normal) | false | +| System.IO.Path.GetDirectoryName(string) | argument 0 -> return (normal) | false | +| System.IO.Path.GetExtension(ReadOnlySpan) | argument 0 -> return (normal) | false | +| System.IO.Path.GetExtension(string) | argument 0 -> return (normal) | false | +| System.IO.Path.GetFileName(ReadOnlySpan) | argument 0 -> return (normal) | false | +| System.IO.Path.GetFileName(string) | argument 0 -> return (normal) | false | +| System.IO.Path.GetFileNameWithoutExtension(ReadOnlySpan) | argument 0 -> return (normal) | false | +| System.IO.Path.GetFileNameWithoutExtension(string) | argument 0 -> return (normal) | false | +| System.IO.Path.GetFullPath(string) | argument 0 -> return (normal) | false | +| System.IO.Path.GetFullPath(string, string) | argument 0 -> return (normal) | false | +| System.IO.Path.GetPathRoot(ReadOnlySpan) | argument 0 -> return (normal) | false | +| System.IO.Path.GetPathRoot(string) | argument 0 -> return (normal) | false | +| System.IO.Path.GetRelativePath(string, string) | argument 1 -> return (normal) | false | +| System.IO.Pipes.PipeStream.BeginRead(Byte[], int, int, AsyncCallback, object) | argument -1 -> return (out parameter 0) | false | +| System.IO.Pipes.PipeStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | argument 0 -> argument -1 | false | +| System.IO.Pipes.PipeStream.Read(Byte[], int, int) | argument -1 -> return (out parameter 0) | false | +| System.IO.Pipes.PipeStream.ReadAsync(Byte[], int, int, CancellationToken) | argument -1 -> return (out parameter 0) | false | +| System.IO.Pipes.PipeStream.Write(Byte[], int, int) | argument 0 -> argument -1 | false | +| System.IO.Pipes.PipeStream.WriteAsync(Byte[], int, int, CancellationToken) | argument 0 -> argument -1 | false | +| System.IO.Stream.BeginRead(Byte[], int, int, AsyncCallback, object) | argument -1 -> return (out parameter 0) | false | +| System.IO.Stream.BeginWrite(Byte[], int, int, AsyncCallback, object) | argument 0 -> argument -1 | false | +| System.IO.Stream.CopyTo(Stream) | argument -1 -> return (out parameter 0) | false | +| System.IO.Stream.CopyTo(Stream, int) | argument -1 -> return (out parameter 0) | false | +| System.IO.Stream.CopyToAsync(Stream) | argument -1 -> return (out parameter 0) | false | +| System.IO.Stream.CopyToAsync(Stream, CancellationToken) | argument -1 -> return (out parameter 0) | false | +| System.IO.Stream.CopyToAsync(Stream, int) | argument -1 -> return (out parameter 0) | false | +| System.IO.Stream.CopyToAsync(Stream, int, CancellationToken) | argument -1 -> return (out parameter 0) | false | +| System.IO.Stream.NullStream.BeginRead(Byte[], int, int, AsyncCallback, object) | argument -1 -> return (out parameter 0) | false | +| System.IO.Stream.NullStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | argument 0 -> argument -1 | false | +| System.IO.Stream.NullStream.CopyTo(Stream, int) | argument -1 -> return (out parameter 0) | false | +| System.IO.Stream.NullStream.CopyToAsync(Stream, int, CancellationToken) | argument -1 -> return (out parameter 0) | false | +| System.IO.Stream.NullStream.Read(Byte[], int, int) | argument -1 -> return (out parameter 0) | false | +| System.IO.Stream.NullStream.ReadAsync(Byte[], int, int, CancellationToken) | argument -1 -> return (out parameter 0) | false | +| System.IO.Stream.NullStream.Write(Byte[], int, int) | argument 0 -> argument -1 | false | +| System.IO.Stream.NullStream.WriteAsync(Byte[], int, int, CancellationToken) | argument 0 -> argument -1 | false | +| System.IO.Stream.Read(Byte[], int, int) | argument -1 -> return (out parameter 0) | false | +| System.IO.Stream.ReadAsync(Byte[], int, int) | argument -1 -> return (out parameter 0) | false | +| System.IO.Stream.ReadAsync(Byte[], int, int, CancellationToken) | argument -1 -> return (out parameter 0) | false | +| System.IO.Stream.SyncStream.BeginRead(Byte[], int, int, AsyncCallback, object) | argument -1 -> return (out parameter 0) | false | +| System.IO.Stream.SyncStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | argument 0 -> argument -1 | false | +| System.IO.Stream.SyncStream.Read(Byte[], int, int) | argument -1 -> return (out parameter 0) | false | +| System.IO.Stream.SyncStream.Write(Byte[], int, int) | argument 0 -> argument -1 | false | +| System.IO.Stream.Write(Byte[], int, int) | argument 0 -> argument -1 | false | +| System.IO.Stream.WriteAsync(Byte[], int, int) | argument 0 -> argument -1 | false | +| System.IO.Stream.WriteAsync(Byte[], int, int, CancellationToken) | argument 0 -> argument -1 | false | +| System.IO.StringReader.Read() | argument -1 -> return (normal) | false | +| System.IO.StringReader.Read(Char[], int, int) | argument -1 -> return (normal) | false | +| System.IO.StringReader.Read(Span) | argument -1 -> return (normal) | false | +| System.IO.StringReader.ReadAsync(Char[], int, int) | argument -1 -> return (normal) | false | +| System.IO.StringReader.ReadAsync(Memory, CancellationToken) | argument -1 -> return (normal) | false | +| System.IO.StringReader.ReadBlock(Span) | argument -1 -> return (normal) | false | +| System.IO.StringReader.ReadBlockAsync(Char[], int, int) | argument -1 -> return (normal) | false | +| System.IO.StringReader.ReadBlockAsync(Memory, CancellationToken) | argument -1 -> return (normal) | false | +| System.IO.StringReader.ReadLine() | argument -1 -> return (normal) | false | +| System.IO.StringReader.ReadLineAsync() | argument -1 -> return (normal) | false | +| System.IO.StringReader.ReadToEnd() | argument -1 -> return (normal) | false | +| System.IO.StringReader.ReadToEndAsync() | argument -1 -> return (normal) | false | +| System.IO.StringReader.StringReader(string) | argument 0 -> return (normal) | false | +| System.IO.TextReader.Read() | argument -1 -> return (normal) | false | +| System.IO.TextReader.Read(Char[], int, int) | argument -1 -> return (normal) | false | +| System.IO.TextReader.Read(Span) | argument -1 -> return (normal) | false | +| System.IO.TextReader.ReadAsync(Char[], int, int) | argument -1 -> return (normal) | false | +| System.IO.TextReader.ReadAsync(Memory, CancellationToken) | argument -1 -> return (normal) | false | +| System.IO.TextReader.ReadAsyncInternal(Memory, CancellationToken) | argument -1 -> return (normal) | false | +| System.IO.TextReader.ReadBlock(Char[], int, int) | argument -1 -> return (normal) | false | +| System.IO.TextReader.ReadBlock(Span) | argument -1 -> return (normal) | false | +| System.IO.TextReader.ReadBlockAsync(Char[], int, int) | argument -1 -> return (normal) | false | +| System.IO.TextReader.ReadBlockAsync(Memory, CancellationToken) | argument -1 -> return (normal) | false | +| System.IO.TextReader.ReadLine() | argument -1 -> return (normal) | false | +| System.IO.TextReader.ReadLineAsync() | argument -1 -> return (normal) | false | +| System.IO.TextReader.ReadToEnd() | argument -1 -> return (normal) | false | +| System.IO.TextReader.ReadToEndAsync() | argument -1 -> return (normal) | false | +| System.IO.UnmanagedMemoryStream.Read(Byte[], int, int) | argument -1 -> return (out parameter 0) | false | +| System.IO.UnmanagedMemoryStream.ReadAsync(Byte[], int, int, CancellationToken) | argument -1 -> return (out parameter 0) | false | +| System.IO.UnmanagedMemoryStream.Write(Byte[], int, int) | argument 0 -> argument -1 | false | +| System.IO.UnmanagedMemoryStream.WriteAsync(Byte[], int, int, CancellationToken) | argument 0 -> argument -1 | false | +| System.IO.UnmanagedMemoryStreamWrapper.CopyToAsync(Stream, int, CancellationToken) | argument -1 -> return (out parameter 0) | false | +| System.IO.UnmanagedMemoryStreamWrapper.Read(Byte[], int, int) | argument -1 -> return (out parameter 0) | false | +| System.IO.UnmanagedMemoryStreamWrapper.ReadAsync(Byte[], int, int, CancellationToken) | argument -1 -> return (out parameter 0) | false | +| System.IO.UnmanagedMemoryStreamWrapper.ToArray() | argument -1 -> return (normal) | false | +| System.IO.UnmanagedMemoryStreamWrapper.Write(Byte[], int, int) | argument 0 -> argument -1 | false | +| System.IO.UnmanagedMemoryStreamWrapper.WriteAsync(Byte[], int, int, CancellationToken) | argument 0 -> argument -1 | false | +| System.Int32.Parse(string) | argument 0 -> return (normal) | false | +| System.Int32.Parse(string, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Int32.Parse(string, NumberStyles) | argument 0 -> return (normal) | false | +| System.Int32.Parse(string, NumberStyles, IFormatProvider) | argument 0 -> return (normal) | false | +| System.Int32.TryParse(string, NumberStyles, IFormatProvider, out int) | argument 0 -> return (normal) | false | +| System.Int32.TryParse(string, NumberStyles, IFormatProvider, out int) | argument 0 -> return (out parameter 3) | false | +| System.Int32.TryParse(string, out int) | argument 0 -> return (normal) | false | +| System.Int32.TryParse(string, out int) | argument 0 -> return (out parameter 1) | false | +| System.Lazy<>.Lazy(Func) | return (normal) of argument 0 -> property Value of return (normal) | true | +| System.Lazy<>.Lazy(Func, LazyThreadSafetyMode) | return (normal) of argument 0 -> property Value of return (normal) | true | +| System.Lazy<>.Lazy(Func, bool) | return (normal) of argument 0 -> property Value of return (normal) | true | +| System.Lazy<>.get_Value() | argument -1 -> return (normal) | false | +| System.Linq.EmptyPartition<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Enumerable.d__64<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Enumerable.d__81<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Enumerable.d__98<,,,>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Enumerable.d__101<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Enumerable.d__105<,,,>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Enumerable.d__62<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Enumerable.d__174<,>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Enumerable.d__177<,>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Enumerable.d__179<,,>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Enumerable.d__181<,,>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Enumerable.d__194<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Enumerable.d__190<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Enumerable.d__192<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Enumerable.d__221<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Enumerable.d__217<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Enumerable.d__219<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Enumerable.d__240<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Enumerable.d__243<,>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Enumerable.d__244<,,>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func, Func) | argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func, Func) | element of argument 0 -> parameter 1 of argument 2 | true | +| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func, Func) | return (normal) of argument 2 -> parameter 0 of argument 3 | true | +| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func, Func) | return (normal) of argument 3 -> return (normal) | true | +| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func) | argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func) | element of argument 0 -> parameter 1 of argument 2 | true | +| System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func) | return (normal) of argument 2 -> return (normal) | true | +| System.Linq.Enumerable.Aggregate(IEnumerable, Func) | element of argument 0 -> parameter 1 of argument 1 | true | +| System.Linq.Enumerable.Aggregate(IEnumerable, Func) | return (normal) of argument 1 -> return (normal) | true | +| System.Linq.Enumerable.All(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Any(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.AsEnumerable(IEnumerable) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Enumerable.Average(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Average(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Average(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Average(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Average(IEnumerable, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Average(IEnumerable, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Average(IEnumerable, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Average(IEnumerable, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Average(IEnumerable, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Average(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Cast(IEnumerable) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Enumerable.Concat(IEnumerable, IEnumerable) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Enumerable.Concat(IEnumerable, IEnumerable) | element of argument 1 -> element of return (normal) | true | +| System.Linq.Enumerable.Count(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.DefaultIfEmpty(IEnumerable) | element of argument 0 -> return (normal) | true | +| System.Linq.Enumerable.DefaultIfEmpty(IEnumerable, TSource) | argument 1 -> return (normal) | true | +| System.Linq.Enumerable.DefaultIfEmpty(IEnumerable, TSource) | element of argument 0 -> return (normal) | true | +| System.Linq.Enumerable.Distinct(IEnumerable) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Enumerable.Distinct(IEnumerable, IEqualityComparer) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Enumerable.ElementAt(IEnumerable, int) | element of argument 0 -> return (normal) | true | +| System.Linq.Enumerable.ElementAtOrDefault(IEnumerable, int) | element of argument 0 -> return (normal) | true | +| System.Linq.Enumerable.Except(IEnumerable, IEnumerable) | element of argument 0 -> return (normal) | true | +| System.Linq.Enumerable.Except(IEnumerable, IEnumerable, IEqualityComparer) | element of argument 0 -> return (normal) | true | +| System.Linq.Enumerable.First(IEnumerable) | element of argument 0 -> return (normal) | true | +| System.Linq.Enumerable.First(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.First(IEnumerable, Func) | element of argument 0 -> return (normal) | true | +| System.Linq.Enumerable.FirstOrDefault(IEnumerable) | element of argument 0 -> return (normal) | true | +| System.Linq.Enumerable.FirstOrDefault(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.FirstOrDefault(IEnumerable, Func) | element of argument 0 -> return (normal) | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | return (normal) of argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | return (normal) of argument 2 -> element of parameter 1 of argument 3 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | return (normal) of argument 3 -> element of return (normal) | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | return (normal) of argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | return (normal) of argument 2 -> element of parameter 1 of argument 3 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | return (normal) of argument 3 -> element of return (normal) | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func) | return (normal) of argument 2 -> element of return (normal) | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, IEqualityComparer) | return (normal) of argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>) | argument 0 -> parameter 1 of argument 2 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>) | return (normal) of argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>) | return (normal) of argument 2 -> element of return (normal) | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, TResult>, IEqualityComparer) | return (normal) of argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.GroupBy(IEnumerable, Func, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | element of argument 0 -> parameter 0 of argument 4 | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | element of argument 1 -> parameter 0 of argument 3 | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | element of argument 1 -> parameter 1 of argument 4 | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>) | return (normal) of argument 4 -> element of return (normal) | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 4 | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | element of argument 1 -> parameter 0 of argument 3 | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | element of argument 1 -> parameter 1 of argument 4 | true | +| System.Linq.Enumerable.GroupJoin(IEnumerable, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | return (normal) of argument 4 -> element of return (normal) | true | +| System.Linq.Enumerable.Intersect(IEnumerable, IEnumerable) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Enumerable.Intersect(IEnumerable, IEnumerable) | element of argument 1 -> element of return (normal) | true | +| System.Linq.Enumerable.Intersect(IEnumerable, IEnumerable, IEqualityComparer) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Enumerable.Intersect(IEnumerable, IEnumerable, IEqualityComparer) | element of argument 1 -> element of return (normal) | true | +| System.Linq.Enumerable.Iterator<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | element of argument 0 -> parameter 0 of argument 4 | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | element of argument 1 -> parameter 0 of argument 3 | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | element of argument 1 -> parameter 1 of argument 4 | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func) | return (normal) of argument 4 -> element of return (normal) | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 4 | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | element of argument 1 -> parameter 0 of argument 3 | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | element of argument 1 -> parameter 1 of argument 4 | true | +| System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | return (normal) of argument 4 -> element of return (normal) | true | +| System.Linq.Enumerable.Last(IEnumerable) | element of argument 0 -> return (normal) | true | +| System.Linq.Enumerable.Last(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Last(IEnumerable, Func) | element of argument 0 -> return (normal) | true | +| System.Linq.Enumerable.LastOrDefault(IEnumerable) | element of argument 0 -> return (normal) | true | +| System.Linq.Enumerable.LastOrDefault(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.LastOrDefault(IEnumerable, Func) | element of argument 0 -> return (normal) | true | +| System.Linq.Enumerable.LongCount(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Max(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Max(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Max(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Max(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Max(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Max(IEnumerable, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Max(IEnumerable, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Max(IEnumerable, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Max(IEnumerable, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Max(IEnumerable, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Max(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Min(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Min(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Min(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Min(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Min(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Min(IEnumerable, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Min(IEnumerable, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Min(IEnumerable, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Min(IEnumerable, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Min(IEnumerable, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Min(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.OfType(IEnumerable) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Enumerable.OrderBy(IEnumerable, Func) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Enumerable.OrderBy(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.OrderBy(IEnumerable, Func, IComparer) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Enumerable.OrderBy(IEnumerable, Func, IComparer) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.OrderByDescending(IEnumerable, Func) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Enumerable.OrderByDescending(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.OrderByDescending(IEnumerable, Func, IComparer) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Enumerable.OrderByDescending(IEnumerable, Func, IComparer) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Reverse(IEnumerable) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Enumerable.Select(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Select(IEnumerable, Func) | return (normal) of argument 1 -> element of return (normal) | true | +| System.Linq.Enumerable.Select(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Select(IEnumerable, Func) | return (normal) of argument 1 -> element of return (normal) | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | element of return (normal) of argument 1 -> parameter 1 of argument 2 | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | return (normal) of argument 2 -> element of return (normal) | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | element of return (normal) of argument 1 -> parameter 1 of argument 2 | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | return (normal) of argument 2 -> element of return (normal) | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>) | return (normal) of argument 1 -> element of return (normal) | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>) | return (normal) of argument 1 -> element of return (normal) | true | +| System.Linq.Enumerable.Single(IEnumerable) | element of argument 0 -> return (normal) | true | +| System.Linq.Enumerable.Single(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Single(IEnumerable, Func) | element of argument 0 -> return (normal) | true | +| System.Linq.Enumerable.SingleOrDefault(IEnumerable) | element of argument 0 -> return (normal) | true | +| System.Linq.Enumerable.SingleOrDefault(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.SingleOrDefault(IEnumerable, Func) | element of argument 0 -> return (normal) | true | +| System.Linq.Enumerable.Skip(IEnumerable, int) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Sum(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Take(IEnumerable, int) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.ThenBy(IOrderedEnumerable, Func) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Enumerable.ThenBy(IOrderedEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.ThenBy(IOrderedEnumerable, Func, IComparer) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Enumerable.ThenBy(IOrderedEnumerable, Func, IComparer) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.ThenByDescending(IOrderedEnumerable, Func) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Enumerable.ThenByDescending(IOrderedEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.ThenByDescending(IOrderedEnumerable, Func, IComparer) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Enumerable.ThenByDescending(IOrderedEnumerable, Func, IComparer) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.ToArray(IEnumerable) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func) | return (normal) of argument 2 -> element of return (normal) | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, Func, IEqualityComparer) | return (normal) of argument 2 -> element of return (normal) | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, IEqualityComparer) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Enumerable.ToDictionary(IEnumerable, Func, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.ToList(IEnumerable) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func) | return (normal) of argument 2 -> element of return (normal) | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func, Func, IEqualityComparer) | return (normal) of argument 2 -> element of return (normal) | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func, IEqualityComparer) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Enumerable.ToLookup(IEnumerable, Func, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Union(IEnumerable, IEnumerable) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Enumerable.Union(IEnumerable, IEnumerable) | element of argument 1 -> element of return (normal) | true | +| System.Linq.Enumerable.Union(IEnumerable, IEnumerable, IEqualityComparer) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Enumerable.Union(IEnumerable, IEnumerable, IEqualityComparer) | element of argument 1 -> element of return (normal) | true | +| System.Linq.Enumerable.Where(IEnumerable, Func) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Enumerable.Where(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Where(IEnumerable, Func) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Enumerable.Where(IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Enumerable.Zip(IEnumerable, IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.Zip(IEnumerable, IEnumerable, Func) | element of argument 1 -> parameter 1 of argument 2 | true | +| System.Linq.Enumerable.Zip(IEnumerable, IEnumerable, Func) | return (normal) of argument 2 -> element of return (normal) | true | +| System.Linq.EnumerableQuery<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Expressions.BlockExpressionList.Add(Expression) | argument 0 -> element of argument -1 | true | +| System.Linq.Expressions.BlockExpressionList.CopyTo(Expression[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Linq.Expressions.BlockExpressionList.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Expressions.BlockExpressionList.Insert(int, Expression) | argument 1 -> element of argument -1 | true | +| System.Linq.Expressions.BlockExpressionList.get_Item(int) | element of argument -1 -> return (normal) | true | +| System.Linq.Expressions.BlockExpressionList.set_Item(int, Expression) | argument 1 -> element of argument -1 | true | +| System.Linq.Expressions.Compiler.CompilerScope.d__32.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Expressions.Compiler.ParameterList.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Expressions.Interpreter.InterpretedFrame.d__29.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.GroupedEnumerable<,,>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.GroupedEnumerable<,>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.GroupedResultEnumerable<,,,>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.GroupedResultEnumerable<,,>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Grouping<,>.Add(TElement) | argument 0 -> element of argument -1 | true | +| System.Linq.Grouping<,>.CopyTo(TElement[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Linq.Grouping<,>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Grouping<,>.Insert(int, TElement) | argument 1 -> element of argument -1 | true | +| System.Linq.Grouping<,>.get_Item(int) | element of argument -1 -> return (normal) | true | +| System.Linq.Grouping<,>.set_Item(int, TElement) | argument 1 -> element of argument -1 | true | +| System.Linq.Lookup<,>.d__19<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Lookup<,>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.OrderedEnumerable<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.OrderedPartition<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Parallel.CancellableEnumerable.d__0<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Parallel.EnumerableWrapperWeakToStrong.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Parallel.ExceptionAggregator.d__0<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Parallel.ExceptionAggregator.d__1<,>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Parallel.GroupByGrouping<,>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Parallel.ListChunk<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Parallel.Lookup<,>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Parallel.MergeExecutor<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Parallel.OrderedGroupByGrouping<,,>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Parallel.ParallelEnumerableWrapper.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Parallel.PartitionerQueryOperator<>.d__5.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Parallel.QueryResults<>.Add(T) | argument 0 -> element of argument -1 | true | +| System.Linq.Parallel.QueryResults<>.CopyTo(T[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Linq.Parallel.QueryResults<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Parallel.QueryResults<>.Insert(int, T) | argument 1 -> element of argument -1 | true | +| System.Linq.Parallel.QueryResults<>.get_Item(int) | element of argument -1 -> return (normal) | true | +| System.Linq.Parallel.QueryResults<>.set_Item(int, T) | argument 1 -> element of argument -1 | true | +| System.Linq.Parallel.RangeEnumerable.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Parallel.ZipQueryOperator<,,>.d__9.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func, Func) | argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func, Func) | element of argument 0 -> parameter 1 of argument 2 | true | +| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func, Func) | return (normal) of argument 2 -> parameter 0 of argument 3 | true | +| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func, Func) | return (normal) of argument 3 -> return (normal) | true | +| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func) | argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func) | element of argument 0 -> parameter 1 of argument 2 | true | +| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func) | return (normal) of argument 2 -> return (normal) | true | +| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, Func) | element of argument 0 -> parameter 1 of argument 1 | true | +| System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, Func) | return (normal) of argument 1 -> return (normal) | true | +| System.Linq.ParallelEnumerable.All(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Any(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.AsEnumerable(ParallelQuery) | element of argument 0 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Cast(ParallelQuery) | element of argument 0 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.Concat(ParallelQuery, IEnumerable) | element of argument 0 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.Concat(ParallelQuery, IEnumerable) | element of argument 1 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.Concat(ParallelQuery, ParallelQuery) | element of argument 0 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.Concat(ParallelQuery, ParallelQuery) | element of argument 1 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.Count(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.DefaultIfEmpty(ParallelQuery) | element of argument 0 -> return (normal) | true | +| System.Linq.ParallelEnumerable.DefaultIfEmpty(ParallelQuery, TSource) | argument 1 -> return (normal) | true | +| System.Linq.ParallelEnumerable.DefaultIfEmpty(ParallelQuery, TSource) | element of argument 0 -> return (normal) | true | +| System.Linq.ParallelEnumerable.Distinct(ParallelQuery) | element of argument 0 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.Distinct(ParallelQuery, IEqualityComparer) | element of argument 0 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.ElementAt(ParallelQuery, int) | element of argument 0 -> return (normal) | true | +| System.Linq.ParallelEnumerable.ElementAtOrDefault(ParallelQuery, int) | element of argument 0 -> return (normal) | true | +| System.Linq.ParallelEnumerable.Except(ParallelQuery, IEnumerable) | element of argument 0 -> return (normal) | true | +| System.Linq.ParallelEnumerable.Except(ParallelQuery, IEnumerable, IEqualityComparer) | element of argument 0 -> return (normal) | true | +| System.Linq.ParallelEnumerable.Except(ParallelQuery, ParallelQuery) | element of argument 0 -> return (normal) | true | +| System.Linq.ParallelEnumerable.Except(ParallelQuery, ParallelQuery, IEqualityComparer) | element of argument 0 -> return (normal) | true | +| System.Linq.ParallelEnumerable.First(ParallelQuery) | element of argument 0 -> return (normal) | true | +| System.Linq.ParallelEnumerable.First(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.First(ParallelQuery, Func) | element of argument 0 -> return (normal) | true | +| System.Linq.ParallelEnumerable.FirstOrDefault(ParallelQuery) | element of argument 0 -> return (normal) | true | +| System.Linq.ParallelEnumerable.FirstOrDefault(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.FirstOrDefault(ParallelQuery, Func) | element of argument 0 -> return (normal) | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | return (normal) of argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | return (normal) of argument 2 -> element of parameter 1 of argument 3 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | return (normal) of argument 3 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | return (normal) of argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | return (normal) of argument 2 -> element of parameter 1 of argument 3 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | return (normal) of argument 3 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func) | return (normal) of argument 2 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, IEqualityComparer) | return (normal) of argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>) | argument 0 -> parameter 1 of argument 2 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>) | return (normal) of argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>) | return (normal) of argument 2 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, TResult>, IEqualityComparer) | return (normal) of argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | element of argument 0 -> parameter 0 of argument 4 | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | element of argument 1 -> parameter 0 of argument 3 | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | element of argument 1 -> parameter 1 of argument 4 | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>) | return (normal) of argument 4 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 4 | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | element of argument 1 -> parameter 0 of argument 3 | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | element of argument 1 -> parameter 1 of argument 4 | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, IEnumerable, Func, Func, Func, TResult>, IEqualityComparer) | return (normal) of argument 4 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | element of argument 0 -> parameter 0 of argument 4 | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | element of argument 1 -> parameter 0 of argument 3 | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | element of argument 1 -> parameter 1 of argument 4 | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>) | return (normal) of argument 4 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 4 | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | element of argument 1 -> parameter 0 of argument 3 | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | element of argument 1 -> parameter 1 of argument 4 | true | +| System.Linq.ParallelEnumerable.GroupJoin(ParallelQuery, ParallelQuery, Func, Func, Func, TResult>, IEqualityComparer) | return (normal) of argument 4 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, IEnumerable) | element of argument 0 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, IEnumerable) | element of argument 1 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, IEnumerable, IEqualityComparer) | element of argument 0 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, IEnumerable, IEqualityComparer) | element of argument 1 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, ParallelQuery) | element of argument 0 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, ParallelQuery) | element of argument 1 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, ParallelQuery, IEqualityComparer) | element of argument 0 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.Intersect(ParallelQuery, ParallelQuery, IEqualityComparer) | element of argument 1 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | element of argument 0 -> parameter 0 of argument 4 | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | element of argument 1 -> parameter 0 of argument 3 | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | element of argument 1 -> parameter 1 of argument 4 | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func) | return (normal) of argument 4 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 4 | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | element of argument 1 -> parameter 0 of argument 3 | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | element of argument 1 -> parameter 1 of argument 4 | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, IEnumerable, Func, Func, Func, IEqualityComparer) | return (normal) of argument 4 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | element of argument 0 -> parameter 0 of argument 4 | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | element of argument 1 -> parameter 0 of argument 3 | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | element of argument 1 -> parameter 1 of argument 4 | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func) | return (normal) of argument 4 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 4 | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | element of argument 1 -> parameter 0 of argument 3 | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | element of argument 1 -> parameter 1 of argument 4 | true | +| System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | return (normal) of argument 4 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.Last(ParallelQuery) | element of argument 0 -> return (normal) | true | +| System.Linq.ParallelEnumerable.Last(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Last(ParallelQuery, Func) | element of argument 0 -> return (normal) | true | +| System.Linq.ParallelEnumerable.LastOrDefault(ParallelQuery) | element of argument 0 -> return (normal) | true | +| System.Linq.ParallelEnumerable.LastOrDefault(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.LastOrDefault(ParallelQuery, Func) | element of argument 0 -> return (normal) | true | +| System.Linq.ParallelEnumerable.LongCount(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.OfType(ParallelQuery) | element of argument 0 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.OrderBy(ParallelQuery, Func) | element of argument 0 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.OrderBy(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.OrderBy(ParallelQuery, Func, IComparer) | element of argument 0 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.OrderBy(ParallelQuery, Func, IComparer) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.OrderByDescending(ParallelQuery, Func) | element of argument 0 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.OrderByDescending(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.OrderByDescending(ParallelQuery, Func, IComparer) | element of argument 0 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.OrderByDescending(ParallelQuery, Func, IComparer) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Reverse(ParallelQuery) | element of argument 0 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.Select(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Select(ParallelQuery, Func) | return (normal) of argument 1 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.Select(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Select(ParallelQuery, Func) | return (normal) of argument 1 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | element of return (normal) of argument 1 -> parameter 1 of argument 2 | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | return (normal) of argument 2 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | element of return (normal) of argument 1 -> parameter 1 of argument 2 | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | return (normal) of argument 2 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>) | return (normal) of argument 1 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>) | return (normal) of argument 1 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.Single(ParallelQuery) | element of argument 0 -> return (normal) | true | +| System.Linq.ParallelEnumerable.Single(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Single(ParallelQuery, Func) | element of argument 0 -> return (normal) | true | +| System.Linq.ParallelEnumerable.SingleOrDefault(ParallelQuery) | element of argument 0 -> return (normal) | true | +| System.Linq.ParallelEnumerable.SingleOrDefault(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.SingleOrDefault(ParallelQuery, Func) | element of argument 0 -> return (normal) | true | +| System.Linq.ParallelEnumerable.Skip(ParallelQuery, int) | element of argument 0 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | element of argument 0 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | element of argument 0 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Take(ParallelQuery, int) | element of argument 0 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | element of argument 0 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | element of argument 0 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.ThenBy(OrderedParallelQuery, Func) | element of argument 0 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.ThenBy(OrderedParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.ThenBy(OrderedParallelQuery, Func, IComparer) | element of argument 0 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.ThenBy(OrderedParallelQuery, Func, IComparer) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.ThenByDescending(OrderedParallelQuery, Func) | element of argument 0 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.ThenByDescending(OrderedParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.ThenByDescending(OrderedParallelQuery, Func, IComparer) | element of argument 0 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.ThenByDescending(OrderedParallelQuery, Func, IComparer) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.ToArray(ParallelQuery) | element of argument 0 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func) | return (normal) of argument 2 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, Func, IEqualityComparer) | return (normal) of argument 2 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func) | element of argument 0 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, IEqualityComparer) | element of argument 0 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.ToDictionary(ParallelQuery, Func, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.ToList(ParallelQuery) | element of argument 0 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func) | return (normal) of argument 2 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, Func, IEqualityComparer) | return (normal) of argument 2 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func) | element of argument 0 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, IEqualityComparer) | element of argument 0 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.ToLookup(ParallelQuery, Func, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Union(ParallelQuery, IEnumerable) | element of argument 0 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.Union(ParallelQuery, IEnumerable) | element of argument 1 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.Union(ParallelQuery, IEnumerable, IEqualityComparer) | element of argument 0 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.Union(ParallelQuery, IEnumerable, IEqualityComparer) | element of argument 1 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.Union(ParallelQuery, ParallelQuery) | element of argument 0 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.Union(ParallelQuery, ParallelQuery) | element of argument 1 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.Union(ParallelQuery, ParallelQuery, IEqualityComparer) | element of argument 0 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.Union(ParallelQuery, ParallelQuery, IEqualityComparer) | element of argument 1 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | element of argument 0 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | element of argument 0 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.ParallelEnumerable.Zip(ParallelQuery, IEnumerable, Func) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.Zip(ParallelQuery, IEnumerable, Func) | element of argument 1 -> parameter 1 of argument 2 | true | +| System.Linq.ParallelEnumerable.Zip(ParallelQuery, IEnumerable, Func) | return (normal) of argument 2 -> element of return (normal) | true | +| System.Linq.ParallelEnumerable.Zip(ParallelQuery, ParallelQuery, Func) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.Zip(ParallelQuery, ParallelQuery, Func) | element of argument 1 -> parameter 1 of argument 2 | true | +| System.Linq.ParallelEnumerable.Zip(ParallelQuery, ParallelQuery, Func) | return (normal) of argument 2 -> element of return (normal) | true | +| System.Linq.ParallelQuery.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>, Expression>) | argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>, Expression>) | element of argument 0 -> parameter 1 of argument 2 | true | +| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>, Expression>) | return (normal) of argument 2 -> parameter 0 of argument 3 | true | +| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>, Expression>) | return (normal) of argument 3 -> return (normal) | true | +| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>) | argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>) | element of argument 0 -> parameter 1 of argument 2 | true | +| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>) | return (normal) of argument 2 -> return (normal) | true | +| System.Linq.Queryable.Aggregate(IQueryable, Expression>) | element of argument 0 -> parameter 1 of argument 1 | true | +| System.Linq.Queryable.Aggregate(IQueryable, Expression>) | return (normal) of argument 1 -> return (normal) | true | +| System.Linq.Queryable.All(IQueryable, Expression>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.Any(IQueryable, Expression>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.AsQueryable(IEnumerable) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Queryable.AsQueryable(IEnumerable) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Queryable.Average(IQueryable, Expression>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.Average(IQueryable, Expression>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.Average(IQueryable, Expression>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.Average(IQueryable, Expression>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.Average(IQueryable, Expression>>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.Average(IQueryable, Expression>>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.Average(IQueryable, Expression>>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.Average(IQueryable, Expression>>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.Average(IQueryable, Expression>>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.Average(IQueryable, Expression>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.Cast(IQueryable) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Queryable.Concat(IQueryable, IEnumerable) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Queryable.Concat(IQueryable, IEnumerable) | element of argument 1 -> element of return (normal) | true | +| System.Linq.Queryable.Count(IQueryable, Expression>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.DefaultIfEmpty(IQueryable) | element of argument 0 -> return (normal) | true | +| System.Linq.Queryable.DefaultIfEmpty(IQueryable, TSource) | argument 1 -> return (normal) | true | +| System.Linq.Queryable.DefaultIfEmpty(IQueryable, TSource) | element of argument 0 -> return (normal) | true | +| System.Linq.Queryable.Distinct(IQueryable) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Queryable.Distinct(IQueryable, IEqualityComparer) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Queryable.ElementAt(IQueryable, int) | element of argument 0 -> return (normal) | true | +| System.Linq.Queryable.ElementAtOrDefault(IQueryable, int) | element of argument 0 -> return (normal) | true | +| System.Linq.Queryable.Except(IQueryable, IEnumerable) | element of argument 0 -> return (normal) | true | +| System.Linq.Queryable.Except(IQueryable, IEnumerable, IEqualityComparer) | element of argument 0 -> return (normal) | true | +| System.Linq.Queryable.First(IQueryable) | element of argument 0 -> return (normal) | true | +| System.Linq.Queryable.First(IQueryable, Expression>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.First(IQueryable, Expression>) | element of argument 0 -> return (normal) | true | +| System.Linq.Queryable.FirstOrDefault(IQueryable) | element of argument 0 -> return (normal) | true | +| System.Linq.Queryable.FirstOrDefault(IQueryable, Expression>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.FirstOrDefault(IQueryable, Expression>) | element of argument 0 -> return (normal) | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | return (normal) of argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | return (normal) of argument 2 -> element of parameter 1 of argument 3 | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | return (normal) of argument 3 -> element of return (normal) | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | return (normal) of argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | return (normal) of argument 2 -> element of parameter 1 of argument 3 | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | return (normal) of argument 3 -> element of return (normal) | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>) | return (normal) of argument 2 -> element of return (normal) | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, IEqualityComparer) | return (normal) of argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>) | return (normal) of argument 2 -> element of return (normal) | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>, IEqualityComparer) | return (normal) of argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | element of argument 0 -> parameter 0 of argument 4 | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | element of argument 1 -> parameter 0 of argument 3 | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | element of argument 1 -> parameter 1 of argument 4 | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | return (normal) of argument 4 -> element of return (normal) | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 4 | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | element of argument 1 -> parameter 0 of argument 3 | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | element of argument 1 -> parameter 1 of argument 4 | true | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | return (normal) of argument 4 -> element of return (normal) | true | +| System.Linq.Queryable.Intersect(IQueryable, IEnumerable) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Queryable.Intersect(IQueryable, IEnumerable) | element of argument 1 -> element of return (normal) | true | +| System.Linq.Queryable.Intersect(IQueryable, IEnumerable, IEqualityComparer) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Queryable.Intersect(IQueryable, IEnumerable, IEqualityComparer) | element of argument 1 -> element of return (normal) | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | element of argument 0 -> parameter 0 of argument 4 | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | element of argument 1 -> parameter 0 of argument 3 | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | element of argument 1 -> parameter 1 of argument 4 | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | return (normal) of argument 4 -> element of return (normal) | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | element of argument 0 -> parameter 0 of argument 4 | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | element of argument 1 -> parameter 0 of argument 3 | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | element of argument 1 -> parameter 1 of argument 4 | true | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | return (normal) of argument 4 -> element of return (normal) | true | +| System.Linq.Queryable.Last(IQueryable) | element of argument 0 -> return (normal) | true | +| System.Linq.Queryable.Last(IQueryable, Expression>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.Last(IQueryable, Expression>) | element of argument 0 -> return (normal) | true | +| System.Linq.Queryable.LastOrDefault(IQueryable) | element of argument 0 -> return (normal) | true | +| System.Linq.Queryable.LastOrDefault(IQueryable, Expression>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.LastOrDefault(IQueryable, Expression>) | element of argument 0 -> return (normal) | true | +| System.Linq.Queryable.LongCount(IQueryable, Expression>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.Max(IQueryable, Expression>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.Min(IQueryable, Expression>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.OfType(IQueryable) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Queryable.OrderBy(IQueryable, Expression>) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Queryable.OrderBy(IQueryable, Expression>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.OrderBy(IQueryable, Expression>, IComparer) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Queryable.OrderBy(IQueryable, Expression>, IComparer) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>, IComparer) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>, IComparer) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.Reverse(IQueryable) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Queryable.Select(IQueryable, Expression>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.Select(IQueryable, Expression>) | return (normal) of argument 1 -> element of return (normal) | true | +| System.Linq.Queryable.Select(IQueryable, Expression>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.Select(IQueryable, Expression>) | return (normal) of argument 1 -> element of return (normal) | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | element of return (normal) of argument 1 -> parameter 1 of argument 2 | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | return (normal) of argument 2 -> element of return (normal) | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | element of return (normal) of argument 1 -> parameter 1 of argument 2 | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | return (normal) of argument 2 -> element of return (normal) | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | return (normal) of argument 1 -> element of return (normal) | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | return (normal) of argument 1 -> element of return (normal) | true | +| System.Linq.Queryable.Single(IQueryable) | element of argument 0 -> return (normal) | true | +| System.Linq.Queryable.Single(IQueryable, Expression>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.Single(IQueryable, Expression>) | element of argument 0 -> return (normal) | true | +| System.Linq.Queryable.SingleOrDefault(IQueryable) | element of argument 0 -> return (normal) | true | +| System.Linq.Queryable.SingleOrDefault(IQueryable, Expression>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.SingleOrDefault(IQueryable, Expression>) | element of argument 0 -> return (normal) | true | +| System.Linq.Queryable.Skip(IQueryable, int) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.Sum(IQueryable, Expression>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.Take(IQueryable, int) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>, IComparer) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>, IComparer) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>, IComparer) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>, IComparer) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.Union(IQueryable, IEnumerable) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Queryable.Union(IQueryable, IEnumerable) | element of argument 1 -> element of return (normal) | true | +| System.Linq.Queryable.Union(IQueryable, IEnumerable, IEqualityComparer) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Queryable.Union(IQueryable, IEnumerable, IEqualityComparer) | element of argument 1 -> element of return (normal) | true | +| System.Linq.Queryable.Where(IQueryable, Expression>) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Queryable.Where(IQueryable, Expression>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.Where(IQueryable, Expression>) | element of argument 0 -> element of return (normal) | true | +| System.Linq.Queryable.Where(IQueryable, Expression>) | element of argument 0 -> parameter 0 of argument 1 | true | +| System.Linq.Queryable.Zip(IQueryable, IEnumerable, Expression>) | element of argument 0 -> parameter 0 of argument 2 | true | +| System.Linq.Queryable.Zip(IQueryable, IEnumerable, Expression>) | element of argument 1 -> parameter 1 of argument 2 | true | +| System.Linq.Queryable.Zip(IQueryable, IEnumerable, Expression>) | return (normal) of argument 2 -> element of return (normal) | true | +| System.Net.Cookie.get_Value() | argument -1 -> return (normal) | false | +| System.Net.CookieCollection.Add(Cookie) | argument 0 -> element of argument -1 | true | +| System.Net.CookieCollection.Add(CookieCollection) | argument 0 -> element of argument -1 | true | +| System.Net.CookieCollection.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Net.CookieCollection.CopyTo(Cookie[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Net.CookieCollection.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Net.CredentialCache.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Net.HttpListenerPrefixCollection.Add(string) | argument 0 -> element of argument -1 | true | +| System.Net.HttpListenerPrefixCollection.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Net.HttpListenerPrefixCollection.CopyTo(String[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Net.HttpListenerPrefixCollection.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Net.HttpRequestStream.BeginRead(Byte[], int, int, AsyncCallback, object) | argument -1 -> return (out parameter 0) | false | +| System.Net.HttpRequestStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | argument 0 -> argument -1 | false | +| System.Net.HttpRequestStream.Read(Byte[], int, int) | argument -1 -> return (out parameter 0) | false | +| System.Net.HttpRequestStream.Write(Byte[], int, int) | argument 0 -> argument -1 | false | +| System.Net.HttpResponseStream.BeginRead(Byte[], int, int, AsyncCallback, object) | argument -1 -> return (out parameter 0) | false | +| System.Net.HttpResponseStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | argument 0 -> argument -1 | false | +| System.Net.HttpResponseStream.Read(Byte[], int, int) | argument -1 -> return (out parameter 0) | false | +| System.Net.HttpResponseStream.Write(Byte[], int, int) | argument 0 -> argument -1 | false | +| System.Net.NetworkInformation.IPAddressCollection.Add(IPAddress) | argument 0 -> element of argument -1 | true | +| System.Net.NetworkInformation.IPAddressCollection.CopyTo(IPAddress[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Net.NetworkInformation.IPAddressCollection.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Net.Security.CipherSuitesPolicy.d__6.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Net.Security.NegotiateStream.BeginRead(Byte[], int, int, AsyncCallback, object) | argument -1 -> return (out parameter 0) | false | +| System.Net.Security.NegotiateStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | argument 0 -> argument -1 | false | +| System.Net.Security.NegotiateStream.Read(Byte[], int, int) | argument -1 -> return (out parameter 0) | false | +| System.Net.Security.NegotiateStream.ReadAsync(Byte[], int, int, CancellationToken) | argument -1 -> return (out parameter 0) | false | +| System.Net.Security.NegotiateStream.Write(Byte[], int, int) | argument 0 -> argument -1 | false | +| System.Net.Security.NegotiateStream.WriteAsync(Byte[], int, int, CancellationToken) | argument 0 -> argument -1 | false | +| System.Net.Security.SslStream.BeginRead(Byte[], int, int, AsyncCallback, object) | argument -1 -> return (out parameter 0) | false | +| System.Net.Security.SslStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | argument 0 -> argument -1 | false | +| System.Net.Security.SslStream.Read(Byte[], int, int) | argument -1 -> return (out parameter 0) | false | +| System.Net.Security.SslStream.ReadAsync(Byte[], int, int, CancellationToken) | argument -1 -> return (out parameter 0) | false | +| System.Net.Security.SslStream.Write(Byte[], int, int) | argument 0 -> argument -1 | false | +| System.Net.Security.SslStream.WriteAsync(Byte[], int, int, CancellationToken) | argument 0 -> argument -1 | false | +| System.Net.WebUtility.HtmlEncode(string) | argument 0 -> return (normal) | false | +| System.Net.WebUtility.HtmlEncode(string, TextWriter) | argument 0 -> return (normal) | false | +| System.Net.WebUtility.UrlEncode(string) | argument 0 -> return (normal) | false | +| System.Nullable<>.GetValueOrDefault() | property Value of argument -1 -> return (normal) | true | +| System.Nullable<>.GetValueOrDefault(T) | argument 0 -> return (normal) | true | +| System.Nullable<>.GetValueOrDefault(T) | property Value of argument -1 -> return (normal) | true | +| System.Nullable<>.Nullable(T) | argument 0 -> property Value of return (normal) | true | +| System.Nullable<>.get_HasValue() | property Value of argument -1 -> return (normal) | false | +| System.Nullable<>.get_Value() | argument -1 -> return (normal) | false | +| System.Reflection.TypeInfo.d__10.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Reflection.TypeInfo.d__22.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Resources.ResourceFallbackManager.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Resources.ResourceReader.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Resources.ResourceSet.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Resources.RuntimeResourceSet.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Runtime.CompilerServices.ConditionalWeakTable<,>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Runtime.CompilerServices.ConfiguredTaskAwaitable<>.ConfiguredTaskAwaiter.GetResult() | property Result of field m_task of argument -1 -> return (normal) | true | +| System.Runtime.CompilerServices.ConfiguredTaskAwaitable<>.GetAwaiter() | field m_configuredTaskAwaiter of argument -1 -> return (normal) | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Add(T) | argument 0 -> element of argument -1 | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Add(object) | argument 0 -> element of argument -1 | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.CopyTo(T[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Insert(int, T) | argument 1 -> element of argument -1 | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Insert(int, object) | argument 1 -> element of argument -1 | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Reverse() | element of argument 0 -> element of return (normal) | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Reverse(int, int) | element of argument 0 -> element of return (normal) | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.get_Item(int) | element of argument -1 -> return (normal) | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.set_Item(int, T) | argument 1 -> element of argument -1 | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.set_Item(int, object) | argument 1 -> element of argument -1 | true | +| System.Runtime.CompilerServices.TaskAwaiter<>.GetResult() | property Result of field m_task of argument -1 -> return (normal) | true | +| System.Runtime.InteropServices.MemoryMarshal.d__15<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Runtime.Loader.AssemblyLoadContext.d__83.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Runtime.Loader.AssemblyLoadContext.d__53.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Runtime.Loader.LibraryNameVariation.d__5.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Security.Cryptography.CryptoStream.BeginRead(Byte[], int, int, AsyncCallback, object) | argument -1 -> return (out parameter 0) | false | +| System.Security.Cryptography.CryptoStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | argument 0 -> argument -1 | false | +| System.Security.Cryptography.CryptoStream.Read(Byte[], int, int) | argument -1 -> return (out parameter 0) | false | +| System.Security.Cryptography.CryptoStream.ReadAsync(Byte[], int, int, CancellationToken) | argument -1 -> return (out parameter 0) | false | +| System.Security.Cryptography.CryptoStream.Write(Byte[], int, int) | argument 0 -> argument -1 | false | +| System.Security.Cryptography.CryptoStream.WriteAsync(Byte[], int, int, CancellationToken) | argument 0 -> argument -1 | false | +| System.Security.PermissionSet.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Security.PermissionSet.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.String.Clone() | argument -1 -> return (normal) | true | +| System.String.Concat(IEnumerable) | element of argument 0 -> return (normal) | false | +| System.String.Concat(ReadOnlySpan, ReadOnlySpan) | argument 0 -> return (normal) | false | +| System.String.Concat(ReadOnlySpan, ReadOnlySpan) | argument 1 -> return (normal) | false | +| System.String.Concat(ReadOnlySpan, ReadOnlySpan, ReadOnlySpan) | argument 0 -> return (normal) | false | +| System.String.Concat(ReadOnlySpan, ReadOnlySpan, ReadOnlySpan) | argument 1 -> return (normal) | false | +| System.String.Concat(ReadOnlySpan, ReadOnlySpan, ReadOnlySpan) | argument 2 -> return (normal) | false | +| System.String.Concat(ReadOnlySpan, ReadOnlySpan, ReadOnlySpan, ReadOnlySpan) | argument 0 -> return (normal) | false | +| System.String.Concat(ReadOnlySpan, ReadOnlySpan, ReadOnlySpan, ReadOnlySpan) | argument 1 -> return (normal) | false | +| System.String.Concat(ReadOnlySpan, ReadOnlySpan, ReadOnlySpan, ReadOnlySpan) | argument 2 -> return (normal) | false | +| System.String.Concat(ReadOnlySpan, ReadOnlySpan, ReadOnlySpan, ReadOnlySpan) | argument 3 -> return (normal) | false | +| System.String.Concat(object) | argument 0 -> return (normal) | false | +| System.String.Concat(object, object) | argument 0 -> return (normal) | false | +| System.String.Concat(object, object) | argument 1 -> return (normal) | false | +| System.String.Concat(object, object, object) | argument 0 -> return (normal) | false | +| System.String.Concat(object, object, object) | argument 1 -> return (normal) | false | +| System.String.Concat(object, object, object) | argument 2 -> return (normal) | false | +| System.String.Concat(params Object[]) | element of argument 0 -> return (normal) | false | +| System.String.Concat(params String[]) | element of argument 0 -> return (normal) | false | +| System.String.Concat(string, string) | argument 0 -> return (normal) | false | +| System.String.Concat(string, string) | argument 1 -> return (normal) | false | +| System.String.Concat(string, string, string) | argument 0 -> return (normal) | false | +| System.String.Concat(string, string, string) | argument 1 -> return (normal) | false | +| System.String.Concat(string, string, string) | argument 2 -> return (normal) | false | +| System.String.Concat(string, string, string, string) | argument 0 -> return (normal) | false | +| System.String.Concat(string, string, string, string) | argument 1 -> return (normal) | false | +| System.String.Concat(string, string, string, string) | argument 2 -> return (normal) | false | +| System.String.Concat(string, string, string, string) | argument 3 -> return (normal) | false | +| System.String.Concat(IEnumerable) | element of argument 0 -> return (normal) | false | +| System.String.Copy(string) | argument 0 -> return (normal) | true | +| System.String.Format(IFormatProvider, string, object) | argument 1 -> return (normal) | false | +| System.String.Format(IFormatProvider, string, object) | argument 2 -> return (normal) | false | +| System.String.Format(IFormatProvider, string, object, object) | argument 1 -> return (normal) | false | +| System.String.Format(IFormatProvider, string, object, object) | argument 2 -> return (normal) | false | +| System.String.Format(IFormatProvider, string, object, object) | argument 3 -> return (normal) | false | +| System.String.Format(IFormatProvider, string, object, object, object) | argument 1 -> return (normal) | false | +| System.String.Format(IFormatProvider, string, object, object, object) | argument 2 -> return (normal) | false | +| System.String.Format(IFormatProvider, string, object, object, object) | argument 3 -> return (normal) | false | +| System.String.Format(IFormatProvider, string, object, object, object) | argument 4 -> return (normal) | false | +| System.String.Format(IFormatProvider, string, params Object[]) | argument 1 -> return (normal) | false | +| System.String.Format(IFormatProvider, string, params Object[]) | element of argument 2 -> return (normal) | false | +| System.String.Format(string, object) | argument 0 -> return (normal) | false | +| System.String.Format(string, object) | argument 1 -> return (normal) | false | +| System.String.Format(string, object, object) | argument 0 -> return (normal) | false | +| System.String.Format(string, object, object) | argument 1 -> return (normal) | false | +| System.String.Format(string, object, object) | argument 2 -> return (normal) | false | +| System.String.Format(string, object, object, object) | argument 0 -> return (normal) | false | +| System.String.Format(string, object, object, object) | argument 1 -> return (normal) | false | +| System.String.Format(string, object, object, object) | argument 2 -> return (normal) | false | +| System.String.Format(string, object, object, object) | argument 3 -> return (normal) | false | +| System.String.Format(string, params Object[]) | argument 0 -> return (normal) | false | +| System.String.Format(string, params Object[]) | element of argument 1 -> return (normal) | false | +| System.String.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.String.Insert(int, string) | argument 1 -> return (normal) | false | +| System.String.Insert(int, string) | argument -1 -> return (normal) | false | +| System.String.Join(char, String[], int, int) | argument 0 -> return (normal) | false | +| System.String.Join(char, String[], int, int) | element of argument 1 -> return (normal) | false | +| System.String.Join(char, params Object[]) | argument 0 -> return (normal) | false | +| System.String.Join(char, params Object[]) | element of argument 1 -> return (normal) | false | +| System.String.Join(char, params String[]) | argument 0 -> return (normal) | false | +| System.String.Join(char, params String[]) | element of argument 1 -> return (normal) | false | +| System.String.Join(string, IEnumerable) | argument 0 -> return (normal) | false | +| System.String.Join(string, IEnumerable) | element of argument 1 -> return (normal) | false | +| System.String.Join(string, String[], int, int) | argument 0 -> return (normal) | false | +| System.String.Join(string, String[], int, int) | element of argument 1 -> return (normal) | false | +| System.String.Join(string, params Object[]) | argument 0 -> return (normal) | false | +| System.String.Join(string, params Object[]) | element of argument 1 -> return (normal) | false | +| System.String.Join(string, params String[]) | argument 0 -> return (normal) | false | +| System.String.Join(string, params String[]) | element of argument 1 -> return (normal) | false | +| System.String.Join(char, IEnumerable) | argument 0 -> return (normal) | false | +| System.String.Join(char, IEnumerable) | element of argument 1 -> return (normal) | false | +| System.String.Join(string, IEnumerable) | argument 0 -> return (normal) | false | +| System.String.Join(string, IEnumerable) | element of argument 1 -> return (normal) | false | +| System.String.Normalize() | argument -1 -> return (normal) | false | +| System.String.Normalize(NormalizationForm) | argument -1 -> return (normal) | false | +| System.String.PadLeft(int) | argument -1 -> return (normal) | false | +| System.String.PadLeft(int, char) | argument -1 -> return (normal) | false | +| System.String.PadRight(int) | argument -1 -> return (normal) | false | +| System.String.PadRight(int, char) | argument -1 -> return (normal) | false | +| System.String.Remove(int) | argument -1 -> return (normal) | false | +| System.String.Remove(int, int) | argument -1 -> return (normal) | false | +| System.String.Replace(char, char) | argument 1 -> return (normal) | false | +| System.String.Replace(char, char) | argument -1 -> return (normal) | false | +| System.String.Replace(string, string) | argument 1 -> return (normal) | false | +| System.String.Replace(string, string) | argument -1 -> return (normal) | false | +| System.String.Split(Char[], StringSplitOptions) | argument -1 -> element of return (normal) | false | +| System.String.Split(Char[], int) | argument -1 -> element of return (normal) | false | +| System.String.Split(Char[], int, StringSplitOptions) | argument -1 -> element of return (normal) | false | +| System.String.Split(String[], StringSplitOptions) | argument -1 -> element of return (normal) | false | +| System.String.Split(String[], int, StringSplitOptions) | argument -1 -> element of return (normal) | false | +| System.String.Split(char, StringSplitOptions) | argument -1 -> element of return (normal) | false | +| System.String.Split(char, int, StringSplitOptions) | argument -1 -> element of return (normal) | false | +| System.String.Split(params Char[]) | argument -1 -> element of return (normal) | false | +| System.String.Split(string, StringSplitOptions) | argument -1 -> element of return (normal) | false | +| System.String.Split(string, int, StringSplitOptions) | argument -1 -> element of return (normal) | false | +| System.String.String(Char[]) | element of argument 0 -> return (normal) | false | +| System.String.String(Char[], int, int) | element of argument 0 -> return (normal) | false | +| System.String.Substring(int) | argument -1 -> return (normal) | false | +| System.String.Substring(int, int) | argument -1 -> return (normal) | false | +| System.String.ToLower() | argument -1 -> return (normal) | false | +| System.String.ToLower(CultureInfo) | argument -1 -> return (normal) | false | +| System.String.ToLowerInvariant() | argument -1 -> return (normal) | false | +| System.String.ToString() | argument -1 -> return (normal) | true | +| System.String.ToString(IFormatProvider) | argument -1 -> return (normal) | true | +| System.String.ToUpper() | argument -1 -> return (normal) | false | +| System.String.ToUpper(CultureInfo) | argument -1 -> return (normal) | false | +| System.String.ToUpperInvariant() | argument -1 -> return (normal) | false | +| System.String.Trim() | argument -1 -> return (normal) | false | +| System.String.Trim(char) | argument -1 -> return (normal) | false | +| System.String.Trim(params Char[]) | argument -1 -> return (normal) | false | +| System.String.TrimEnd() | argument -1 -> return (normal) | false | +| System.String.TrimEnd(char) | argument -1 -> return (normal) | false | +| System.String.TrimEnd(params Char[]) | argument -1 -> return (normal) | false | +| System.String.TrimStart() | argument -1 -> return (normal) | false | +| System.String.TrimStart(char) | argument -1 -> return (normal) | false | +| System.String.TrimStart(params Char[]) | argument -1 -> return (normal) | false | +| System.Text.Encoding.GetBytes(Char[]) | element of argument 0 -> return (normal) | false | +| System.Text.Encoding.GetBytes(Char[], int, int) | element of argument 0 -> return (normal) | false | +| System.Text.Encoding.GetBytes(Char[], int, int, Byte[], int) | element of argument 0 -> return (normal) | false | +| System.Text.Encoding.GetBytes(ReadOnlySpan, Span) | argument 0 -> return (normal) | false | +| System.Text.Encoding.GetBytes(char*, int, byte*, int) | argument 0 -> return (normal) | false | +| System.Text.Encoding.GetBytes(char*, int, byte*, int, EncoderNLS) | argument 0 -> return (normal) | false | +| System.Text.Encoding.GetBytes(string) | argument 0 -> return (normal) | false | +| System.Text.Encoding.GetBytes(string, int, int) | argument 0 -> return (normal) | false | +| System.Text.Encoding.GetBytes(string, int, int, Byte[], int) | argument 0 -> return (normal) | false | +| System.Text.Encoding.GetChars(Byte[]) | element of argument 0 -> return (normal) | false | +| System.Text.Encoding.GetChars(Byte[], int, int) | element of argument 0 -> return (normal) | false | +| System.Text.Encoding.GetChars(Byte[], int, int, Char[], int) | element of argument 0 -> return (normal) | false | +| System.Text.Encoding.GetChars(ReadOnlySpan, Span) | element of argument 0 -> return (normal) | false | +| System.Text.Encoding.GetChars(byte*, int, char*, int) | element of argument 0 -> return (normal) | false | +| System.Text.Encoding.GetChars(byte*, int, char*, int, DecoderNLS) | element of argument 0 -> return (normal) | false | +| System.Text.Encoding.GetString(Byte[]) | element of argument 0 -> return (normal) | false | +| System.Text.Encoding.GetString(Byte[], int, int) | element of argument 0 -> return (normal) | false | +| System.Text.Encoding.GetString(ReadOnlySpan) | element of argument 0 -> return (normal) | false | +| System.Text.Encoding.GetString(byte*, int) | element of argument 0 -> return (normal) | false | +| System.Text.RegularExpressions.CaptureCollection.Add(Capture) | argument 0 -> element of argument -1 | true | +| System.Text.RegularExpressions.CaptureCollection.Add(object) | argument 0 -> element of argument -1 | true | +| System.Text.RegularExpressions.CaptureCollection.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Text.RegularExpressions.CaptureCollection.CopyTo(Capture[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Text.RegularExpressions.CaptureCollection.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Text.RegularExpressions.CaptureCollection.Insert(int, Capture) | argument 1 -> element of argument -1 | true | +| System.Text.RegularExpressions.CaptureCollection.Insert(int, object) | argument 1 -> element of argument -1 | true | +| System.Text.RegularExpressions.CaptureCollection.get_Item(int) | element of argument -1 -> return (normal) | true | +| System.Text.RegularExpressions.CaptureCollection.set_Item(int, Capture) | argument 1 -> element of argument -1 | true | +| System.Text.RegularExpressions.CaptureCollection.set_Item(int, object) | argument 1 -> element of argument -1 | true | +| System.Text.RegularExpressions.GroupCollection.d__49.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Text.RegularExpressions.GroupCollection.d__51.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Text.RegularExpressions.GroupCollection.Add(Group) | argument 0 -> element of argument -1 | true | +| System.Text.RegularExpressions.GroupCollection.Add(object) | argument 0 -> element of argument -1 | true | +| System.Text.RegularExpressions.GroupCollection.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Text.RegularExpressions.GroupCollection.CopyTo(Group[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Text.RegularExpressions.GroupCollection.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Text.RegularExpressions.GroupCollection.Insert(int, Group) | argument 1 -> element of argument -1 | true | +| System.Text.RegularExpressions.GroupCollection.Insert(int, object) | argument 1 -> element of argument -1 | true | +| System.Text.RegularExpressions.GroupCollection.get_Item(int) | element of argument -1 -> return (normal) | true | +| System.Text.RegularExpressions.GroupCollection.get_Item(string) | element of argument -1 -> return (normal) | true | +| System.Text.RegularExpressions.GroupCollection.set_Item(int, Group) | argument 1 -> element of argument -1 | true | +| System.Text.RegularExpressions.GroupCollection.set_Item(int, object) | argument 1 -> element of argument -1 | true | +| System.Text.RegularExpressions.MatchCollection.Add(Match) | argument 0 -> element of argument -1 | true | +| System.Text.RegularExpressions.MatchCollection.Add(object) | argument 0 -> element of argument -1 | true | +| System.Text.RegularExpressions.MatchCollection.CopyTo(Array, int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Text.RegularExpressions.MatchCollection.CopyTo(Match[], int) | element of argument -1 -> element of return (out parameter 0) | true | +| System.Text.RegularExpressions.MatchCollection.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Text.RegularExpressions.MatchCollection.Insert(int, Match) | argument 1 -> element of argument -1 | true | +| System.Text.RegularExpressions.MatchCollection.Insert(int, object) | argument 1 -> element of argument -1 | true | +| System.Text.RegularExpressions.MatchCollection.get_Item(int) | element of argument -1 -> return (normal) | true | +| System.Text.RegularExpressions.MatchCollection.set_Item(int, Match) | argument 1 -> element of argument -1 | true | +| System.Text.RegularExpressions.MatchCollection.set_Item(int, object) | argument 1 -> element of argument -1 | true | +| System.Text.StringBuilder.Append(object) | argument 0 -> element of argument -1 | true | +| System.Text.StringBuilder.Append(object) | argument 0 -> element of return (normal) | true | +| System.Text.StringBuilder.Append(string) | argument 0 -> element of argument -1 | true | +| System.Text.StringBuilder.Append(string) | argument 0 -> element of return (normal) | true | +| System.Text.StringBuilder.Append(string, int, int) | argument 0 -> element of argument -1 | true | +| System.Text.StringBuilder.Append(string, int, int) | argument 0 -> element of return (normal) | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object) | argument 1 -> element of argument -1 | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object) | argument 1 -> element of return (normal) | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object) | argument 2 -> element of argument -1 | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object) | argument 2 -> element of return (normal) | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | argument 1 -> element of argument -1 | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | argument 1 -> element of return (normal) | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | argument 2 -> element of argument -1 | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | argument 2 -> element of return (normal) | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | argument 3 -> element of argument -1 | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | argument 3 -> element of return (normal) | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 1 -> element of argument -1 | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 1 -> element of return (normal) | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 2 -> element of argument -1 | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 2 -> element of return (normal) | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 3 -> element of argument -1 | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 3 -> element of return (normal) | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 4 -> element of argument -1 | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 4 -> element of return (normal) | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, params Object[]) | argument 1 -> element of argument -1 | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, params Object[]) | argument 1 -> element of return (normal) | true | +| System.Text.StringBuilder.AppendFormat(string, object) | argument 0 -> element of argument -1 | true | +| System.Text.StringBuilder.AppendFormat(string, object) | argument 0 -> element of return (normal) | true | +| System.Text.StringBuilder.AppendFormat(string, object) | argument 1 -> element of argument -1 | true | +| System.Text.StringBuilder.AppendFormat(string, object) | argument 1 -> element of return (normal) | true | +| System.Text.StringBuilder.AppendFormat(string, object, object) | argument 0 -> element of argument -1 | true | +| System.Text.StringBuilder.AppendFormat(string, object, object) | argument 0 -> element of return (normal) | true | +| System.Text.StringBuilder.AppendFormat(string, object, object) | argument 1 -> element of argument -1 | true | +| System.Text.StringBuilder.AppendFormat(string, object, object) | argument 1 -> element of return (normal) | true | +| System.Text.StringBuilder.AppendFormat(string, object, object) | argument 2 -> element of argument -1 | true | +| System.Text.StringBuilder.AppendFormat(string, object, object) | argument 2 -> element of return (normal) | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 0 -> element of argument -1 | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 0 -> element of return (normal) | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 1 -> element of argument -1 | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 1 -> element of return (normal) | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 2 -> element of argument -1 | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 2 -> element of return (normal) | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 3 -> element of argument -1 | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 3 -> element of return (normal) | true | +| System.Text.StringBuilder.AppendFormat(string, params Object[]) | argument 0 -> element of argument -1 | true | +| System.Text.StringBuilder.AppendFormat(string, params Object[]) | argument 0 -> element of return (normal) | true | +| System.Text.StringBuilder.AppendLine(string) | argument 0 -> element of argument -1 | true | +| System.Text.StringBuilder.AppendLine(string) | argument 0 -> element of return (normal) | true | +| System.Text.StringBuilder.StringBuilder(string) | argument 0 -> element of return (normal) | true | +| System.Text.StringBuilder.StringBuilder(string, int) | argument 0 -> element of return (normal) | true | +| System.Text.StringBuilder.StringBuilder(string, int, int, int) | argument 0 -> element of return (normal) | true | +| System.Text.StringBuilder.ToString() | element of argument -1 -> return (normal) | false | +| System.Text.StringBuilder.ToString(int, int) | element of argument -1 -> return (normal) | false | +| System.Text.TranscodingStream.BeginRead(Byte[], int, int, AsyncCallback, object) | argument -1 -> return (out parameter 0) | false | +| System.Text.TranscodingStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | argument 0 -> argument -1 | false | +| System.Text.TranscodingStream.Read(Byte[], int, int) | argument -1 -> return (out parameter 0) | false | +| System.Text.TranscodingStream.ReadAsync(Byte[], int, int, CancellationToken) | argument -1 -> return (out parameter 0) | false | +| System.Text.TranscodingStream.Write(Byte[], int, int) | argument 0 -> argument -1 | false | +| System.Text.TranscodingStream.WriteAsync(Byte[], int, int, CancellationToken) | argument 0 -> argument -1 | false | +| System.Threading.Tasks.SingleProducerSingleConsumerQueue<>.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Threading.Tasks.Task.ContinueWith(Action, object) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task.ContinueWith(Action, object, CancellationToken) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task.ContinueWith(Action, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task.ContinueWith(Action, object, TaskContinuationOptions) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task.ContinueWith(Action, object, TaskScheduler) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task.ContinueWith(Func, object) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task.ContinueWith(Func, object) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.Task.ContinueWith(Func, object, CancellationToken) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task.ContinueWith(Func, object, CancellationToken) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.Task.ContinueWith(Func, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task.ContinueWith(Func, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.Task.ContinueWith(Func, object, TaskContinuationOptions) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task.ContinueWith(Func, object, TaskContinuationOptions) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.Task.ContinueWith(Func, object, TaskScheduler) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task.ContinueWith(Func, object, TaskScheduler) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.Task.ContinueWith(Func) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.Task.ContinueWith(Func, CancellationToken) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.Task.ContinueWith(Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.Task.ContinueWith(Func, TaskContinuationOptions) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.Task.ContinueWith(Func, TaskScheduler) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.Task.FromResult(TResult) | argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.Task.Run(Func) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.Task.Run(Func, CancellationToken) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.Task.Run(Func>) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.Task.Run(Func>, CancellationToken) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.Task.Task(Action, object) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task.Task(Action, object, CancellationToken) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task.Task(Action, object, CancellationToken, TaskCreationOptions) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task.Task(Action, object, TaskCreationOptions) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task.WhenAll(IEnumerable>) | property Result of element of argument 0 -> element of property Result of return (normal) | true | +| System.Threading.Tasks.Task.WhenAll(params Task[]) | property Result of element of argument 0 -> element of property Result of return (normal) | true | +| System.Threading.Tasks.Task.WhenAny(IEnumerable>) | property Result of element of argument 0 -> element of property Result of return (normal) | true | +| System.Threading.Tasks.Task.WhenAny(Task, Task) | property Result of element of argument 0 -> element of property Result of return (normal) | true | +| System.Threading.Tasks.Task.WhenAny(Task, Task) | property Result of element of argument 1 -> element of property Result of return (normal) | true | +| System.Threading.Tasks.Task.WhenAny(params Task[]) | property Result of element of argument 0 -> element of property Result of return (normal) | true | +| System.Threading.Tasks.Task<>.ConfigureAwait(bool) | argument -1 -> field m_task of field m_configuredTaskAwaiter of return (normal) | true | +| System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object) | argument -1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object, CancellationToken) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object, CancellationToken) | argument -1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument -1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object, TaskContinuationOptions) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object, TaskContinuationOptions) | argument -1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object, TaskScheduler) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object, TaskScheduler) | argument -1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Action>) | argument -1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Action>, CancellationToken) | argument -1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Action>, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument -1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Action>, TaskContinuationOptions) | argument -1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Action>, TaskScheduler) | argument -1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object) | argument -1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, CancellationToken) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, CancellationToken) | argument -1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, CancellationToken) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument -1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, TaskContinuationOptions) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, TaskContinuationOptions) | argument -1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, TaskContinuationOptions) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, TaskScheduler) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, TaskScheduler) | argument -1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, TaskScheduler) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>) | argument -1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, CancellationToken) | argument -1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, CancellationToken) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument -1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, TaskContinuationOptions) | argument -1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, TaskContinuationOptions) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, TaskScheduler) | argument -1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, TaskScheduler) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.Task<>.GetAwaiter() | argument -1 -> field m_task of return (normal) | true | +| System.Threading.Tasks.Task<>.Task(Func, object) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.Task(Func, object) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.Task<>.Task(Func, object, CancellationToken) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.Task(Func, object, CancellationToken) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.Task<>.Task(Func, object, CancellationToken, TaskCreationOptions) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.Task(Func, object, CancellationToken, TaskCreationOptions) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.Task<>.Task(Func, object, TaskCreationOptions) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.Task(Func, object, TaskCreationOptions) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.Task<>.Task(Func) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.Task<>.Task(Func, CancellationToken) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.Task<>.Task(Func, CancellationToken, TaskCreationOptions) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.Task<>.Task(Func, TaskCreationOptions) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.Task<>.get_Result() | argument -1 -> return (normal) | false | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func) | argument 0 -> parameter 0 of argument 1 | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func) | return (normal) of argument 1 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, CancellationToken) | argument 0 -> parameter 0 of argument 1 | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, CancellationToken) | return (normal) of argument 1 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument 0 -> parameter 0 of argument 1 | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | return (normal) of argument 1 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, TaskContinuationOptions) | argument 0 -> parameter 0 of argument 1 | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, TaskContinuationOptions) | return (normal) of argument 1 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Action) | argument 0 -> parameter 0 of argument 1 | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Action, CancellationToken) | argument 0 -> parameter 0 of argument 1 | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Action, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument 0 -> parameter 0 of argument 1 | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Action, TaskContinuationOptions) | argument 0 -> parameter 0 of argument 1 | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func) | return (normal) of argument 1 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, CancellationToken) | return (normal) of argument 1 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | return (normal) of argument 1 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, TaskContinuationOptions) | return (normal) of argument 1 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>) | argument 0 -> parameter 0 of argument 1 | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>) | return (normal) of argument 1 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>, CancellationToken) | argument 0 -> parameter 0 of argument 1 | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>, CancellationToken) | return (normal) of argument 1 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument 0 -> parameter 0 of argument 1 | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | return (normal) of argument 1 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>, TaskContinuationOptions) | argument 0 -> parameter 0 of argument 1 | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TResult>, TaskContinuationOptions) | return (normal) of argument 1 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Action>) | argument 0 -> parameter 0 of argument 1 | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Action>, CancellationToken) | argument 0 -> parameter 0 of argument 1 | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Action>, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument 0 -> parameter 0 of argument 1 | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Action>, TaskContinuationOptions) | argument 0 -> parameter 0 of argument 1 | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func) | return (normal) of argument 1 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, CancellationToken) | return (normal) of argument 1 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | return (normal) of argument 1 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TaskContinuationOptions) | return (normal) of argument 1 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory.StartNew(Action, object) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.TaskFactory.StartNew(Action, object, CancellationToken) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.TaskFactory.StartNew(Action, object, CancellationToken, TaskCreationOptions, TaskScheduler) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.TaskFactory.StartNew(Action, object, TaskCreationOptions) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.TaskFactory.StartNew(Func, object) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.TaskFactory.StartNew(Func, object) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory.StartNew(Func, object, CancellationToken) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.TaskFactory.StartNew(Func, object, CancellationToken) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory.StartNew(Func, object, CancellationToken, TaskCreationOptions, TaskScheduler) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.TaskFactory.StartNew(Func, object, CancellationToken, TaskCreationOptions, TaskScheduler) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory.StartNew(Func, object, TaskCreationOptions) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.TaskFactory.StartNew(Func, object, TaskCreationOptions) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory.StartNew(Func) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory.StartNew(Func, CancellationToken) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory.StartNew(Func, CancellationToken, TaskCreationOptions, TaskScheduler) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory.StartNew(Func, TaskCreationOptions) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func) | return (normal) of argument 1 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, CancellationToken) | return (normal) of argument 1 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | return (normal) of argument 1 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, TaskContinuationOptions) | return (normal) of argument 1 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func) | argument 0 -> parameter 0 of argument 1 | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func) | return (normal) of argument 1 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, CancellationToken) | argument 0 -> parameter 0 of argument 1 | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, CancellationToken) | return (normal) of argument 1 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument 0 -> parameter 0 of argument 1 | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | return (normal) of argument 1 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, TaskContinuationOptions) | argument 0 -> parameter 0 of argument 1 | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, TaskContinuationOptions) | return (normal) of argument 1 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func) | return (normal) of argument 1 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, CancellationToken) | return (normal) of argument 1 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | return (normal) of argument 1 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TaskContinuationOptions) | return (normal) of argument 1 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>) | argument 0 -> parameter 0 of argument 1 | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>) | return (normal) of argument 1 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>, CancellationToken) | argument 0 -> parameter 0 of argument 1 | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>, CancellationToken) | return (normal) of argument 1 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument 0 -> parameter 0 of argument 1 | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | return (normal) of argument 1 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>, TaskContinuationOptions) | argument 0 -> parameter 0 of argument 1 | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>, TaskContinuationOptions) | return (normal) of argument 1 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, CancellationToken) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, CancellationToken) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, CancellationToken, TaskCreationOptions, TaskScheduler) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, CancellationToken, TaskCreationOptions, TaskScheduler) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, TaskCreationOptions) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, TaskCreationOptions) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory<>.StartNew(Func) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory<>.StartNew(Func, CancellationToken) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory<>.StartNew(Func, CancellationToken, TaskCreationOptions, TaskScheduler) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.TaskFactory<>.StartNew(Func, TaskCreationOptions) | return (normal) of argument 0 -> property Result of return (normal) | true | +| System.Threading.Tasks.ThreadPoolTaskScheduler.d__6.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Threading.ThreadPool.d__52.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Threading.ThreadPool.d__51.GetEnumerator() | element of argument -1 -> property Current of return (normal) | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7, T8) | argument 0 -> property Item1 of return (normal) | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7, T8) | argument 1 -> property Item2 of return (normal) | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7, T8) | argument 2 -> property Item3 of return (normal) | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7, T8) | argument 3 -> property Item4 of return (normal) | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7, T8) | argument 4 -> property Item5 of return (normal) | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7, T8) | argument 5 -> property Item6 of return (normal) | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7, T8) | argument 6 -> property Item7 of return (normal) | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7) | argument 0 -> property Item1 of return (normal) | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7) | argument 1 -> property Item2 of return (normal) | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7) | argument 2 -> property Item3 of return (normal) | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7) | argument 3 -> property Item4 of return (normal) | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7) | argument 4 -> property Item5 of return (normal) | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7) | argument 5 -> property Item6 of return (normal) | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7) | argument 6 -> property Item7 of return (normal) | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6) | argument 0 -> property Item1 of return (normal) | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6) | argument 1 -> property Item2 of return (normal) | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6) | argument 2 -> property Item3 of return (normal) | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6) | argument 3 -> property Item4 of return (normal) | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6) | argument 4 -> property Item5 of return (normal) | true | +| System.Tuple.Create(T1, T2, T3, T4, T5, T6) | argument 5 -> property Item6 of return (normal) | true | +| System.Tuple.Create(T1, T2, T3, T4, T5) | argument 0 -> property Item1 of return (normal) | true | +| System.Tuple.Create(T1, T2, T3, T4, T5) | argument 1 -> property Item2 of return (normal) | true | +| System.Tuple.Create(T1, T2, T3, T4, T5) | argument 2 -> property Item3 of return (normal) | true | +| System.Tuple.Create(T1, T2, T3, T4, T5) | argument 3 -> property Item4 of return (normal) | true | +| System.Tuple.Create(T1, T2, T3, T4, T5) | argument 4 -> property Item5 of return (normal) | true | +| System.Tuple.Create(T1, T2, T3, T4) | argument 0 -> property Item1 of return (normal) | true | +| System.Tuple.Create(T1, T2, T3, T4) | argument 1 -> property Item2 of return (normal) | true | +| System.Tuple.Create(T1, T2, T3, T4) | argument 2 -> property Item3 of return (normal) | true | +| System.Tuple.Create(T1, T2, T3, T4) | argument 3 -> property Item4 of return (normal) | true | +| System.Tuple.Create(T1, T2, T3) | argument 0 -> property Item1 of return (normal) | true | +| System.Tuple.Create(T1, T2, T3) | argument 1 -> property Item2 of return (normal) | true | +| System.Tuple.Create(T1, T2, T3) | argument 2 -> property Item3 of return (normal) | true | +| System.Tuple.Create(T1, T2) | argument 0 -> property Item1 of return (normal) | true | +| System.Tuple.Create(T1, T2) | argument 1 -> property Item2 of return (normal) | true | +| System.Tuple.Create(T1) | argument 0 -> property Item1 of return (normal) | true | +| System.Tuple<,,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7, TRest) | argument 0 -> property Item1 of return (normal) | true | +| System.Tuple<,,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7, TRest) | argument 1 -> property Item2 of return (normal) | true | +| System.Tuple<,,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7, TRest) | argument 2 -> property Item3 of return (normal) | true | +| System.Tuple<,,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7, TRest) | argument 3 -> property Item4 of return (normal) | true | +| System.Tuple<,,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7, TRest) | argument 4 -> property Item5 of return (normal) | true | +| System.Tuple<,,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7, TRest) | argument 5 -> property Item6 of return (normal) | true | +| System.Tuple<,,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7, TRest) | argument 6 -> property Item7 of return (normal) | true | +| System.Tuple<,,,,,,,>.get_Item(int) | property Item1 of argument -1 -> return (normal) | true | +| System.Tuple<,,,,,,,>.get_Item(int) | property Item2 of argument -1 -> return (normal) | true | +| System.Tuple<,,,,,,,>.get_Item(int) | property Item3 of argument -1 -> return (normal) | true | +| System.Tuple<,,,,,,,>.get_Item(int) | property Item4 of argument -1 -> return (normal) | true | +| System.Tuple<,,,,,,,>.get_Item(int) | property Item5 of argument -1 -> return (normal) | true | +| System.Tuple<,,,,,,,>.get_Item(int) | property Item6 of argument -1 -> return (normal) | true | +| System.Tuple<,,,,,,,>.get_Item(int) | property Item7 of argument -1 -> return (normal) | true | +| System.Tuple<,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7) | argument 0 -> property Item1 of return (normal) | true | +| System.Tuple<,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7) | argument 1 -> property Item2 of return (normal) | true | +| System.Tuple<,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7) | argument 2 -> property Item3 of return (normal) | true | +| System.Tuple<,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7) | argument 3 -> property Item4 of return (normal) | true | +| System.Tuple<,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7) | argument 4 -> property Item5 of return (normal) | true | +| System.Tuple<,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7) | argument 5 -> property Item6 of return (normal) | true | +| System.Tuple<,,,,,,>.Tuple(T1, T2, T3, T4, T5, T6, T7) | argument 6 -> property Item7 of return (normal) | true | +| System.Tuple<,,,,,,>.get_Item(int) | property Item1 of argument -1 -> return (normal) | true | +| System.Tuple<,,,,,,>.get_Item(int) | property Item2 of argument -1 -> return (normal) | true | +| System.Tuple<,,,,,,>.get_Item(int) | property Item3 of argument -1 -> return (normal) | true | +| System.Tuple<,,,,,,>.get_Item(int) | property Item4 of argument -1 -> return (normal) | true | +| System.Tuple<,,,,,,>.get_Item(int) | property Item5 of argument -1 -> return (normal) | true | +| System.Tuple<,,,,,,>.get_Item(int) | property Item6 of argument -1 -> return (normal) | true | +| System.Tuple<,,,,,,>.get_Item(int) | property Item7 of argument -1 -> return (normal) | true | +| System.Tuple<,,,,,>.Tuple(T1, T2, T3, T4, T5, T6) | argument 0 -> property Item1 of return (normal) | true | +| System.Tuple<,,,,,>.Tuple(T1, T2, T3, T4, T5, T6) | argument 1 -> property Item2 of return (normal) | true | +| System.Tuple<,,,,,>.Tuple(T1, T2, T3, T4, T5, T6) | argument 2 -> property Item3 of return (normal) | true | +| System.Tuple<,,,,,>.Tuple(T1, T2, T3, T4, T5, T6) | argument 3 -> property Item4 of return (normal) | true | +| System.Tuple<,,,,,>.Tuple(T1, T2, T3, T4, T5, T6) | argument 4 -> property Item5 of return (normal) | true | +| System.Tuple<,,,,,>.Tuple(T1, T2, T3, T4, T5, T6) | argument 5 -> property Item6 of return (normal) | true | +| System.Tuple<,,,,,>.get_Item(int) | property Item1 of argument -1 -> return (normal) | true | +| System.Tuple<,,,,,>.get_Item(int) | property Item2 of argument -1 -> return (normal) | true | +| System.Tuple<,,,,,>.get_Item(int) | property Item3 of argument -1 -> return (normal) | true | +| System.Tuple<,,,,,>.get_Item(int) | property Item4 of argument -1 -> return (normal) | true | +| System.Tuple<,,,,,>.get_Item(int) | property Item5 of argument -1 -> return (normal) | true | +| System.Tuple<,,,,,>.get_Item(int) | property Item6 of argument -1 -> return (normal) | true | +| System.Tuple<,,,,>.Tuple(T1, T2, T3, T4, T5) | argument 0 -> property Item1 of return (normal) | true | +| System.Tuple<,,,,>.Tuple(T1, T2, T3, T4, T5) | argument 1 -> property Item2 of return (normal) | true | +| System.Tuple<,,,,>.Tuple(T1, T2, T3, T4, T5) | argument 2 -> property Item3 of return (normal) | true | +| System.Tuple<,,,,>.Tuple(T1, T2, T3, T4, T5) | argument 3 -> property Item4 of return (normal) | true | +| System.Tuple<,,,,>.Tuple(T1, T2, T3, T4, T5) | argument 4 -> property Item5 of return (normal) | true | +| System.Tuple<,,,,>.get_Item(int) | property Item1 of argument -1 -> return (normal) | true | +| System.Tuple<,,,,>.get_Item(int) | property Item2 of argument -1 -> return (normal) | true | +| System.Tuple<,,,,>.get_Item(int) | property Item3 of argument -1 -> return (normal) | true | +| System.Tuple<,,,,>.get_Item(int) | property Item4 of argument -1 -> return (normal) | true | +| System.Tuple<,,,,>.get_Item(int) | property Item5 of argument -1 -> return (normal) | true | +| System.Tuple<,,,>.Tuple(T1, T2, T3, T4) | argument 0 -> property Item1 of return (normal) | true | +| System.Tuple<,,,>.Tuple(T1, T2, T3, T4) | argument 1 -> property Item2 of return (normal) | true | +| System.Tuple<,,,>.Tuple(T1, T2, T3, T4) | argument 2 -> property Item3 of return (normal) | true | +| System.Tuple<,,,>.Tuple(T1, T2, T3, T4) | argument 3 -> property Item4 of return (normal) | true | +| System.Tuple<,,,>.get_Item(int) | property Item1 of argument -1 -> return (normal) | true | +| System.Tuple<,,,>.get_Item(int) | property Item2 of argument -1 -> return (normal) | true | +| System.Tuple<,,,>.get_Item(int) | property Item3 of argument -1 -> return (normal) | true | +| System.Tuple<,,,>.get_Item(int) | property Item4 of argument -1 -> return (normal) | true | +| System.Tuple<,,>.Tuple(T1, T2, T3) | argument 0 -> property Item1 of return (normal) | true | +| System.Tuple<,,>.Tuple(T1, T2, T3) | argument 1 -> property Item2 of return (normal) | true | +| System.Tuple<,,>.Tuple(T1, T2, T3) | argument 2 -> property Item3 of return (normal) | true | +| System.Tuple<,,>.get_Item(int) | property Item1 of argument -1 -> return (normal) | true | +| System.Tuple<,,>.get_Item(int) | property Item2 of argument -1 -> return (normal) | true | +| System.Tuple<,,>.get_Item(int) | property Item3 of argument -1 -> return (normal) | true | +| System.Tuple<,>.Tuple(T1, T2) | argument 0 -> property Item1 of return (normal) | true | +| System.Tuple<,>.Tuple(T1, T2) | argument 1 -> property Item2 of return (normal) | true | +| System.Tuple<,>.get_Item(int) | property Item1 of argument -1 -> return (normal) | true | +| System.Tuple<,>.get_Item(int) | property Item2 of argument -1 -> return (normal) | true | +| System.Tuple<>.Tuple(T1) | argument 0 -> property Item1 of return (normal) | true | +| System.Tuple<>.get_Item(int) | property Item1 of argument -1 -> return (normal) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20, out T21) | property Item1 of argument 0 -> return (out parameter 1) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20, out T21) | property Item2 of argument 0 -> return (out parameter 2) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20, out T21) | property Item3 of argument 0 -> return (out parameter 3) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20, out T21) | property Item4 of argument 0 -> return (out parameter 4) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20, out T21) | property Item5 of argument 0 -> return (out parameter 5) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20, out T21) | property Item6 of argument 0 -> return (out parameter 6) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20, out T21) | property Item7 of argument 0 -> return (out parameter 7) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20) | property Item1 of argument 0 -> return (out parameter 1) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20) | property Item2 of argument 0 -> return (out parameter 2) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20) | property Item3 of argument 0 -> return (out parameter 3) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20) | property Item4 of argument 0 -> return (out parameter 4) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20) | property Item5 of argument 0 -> return (out parameter 5) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20) | property Item6 of argument 0 -> return (out parameter 6) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19, out T20) | property Item7 of argument 0 -> return (out parameter 7) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19) | property Item1 of argument 0 -> return (out parameter 1) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19) | property Item2 of argument 0 -> return (out parameter 2) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19) | property Item3 of argument 0 -> return (out parameter 3) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19) | property Item4 of argument 0 -> return (out parameter 4) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19) | property Item5 of argument 0 -> return (out parameter 5) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19) | property Item6 of argument 0 -> return (out parameter 6) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18, out T19) | property Item7 of argument 0 -> return (out parameter 7) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18) | property Item1 of argument 0 -> return (out parameter 1) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18) | property Item2 of argument 0 -> return (out parameter 2) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18) | property Item3 of argument 0 -> return (out parameter 3) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18) | property Item4 of argument 0 -> return (out parameter 4) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18) | property Item5 of argument 0 -> return (out parameter 5) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18) | property Item6 of argument 0 -> return (out parameter 6) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17, out T18) | property Item7 of argument 0 -> return (out parameter 7) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17) | property Item1 of argument 0 -> return (out parameter 1) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17) | property Item2 of argument 0 -> return (out parameter 2) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17) | property Item3 of argument 0 -> return (out parameter 3) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17) | property Item4 of argument 0 -> return (out parameter 4) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17) | property Item5 of argument 0 -> return (out parameter 5) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17) | property Item6 of argument 0 -> return (out parameter 6) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16, out T17) | property Item7 of argument 0 -> return (out parameter 7) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16) | property Item1 of argument 0 -> return (out parameter 1) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16) | property Item2 of argument 0 -> return (out parameter 2) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16) | property Item3 of argument 0 -> return (out parameter 3) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16) | property Item4 of argument 0 -> return (out parameter 4) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16) | property Item5 of argument 0 -> return (out parameter 5) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16) | property Item6 of argument 0 -> return (out parameter 6) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15, out T16) | property Item7 of argument 0 -> return (out parameter 7) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15) | property Item1 of argument 0 -> return (out parameter 1) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15) | property Item2 of argument 0 -> return (out parameter 2) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15) | property Item3 of argument 0 -> return (out parameter 3) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15) | property Item4 of argument 0 -> return (out parameter 4) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15) | property Item5 of argument 0 -> return (out parameter 5) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15) | property Item6 of argument 0 -> return (out parameter 6) | true | +| System.TupleExtensions.Deconstruct(Tuple>>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14, out T15) | property Item7 of argument 0 -> return (out parameter 7) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14) | property Item1 of argument 0 -> return (out parameter 1) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14) | property Item2 of argument 0 -> return (out parameter 2) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14) | property Item3 of argument 0 -> return (out parameter 3) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14) | property Item4 of argument 0 -> return (out parameter 4) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14) | property Item5 of argument 0 -> return (out parameter 5) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14) | property Item6 of argument 0 -> return (out parameter 6) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13, out T14) | property Item7 of argument 0 -> return (out parameter 7) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13) | property Item1 of argument 0 -> return (out parameter 1) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13) | property Item2 of argument 0 -> return (out parameter 2) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13) | property Item3 of argument 0 -> return (out parameter 3) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13) | property Item4 of argument 0 -> return (out parameter 4) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13) | property Item5 of argument 0 -> return (out parameter 5) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13) | property Item6 of argument 0 -> return (out parameter 6) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12, out T13) | property Item7 of argument 0 -> return (out parameter 7) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12) | property Item1 of argument 0 -> return (out parameter 1) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12) | property Item2 of argument 0 -> return (out parameter 2) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12) | property Item3 of argument 0 -> return (out parameter 3) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12) | property Item4 of argument 0 -> return (out parameter 4) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12) | property Item5 of argument 0 -> return (out parameter 5) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12) | property Item6 of argument 0 -> return (out parameter 6) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11, out T12) | property Item7 of argument 0 -> return (out parameter 7) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11) | property Item1 of argument 0 -> return (out parameter 1) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11) | property Item2 of argument 0 -> return (out parameter 2) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11) | property Item3 of argument 0 -> return (out parameter 3) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11) | property Item4 of argument 0 -> return (out parameter 4) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11) | property Item5 of argument 0 -> return (out parameter 5) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11) | property Item6 of argument 0 -> return (out parameter 6) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10, out T11) | property Item7 of argument 0 -> return (out parameter 7) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10) | property Item1 of argument 0 -> return (out parameter 1) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10) | property Item2 of argument 0 -> return (out parameter 2) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10) | property Item3 of argument 0 -> return (out parameter 3) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10) | property Item4 of argument 0 -> return (out parameter 4) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10) | property Item5 of argument 0 -> return (out parameter 5) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10) | property Item6 of argument 0 -> return (out parameter 6) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9, out T10) | property Item7 of argument 0 -> return (out parameter 7) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9) | property Item1 of argument 0 -> return (out parameter 1) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9) | property Item2 of argument 0 -> return (out parameter 2) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9) | property Item3 of argument 0 -> return (out parameter 3) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9) | property Item4 of argument 0 -> return (out parameter 4) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9) | property Item5 of argument 0 -> return (out parameter 5) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9) | property Item6 of argument 0 -> return (out parameter 6) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9) | property Item7 of argument 0 -> return (out parameter 7) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8) | property Item1 of argument 0 -> return (out parameter 1) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8) | property Item2 of argument 0 -> return (out parameter 2) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8) | property Item3 of argument 0 -> return (out parameter 3) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8) | property Item4 of argument 0 -> return (out parameter 4) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8) | property Item5 of argument 0 -> return (out parameter 5) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8) | property Item6 of argument 0 -> return (out parameter 6) | true | +| System.TupleExtensions.Deconstruct(Tuple>, out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8) | property Item7 of argument 0 -> return (out parameter 7) | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6, out T7) | property Item1 of argument 0 -> return (out parameter 1) | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6, out T7) | property Item2 of argument 0 -> return (out parameter 2) | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6, out T7) | property Item3 of argument 0 -> return (out parameter 3) | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6, out T7) | property Item4 of argument 0 -> return (out parameter 4) | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6, out T7) | property Item5 of argument 0 -> return (out parameter 5) | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6, out T7) | property Item6 of argument 0 -> return (out parameter 6) | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6, out T7) | property Item7 of argument 0 -> return (out parameter 7) | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6) | property Item1 of argument 0 -> return (out parameter 1) | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6) | property Item2 of argument 0 -> return (out parameter 2) | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6) | property Item3 of argument 0 -> return (out parameter 3) | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6) | property Item4 of argument 0 -> return (out parameter 4) | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6) | property Item5 of argument 0 -> return (out parameter 5) | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5, out T6) | property Item6 of argument 0 -> return (out parameter 6) | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5) | property Item1 of argument 0 -> return (out parameter 1) | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5) | property Item2 of argument 0 -> return (out parameter 2) | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5) | property Item3 of argument 0 -> return (out parameter 3) | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5) | property Item4 of argument 0 -> return (out parameter 4) | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4, out T5) | property Item5 of argument 0 -> return (out parameter 5) | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4) | property Item1 of argument 0 -> return (out parameter 1) | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4) | property Item2 of argument 0 -> return (out parameter 2) | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4) | property Item3 of argument 0 -> return (out parameter 3) | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3, out T4) | property Item4 of argument 0 -> return (out parameter 4) | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3) | property Item1 of argument 0 -> return (out parameter 1) | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3) | property Item2 of argument 0 -> return (out parameter 2) | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2, out T3) | property Item3 of argument 0 -> return (out parameter 3) | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2) | property Item1 of argument 0 -> return (out parameter 1) | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1, out T2) | property Item2 of argument 0 -> return (out parameter 2) | true | +| System.TupleExtensions.Deconstruct(Tuple, out T1) | property Item1 of argument 0 -> return (out parameter 1) | true | +| System.Uri.ToString() | argument -1 -> return (normal) | false | +| System.Uri.Uri(string) | argument 0 -> return (normal) | false | +| System.Uri.Uri(string, UriKind) | argument 0 -> return (normal) | false | +| System.Uri.Uri(string, bool) | argument 0 -> return (normal) | false | +| System.Uri.get_OriginalString() | argument -1 -> return (normal) | false | +| System.Uri.get_PathAndQuery() | argument -1 -> return (normal) | false | +| System.Uri.get_Query() | argument -1 -> return (normal) | false | +| System.ValueTuple<,,,,,,,>.ValueTuple(T1, T2, T3, T4, T5, T6, T7, TRest) | argument 0 -> field Item1 of return (normal) | true | +| System.ValueTuple<,,,,,,,>.ValueTuple(T1, T2, T3, T4, T5, T6, T7, TRest) | argument 1 -> field Item2 of return (normal) | true | +| System.ValueTuple<,,,,,,,>.ValueTuple(T1, T2, T3, T4, T5, T6, T7, TRest) | argument 2 -> field Item3 of return (normal) | true | +| System.ValueTuple<,,,,,,,>.ValueTuple(T1, T2, T3, T4, T5, T6, T7, TRest) | argument 3 -> field Item4 of return (normal) | true | +| System.ValueTuple<,,,,,,,>.ValueTuple(T1, T2, T3, T4, T5, T6, T7, TRest) | argument 4 -> field Item5 of return (normal) | true | +| System.ValueTuple<,,,,,,,>.ValueTuple(T1, T2, T3, T4, T5, T6, T7, TRest) | argument 5 -> field Item6 of return (normal) | true | +| System.ValueTuple<,,,,,,,>.ValueTuple(T1, T2, T3, T4, T5, T6, T7, TRest) | argument 6 -> field Item7 of return (normal) | true | +| System.ValueTuple<,,,,,,,>.get_Item(int) | field Item1 of argument -1 -> return (normal) | true | +| System.ValueTuple<,,,,,,,>.get_Item(int) | field Item2 of argument -1 -> return (normal) | true | +| System.ValueTuple<,,,,,,,>.get_Item(int) | field Item3 of argument -1 -> return (normal) | true | +| System.ValueTuple<,,,,,,,>.get_Item(int) | field Item4 of argument -1 -> return (normal) | true | +| System.ValueTuple<,,,,,,,>.get_Item(int) | field Item5 of argument -1 -> return (normal) | true | +| System.ValueTuple<,,,,,,,>.get_Item(int) | field Item6 of argument -1 -> return (normal) | true | +| System.ValueTuple<,,,,,,,>.get_Item(int) | field Item7 of argument -1 -> return (normal) | true | +| System.Web.HttpCookie.get_Value() | argument -1 -> return (normal) | false | +| System.Web.HttpCookie.get_Values() | argument -1 -> return (normal) | false | +| System.Web.HttpServerUtility.UrlEncode(string) | argument 0 -> return (normal) | false | +| System.Web.HttpUtility.HtmlAttributeEncode(string) | argument 0 -> return (normal) | false | +| System.Web.HttpUtility.HtmlEncode(object) | argument 0 -> return (normal) | false | +| System.Web.HttpUtility.HtmlEncode(string) | argument 0 -> return (normal) | false | +| System.Web.HttpUtility.UrlEncode(string) | argument 0 -> return (normal) | false | +| System.Web.UI.WebControls.TextBox.get_Text() | argument -1 -> return (normal) | false | diff --git a/csharp/ql/test/library-tests/dataflow/library/FlowSummaries.ql b/csharp/ql/test/library-tests/dataflow/library/FlowSummaries.ql index 12eafa32a0f..0ff3ce7de04 100644 --- a/csharp/ql/test/library-tests/dataflow/library/FlowSummaries.ql +++ b/csharp/ql/test/library-tests/dataflow/library/FlowSummaries.ql @@ -1,6 +1,8 @@ import semmle.code.csharp.dataflow.FlowSummary -import semmle.code.csharp.dataflow.FlowSummary::TestOutput +import semmle.code.csharp.dataflow.internal.FlowSummaryImpl::Private::TestOutput -private class IncludeEFSummarizedCallable extends RelevantSummarizedCallable { - IncludeEFSummarizedCallable() { this instanceof SummarizedCallable } +private class IncludeSummarizedCallable extends RelevantSummarizedCallable { + IncludeSummarizedCallable() { this instanceof SummarizedCallable } + + override string getFullString() { result = this.(Callable).getQualifiedNameWithTypes() } } diff --git a/csharp/ql/test/library-tests/frameworks/EntityFramework/FlowSummaries.expected b/csharp/ql/test/library-tests/frameworks/EntityFramework/FlowSummaries.expected index a28d064f2d1..91b24479fbb 100644 --- a/csharp/ql/test/library-tests/frameworks/EntityFramework/FlowSummaries.expected +++ b/csharp/ql/test/library-tests/frameworks/EntityFramework/FlowSummaries.expected @@ -1,158 +1,134 @@ -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Addresses, element, property Id] -> jump to get_Addresses (normal) [element, property Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Addresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Address, property Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Addresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Addresses, element, property Id] -> jump to get_Persons (normal) [element, property Addresses, element, property Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Addresses, element, property Street] -> jump to get_Addresses (normal) [element, property Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Addresses, element, property Street] -> jump to get_PersonAddresses (normal) [element, property Address, property Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Addresses, element, property Street] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Addresses, element, property Street] -> jump to get_Persons (normal) [element, property Addresses, element, property Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Address, property Id] -> jump to get_Addresses (normal) [element, property Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Address, property Id] -> jump to get_PersonAddresses (normal) [element, property Address, property Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Address, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Address, property Id] -> jump to get_Persons (normal) [element, property Addresses, element, property Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Address, property Street] -> jump to get_Addresses (normal) [element, property Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Address, property Street] -> jump to get_PersonAddresses (normal) [element, property Address, property Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Address, property Street] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Address, property Street] -> jump to get_Persons (normal) [element, property Addresses, element, property Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property AddressId] -> jump to get_PersonAddresses (normal) [element, property AddressId] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Person, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Person, property Id] -> jump to get_Persons (normal) [element, property Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Person, property Name] -> jump to get_PersonAddresses (normal) [element, property Person, property Name] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Person, property Name] -> jump to get_Persons (normal) [element, property Name] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property PersonId] -> jump to get_PersonAddresses (normal) [element, property PersonId] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Persons, element, property Addresses, element, property Id] -> jump to get_Addresses (normal) [element, property Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Persons, element, property Addresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Address, property Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Persons, element, property Addresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Persons, element, property Addresses, element, property Id] -> jump to get_Persons (normal) [element, property Addresses, element, property Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Persons, element, property Addresses, element, property Street] -> jump to get_Addresses (normal) [element, property Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Persons, element, property Addresses, element, property Street] -> jump to get_PersonAddresses (normal) [element, property Address, property Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Persons, element, property Addresses, element, property Street] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Persons, element, property Addresses, element, property Street] -> jump to get_Persons (normal) [element, property Addresses, element, property Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Persons, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Persons, element, property Id] -> jump to get_Persons (normal) [element, property Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Persons, element, property Name] -> jump to get_PersonAddresses (normal) [element, property Person, property Name] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | this parameter [property Persons, element, property Name] -> jump to get_Persons (normal) [element, property Name] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Addresses, element, property Id] -> jump to get_Addresses (normal) [element, property Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Addresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Address, property Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Addresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Addresses, element, property Id] -> jump to get_Persons (normal) [element, property Addresses, element, property Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Addresses, element, property Street] -> jump to get_Addresses (normal) [element, property Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Addresses, element, property Street] -> jump to get_PersonAddresses (normal) [element, property Address, property Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Addresses, element, property Street] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Addresses, element, property Street] -> jump to get_Persons (normal) [element, property Addresses, element, property Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Address, property Id] -> jump to get_Addresses (normal) [element, property Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Address, property Id] -> jump to get_PersonAddresses (normal) [element, property Address, property Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Address, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Address, property Id] -> jump to get_Persons (normal) [element, property Addresses, element, property Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Address, property Street] -> jump to get_Addresses (normal) [element, property Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Address, property Street] -> jump to get_PersonAddresses (normal) [element, property Address, property Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Address, property Street] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Address, property Street] -> jump to get_Persons (normal) [element, property Addresses, element, property Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property AddressId] -> jump to get_PersonAddresses (normal) [element, property AddressId] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Person, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Person, property Id] -> jump to get_Persons (normal) [element, property Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Person, property Name] -> jump to get_PersonAddresses (normal) [element, property Person, property Name] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Person, property Name] -> jump to get_Persons (normal) [element, property Name] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property PersonId] -> jump to get_PersonAddresses (normal) [element, property PersonId] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Addresses, element, property Id] -> jump to get_Addresses (normal) [element, property Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Addresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Address, property Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Addresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Addresses, element, property Id] -> jump to get_Persons (normal) [element, property Addresses, element, property Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Addresses, element, property Street] -> jump to get_Addresses (normal) [element, property Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Addresses, element, property Street] -> jump to get_PersonAddresses (normal) [element, property Address, property Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Addresses, element, property Street] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Addresses, element, property Street] -> jump to get_Persons (normal) [element, property Addresses, element, property Street] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Id] -> jump to get_Persons (normal) [element, property Id] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Name] -> jump to get_PersonAddresses (normal) [element, property Person, property Name] | true | -| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Name] -> jump to get_Persons (normal) [element, property Name] | true | -| Microsoft.EntityFrameworkCore.DbSet<>.Add(T) | parameter 0 -> this parameter [element] | true | -| Microsoft.EntityFrameworkCore.DbSet<>.AddAsync(T) | parameter 0 -> this parameter [element] | true | -| Microsoft.EntityFrameworkCore.DbSet<>.AddRange(IEnumerable) | parameter 0 [element] -> this parameter [element] | true | -| Microsoft.EntityFrameworkCore.DbSet<>.AddRangeAsync(IEnumerable) | parameter 0 [element] -> this parameter [element] | true | -| Microsoft.EntityFrameworkCore.DbSet<>.Attach(T) | parameter 0 -> this parameter [element] | true | -| Microsoft.EntityFrameworkCore.DbSet<>.AttachRange(IEnumerable) | parameter 0 [element] -> this parameter [element] | true | -| Microsoft.EntityFrameworkCore.DbSet<>.Update(T) | parameter 0 -> this parameter [element] | true | -| Microsoft.EntityFrameworkCore.DbSet<>.UpdateRange(IEnumerable) | parameter 0 [element] -> this parameter [element] | true | -| Microsoft.EntityFrameworkCore.RawSqlString.RawSqlString(string) | parameter 0 -> return | false | -| Microsoft.EntityFrameworkCore.RawSqlString.implicit conversion(string) | parameter 0 -> return | false | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Addresses, element, property Id] -> jump to get_Addresses (normal) [element, property Id] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Addresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Address, property Id] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Addresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Id] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Addresses, element, property Id] -> jump to get_Persons (normal) [element, property Addresses, element, property Id] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Addresses, element, property Street] -> jump to get_Addresses (normal) [element, property Street] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Addresses, element, property Street] -> jump to get_PersonAddresses (normal) [element, property Address, property Street] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Addresses, element, property Street] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Street] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Addresses, element, property Street] -> jump to get_Persons (normal) [element, property Addresses, element, property Street] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Address, property Id] -> jump to get_Addresses (normal) [element, property Id] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Address, property Id] -> jump to get_PersonAddresses (normal) [element, property Address, property Id] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Address, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Id] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Address, property Id] -> jump to get_Persons (normal) [element, property Addresses, element, property Id] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Address, property Street] -> jump to get_Addresses (normal) [element, property Street] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Address, property Street] -> jump to get_PersonAddresses (normal) [element, property Address, property Street] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Address, property Street] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Street] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Address, property Street] -> jump to get_Persons (normal) [element, property Addresses, element, property Street] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property AddressId] -> jump to get_PersonAddresses (normal) [element, property AddressId] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Id] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Person, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Id] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Person, property Id] -> jump to get_Persons (normal) [element, property Id] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Person, property Name] -> jump to get_PersonAddresses (normal) [element, property Person, property Name] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property Person, property Name] -> jump to get_Persons (normal) [element, property Name] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [property PersonAddresses, element, property PersonId] -> jump to get_PersonAddresses (normal) [element, property PersonId] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Persons, element, property Addresses, element, property Id] -> jump to get_Addresses (normal) [element, property Id] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Persons, element, property Addresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Address, property Id] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Persons, element, property Addresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Id] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Persons, element, property Addresses, element, property Id] -> jump to get_Persons (normal) [element, property Addresses, element, property Id] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Persons, element, property Addresses, element, property Street] -> jump to get_Addresses (normal) [element, property Street] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Persons, element, property Addresses, element, property Street] -> jump to get_PersonAddresses (normal) [element, property Address, property Street] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Persons, element, property Addresses, element, property Street] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Street] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Persons, element, property Addresses, element, property Street] -> jump to get_Persons (normal) [element, property Addresses, element, property Street] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Persons, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Id] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Persons, element, property Id] -> jump to get_Persons (normal) [element, property Id] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Persons, element, property Name] -> jump to get_PersonAddresses (normal) [element, property Person, property Name] | true | -| System.Data.Entity.DbContext.SaveChanges() | this parameter [property Persons, element, property Name] -> jump to get_Persons (normal) [element, property Name] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Addresses, element, property Id] -> jump to get_Addresses (normal) [element, property Id] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Addresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Address, property Id] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Addresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Id] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Addresses, element, property Id] -> jump to get_Persons (normal) [element, property Addresses, element, property Id] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Addresses, element, property Street] -> jump to get_Addresses (normal) [element, property Street] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Addresses, element, property Street] -> jump to get_PersonAddresses (normal) [element, property Address, property Street] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Addresses, element, property Street] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Street] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Addresses, element, property Street] -> jump to get_Persons (normal) [element, property Addresses, element, property Street] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Address, property Id] -> jump to get_Addresses (normal) [element, property Id] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Address, property Id] -> jump to get_PersonAddresses (normal) [element, property Address, property Id] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Address, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Id] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Address, property Id] -> jump to get_Persons (normal) [element, property Addresses, element, property Id] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Address, property Street] -> jump to get_Addresses (normal) [element, property Street] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Address, property Street] -> jump to get_PersonAddresses (normal) [element, property Address, property Street] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Address, property Street] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Street] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Address, property Street] -> jump to get_Persons (normal) [element, property Addresses, element, property Street] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property AddressId] -> jump to get_PersonAddresses (normal) [element, property AddressId] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Id] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Person, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Id] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Person, property Id] -> jump to get_Persons (normal) [element, property Id] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Person, property Name] -> jump to get_PersonAddresses (normal) [element, property Person, property Name] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property Person, property Name] -> jump to get_Persons (normal) [element, property Name] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property PersonAddresses, element, property PersonId] -> jump to get_PersonAddresses (normal) [element, property PersonId] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Addresses, element, property Id] -> jump to get_Addresses (normal) [element, property Id] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Addresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Address, property Id] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Addresses, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Id] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Addresses, element, property Id] -> jump to get_Persons (normal) [element, property Addresses, element, property Id] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Addresses, element, property Street] -> jump to get_Addresses (normal) [element, property Street] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Addresses, element, property Street] -> jump to get_PersonAddresses (normal) [element, property Address, property Street] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Addresses, element, property Street] -> jump to get_PersonAddresses (normal) [element, property Person, property Addresses, element, property Street] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Addresses, element, property Street] -> jump to get_Persons (normal) [element, property Addresses, element, property Street] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Id] -> jump to get_PersonAddresses (normal) [element, property Person, property Id] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Id] -> jump to get_Persons (normal) [element, property Id] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Name] -> jump to get_PersonAddresses (normal) [element, property Person, property Name] | true | -| System.Data.Entity.DbContext.SaveChangesAsync() | this parameter [property Persons, element, property Name] -> jump to get_Persons (normal) [element, property Name] | true | -| System.Data.Entity.DbSet<>.Add(T) | parameter 0 -> this parameter [element] | true | -| System.Data.Entity.DbSet<>.AddAsync(T) | parameter 0 -> this parameter [element] | true | -| System.Data.Entity.DbSet<>.AddRange(IEnumerable) | parameter 0 [element] -> this parameter [element] | true | -| System.Data.Entity.DbSet<>.AddRangeAsync(IEnumerable) | parameter 0 [element] -> this parameter [element] | true | -| System.Data.Entity.DbSet<>.Attach(T) | parameter 0 -> this parameter [element] | true | -| System.Data.Entity.DbSet<>.AttachRange(IEnumerable) | parameter 0 [element] -> this parameter [element] | true | -| System.Data.Entity.DbSet<>.Update(T) | parameter 0 -> this parameter [element] | true | -| System.Data.Entity.DbSet<>.UpdateRange(IEnumerable) | parameter 0 [element] -> this parameter [element] | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | property AddressId of element of property PersonAddresses of argument -1 -> property AddressId of element of return (jump to get_PersonAddresses) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | property Id of element of property Addresses of argument -1 -> property Id of element of property Addresses of element of return (jump to get_Persons) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | property Id of element of property Addresses of argument -1 -> property Id of element of return (jump to get_Addresses) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | property Id of element of property Addresses of argument -1 -> property Id of property Address of element of return (jump to get_PersonAddresses) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | property Id of element of property Addresses of element of property Persons of argument -1 -> property Id of element of property Addresses of element of return (jump to get_Persons) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | property Id of element of property Addresses of element of property Persons of argument -1 -> property Id of element of return (jump to get_Addresses) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | property Id of element of property Addresses of element of property Persons of argument -1 -> property Id of property Address of element of return (jump to get_PersonAddresses) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | property Id of element of property PersonAddresses of argument -1 -> property Id of element of return (jump to get_PersonAddresses) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | property Id of element of property Persons of argument -1 -> property Id of element of return (jump to get_Persons) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | property Id of element of property Persons of argument -1 -> property Id of property Person of element of return (jump to get_PersonAddresses) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | property Id of property Address of element of property PersonAddresses of argument -1 -> property Id of element of property Addresses of element of return (jump to get_Persons) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | property Id of property Address of element of property PersonAddresses of argument -1 -> property Id of element of return (jump to get_Addresses) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | property Id of property Address of element of property PersonAddresses of argument -1 -> property Id of property Address of element of return (jump to get_PersonAddresses) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | property Id of property Person of element of property PersonAddresses of argument -1 -> property Id of element of return (jump to get_Persons) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | property Id of property Person of element of property PersonAddresses of argument -1 -> property Id of property Person of element of return (jump to get_PersonAddresses) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | property Name of element of property Persons of argument -1 -> property Name of element of return (jump to get_Persons) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | property Name of element of property Persons of argument -1 -> property Name of property Person of element of return (jump to get_PersonAddresses) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | property Name of property Person of element of property PersonAddresses of argument -1 -> property Name of element of return (jump to get_Persons) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | property Name of property Person of element of property PersonAddresses of argument -1 -> property Name of property Person of element of return (jump to get_PersonAddresses) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | property PersonId of element of property PersonAddresses of argument -1 -> property PersonId of element of return (jump to get_PersonAddresses) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | property Street of element of property Addresses of argument -1 -> property Street of element of property Addresses of element of return (jump to get_Persons) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | property Street of element of property Addresses of argument -1 -> property Street of element of return (jump to get_Addresses) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | property Street of element of property Addresses of argument -1 -> property Street of property Address of element of return (jump to get_PersonAddresses) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | property Street of element of property Addresses of element of property Persons of argument -1 -> property Street of element of property Addresses of element of return (jump to get_Persons) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | property Street of element of property Addresses of element of property Persons of argument -1 -> property Street of element of return (jump to get_Addresses) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | property Street of element of property Addresses of element of property Persons of argument -1 -> property Street of property Address of element of return (jump to get_PersonAddresses) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | property Street of property Address of element of property PersonAddresses of argument -1 -> property Street of element of property Addresses of element of return (jump to get_Persons) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | property Street of property Address of element of property PersonAddresses of argument -1 -> property Street of element of return (jump to get_Addresses) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChanges() | property Street of property Address of element of property PersonAddresses of argument -1 -> property Street of property Address of element of return (jump to get_PersonAddresses) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | property AddressId of element of property PersonAddresses of argument -1 -> property AddressId of element of return (jump to get_PersonAddresses) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | property Id of element of property Addresses of argument -1 -> property Id of element of property Addresses of element of return (jump to get_Persons) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | property Id of element of property Addresses of argument -1 -> property Id of element of return (jump to get_Addresses) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | property Id of element of property Addresses of argument -1 -> property Id of property Address of element of return (jump to get_PersonAddresses) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | property Id of element of property Addresses of element of property Persons of argument -1 -> property Id of element of property Addresses of element of return (jump to get_Persons) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | property Id of element of property Addresses of element of property Persons of argument -1 -> property Id of element of return (jump to get_Addresses) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | property Id of element of property Addresses of element of property Persons of argument -1 -> property Id of property Address of element of return (jump to get_PersonAddresses) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | property Id of element of property PersonAddresses of argument -1 -> property Id of element of return (jump to get_PersonAddresses) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | property Id of element of property Persons of argument -1 -> property Id of element of return (jump to get_Persons) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | property Id of element of property Persons of argument -1 -> property Id of property Person of element of return (jump to get_PersonAddresses) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | property Id of property Address of element of property PersonAddresses of argument -1 -> property Id of element of property Addresses of element of return (jump to get_Persons) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | property Id of property Address of element of property PersonAddresses of argument -1 -> property Id of element of return (jump to get_Addresses) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | property Id of property Address of element of property PersonAddresses of argument -1 -> property Id of property Address of element of return (jump to get_PersonAddresses) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | property Id of property Person of element of property PersonAddresses of argument -1 -> property Id of element of return (jump to get_Persons) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | property Id of property Person of element of property PersonAddresses of argument -1 -> property Id of property Person of element of return (jump to get_PersonAddresses) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | property Name of element of property Persons of argument -1 -> property Name of element of return (jump to get_Persons) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | property Name of element of property Persons of argument -1 -> property Name of property Person of element of return (jump to get_PersonAddresses) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | property Name of property Person of element of property PersonAddresses of argument -1 -> property Name of element of return (jump to get_Persons) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | property Name of property Person of element of property PersonAddresses of argument -1 -> property Name of property Person of element of return (jump to get_PersonAddresses) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | property PersonId of element of property PersonAddresses of argument -1 -> property PersonId of element of return (jump to get_PersonAddresses) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | property Street of element of property Addresses of argument -1 -> property Street of element of property Addresses of element of return (jump to get_Persons) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | property Street of element of property Addresses of argument -1 -> property Street of element of return (jump to get_Addresses) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | property Street of element of property Addresses of argument -1 -> property Street of property Address of element of return (jump to get_PersonAddresses) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | property Street of element of property Addresses of element of property Persons of argument -1 -> property Street of element of property Addresses of element of return (jump to get_Persons) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | property Street of element of property Addresses of element of property Persons of argument -1 -> property Street of element of return (jump to get_Addresses) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | property Street of element of property Addresses of element of property Persons of argument -1 -> property Street of property Address of element of return (jump to get_PersonAddresses) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | property Street of property Address of element of property PersonAddresses of argument -1 -> property Street of element of property Addresses of element of return (jump to get_Persons) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | property Street of property Address of element of property PersonAddresses of argument -1 -> property Street of element of return (jump to get_Addresses) | true | +| Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync() | property Street of property Address of element of property PersonAddresses of argument -1 -> property Street of property Address of element of return (jump to get_PersonAddresses) | true | +| Microsoft.EntityFrameworkCore.DbSet<>.Add(T) | argument 0 -> element of argument -1 | true | +| Microsoft.EntityFrameworkCore.DbSet<>.AddAsync(T) | argument 0 -> element of argument -1 | true | +| Microsoft.EntityFrameworkCore.DbSet<>.AddRange(IEnumerable) | element of argument 0 -> element of argument -1 | true | +| Microsoft.EntityFrameworkCore.DbSet<>.AddRangeAsync(IEnumerable) | element of argument 0 -> element of argument -1 | true | +| Microsoft.EntityFrameworkCore.DbSet<>.Attach(T) | argument 0 -> element of argument -1 | true | +| Microsoft.EntityFrameworkCore.DbSet<>.AttachRange(IEnumerable) | element of argument 0 -> element of argument -1 | true | +| Microsoft.EntityFrameworkCore.DbSet<>.Update(T) | argument 0 -> element of argument -1 | true | +| Microsoft.EntityFrameworkCore.DbSet<>.UpdateRange(IEnumerable) | element of argument 0 -> element of argument -1 | true | +| Microsoft.EntityFrameworkCore.RawSqlString.RawSqlString(string) | argument 0 -> return (normal) | false | +| Microsoft.EntityFrameworkCore.RawSqlString.implicit conversion(string) | argument 0 -> return (normal) | false | +| System.Data.Entity.DbContext.SaveChanges() | property AddressId of element of property PersonAddresses of argument -1 -> property AddressId of element of return (jump to get_PersonAddresses) | true | +| System.Data.Entity.DbContext.SaveChanges() | property Id of element of property Addresses of argument -1 -> property Id of element of property Addresses of element of return (jump to get_Persons) | true | +| System.Data.Entity.DbContext.SaveChanges() | property Id of element of property Addresses of argument -1 -> property Id of element of return (jump to get_Addresses) | true | +| System.Data.Entity.DbContext.SaveChanges() | property Id of element of property Addresses of argument -1 -> property Id of property Address of element of return (jump to get_PersonAddresses) | true | +| System.Data.Entity.DbContext.SaveChanges() | property Id of element of property Addresses of element of property Persons of argument -1 -> property Id of element of property Addresses of element of return (jump to get_Persons) | true | +| System.Data.Entity.DbContext.SaveChanges() | property Id of element of property Addresses of element of property Persons of argument -1 -> property Id of element of return (jump to get_Addresses) | true | +| System.Data.Entity.DbContext.SaveChanges() | property Id of element of property Addresses of element of property Persons of argument -1 -> property Id of property Address of element of return (jump to get_PersonAddresses) | true | +| System.Data.Entity.DbContext.SaveChanges() | property Id of element of property PersonAddresses of argument -1 -> property Id of element of return (jump to get_PersonAddresses) | true | +| System.Data.Entity.DbContext.SaveChanges() | property Id of element of property Persons of argument -1 -> property Id of element of return (jump to get_Persons) | true | +| System.Data.Entity.DbContext.SaveChanges() | property Id of element of property Persons of argument -1 -> property Id of property Person of element of return (jump to get_PersonAddresses) | true | +| System.Data.Entity.DbContext.SaveChanges() | property Id of property Address of element of property PersonAddresses of argument -1 -> property Id of element of property Addresses of element of return (jump to get_Persons) | true | +| System.Data.Entity.DbContext.SaveChanges() | property Id of property Address of element of property PersonAddresses of argument -1 -> property Id of element of return (jump to get_Addresses) | true | +| System.Data.Entity.DbContext.SaveChanges() | property Id of property Address of element of property PersonAddresses of argument -1 -> property Id of property Address of element of return (jump to get_PersonAddresses) | true | +| System.Data.Entity.DbContext.SaveChanges() | property Id of property Person of element of property PersonAddresses of argument -1 -> property Id of element of return (jump to get_Persons) | true | +| System.Data.Entity.DbContext.SaveChanges() | property Id of property Person of element of property PersonAddresses of argument -1 -> property Id of property Person of element of return (jump to get_PersonAddresses) | true | +| System.Data.Entity.DbContext.SaveChanges() | property Name of element of property Persons of argument -1 -> property Name of element of return (jump to get_Persons) | true | +| System.Data.Entity.DbContext.SaveChanges() | property Name of element of property Persons of argument -1 -> property Name of property Person of element of return (jump to get_PersonAddresses) | true | +| System.Data.Entity.DbContext.SaveChanges() | property Name of property Person of element of property PersonAddresses of argument -1 -> property Name of element of return (jump to get_Persons) | true | +| System.Data.Entity.DbContext.SaveChanges() | property Name of property Person of element of property PersonAddresses of argument -1 -> property Name of property Person of element of return (jump to get_PersonAddresses) | true | +| System.Data.Entity.DbContext.SaveChanges() | property PersonId of element of property PersonAddresses of argument -1 -> property PersonId of element of return (jump to get_PersonAddresses) | true | +| System.Data.Entity.DbContext.SaveChanges() | property Street of element of property Addresses of argument -1 -> property Street of element of property Addresses of element of return (jump to get_Persons) | true | +| System.Data.Entity.DbContext.SaveChanges() | property Street of element of property Addresses of argument -1 -> property Street of element of return (jump to get_Addresses) | true | +| System.Data.Entity.DbContext.SaveChanges() | property Street of element of property Addresses of argument -1 -> property Street of property Address of element of return (jump to get_PersonAddresses) | true | +| System.Data.Entity.DbContext.SaveChanges() | property Street of element of property Addresses of element of property Persons of argument -1 -> property Street of element of property Addresses of element of return (jump to get_Persons) | true | +| System.Data.Entity.DbContext.SaveChanges() | property Street of element of property Addresses of element of property Persons of argument -1 -> property Street of element of return (jump to get_Addresses) | true | +| System.Data.Entity.DbContext.SaveChanges() | property Street of element of property Addresses of element of property Persons of argument -1 -> property Street of property Address of element of return (jump to get_PersonAddresses) | true | +| System.Data.Entity.DbContext.SaveChanges() | property Street of property Address of element of property PersonAddresses of argument -1 -> property Street of element of property Addresses of element of return (jump to get_Persons) | true | +| System.Data.Entity.DbContext.SaveChanges() | property Street of property Address of element of property PersonAddresses of argument -1 -> property Street of element of return (jump to get_Addresses) | true | +| System.Data.Entity.DbContext.SaveChanges() | property Street of property Address of element of property PersonAddresses of argument -1 -> property Street of property Address of element of return (jump to get_PersonAddresses) | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | property AddressId of element of property PersonAddresses of argument -1 -> property AddressId of element of return (jump to get_PersonAddresses) | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | property Id of element of property Addresses of argument -1 -> property Id of element of property Addresses of element of return (jump to get_Persons) | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | property Id of element of property Addresses of argument -1 -> property Id of element of return (jump to get_Addresses) | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | property Id of element of property Addresses of argument -1 -> property Id of property Address of element of return (jump to get_PersonAddresses) | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | property Id of element of property Addresses of element of property Persons of argument -1 -> property Id of element of property Addresses of element of return (jump to get_Persons) | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | property Id of element of property Addresses of element of property Persons of argument -1 -> property Id of element of return (jump to get_Addresses) | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | property Id of element of property Addresses of element of property Persons of argument -1 -> property Id of property Address of element of return (jump to get_PersonAddresses) | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | property Id of element of property PersonAddresses of argument -1 -> property Id of element of return (jump to get_PersonAddresses) | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | property Id of element of property Persons of argument -1 -> property Id of element of return (jump to get_Persons) | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | property Id of element of property Persons of argument -1 -> property Id of property Person of element of return (jump to get_PersonAddresses) | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | property Id of property Address of element of property PersonAddresses of argument -1 -> property Id of element of property Addresses of element of return (jump to get_Persons) | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | property Id of property Address of element of property PersonAddresses of argument -1 -> property Id of element of return (jump to get_Addresses) | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | property Id of property Address of element of property PersonAddresses of argument -1 -> property Id of property Address of element of return (jump to get_PersonAddresses) | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | property Id of property Person of element of property PersonAddresses of argument -1 -> property Id of element of return (jump to get_Persons) | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | property Id of property Person of element of property PersonAddresses of argument -1 -> property Id of property Person of element of return (jump to get_PersonAddresses) | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | property Name of element of property Persons of argument -1 -> property Name of element of return (jump to get_Persons) | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | property Name of element of property Persons of argument -1 -> property Name of property Person of element of return (jump to get_PersonAddresses) | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | property Name of property Person of element of property PersonAddresses of argument -1 -> property Name of element of return (jump to get_Persons) | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | property Name of property Person of element of property PersonAddresses of argument -1 -> property Name of property Person of element of return (jump to get_PersonAddresses) | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | property PersonId of element of property PersonAddresses of argument -1 -> property PersonId of element of return (jump to get_PersonAddresses) | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | property Street of element of property Addresses of argument -1 -> property Street of element of property Addresses of element of return (jump to get_Persons) | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | property Street of element of property Addresses of argument -1 -> property Street of element of return (jump to get_Addresses) | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | property Street of element of property Addresses of argument -1 -> property Street of property Address of element of return (jump to get_PersonAddresses) | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | property Street of element of property Addresses of element of property Persons of argument -1 -> property Street of element of property Addresses of element of return (jump to get_Persons) | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | property Street of element of property Addresses of element of property Persons of argument -1 -> property Street of element of return (jump to get_Addresses) | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | property Street of element of property Addresses of element of property Persons of argument -1 -> property Street of property Address of element of return (jump to get_PersonAddresses) | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | property Street of property Address of element of property PersonAddresses of argument -1 -> property Street of element of property Addresses of element of return (jump to get_Persons) | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | property Street of property Address of element of property PersonAddresses of argument -1 -> property Street of element of return (jump to get_Addresses) | true | +| System.Data.Entity.DbContext.SaveChangesAsync() | property Street of property Address of element of property PersonAddresses of argument -1 -> property Street of property Address of element of return (jump to get_PersonAddresses) | true | +| System.Data.Entity.DbSet<>.Add(T) | argument 0 -> element of argument -1 | true | +| System.Data.Entity.DbSet<>.AddAsync(T) | argument 0 -> element of argument -1 | true | +| System.Data.Entity.DbSet<>.AddRange(IEnumerable) | element of argument 0 -> element of argument -1 | true | +| System.Data.Entity.DbSet<>.AddRangeAsync(IEnumerable) | element of argument 0 -> element of argument -1 | true | +| System.Data.Entity.DbSet<>.Attach(T) | argument 0 -> element of argument -1 | true | +| System.Data.Entity.DbSet<>.AttachRange(IEnumerable) | element of argument 0 -> element of argument -1 | true | +| System.Data.Entity.DbSet<>.Update(T) | argument 0 -> element of argument -1 | true | +| System.Data.Entity.DbSet<>.UpdateRange(IEnumerable) | element of argument 0 -> element of argument -1 | true | diff --git a/csharp/ql/test/library-tests/frameworks/EntityFramework/FlowSummaries.ql b/csharp/ql/test/library-tests/frameworks/EntityFramework/FlowSummaries.ql index 598d8c0f20c..ff518640b00 100644 --- a/csharp/ql/test/library-tests/frameworks/EntityFramework/FlowSummaries.ql +++ b/csharp/ql/test/library-tests/frameworks/EntityFramework/FlowSummaries.ql @@ -1,6 +1,9 @@ -import semmle.code.csharp.dataflow.FlowSummary::TestOutput +import semmle.code.csharp.dataflow.FlowSummary +import semmle.code.csharp.dataflow.internal.FlowSummaryImpl::Private::TestOutput import semmle.code.csharp.frameworks.EntityFramework::EntityFramework -private class IncludeEFSummarizedCallable extends RelevantSummarizedCallable { - IncludeEFSummarizedCallable() { this instanceof EFSummarizedCallable } +private class IncludeSummarizedCallable extends RelevantSummarizedCallable { + IncludeSummarizedCallable() { this instanceof EFSummarizedCallable } + + override string getFullString() { result = this.(Callable).getQualifiedNameWithTypes() } } From 9610ed163aa0fd767abe41749cdbae6c88b5b928 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 24 Mar 2021 11:59:56 +0100 Subject: [PATCH 321/725] remove SourceNode type to preserve behavior --- .../javascript/frameworks/AngularJS/ServiceDefinitions.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/AngularJS/ServiceDefinitions.qll b/javascript/ql/src/semmle/javascript/frameworks/AngularJS/ServiceDefinitions.qll index 2956f6d07ae..fe7885b435e 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/AngularJS/ServiceDefinitions.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/AngularJS/ServiceDefinitions.qll @@ -300,7 +300,7 @@ abstract private class CustomSpecialServiceDefinition extends CustomServiceDefin bindingset[moduleMethodName] private predicate isCustomServiceDefinitionOnModule( DataFlow::CallNode mce, string moduleMethodName, string serviceName, - DataFlow::SourceNode factoryArgument + DataFlow::Node factoryArgument ) { mce = moduleRef(_).getAMethodCall(moduleMethodName) and mce.getArgument(0).asExpr().mayHaveStringValue(serviceName) and From 6d86239929dda58bdb3b0dfe226d88902c7422d0 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Wed, 24 Mar 2021 13:14:46 +0100 Subject: [PATCH 322/725] Python: Test all cases Note that the test in `no_py_extension` isn't complete, since we're not extracting the `main` file there. --- .../entry_point/{code => hash_bang}/main.py | 0 .../entry_point/{code => hash_bang}/module.py | 0 .../namespace_package_main.py | 0 .../namespace_package_module.py | 0 .../{code => hash_bang}/package/__init__.py | 0 .../package/package_main.py | 0 .../package/package_module.py | 0 .../modules/entry_point/modules.expected | 22 ++++++++++++++----- .../modules/entry_point/name_main/main.py | 8 +++++++ .../modules/entry_point/name_main/module.py | 2 ++ .../namespace_package_main.py | 2 ++ .../namespace_package_module.py | 1 + .../entry_point/name_main/package/__init__.py | 2 ++ .../name_main/package/package_main.py | 2 ++ .../name_main/package/package_module.py | 1 + .../modules/entry_point/no_py_extension/main | 6 +++++ .../entry_point/no_py_extension/module.py | 2 ++ .../namespace_package_main.py | 2 ++ .../namespace_package_module.py | 1 + .../no_py_extension/package/__init__.py | 2 ++ .../no_py_extension/package/package_main.py | 2 ++ .../no_py_extension/package/package_module.py | 1 + 22 files changed, 50 insertions(+), 6 deletions(-) rename python/ql/test/3/library-tests/modules/entry_point/{code => hash_bang}/main.py (100%) rename python/ql/test/3/library-tests/modules/entry_point/{code => hash_bang}/module.py (100%) rename python/ql/test/3/library-tests/modules/entry_point/{code => hash_bang}/namespace_package/namespace_package_main.py (100%) rename python/ql/test/3/library-tests/modules/entry_point/{code => hash_bang}/namespace_package/namespace_package_module.py (100%) rename python/ql/test/3/library-tests/modules/entry_point/{code => hash_bang}/package/__init__.py (100%) rename python/ql/test/3/library-tests/modules/entry_point/{code => hash_bang}/package/package_main.py (100%) rename python/ql/test/3/library-tests/modules/entry_point/{code => hash_bang}/package/package_module.py (100%) create mode 100755 python/ql/test/3/library-tests/modules/entry_point/name_main/main.py create mode 100644 python/ql/test/3/library-tests/modules/entry_point/name_main/module.py create mode 100644 python/ql/test/3/library-tests/modules/entry_point/name_main/namespace_package/namespace_package_main.py create mode 100644 python/ql/test/3/library-tests/modules/entry_point/name_main/namespace_package/namespace_package_module.py create mode 100644 python/ql/test/3/library-tests/modules/entry_point/name_main/package/__init__.py create mode 100644 python/ql/test/3/library-tests/modules/entry_point/name_main/package/package_main.py create mode 100644 python/ql/test/3/library-tests/modules/entry_point/name_main/package/package_module.py create mode 100755 python/ql/test/3/library-tests/modules/entry_point/no_py_extension/main create mode 100644 python/ql/test/3/library-tests/modules/entry_point/no_py_extension/module.py create mode 100644 python/ql/test/3/library-tests/modules/entry_point/no_py_extension/namespace_package/namespace_package_main.py create mode 100644 python/ql/test/3/library-tests/modules/entry_point/no_py_extension/namespace_package/namespace_package_module.py create mode 100644 python/ql/test/3/library-tests/modules/entry_point/no_py_extension/package/__init__.py create mode 100644 python/ql/test/3/library-tests/modules/entry_point/no_py_extension/package/package_main.py create mode 100644 python/ql/test/3/library-tests/modules/entry_point/no_py_extension/package/package_module.py diff --git a/python/ql/test/3/library-tests/modules/entry_point/code/main.py b/python/ql/test/3/library-tests/modules/entry_point/hash_bang/main.py similarity index 100% rename from python/ql/test/3/library-tests/modules/entry_point/code/main.py rename to python/ql/test/3/library-tests/modules/entry_point/hash_bang/main.py diff --git a/python/ql/test/3/library-tests/modules/entry_point/code/module.py b/python/ql/test/3/library-tests/modules/entry_point/hash_bang/module.py similarity index 100% rename from python/ql/test/3/library-tests/modules/entry_point/code/module.py rename to python/ql/test/3/library-tests/modules/entry_point/hash_bang/module.py diff --git a/python/ql/test/3/library-tests/modules/entry_point/code/namespace_package/namespace_package_main.py b/python/ql/test/3/library-tests/modules/entry_point/hash_bang/namespace_package/namespace_package_main.py similarity index 100% rename from python/ql/test/3/library-tests/modules/entry_point/code/namespace_package/namespace_package_main.py rename to python/ql/test/3/library-tests/modules/entry_point/hash_bang/namespace_package/namespace_package_main.py diff --git a/python/ql/test/3/library-tests/modules/entry_point/code/namespace_package/namespace_package_module.py b/python/ql/test/3/library-tests/modules/entry_point/hash_bang/namespace_package/namespace_package_module.py similarity index 100% rename from python/ql/test/3/library-tests/modules/entry_point/code/namespace_package/namespace_package_module.py rename to python/ql/test/3/library-tests/modules/entry_point/hash_bang/namespace_package/namespace_package_module.py diff --git a/python/ql/test/3/library-tests/modules/entry_point/code/package/__init__.py b/python/ql/test/3/library-tests/modules/entry_point/hash_bang/package/__init__.py similarity index 100% rename from python/ql/test/3/library-tests/modules/entry_point/code/package/__init__.py rename to python/ql/test/3/library-tests/modules/entry_point/hash_bang/package/__init__.py diff --git a/python/ql/test/3/library-tests/modules/entry_point/code/package/package_main.py b/python/ql/test/3/library-tests/modules/entry_point/hash_bang/package/package_main.py similarity index 100% rename from python/ql/test/3/library-tests/modules/entry_point/code/package/package_main.py rename to python/ql/test/3/library-tests/modules/entry_point/hash_bang/package/package_main.py diff --git a/python/ql/test/3/library-tests/modules/entry_point/code/package/package_module.py b/python/ql/test/3/library-tests/modules/entry_point/hash_bang/package/package_module.py similarity index 100% rename from python/ql/test/3/library-tests/modules/entry_point/code/package/package_module.py rename to python/ql/test/3/library-tests/modules/entry_point/hash_bang/package/package_module.py diff --git a/python/ql/test/3/library-tests/modules/entry_point/modules.expected b/python/ql/test/3/library-tests/modules/entry_point/modules.expected index 8c96490597c..e5f6b300074 100644 --- a/python/ql/test/3/library-tests/modules/entry_point/modules.expected +++ b/python/ql/test/3/library-tests/modules/entry_point/modules.expected @@ -1,6 +1,16 @@ -| main | code/main.py:0:0:0:0 | Script main | -| module | code/module.py:0:0:0:0 | Module module | -| package | code/package:0:0:0:0 | Package package | -| package.__init__ | code/package/__init__.py:0:0:0:0 | Module package.__init__ | -| package.package_main | code/package/package_main.py:0:0:0:0 | Module package.package_main | -| package.package_module | code/package/package_module.py:0:0:0:0 | Module package.package_module | +| main | hash_bang/main.py:0:0:0:0 | Script main | +| main | name_main/main.py:0:0:0:0 | Module main | +| module | hash_bang/module.py:0:0:0:0 | Module module | +| module | name_main/module.py:0:0:0:0 | Module module | +| package | hash_bang/package:0:0:0:0 | Package package | +| package | name_main/package:0:0:0:0 | Package package | +| package | no_py_extension/package:0:0:0:0 | Package package | +| package.__init__ | hash_bang/package/__init__.py:0:0:0:0 | Module package.__init__ | +| package.__init__ | name_main/package/__init__.py:0:0:0:0 | Module package.__init__ | +| package.__init__ | no_py_extension/package/__init__.py:0:0:0:0 | Module package.__init__ | +| package.package_main | hash_bang/package/package_main.py:0:0:0:0 | Module package.package_main | +| package.package_main | name_main/package/package_main.py:0:0:0:0 | Module package.package_main | +| package.package_main | no_py_extension/package/package_main.py:0:0:0:0 | Module package.package_main | +| package.package_module | hash_bang/package/package_module.py:0:0:0:0 | Module package.package_module | +| package.package_module | name_main/package/package_module.py:0:0:0:0 | Module package.package_module | +| package.package_module | no_py_extension/package/package_module.py:0:0:0:0 | Module package.package_module | diff --git a/python/ql/test/3/library-tests/modules/entry_point/name_main/main.py b/python/ql/test/3/library-tests/modules/entry_point/name_main/main.py new file mode 100755 index 00000000000..08ec212383b --- /dev/null +++ b/python/ql/test/3/library-tests/modules/entry_point/name_main/main.py @@ -0,0 +1,8 @@ +print(__file__) +import module +import package +import namespace_package +import namespace_package.namespace_package_main + +if __name__ == '__main__': + print(module.message) diff --git a/python/ql/test/3/library-tests/modules/entry_point/name_main/module.py b/python/ql/test/3/library-tests/modules/entry_point/name_main/module.py new file mode 100644 index 00000000000..36206ca60b7 --- /dev/null +++ b/python/ql/test/3/library-tests/modules/entry_point/name_main/module.py @@ -0,0 +1,2 @@ +print(__file__.split("entry_point")[1]) +message = "Hello world!" diff --git a/python/ql/test/3/library-tests/modules/entry_point/name_main/namespace_package/namespace_package_main.py b/python/ql/test/3/library-tests/modules/entry_point/name_main/namespace_package/namespace_package_main.py new file mode 100644 index 00000000000..5db80f18a27 --- /dev/null +++ b/python/ql/test/3/library-tests/modules/entry_point/name_main/namespace_package/namespace_package_main.py @@ -0,0 +1,2 @@ +print(__file__.split("entry_point")[1]) +import namespace_package.namespace_package_module diff --git a/python/ql/test/3/library-tests/modules/entry_point/name_main/namespace_package/namespace_package_module.py b/python/ql/test/3/library-tests/modules/entry_point/name_main/namespace_package/namespace_package_module.py new file mode 100644 index 00000000000..567a23d59ce --- /dev/null +++ b/python/ql/test/3/library-tests/modules/entry_point/name_main/namespace_package/namespace_package_module.py @@ -0,0 +1 @@ +print(__file__.split("entry_point")[1]) diff --git a/python/ql/test/3/library-tests/modules/entry_point/name_main/package/__init__.py b/python/ql/test/3/library-tests/modules/entry_point/name_main/package/__init__.py new file mode 100644 index 00000000000..ca14a9f5804 --- /dev/null +++ b/python/ql/test/3/library-tests/modules/entry_point/name_main/package/__init__.py @@ -0,0 +1,2 @@ +print(__file__.split("entry_point")[1]) +from . import package_main diff --git a/python/ql/test/3/library-tests/modules/entry_point/name_main/package/package_main.py b/python/ql/test/3/library-tests/modules/entry_point/name_main/package/package_main.py new file mode 100644 index 00000000000..158b12678e3 --- /dev/null +++ b/python/ql/test/3/library-tests/modules/entry_point/name_main/package/package_main.py @@ -0,0 +1,2 @@ +print(__file__.split("entry_point")[1]) +from . import package_module diff --git a/python/ql/test/3/library-tests/modules/entry_point/name_main/package/package_module.py b/python/ql/test/3/library-tests/modules/entry_point/name_main/package/package_module.py new file mode 100644 index 00000000000..567a23d59ce --- /dev/null +++ b/python/ql/test/3/library-tests/modules/entry_point/name_main/package/package_module.py @@ -0,0 +1 @@ +print(__file__.split("entry_point")[1]) diff --git a/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/main b/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/main new file mode 100755 index 00000000000..e2673d4da78 --- /dev/null +++ b/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/main @@ -0,0 +1,6 @@ +print(__file__) +import module +import package +import namespace_package +import namespace_package.namespace_package_main +print(module.message) diff --git a/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/module.py b/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/module.py new file mode 100644 index 00000000000..36206ca60b7 --- /dev/null +++ b/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/module.py @@ -0,0 +1,2 @@ +print(__file__.split("entry_point")[1]) +message = "Hello world!" diff --git a/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/namespace_package/namespace_package_main.py b/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/namespace_package/namespace_package_main.py new file mode 100644 index 00000000000..5db80f18a27 --- /dev/null +++ b/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/namespace_package/namespace_package_main.py @@ -0,0 +1,2 @@ +print(__file__.split("entry_point")[1]) +import namespace_package.namespace_package_module diff --git a/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/namespace_package/namespace_package_module.py b/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/namespace_package/namespace_package_module.py new file mode 100644 index 00000000000..567a23d59ce --- /dev/null +++ b/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/namespace_package/namespace_package_module.py @@ -0,0 +1 @@ +print(__file__.split("entry_point")[1]) diff --git a/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/package/__init__.py b/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/package/__init__.py new file mode 100644 index 00000000000..ca14a9f5804 --- /dev/null +++ b/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/package/__init__.py @@ -0,0 +1,2 @@ +print(__file__.split("entry_point")[1]) +from . import package_main diff --git a/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/package/package_main.py b/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/package/package_main.py new file mode 100644 index 00000000000..158b12678e3 --- /dev/null +++ b/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/package/package_main.py @@ -0,0 +1,2 @@ +print(__file__.split("entry_point")[1]) +from . import package_module diff --git a/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/package/package_module.py b/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/package/package_module.py new file mode 100644 index 00000000000..567a23d59ce --- /dev/null +++ b/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/package/package_module.py @@ -0,0 +1 @@ +print(__file__.split("entry_point")[1]) From 234f62fd055422187b032657e461ee9927def62e Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Wed, 24 Mar 2021 13:17:04 +0100 Subject: [PATCH 323/725] Java: Merge packages that likely belong to the same framework. --- java/ql/src/meta/frameworks/Coverage.ql | 8 +-- .../code/java/dataflow/ExternalFlow.qll | 65 ++++++++++++++----- 2 files changed, 52 insertions(+), 21 deletions(-) diff --git a/java/ql/src/meta/frameworks/Coverage.ql b/java/ql/src/meta/frameworks/Coverage.ql index d945d7b4002..ca0f78d99f1 100644 --- a/java/ql/src/meta/frameworks/Coverage.ql +++ b/java/ql/src/meta/frameworks/Coverage.ql @@ -2,13 +2,13 @@ * @name Framework coverage * @description The number of API endpoints covered by CSV models sorted by * package and source-, sink-, and summary-kind. - * @kind metric + * @kind table * @id java/meta/framework-coverage */ import java import semmle.code.java.dataflow.ExternalFlow -from string package, string kind, string part, int n -where modelCoverage(package, kind, part, n) -select package, kind, part, n +from string package, int pkgs, string kind, string part, int n +where modelCoverage(package, pkgs, kind, part, n) +select package, pkgs, kind, part, n diff --git a/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll b/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll index 2f285d5a115..5e983a350bf 100644 --- a/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll +++ b/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll @@ -204,27 +204,58 @@ private predicate summaryModel( ) } +private predicate relevantPackage(string package) { + sourceModel(package, _, _, _, _, _, _, _) or + sinkModel(package, _, _, _, _, _, _, _) or + summaryModel(package, _, _, _, _, _, _, _, _) +} + +private predicate packageLink(string shortpkg, string longpkg) { + relevantPackage(shortpkg) and + relevantPackage(longpkg) and + longpkg.prefix(longpkg.indexOf(".")) = shortpkg +} + +private predicate canonicalPackage(string package) { + relevantPackage(package) and not packageLink(_, package) +} + +private predicate canonicalPkgLink(string package, string subpkg) { + canonicalPackage(package) and + (subpkg = package or packageLink(package, subpkg)) +} + /** * Holds if CSV framework coverage of `package` is `n` api endpoints of the * kind `(kind, part)`. */ -predicate modelCoverage(string package, string kind, string part, int n) { - part = "source" and - n = - strictcount(string type, boolean subtypes, string name, string signature, string ext, - string output | sourceModel(package, type, subtypes, name, signature, ext, output, kind)) - or - part = "sink" and - n = - strictcount(string type, boolean subtypes, string name, string signature, string ext, - string input | sinkModel(package, type, subtypes, name, signature, ext, input, kind)) - or - part = "summary" and - n = - strictcount(string type, boolean subtypes, string name, string signature, string ext, - string input, string output | - summaryModel(package, type, subtypes, name, signature, ext, input, output, kind) - ) +predicate modelCoverage(string package, int pkgs, string kind, string part, int n) { + pkgs = strictcount(string subpkg | canonicalPkgLink(package, subpkg)) and + ( + part = "source" and + n = + strictcount(string subpkg, string type, boolean subtypes, string name, string signature, + string ext, string output | + canonicalPkgLink(package, subpkg) and + sourceModel(subpkg, type, subtypes, name, signature, ext, output, kind) + ) + or + part = "sink" and + n = + strictcount(string subpkg, string type, boolean subtypes, string name, string signature, + string ext, string input | + canonicalPkgLink(package, subpkg) and + sinkModel(subpkg, type, subtypes, name, signature, ext, input, kind) + ) + or + part = "summary" and + n = + strictcount(string subpkg, string type, boolean subtypes, string name, string signature, + string ext, string input, string output | + canonicalPkgLink(package, subpkg) and + summaryModel(subpkg, type, subtypes, name, signature, ext, input, output, kind) + ) + ) } /** Provides a query predicate to check the CSV data for validation errors. */ From 41168e2b3684f0723fde6b5e557bbde28f4b59dc Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Wed, 24 Mar 2021 13:32:30 +0100 Subject: [PATCH 324/725] Java: Support argument and parameter ranges. --- .../code/java/dataflow/ExternalFlow.qll | 44 ++++++++++++++----- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll b/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll index 28808bc722d..462fb1b1014 100644 --- a/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll +++ b/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll @@ -32,26 +32,30 @@ * 7. The `input` column specifies how data enters the element selected by the * first 6 columns, and the `output` column specifies how data leaves the * element selected by the first 6 columns. An `input` can be either "", - * "Argument", "Argument[n]", "ReturnValue": + * "Argument[n]", "Argument[n1..n2]", "ReturnValue": * - "": Selects a write to the selected element in case this is a field. - * - "Argument": Selects any argument in a call to the selected element. - * - "Argument[n]": Similar to "Argument" but restricted to a specific numbered - * argument (zero-indexed, and `-1` specifies the qualifier). + * - "Argument[n]": Selects an argument in a call to the selected element. + * The arguments are zero-indexed, and `-1` specifies the qualifier. + * - "Argument[n1..n2]": Similar to "Argument[n]" but select any argument in + * the given range. * - "ReturnValue": Selects a value being returned by the selected element. * This requires that the selected element is a method with a body. * - * An `output` can be either "", "Argument", "Argument[n]", "Parameter", - * "Parameter[n]", or "ReturnValue": + * An `output` can be either "", "Argument[n]", "Argument[n1..n2]", "Parameter", + * "Parameter[n]", "Parameter[n1..n2]", or "ReturnValue": * - "": Selects a read of a selected field, or a selected parameter. - * - "Argument": Selects the post-update value of an argument in a call to the + * - "Argument[n]": Selects the post-update value of an argument in a call to the * selected element. That is, the value of the argument after the call returns. - * - "Argument[n]": Similar to "Argument" but restricted to a specific numbered - * argument (zero-indexed, and `-1` specifies the qualifier). + * The arguments are zero-indexed, and `-1` specifies the qualifier. + * - "Argument[n1..n2]": Similar to "Argument[n]" but select any argument in + * the given range. * - "Parameter": Selects the value of a parameter of the selected element. * "Parameter" is also allowed in case the selected element is already a * parameter itself. * - "Parameter[n]": Similar to "Parameter" but restricted to a specific * numbered parameter (zero-indexed, and `-1` specifies the value of `this`). + * - "Parameter[n1..n2]": Similar to "Parameter[n]" but selects any parameter + * in the given range. * - "ReturnValue": Selects the return value of a call to the selected element. * 8. The `kind` column is a tag that can be referenced from QL to determine to * which classes the interpreted elements should be added. For example, for @@ -554,11 +558,29 @@ private string getLast(string s) { } private predicate parseParam(string c, int n) { - specSplit(_, c, _) and c.regexpCapture("Parameter\\[([-0-9]+)\\]", 1).toInt() = n + specSplit(_, c, _) and + ( + c.regexpCapture("Parameter\\[([-0-9]+)\\]", 1).toInt() = n + or + exists(int n1, int n2 | + c.regexpCapture("Parameter\\[([-0-9]+)\\.\\.([0-9]+)\\]", 1).toInt() = n1 and + c.regexpCapture("Parameter\\[([-0-9]+)\\.\\.([0-9]+)\\]", 2).toInt() = n2 and + n = [n1 .. n2] + ) + ) } private predicate parseArg(string c, int n) { - specSplit(_, c, _) and c.regexpCapture("Argument\\[([-0-9]+)\\]", 1).toInt() = n + specSplit(_, c, _) and + ( + c.regexpCapture("Argument\\[([-0-9]+)\\]", 1).toInt() = n + or + exists(int n1, int n2 | + c.regexpCapture("Argument\\[([-0-9]+)\\.\\.([0-9]+)\\]", 1).toInt() = n1 and + c.regexpCapture("Argument\\[([-0-9]+)\\.\\.([0-9]+)\\]", 2).toInt() = n2 and + n = [n1 .. n2] + ) + ) } private predicate inputNeedsReference(string c) { From f2fb26df374de36f51c8d4658b06d914a3a065d2 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 24 Mar 2021 13:48:32 +0100 Subject: [PATCH 325/725] C#: Document input/output stack restrictions --- .../csharp/dataflow/internal/FlowSummaryImpl.qll | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll index 08a341ce8c0..850ba6a7aa5 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll @@ -139,6 +139,20 @@ module Public { * * `preservesValue` indicates whether this is a value-preserving step * or a taint-step. + * + * Input specications are restricted to stacks that end with + * `SummaryComponent::argument(_)`, preceded by zero or more + * `SummaryComponent::return(_)` or `SummaryComponent::content(_)` components. + * + * Output specications are restricted to stacks that end with + * `SummaryComponent::return(_)` or `SummaryComponent::argument(_)`. + * + * Output stacks ending with `SummaryComponent::return(_)` can be preceded by zero + * or more `SummaryComponent::content(_)` components. + * + * Output stacks ending with `SummaryComponent::argument(_)` can be preceded by an + * optional `SummaryComponent::parameter(_)` component, which in turn can be preceded + * by zero or more `SummaryComponent::content(_)` components. */ pragma[nomagic] predicate propagatesFlow( From 59200386a7a2fc3bae8ec2771bc2d14b67b7417f Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 24 Mar 2021 13:51:29 +0100 Subject: [PATCH 326/725] Python: Fix mistake in refactor --- python/ql/src/semmle/python/frameworks/Cryptography.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/frameworks/Cryptography.qll b/python/ql/src/semmle/python/frameworks/Cryptography.qll index a3254fdc6da..3396d7dfa55 100644 --- a/python/ql/src/semmle/python/frameworks/Cryptography.qll +++ b/python/ql/src/semmle/python/frameworks/Cryptography.qll @@ -102,7 +102,7 @@ private module CryptographyModel { /** Gets a reference to a predefined curve class instance with a specific key size (in bits), as well as the origin of the class. */ DataFlow::Node curveClassInstanceWithKeySize(int keySize, DataFlow::Node origin) { - result = curveClassInstanceWithKeySize(DataFlow::TypeTracker::end(), keySize, origin) + curveClassInstanceWithKeySize(DataFlow::TypeTracker::end(), keySize, origin).flowsTo(result) } } From 88932a495c95a45edc67cb2f80d6736c7fce3fea Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 12 Nov 2020 10:09:50 +0000 Subject: [PATCH 327/725] JS: Handle redux-form HOCs --- javascript/ql/src/semmle/javascript/frameworks/React.qll | 2 ++ 1 file changed, 2 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/frameworks/React.qll b/javascript/ql/src/semmle/javascript/frameworks/React.qll index 5adbcaeab14..ef9b82b0897 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/React.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/React.qll @@ -759,6 +759,8 @@ private DataFlow::SourceNode higherOrderComponentBuilder() { or result = DataFlow::moduleMember(["react-hot-loader", "react-hot-loader/root"], "hot").getACall() or + result = DataFlow::moduleMember("redux-form", "reduxForm").getACall() + or result = reactRouterDom().getAPropertyRead("withRouter") or exists(FunctionCompositionCall compose | From 2f2d72f28287a060a51a0ba5e11a4016d4dc7062 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 13 Nov 2020 16:43:05 +0000 Subject: [PATCH 328/725] JS: Improve react-router support --- .../semmle/javascript/frameworks/React.qll | 30 ++++++++++++++----- .../frameworks/ReactJS/importedComponent.jsx | 2 +- .../frameworks/ReactJS/tests.expected | 11 +++++++ .../library-tests/frameworks/ReactJS/tests.ql | 2 ++ .../frameworks/ReactJS/use-react-router.jsx | 5 ++++ 5 files changed, 42 insertions(+), 8 deletions(-) create mode 100644 javascript/ql/test/library-tests/frameworks/ReactJS/use-react-router.jsx diff --git a/javascript/ql/src/semmle/javascript/frameworks/React.qll b/javascript/ql/src/semmle/javascript/frameworks/React.qll index ef9b82b0897..784bd03a29c 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/React.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/React.qll @@ -691,15 +691,22 @@ private DataFlow::SourceNode reactRouterDom() { result = DataFlow::moduleImport("react-router-dom") } +private DataFlow::SourceNode reactRouterMatchObject() { + result = reactRouterDom().getAMemberCall(["useRouteMatch", "matchPath"]) + or + exists(ReactComponent c | + dependedOnByReactRouterClient(c.getTopLevel()) and + result = c.getAPropRead("match") + ) +} + private class ReactRouterSource extends ClientSideRemoteFlowSource { ClientSideRemoteFlowKind kind; ReactRouterSource() { this = reactRouterDom().getAMemberCall("useParams") and kind.isPath() or - exists(string prop | - this = reactRouterDom().getAMemberCall("useRouteMatch").getAPropertyRead(prop) - | + exists(string prop | this = reactRouterMatchObject().getAPropertyRead(prop) | prop = "params" and kind.isPath() or prop = "url" and kind.isUrl() @@ -713,9 +720,6 @@ private class ReactRouterSource extends ClientSideRemoteFlowSource { /** * Holds if `mod` transitively depends on `react-router-dom`. - * - * We assume any React component in such a file may be used in a context where react-router - * injects the `location` property in its `props` object. */ private predicate dependsOnReactRouter(Module mod) { mod.getAnImport().getImportedPath().getValue() = "react-router-dom" @@ -723,6 +727,18 @@ private predicate dependsOnReactRouter(Module mod) { dependsOnReactRouter(mod.getAnImportedModule()) } +/** + * Holds if `mod` is imported from a module that transitively depends on `react-router-dom`. + * + * We assume any React component in such a file may be used in a context where react-router + * injects the `location` and `match` properties in its `props` object. + */ +private predicate dependedOnByReactRouterClient(Module mod) { + dependsOnReactRouter(mod) + or + dependedOnByReactRouterClient(any(Module m | m.getAnImportedModule() = mod)) +} + /** * A reference to the DOM location obtained through `react-router-dom` * @@ -740,7 +756,7 @@ private class ReactRouterLocationSource extends DOM::LocationSource::Range { this = reactRouterDom().getAMemberCall("useLocation") or exists(ReactComponent component | - dependsOnReactRouter(component.getTopLevel()) and + dependedOnByReactRouterClient(component.getTopLevel()) and this = component.getAPropRead("location") ) } diff --git a/javascript/ql/test/library-tests/frameworks/ReactJS/importedComponent.jsx b/javascript/ql/test/library-tests/frameworks/ReactJS/importedComponent.jsx index edc333528a7..d94acf59abe 100644 --- a/javascript/ql/test/library-tests/frameworks/ReactJS/importedComponent.jsx +++ b/javascript/ql/test/library-tests/frameworks/ReactJS/importedComponent.jsx @@ -1,5 +1,5 @@ import { MyComponent } from "./exportedComponent"; -export function render(color) { +export function render({color, location}) { return } diff --git a/javascript/ql/test/library-tests/frameworks/ReactJS/tests.expected b/javascript/ql/test/library-tests/frameworks/ReactJS/tests.expected index fba8084a937..f64d386b45b 100644 --- a/javascript/ql/test/library-tests/frameworks/ReactJS/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/ReactJS/tests.expected @@ -16,6 +16,7 @@ test_ReactComponent_getInstanceMethod | es5.js:18:33:22:1 | {\\n ren ... ;\\n }\\n} | render | es5.js:19:11:21:3 | functio ... 1>;\\n } | | es6.js:1:1:8:1 | class H ... ;\\n }\\n} | render | es6.js:2:9:4:3 | () {\\n ... v>;\\n } | | exportedComponent.jsx:1:8:3:1 | functio ... r}}/>\\n} | render | exportedComponent.jsx:1:8:3:1 | functio ... r}}/>\\n} | +| importedComponent.jsx:3:8:5:1 | functio ... or}/>\\n} | render | importedComponent.jsx:3:8:5:1 | functio ... or}/>\\n} | | plainfn.js:1:1:3:1 | functio ... div>;\\n} | render | plainfn.js:1:1:3:1 | functio ... div>;\\n} | | plainfn.js:5:1:7:1 | functio ... iv");\\n} | render | plainfn.js:5:1:7:1 | functio ... iv");\\n} | | plainfn.js:9:1:12:1 | functio ... rn x;\\n} | render | plainfn.js:9:1:12:1 | functio ... rn x;\\n} | @@ -97,6 +98,7 @@ test_ReactComponent_ref | es6.js:14:1:20:1 | class H ... }\\n} | es6.js:17:9:17:12 | this | | es6.js:14:1:20:1 | class H ... }\\n} | es6.js:18:9:18:12 | this | | exportedComponent.jsx:1:8:3:1 | functio ... r}}/>\\n} | exportedComponent.jsx:1:8:1:7 | this | +| importedComponent.jsx:3:8:5:1 | functio ... or}/>\\n} | importedComponent.jsx:3:8:3:7 | this | | namedImport.js:3:1:3:28 | class C ... nent {} | namedImport.js:3:27:3:26 | this | | namedImport.js:5:1:5:20 | class D extends C {} | namedImport.js:5:19:5:18 | this | | plainfn.js:1:1:3:1 | functio ... div>;\\n} | plainfn.js:1:1:1:0 | this | @@ -198,6 +200,7 @@ test_ReactComponent_getADirectPropsSource | es6.js:1:1:8:1 | class H ... ;\\n }\\n} | es6.js:1:37:1:36 | args | | es6.js:1:1:8:1 | class H ... ;\\n }\\n} | es6.js:3:24:3:33 | this.props | | exportedComponent.jsx:1:8:3:1 | functio ... r}}/>\\n} | exportedComponent.jsx:1:29:1:33 | props | +| importedComponent.jsx:3:8:5:1 | functio ... or}/>\\n} | importedComponent.jsx:3:24:3:40 | {color, location} | | namedImport.js:3:1:3:28 | class C ... nent {} | namedImport.js:3:27:3:26 | args | | namedImport.js:5:1:5:20 | class D extends C {} | namedImport.js:5:19:5:18 | args | | plainfn.js:1:1:3:1 | functio ... div>;\\n} | plainfn.js:1:16:1:20 | props | @@ -236,6 +239,7 @@ test_ReactComponent | es6.js:1:1:8:1 | class H ... ;\\n }\\n} | | es6.js:14:1:20:1 | class H ... }\\n} | | exportedComponent.jsx:1:8:3:1 | functio ... r}}/>\\n} | +| importedComponent.jsx:3:8:5:1 | functio ... or}/>\\n} | | namedImport.js:3:1:3:28 | class C ... nent {} | | namedImport.js:5:1:5:20 | class D extends C {} | | plainfn.js:1:1:3:1 | functio ... div>;\\n} | @@ -264,6 +268,8 @@ test_ReactComponent_getAPropRead | es5.js:18:33:22:1 | {\\n ren ... ;\\n }\\n} | name | es5.js:20:24:20:38 | this.props.name | | es6.js:1:1:8:1 | class H ... ;\\n }\\n} | name | es6.js:3:24:3:38 | this.props.name | | exportedComponent.jsx:1:8:3:1 | functio ... r}}/>\\n} | color | exportedComponent.jsx:2:32:2:42 | props.color | +| importedComponent.jsx:3:8:5:1 | functio ... or}/>\\n} | color | importedComponent.jsx:3:25:3:29 | color | +| importedComponent.jsx:3:8:5:1 | functio ... or}/>\\n} | location | importedComponent.jsx:3:32:3:39 | location | | plainfn.js:1:1:3:1 | functio ... div>;\\n} | name | plainfn.js:2:22:2:31 | props.name | | preact.js:1:1:7:1 | class H ... }\\n} | name | preact.js:3:9:3:18 | props.name | | probably-a-component.js:1:1:6:1 | class H ... }\\n} | name | probably-a-component.js:3:9:3:23 | this.props.name | @@ -288,6 +294,9 @@ test_JSXname | thisAccesses.js:60:19:60:41 | | thisAccesses.js:60:20:60:28 | this.name | this.name | dot | | thisAccesses.js:61:19:61:41 | | thisAccesses.js:61:20:61:28 | this.this | this.this | dot | | thisAccesses_importedMappers.js:13:16:13:21 |
    | thisAccesses_importedMappers.js:13:17:13:19 | div | div | Identifier | +| use-react-router.jsx:5:17:5:87 | | use-react-router.jsx:5:18:5:23 | Router | Router | Identifier | +| use-react-router.jsx:5:25:5:78 | ... /Route> | use-react-router.jsx:5:26:5:30 | Route | Route | Identifier | +| use-react-router.jsx:5:32:5:70 | | use-react-router.jsx:5:33:5:49 | ImportedComponent | ImportedComponent | Identifier | | useHigherOrderComponent.jsx:5:12:5:39 | | useHigherOrderComponent.jsx:5:13:5:25 | SomeComponent | SomeComponent | Identifier | | useHigherOrderComponent.jsx:11:12:11:46 | | useHigherOrderComponent.jsx:11:13:11:31 | LazyLoadedComponent | LazyLoadedComponent | Identifier | | useHigherOrderComponent.jsx:17:12:17:48 | | useHigherOrderComponent.jsx:17:13:17:32 | LazyLoadedComponent2 | LazyLoadedComponent2 | Identifier | @@ -298,3 +307,5 @@ test_JSXName_this | statePropertyWrites.js:38:12:38:45 |
    He ... }
    | statePropertyWrites.js:38:24:38:27 | this | | thisAccesses.js:60:19:60:41 | | thisAccesses.js:60:20:60:23 | this | | thisAccesses.js:61:19:61:41 | | thisAccesses.js:61:20:61:23 | this | +locationSource +| importedComponent.jsx:3:32:3:39 | location | diff --git a/javascript/ql/test/library-tests/frameworks/ReactJS/tests.ql b/javascript/ql/test/library-tests/frameworks/ReactJS/tests.ql index 5289aa02249..b97e69b2526 100644 --- a/javascript/ql/test/library-tests/frameworks/ReactJS/tests.ql +++ b/javascript/ql/test/library-tests/frameworks/ReactJS/tests.ql @@ -9,3 +9,5 @@ import ReactComponent_getACandidatePropsValue import ReactComponent import ReactComponent_getAPropRead import ReactName + +query DataFlow::SourceNode locationSource() { result = DOM::locationSource() } diff --git a/javascript/ql/test/library-tests/frameworks/ReactJS/use-react-router.jsx b/javascript/ql/test/library-tests/frameworks/ReactJS/use-react-router.jsx new file mode 100644 index 00000000000..044c7f5e492 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/ReactJS/use-react-router.jsx @@ -0,0 +1,5 @@ +import * as ReactDOM from "react-dom" +import { Route, Router } from "react-router-dom"; +import ImportedComponent from "./importedComponent"; + +ReactDOM.render(); From de879c0707090d2090e04c3d1c19c8d4bb39d6ee Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Tue, 23 Mar 2021 16:30:53 +0000 Subject: [PATCH 329/725] JS: Make PropRef.getBase non-recursive --- javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll index 3db26d0af33..75c8cd7b236 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll @@ -724,7 +724,7 @@ module DataFlow { override ParameterField prop; override Node getBase() { - result = thisNode(prop.getDeclaringClass().getConstructor().getBody()) + thisNode(result, prop.getDeclaringClass().getConstructor().getBody()) } override Expr getPropertyNameExpr() { @@ -758,7 +758,7 @@ module DataFlow { } override Node getBase() { - result = thisNode(prop.getDeclaringClass().getConstructor().getBody()) + thisNode(result, prop.getDeclaringClass().getConstructor().getBody()) } override Expr getPropertyNameExpr() { result = prop.getNameExpr() } From 8d30ee5c3cb1193ec464c6bb8d5632c72d304f5c Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Wed, 24 Mar 2021 14:01:13 +0100 Subject: [PATCH 330/725] Python: Include unmarked Python file in snapshot Sadly, it seems we're not interpreting this as Python code, even if we explicitly ask to have it included. --- .../modules/entry_point/no_py_extension/{main => main.secretpy} | 0 python/ql/test/3/library-tests/modules/entry_point/options | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename python/ql/test/3/library-tests/modules/entry_point/no_py_extension/{main => main.secretpy} (100%) diff --git a/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/main b/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/main.secretpy similarity index 100% rename from python/ql/test/3/library-tests/modules/entry_point/no_py_extension/main rename to python/ql/test/3/library-tests/modules/entry_point/no_py_extension/main.secretpy diff --git a/python/ql/test/3/library-tests/modules/entry_point/options b/python/ql/test/3/library-tests/modules/entry_point/options index 619afd242ed..6beceeb08ed 100644 --- a/python/ql/test/3/library-tests/modules/entry_point/options +++ b/python/ql/test/3/library-tests/modules/entry_point/options @@ -1 +1 @@ -semmle-extractor-options: --lang=3 --path bogus -R . +semmle-extractor-options: --lang=3 --path bogus -R . --filter=include:**/*.secretpy From 47686a6e4ccd67dab5e7862662ef7dab5168ce38 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Wed, 24 Mar 2021 14:03:00 +0100 Subject: [PATCH 331/725] Python: Disregard all files matching `.py%` --- python/ql/src/semmle/python/Files.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/Files.qll b/python/ql/src/semmle/python/Files.qll index 07bbbed2154..83ba92f0abc 100644 --- a/python/ql/src/semmle/python/Files.qll +++ b/python/ql/src/semmle/python/Files.qll @@ -79,7 +79,7 @@ class File extends Container { exists(this.getRelativePath()) and ( // The file doesn't have the extension `.py` but still contains Python statements - not this.getExtension() = "py" and + not this.getExtension().matches("py%") and exists(Stmt s | s.getLocation().getFile() = this) or // The file contains the usual `if __name__ == '__main__':` construction From 70974ea197d52ba2201aa984ebc7827ee6e6d366 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 24 Mar 2021 14:06:06 +0100 Subject: [PATCH 332/725] Python: Fix grammar in QLDoc Co-authored-by: yoff --- .../test/library-tests/frameworks/django-v2-v3/taint_forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/test/library-tests/frameworks/django-v2-v3/taint_forms.py b/python/ql/test/library-tests/frameworks/django-v2-v3/taint_forms.py index a702f89ee26..5cc9c830e7c 100644 --- a/python/ql/test/library-tests/frameworks/django-v2-v3/taint_forms.py +++ b/python/ql/test/library-tests/frameworks/django-v2-v3/taint_forms.py @@ -42,5 +42,5 @@ class MyForm(django.forms.Form): ) def clean_foo(self): - # This method is supposed to clean a the `foo` field in context of this form. + # This method is supposed to clean the `foo` field in context of this form. ensure_tainted(self.cleaned_data) From 4955f95f64ecc0627a4b67e39a259b3f29035840 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Wed, 24 Mar 2021 14:32:18 +0100 Subject: [PATCH 333/725] Apply suggestions from code review Clarify documentation. Co-authored-by: Chris Smowton --- java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll b/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll index 462fb1b1014..10d0433fcd6 100644 --- a/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll +++ b/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll @@ -37,7 +37,7 @@ * - "Argument[n]": Selects an argument in a call to the selected element. * The arguments are zero-indexed, and `-1` specifies the qualifier. * - "Argument[n1..n2]": Similar to "Argument[n]" but select any argument in - * the given range. + * the given range. The range is inclusive at both ends. * - "ReturnValue": Selects a value being returned by the selected element. * This requires that the selected element is a method with a body. * @@ -48,14 +48,14 @@ * selected element. That is, the value of the argument after the call returns. * The arguments are zero-indexed, and `-1` specifies the qualifier. * - "Argument[n1..n2]": Similar to "Argument[n]" but select any argument in - * the given range. + * the given range. The range is inclusive at both ends. * - "Parameter": Selects the value of a parameter of the selected element. * "Parameter" is also allowed in case the selected element is already a * parameter itself. * - "Parameter[n]": Similar to "Parameter" but restricted to a specific * numbered parameter (zero-indexed, and `-1` specifies the value of `this`). * - "Parameter[n1..n2]": Similar to "Parameter[n]" but selects any parameter - * in the given range. + * in the given range. The range is inclusive at both ends. * - "ReturnValue": Selects the return value of a call to the selected element. * 8. The `kind` column is a tag that can be referenced from QL to determine to * which classes the interpreted elements should be added. For example, for From e13a9c97165253df2ad40ed4c21f668eabebbcb8 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 24 Mar 2021 15:03:56 +0000 Subject: [PATCH 334/725] JS: Avoid recursion through SourceNode::Range, again --- .../ql/src/semmle/javascript/NodeJS.qll | 43 ++++++++++++++----- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/NodeJS.qll b/javascript/ql/src/semmle/javascript/NodeJS.qll index 4c98c4fbefe..c40b8d2b802 100644 --- a/javascript/ql/src/semmle/javascript/NodeJS.qll +++ b/javascript/ql/src/semmle/javascript/NodeJS.qll @@ -202,6 +202,34 @@ private class RequireVariable extends Variable { */ private predicate moduleInFile(Module m, File f) { m.getFile() = f } +private predicate isModuleModule(DataFlow::Node nd) { + exists(ImportDeclaration imp | + imp.getImportedPath().getValue() = "module" and + nd = [ + DataFlow::destructuredModuleImportNode(imp), + DataFlow::valueNode(imp.getASpecifier().(ImportNamespaceSpecifier)) + ] + ) + or + isModuleModule(nd.getAPredecessor()) +} + +private predicate isCreateRequire(DataFlow::Node nd) { + exists(PropAccess prop | + isModuleModule(prop.getBase().flow()) and + prop.getPropertyName() = "createRequire" and + nd = prop.flow() + ) + or + exists(PropertyPattern prop | + isModuleModule(prop.getObjectPattern().flow()) and + prop.getName() = "createRequire" and + nd = prop.getValuePattern().flow() + ) + or + isCreateRequire(nd.getAPredecessor()) +} + /** * Holds if `nd` may refer to `require`, either directly or modulo local data flow. */ @@ -215,16 +243,11 @@ private predicate isRequire(DataFlow::Node nd) { or // `import { createRequire } from 'module';`. // specialized to ES2015 modules to avoid recursion in the `DataFlow::moduleImport()` predicate and to avoid - // negative recursion between `Import.getImportedModuleNode()` and `Import.getImportedModule()`. - exists(ImportDeclaration imp, DataFlow::SourceNode baseObj | - imp.getImportedPath().getValue() = "module" - | - baseObj = - [ - DataFlow::destructuredModuleImportNode(imp), - DataFlow::valueNode(imp.getASpecifier().(ImportNamespaceSpecifier)) - ] and - nd = baseObj.getAPropertyRead("createRequire").getACall() + // negative recursion between `Import.getImportedModuleNode()` and `Import.getImportedModule()`, and + // to avoid depending on `SourceNode` as this would make `SourceNode::Range` recursive. + exists(CallExpr call | + isCreateRequire(call.getCallee().flow()) and + nd = call.flow() ) } From b25dc03dac1f9224aa40f98b9cf5b032bbf54184 Mon Sep 17 00:00:00 2001 From: Arthur Baars Date: Wed, 24 Mar 2021 16:47:27 +0100 Subject: [PATCH 335/725] Javascript: remove bad QLDoc tag --- javascript/ql/src/meta/Consistency.ql | 1 - 1 file changed, 1 deletion(-) diff --git a/javascript/ql/src/meta/Consistency.ql b/javascript/ql/src/meta/Consistency.ql index 61ee64b035f..b87c256f609 100644 --- a/javascript/ql/src/meta/Consistency.ql +++ b/javascript/ql/src/meta/Consistency.ql @@ -4,7 +4,6 @@ * in the documentation, queries that rely on the contract may yield unexpected * results. * @kind table - * @problem.severity error * @id js/consistency/api-contracts * @tags consistency */ From 47530d75262fdd639b9f792bef81cf618401ff6e Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Wed, 24 Mar 2021 17:55:25 +0100 Subject: [PATCH 336/725] C++: Fix query metadata warnings. --- cpp/ql/src/Metrics/Dependencies/ExternalDependencies.ql | 1 - cpp/ql/src/Metrics/Files/FLinesOfCode.ql | 1 - cpp/ql/src/Metrics/Files/FLinesOfCommentedOutCode.ql | 1 - cpp/ql/src/Metrics/Files/FLinesOfComments.ql | 1 - cpp/ql/src/Metrics/Files/FLinesOfDuplicatedCode.ql | 1 - cpp/ql/src/Metrics/Files/FNumberOfTests.ql | 1 - cpp/ql/src/external/tests/DefectFromExternalData.ql | 1 + cpp/ql/src/filters/FilterAutogenerated.ql | 1 + cpp/ql/src/filters/FromSource.ql | 1 + cpp/ql/src/filters/Macros.ql | 1 + 10 files changed, 4 insertions(+), 6 deletions(-) diff --git a/cpp/ql/src/Metrics/Dependencies/ExternalDependencies.ql b/cpp/ql/src/Metrics/Dependencies/ExternalDependencies.ql index 47ddb9d1f1e..a4e9c925119 100644 --- a/cpp/ql/src/Metrics/Dependencies/ExternalDependencies.ql +++ b/cpp/ql/src/Metrics/Dependencies/ExternalDependencies.ql @@ -5,7 +5,6 @@ * @kind treemap * @treemap.warnOn highValues * @metricType externalDependency - * @precision medium * @id cpp/external-dependencies * @tags modularity */ diff --git a/cpp/ql/src/Metrics/Files/FLinesOfCode.ql b/cpp/ql/src/Metrics/Files/FLinesOfCode.ql index 07c8934115c..11b3eac2977 100644 --- a/cpp/ql/src/Metrics/Files/FLinesOfCode.ql +++ b/cpp/ql/src/Metrics/Files/FLinesOfCode.ql @@ -7,7 +7,6 @@ * @treemap.warnOn highValues * @metricType file * @metricAggregate avg sum max - * @precision very-high * @id cpp/lines-of-code-in-files * @tags maintainability * complexity diff --git a/cpp/ql/src/Metrics/Files/FLinesOfCommentedOutCode.ql b/cpp/ql/src/Metrics/Files/FLinesOfCommentedOutCode.ql index 495464d633b..13ff54e5525 100644 --- a/cpp/ql/src/Metrics/Files/FLinesOfCommentedOutCode.ql +++ b/cpp/ql/src/Metrics/Files/FLinesOfCommentedOutCode.ql @@ -5,7 +5,6 @@ * @treemap.warnOn highValues * @metricType file * @metricAggregate avg sum max - * @precision high * @id cpp/lines-of-commented-out-code-in-files * @tags documentation */ diff --git a/cpp/ql/src/Metrics/Files/FLinesOfComments.ql b/cpp/ql/src/Metrics/Files/FLinesOfComments.ql index 4787587474e..2372f5cc375 100644 --- a/cpp/ql/src/Metrics/Files/FLinesOfComments.ql +++ b/cpp/ql/src/Metrics/Files/FLinesOfComments.ql @@ -7,7 +7,6 @@ * @treemap.warnOn lowValues * @metricType file * @metricAggregate avg sum max - * @precision very-high * @id cpp/lines-of-comments-in-files * @tags maintainability * documentation diff --git a/cpp/ql/src/Metrics/Files/FLinesOfDuplicatedCode.ql b/cpp/ql/src/Metrics/Files/FLinesOfDuplicatedCode.ql index ab9317ea316..8b46df05adc 100644 --- a/cpp/ql/src/Metrics/Files/FLinesOfDuplicatedCode.ql +++ b/cpp/ql/src/Metrics/Files/FLinesOfDuplicatedCode.ql @@ -8,7 +8,6 @@ * @treemap.warnOn highValues * @metricType file * @metricAggregate avg sum max - * @precision high * @id cpp/duplicated-lines-in-files * @tags testability * modularity diff --git a/cpp/ql/src/Metrics/Files/FNumberOfTests.ql b/cpp/ql/src/Metrics/Files/FNumberOfTests.ql index 421fc2baba1..c7ec5983253 100644 --- a/cpp/ql/src/Metrics/Files/FNumberOfTests.ql +++ b/cpp/ql/src/Metrics/Files/FNumberOfTests.ql @@ -5,7 +5,6 @@ * @treemap.warnOn lowValues * @metricType file * @metricAggregate avg sum max - * @precision medium * @id cpp/tests-in-files * @tags maintainability */ diff --git a/cpp/ql/src/external/tests/DefectFromExternalData.ql b/cpp/ql/src/external/tests/DefectFromExternalData.ql index 276977e35b5..35bf494b9d4 100644 --- a/cpp/ql/src/external/tests/DefectFromExternalData.ql +++ b/cpp/ql/src/external/tests/DefectFromExternalData.ql @@ -1,5 +1,6 @@ /** * @name Defect from external data + * @id cpp/external/tests/defects-from-external-data * @description Insert description here... * @kind problem * @problem.severity warning diff --git a/cpp/ql/src/filters/FilterAutogenerated.ql b/cpp/ql/src/filters/FilterAutogenerated.ql index 43956b48d05..90df03add5c 100644 --- a/cpp/ql/src/filters/FilterAutogenerated.ql +++ b/cpp/ql/src/filters/FilterAutogenerated.ql @@ -3,6 +3,7 @@ * @description Use this filter to return results only if they are * located in files that are maintained manually. * @kind problem + * @problem.severity recommendation * @id cpp/autogenerated-filter * @tags filter */ diff --git a/cpp/ql/src/filters/FromSource.ql b/cpp/ql/src/filters/FromSource.ql index 459ca94d3c6..b0213721d0b 100644 --- a/cpp/ql/src/filters/FromSource.ql +++ b/cpp/ql/src/filters/FromSource.ql @@ -4,6 +4,7 @@ * @description Use this filter to return results only if they are * located in files for which we have source code. * @kind problem + * @problem.severity recommendation * @id cpp/from-source-filter * @tags filter */ diff --git a/cpp/ql/src/filters/Macros.ql b/cpp/ql/src/filters/Macros.ql index b5e9e7ca5bf..5191171196a 100644 --- a/cpp/ql/src/filters/Macros.ql +++ b/cpp/ql/src/filters/Macros.ql @@ -4,6 +4,7 @@ * macro expansion whose location spans all the lines of * the result's location. * @kind problem + * @problem.severity recommendation * @id cpp/macros-filter * @tags filter */ From ed8ffab35677eb03a80e0fda4dfbea5d1985103a Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Wed, 24 Mar 2021 19:20:19 +0100 Subject: [PATCH 337/725] Python: Prevent potentially bad join order This has no effect on the current compilation (indeed, `ssa_filter_definition_bool` is not currently inlined), but will prevent this from ever occurring, should the heuristics for inlining ever change... --- python/ql/src/semmle/python/pointsto/PointsTo.qll | 1 + 1 file changed, 1 insertion(+) diff --git a/python/ql/src/semmle/python/pointsto/PointsTo.qll b/python/ql/src/semmle/python/pointsto/PointsTo.qll index 9614b02d2f6..9706c6846f3 100644 --- a/python/ql/src/semmle/python/pointsto/PointsTo.qll +++ b/python/ql/src/semmle/python/pointsto/PointsTo.qll @@ -524,6 +524,7 @@ module PointsToInternal { ) } + pragma[noinline] private boolean ssa_filter_definition_bool( PyEdgeRefinement def, PointsToContext context, ObjectInternal value, ControlFlowNode origin ) { From a0465d20cbae2edfc4177ba29b03ce5f7e08abf3 Mon Sep 17 00:00:00 2001 From: Aditya Sharad <6874315+adityasharad@users.noreply.github.com> Date: Wed, 24 Mar 2021 11:26:00 -0700 Subject: [PATCH 338/725] Actions: Remove docs-review workflow Being replaced by internal automation that polls the repo for open labelled PRs, since this workflow currently cannot tag the docs team in a comment. --- .github/workflows/docs-review.yml | 29 ----------------------------- 1 file changed, 29 deletions(-) delete mode 100644 .github/workflows/docs-review.yml diff --git a/.github/workflows/docs-review.yml b/.github/workflows/docs-review.yml deleted file mode 100644 index bf813f46ead..00000000000 --- a/.github/workflows/docs-review.yml +++ /dev/null @@ -1,29 +0,0 @@ -# When a PR is labelled with 'ready-for-docs-review', -# this workflow comments on the PR to notify the GitHub CodeQL docs team. -name: Request docs review -on: - # Runs in the context of the base repo. - # This gives the workflow write access to comment on PRs. - # The workflow should not check out or build the given ref, - # or use untrusted data from the event payload in a command line. - pull_request_target: - types: [labeled] - -jobs: - request-docs-review: - name: Request docs review - # Run only on labelled PRs to the main repository. - # Do not run on PRs to forks. - if: - github.event.label.name == 'ready-for-docs-review' - && github.event.pull_request.draft == false - && github.event.pull_request.base.repo.full_name == 'github/codeql' - runs-on: ubuntu-latest - steps: - - name: Comment to request docs review - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PR_NUMBER: ${{ github.event.pull_request.number }} - run: | - gh pr comment "$PR_NUMBER" --repo "github/codeql" \ - --body "Hello @github/docs-content-codeql - this PR is ready for docs review." From 28d6cad3d08f10d084b8b1b555a9c070d9fe6465 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Wed, 24 Mar 2021 23:11:09 +0100 Subject: [PATCH 339/725] Python: Prevent joining on `name` as the first thing Many instances of `lookup` are restricted by the presence of `attributeRequired`, but this does not work well if we join on `name`. A few instances of `only_bind_into` prevents this. --- .../ql/src/semmle/python/objects/Classes.qll | 4 ++-- .../src/semmle/python/objects/Constants.qll | 6 ++++-- .../src/semmle/python/objects/Instances.qll | 19 +++++++++++-------- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/python/ql/src/semmle/python/objects/Classes.qll b/python/ql/src/semmle/python/objects/Classes.qll index 2f092dd4483..249fb331466 100644 --- a/python/ql/src/semmle/python/objects/Classes.qll +++ b/python/ql/src/semmle/python/objects/Classes.qll @@ -61,8 +61,8 @@ abstract class ClassObjectInternal extends ObjectInternal { pragma[noinline] override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { instance = this and - PointsToInternal::attributeRequired(this, name) and - this.lookup(name, descriptor, _) and + PointsToInternal::attributeRequired(this, pragma[only_bind_into](name)) and + this.lookup(pragma[only_bind_into](name), descriptor, _) and descriptor.isDescriptor() = true } diff --git a/python/ql/src/semmle/python/objects/Constants.qll b/python/ql/src/semmle/python/objects/Constants.qll index d2ba2f44655..941f631b9b3 100644 --- a/python/ql/src/semmle/python/objects/Constants.qll +++ b/python/ql/src/semmle/python/objects/Constants.qll @@ -34,9 +34,11 @@ abstract class ConstantObjectInternal extends ObjectInternal { pragma[noinline] override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { - PointsToInternal::attributeRequired(this, name) and + PointsToInternal::attributeRequired(pragma[only_bind_into](this), pragma[only_bind_into](name)) and exists(ObjectInternal cls_attr, CfgOrigin attr_orig | - this.getClass().(ClassObjectInternal).lookup(name, cls_attr, attr_orig) and + this.getClass() + .(ClassObjectInternal) + .lookup(pragma[only_bind_into](name), cls_attr, attr_orig) and cls_attr.isDescriptor() = true and cls_attr.descriptorGetInstance(this, value, origin) ) diff --git a/python/ql/src/semmle/python/objects/Instances.qll b/python/ql/src/semmle/python/objects/Instances.qll index bbde0b1a5f5..9569fa1a25d 100644 --- a/python/ql/src/semmle/python/objects/Instances.qll +++ b/python/ql/src/semmle/python/objects/Instances.qll @@ -30,18 +30,19 @@ abstract class InstanceObject extends ObjectInternal { pragma[noinline] private predicate classAttribute(string name, ObjectInternal cls_attr) { - PointsToInternal::attributeRequired(this, name) and - this.getClass().(ClassObjectInternal).lookup(name, cls_attr, _) + PointsToInternal::attributeRequired(this, pragma[only_bind_into](name)) and + this.getClass().(ClassObjectInternal).lookup(pragma[only_bind_into](name), cls_attr, _) } pragma[noinline] private predicate selfAttribute(string name, ObjectInternal value, CfgOrigin origin) { - PointsToInternal::attributeRequired(this, name) and + PointsToInternal::attributeRequired(this, pragma[only_bind_into](name)) and exists(EssaVariable self, PythonFunctionObjectInternal init, Context callee | this.initializer(init, callee) and self_variable_reaching_init_exit(self) and self.getScope() = init.getScope() and - AttributePointsTo::variableAttributePointsTo(self, callee, name, value, origin) + AttributePointsTo::variableAttributePointsTo(self, callee, pragma[only_bind_into](name), + value, origin) ) } @@ -316,9 +317,11 @@ class UnknownInstanceInternal extends TUnknownInstance, ObjectInternal { pragma[noinline] override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { - PointsToInternal::attributeRequired(this, name) and + PointsToInternal::attributeRequired(this, pragma[only_bind_into](name)) and exists(ObjectInternal cls_attr, CfgOrigin attr_orig | - this.getClass().(ClassObjectInternal).lookup(name, cls_attr, attr_orig) + this.getClass() + .(ClassObjectInternal) + .lookup(pragma[only_bind_into](name), cls_attr, attr_orig) | cls_attr.isDescriptor() = false and value = cls_attr and origin = attr_orig or @@ -456,8 +459,8 @@ class SuperInstance extends TSuperInstance, ObjectInternal { /* Helper for `attribute` */ pragma[noinline] private predicate attribute_descriptor(string name, ObjectInternal cls_attr, CfgOrigin attr_orig) { - PointsToInternal::attributeRequired(this, name) and - this.lookup(name, cls_attr, attr_orig) + PointsToInternal::attributeRequired(this, pragma[only_bind_into](name)) and + this.lookup(pragma[only_bind_into](name), cls_attr, attr_orig) } private predicate lookup(string name, ObjectInternal value, CfgOrigin origin) { From 0ae8b69102b82ec7ba01d0034462cd9d8650864f Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Wed, 24 Mar 2021 23:12:48 +0100 Subject: [PATCH 340/725] Python: Prevent joining on scope in `PointsToContext::appliesTo` One of those cases where I _wish_ `pragma[inline]` also meant "don't join on the stuff inside this predicate -- it's inlined for a reason". Unsurprisingly, joining on the scope first works poorly. --- python/ql/src/semmle/python/pointsto/PointsToContext.qll | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/pointsto/PointsToContext.qll b/python/ql/src/semmle/python/pointsto/PointsToContext.qll index 8b4178c796f..15b28d9cdb0 100644 --- a/python/ql/src/semmle/python/pointsto/PointsToContext.qll +++ b/python/ql/src/semmle/python/pointsto/PointsToContext.qll @@ -184,7 +184,11 @@ class PointsToContext extends TPointsToContext { /** Holds if this context can apply to the CFG node `n`. */ pragma[inline] - predicate appliesTo(ControlFlowNode n) { this.appliesToScope(n.getScope()) } + predicate appliesTo(ControlFlowNode n) { + exists(Scope s | + this.appliesToScope(pragma[only_bind_into](s)) and pragma[only_bind_into](s) = n.getScope() + ) + } /** Holds if this context is a call context. */ predicate isCall() { this = TCallContext(_, _, _) } From 08c3bf26d558d1bfaf0504fa1a0ba6837910829a Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Tue, 16 Mar 2021 03:18:26 +0000 Subject: [PATCH 341/725] Update the query to accommodate more cases --- .../CWE-1004/SensitiveCookieNotHttpOnly.ql | 73 +++++++++++++++++-- .../SensitiveCookieNotHttpOnly.expected | 8 ++ .../CWE-1004/SensitiveCookieNotHttpOnly.java | 57 +++++++++++++++ 3 files changed, 130 insertions(+), 8 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql b/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql index 693dad68082..ac33a6cecb2 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql @@ -33,7 +33,23 @@ predicate isSensitiveCookieNameExpr(Expr expr) { /** Holds if a string is concatenated with the `HttpOnly` flag. */ predicate hasHttpOnlyExpr(Expr expr) { - expr.(CompileTimeConstantExpr).getStringValue().toLowerCase().matches("%httponly%") or + ( + expr.(CompileTimeConstantExpr).getStringValue().toLowerCase().matches("%httponly%") + or + exists( + StaticMethodAccess ma // String.format("%s=%s;HttpOnly", "sessionkey", sessionKey) + | + ma.getType().getName() = "String" and + ma.getMethod().getName() = "format" and + ma.getArgument(0) + .(CompileTimeConstantExpr) + .getStringValue() + .toLowerCase() + .matches("%httponly%") and + expr = ma + ) + ) + or hasHttpOnlyExpr(expr.(AddExpr).getAnOperand()) } @@ -56,6 +72,40 @@ class CookieClass extends RefType { } } +/** Holds if the `Expr` expr is evaluated to boolean true. */ +predicate isBooleanTrue(Expr expr) { + expr.(CompileTimeConstantExpr).getBooleanValue() = true or + expr.(VarAccess).getVariable().getAnAssignedValue().(CompileTimeConstantExpr).getBooleanValue() = + true +} + +/** Holds if the method or a wrapper method sets the `HttpOnly` flag. */ +predicate setHttpOnlyInCookie(MethodAccess ma) { + ma.getMethod().getName() = "setHttpOnly" and + ( + isBooleanTrue(ma.getArgument(0)) // boolean literal true + or + exists( + MethodAccess mpa, int i // runtime assignment of boolean value true + | + TaintTracking::localTaint(DataFlow::parameterNode(mpa.getMethod().getParameter(i)), + DataFlow::exprNode(ma.getArgument(0))) and + isBooleanTrue(mpa.getArgument(i)) + ) + ) + or + exists(MethodAccess mca | + ma.getMethod().calls(mca.getMethod()) and + setHttpOnlyInCookie(mca) + ) +} + +/** Holds if the method or a wrapper method removes a cookie. */ +predicate removeCookie(MethodAccess ma) { + ma.getMethod().getName() = "setMaxAge" and + ma.getArgument(0).(IntegerLiteral).getIntValue() = 0 +} + /** Sensitive cookie name used in a `Cookie` constructor or a `Set-Cookie` call. */ class SensitiveCookieNameExpr extends Expr { SensitiveCookieNameExpr() { isSensitiveCookieNameExpr(this) } @@ -69,11 +119,16 @@ class CookieResponseSink extends DataFlow::ExprNode { ma.getMethod() instanceof ResponseAddCookieMethod and this.getExpr() = ma.getArgument(0) and not exists( - MethodAccess ma2 // cookie.setHttpOnly(true) + MethodAccess ma2 // a method or wrapper method that invokes cookie.setHttpOnly(true) | - ma2.getMethod().getName() = "setHttpOnly" and - ma2.getArgument(0).(BooleanLiteral).getBooleanValue() = true and - DataFlow::localExprFlow(ma2.getQualifier(), this.getExpr()) + ( + setHttpOnlyInCookie(ma2) or + removeCookie(ma2) + ) and + ( + DataFlow::localExprFlow(ma2.getQualifier(), this.getExpr()) or + DataFlow::localExprFlow(ma2, this.getExpr()) + ) ) or ma instanceof SetCookieMethodAccess and @@ -92,13 +147,15 @@ class CookieResponseSink extends DataFlow::ExprNode { predicate setHttpOnlyInNewCookie(ClassInstanceExpr cie) { cie.getConstructedType().hasQualifiedName(["javax.ws.rs.core", "jakarta.ws.rs.core"], "NewCookie") and ( - cie.getNumArgument() = 6 and cie.getArgument(5).(BooleanLiteral).getBooleanValue() = true // NewCookie(Cookie cookie, String comment, int maxAge, Date expiry, boolean secure, boolean httpOnly) + cie.getNumArgument() = 6 and + isBooleanTrue(cie.getArgument(5)) // NewCookie(Cookie cookie, String comment, int maxAge, Date expiry, boolean secure, boolean httpOnly) or cie.getNumArgument() = 8 and cie.getArgument(6).getType() instanceof BooleanType and - cie.getArgument(7).(BooleanLiteral).getBooleanValue() = true // NewCookie(String name, String value, String path, String domain, String comment, int maxAge, boolean secure, boolean httpOnly) + isBooleanTrue(cie.getArgument(7)) // NewCookie(String name, String value, String path, String domain, String comment, int maxAge, boolean secure, boolean httpOnly) or - cie.getNumArgument() = 10 and cie.getArgument(9).(BooleanLiteral).getBooleanValue() = true // NewCookie(String name, String value, String path, String domain, int version, String comment, int maxAge, Date expiry, boolean secure, boolean httpOnly) + cie.getNumArgument() = 10 and + isBooleanTrue(cie.getArgument(9)) // NewCookie(String name, String value, String path, String domain, int version, String comment, int maxAge, Date expiry, boolean secure, boolean httpOnly) ) } diff --git a/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.expected b/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.expected index 8fa688bef2a..dae98e92e67 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.expected @@ -7,6 +7,9 @@ edges | SensitiveCookieNotHttpOnly.java:70:28:70:35 | "token=" : String | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | | SensitiveCookieNotHttpOnly.java:70:28:70:43 | ... + ... : String | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | | SensitiveCookieNotHttpOnly.java:70:28:70:55 | ... + ... : String | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | +| SensitiveCookieNotHttpOnly.java:88:35:88:51 | "Presto-UI-Token" : String | SensitiveCookieNotHttpOnly.java:91:16:91:21 | cookie : Cookie | +| SensitiveCookieNotHttpOnly.java:91:16:91:21 | cookie : Cookie | SensitiveCookieNotHttpOnly.java:102:25:102:64 | createAuthenticationCookie(...) : Cookie | +| SensitiveCookieNotHttpOnly.java:102:25:102:64 | createAuthenticationCookie(...) : Cookie | SensitiveCookieNotHttpOnly.java:103:28:103:33 | cookie | nodes | SensitiveCookieNotHttpOnly.java:24:33:24:43 | "jwt_token" : String | semmle.label | "jwt_token" : String | | SensitiveCookieNotHttpOnly.java:31:28:31:36 | jwtCookie | semmle.label | jwtCookie | @@ -21,6 +24,10 @@ nodes | SensitiveCookieNotHttpOnly.java:70:28:70:43 | ... + ... : String | semmle.label | ... + ... : String | | SensitiveCookieNotHttpOnly.java:70:28:70:55 | ... + ... : String | semmle.label | ... + ... : String | | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | semmle.label | secString | +| SensitiveCookieNotHttpOnly.java:88:35:88:51 | "Presto-UI-Token" : String | semmle.label | "Presto-UI-Token" : String | +| SensitiveCookieNotHttpOnly.java:91:16:91:21 | cookie : Cookie | semmle.label | cookie : Cookie | +| SensitiveCookieNotHttpOnly.java:102:25:102:64 | createAuthenticationCookie(...) : Cookie | semmle.label | createAuthenticationCookie(...) : Cookie | +| SensitiveCookieNotHttpOnly.java:103:28:103:33 | cookie | semmle.label | cookie | #select | SensitiveCookieNotHttpOnly.java:31:28:31:36 | jwtCookie | SensitiveCookieNotHttpOnly.java:24:33:24:43 | "jwt_token" : String | SensitiveCookieNotHttpOnly.java:31:28:31:36 | jwtCookie | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:24:33:24:43 | "jwt_token" | This sensitive cookie | | SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... | SensitiveCookieNotHttpOnly.java:42:42:42:49 | "token=" : String | SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:42:42:42:49 | "token=" | This sensitive cookie | @@ -31,3 +38,4 @@ nodes | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | SensitiveCookieNotHttpOnly.java:70:28:70:35 | "token=" : String | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:70:28:70:35 | "token=" | This sensitive cookie | | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | SensitiveCookieNotHttpOnly.java:70:28:70:43 | ... + ... : String | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:70:28:70:43 | ... + ... | This sensitive cookie | | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | SensitiveCookieNotHttpOnly.java:70:28:70:55 | ... + ... : String | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:70:28:70:55 | ... + ... | This sensitive cookie | +| SensitiveCookieNotHttpOnly.java:103:28:103:33 | cookie | SensitiveCookieNotHttpOnly.java:88:35:88:51 | "Presto-UI-Token" : String | SensitiveCookieNotHttpOnly.java:103:28:103:33 | cookie | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:88:35:88:51 | "Presto-UI-Token" | This sensitive cookie | diff --git a/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.java b/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.java index 337a99cc096..fdc831d7836 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.java +++ b/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.java @@ -71,6 +71,63 @@ class SensitiveCookieNotHttpOnly { response.addHeader("Set-Cookie", secString); } + // GOOD - Tests set a sensitive cookie header with the `HttpOnly` flag set using `String.format(...)`. + public void addCookie10(HttpServletRequest request, HttpServletResponse response) { + response.addHeader("SET-COOKIE", String.format("%s=%s;HttpOnly", "sessionkey", request.getSession().getAttribute("sessionkey"))); + } + + public Cookie createHttpOnlyAuthenticationCookie(HttpServletRequest request, String jwt) { + String PRESTO_UI_COOKIE = "Presto-UI-Token"; + Cookie cookie = new Cookie(PRESTO_UI_COOKIE, jwt); + cookie.setHttpOnly(true); + cookie.setPath("/ui"); + return cookie; + } + + public Cookie createAuthenticationCookie(HttpServletRequest request, String jwt) { + String PRESTO_UI_COOKIE = "Presto-UI-Token"; + Cookie cookie = new Cookie(PRESTO_UI_COOKIE, jwt); + cookie.setPath("/ui"); + return cookie; + } + + // GOOD - Tests set a sensitive cookie header with the `HttpOnly` flag set using a wrapper method. + public void addCookie11(HttpServletRequest request, HttpServletResponse response, String jwt) { + Cookie cookie = createHttpOnlyAuthenticationCookie(request, jwt); + response.addCookie(cookie); + } + + // BAD - Tests set a sensitive cookie header without the `HttpOnly` flag set using a wrapper method. + public void addCookie12(HttpServletRequest request, HttpServletResponse response, String jwt) { + Cookie cookie = createAuthenticationCookie(request, jwt); + response.addCookie(cookie); + } + + private Cookie createCookie(String name, String value, Boolean httpOnly){ + Cookie cookie = null; + cookie = new Cookie(name, value); + cookie.setDomain("/"); + cookie.setHttpOnly(httpOnly); + + //for production https + cookie.setSecure(true); + + cookie.setMaxAge(60*60*24*30); + cookie.setPath("/"); + + return cookie; + } + + // GOOD - Tests set a sensitive cookie header with the `HttpOnly` flag set through a boolean variable using a wrapper method. + public void addCookie13(HttpServletRequest request, HttpServletResponse response, String refreshToken) { + response.addCookie(createCookie("refresh_token", refreshToken, true)); + } + + // BAD - Tests set a sensitive cookie header with the `HttpOnly` flag not set through a boolean variable using a wrapper method. + public void addCookie14(HttpServletRequest request, HttpServletResponse response, String refreshToken) { + response.addCookie(createCookie("refresh_token", refreshToken, false)); + } + // GOOD - CSRF token doesn't need to have the `HttpOnly` flag set. public void addCsrfCookie(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Spring put the CSRF token in session attribute "_csrf" From fe0e7f5eac232e2aae155fe332c57c9e30e61cdf Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Thu, 25 Mar 2021 01:45:13 +0000 Subject: [PATCH 342/725] Change method check to taint flow --- .../CWE-1004/SensitiveCookieNotHttpOnly.ql | 70 ++++++++++--------- .../SensitiveCookieNotHttpOnly.expected | 10 +-- .../CWE-1004/SensitiveCookieNotHttpOnly.java | 18 ++++- 3 files changed, 58 insertions(+), 40 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql b/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql index ac33a6cecb2..db9adc2ee09 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql @@ -11,6 +11,7 @@ import java import semmle.code.java.dataflow.FlowSteps import semmle.code.java.frameworks.Servlets import semmle.code.java.dataflow.TaintTracking +import semmle.code.java.dataflow.TaintTracking2 import DataFlow::PathGraph /** Gets a regular expression for matching common names of sensitive cookies. */ @@ -31,28 +32,6 @@ predicate isSensitiveCookieNameExpr(Expr expr) { isSensitiveCookieNameExpr(expr.(AddExpr).getAnOperand()) } -/** Holds if a string is concatenated with the `HttpOnly` flag. */ -predicate hasHttpOnlyExpr(Expr expr) { - ( - expr.(CompileTimeConstantExpr).getStringValue().toLowerCase().matches("%httponly%") - or - exists( - StaticMethodAccess ma // String.format("%s=%s;HttpOnly", "sessionkey", sessionKey) - | - ma.getType().getName() = "String" and - ma.getMethod().getName() = "format" and - ma.getArgument(0) - .(CompileTimeConstantExpr) - .getStringValue() - .toLowerCase() - .matches("%httponly%") and - expr = ma - ) - ) - or - hasHttpOnlyExpr(expr.(AddExpr).getAnOperand()) -} - /** The method call `Set-Cookie` of `addHeader` or `setHeader`. */ class SetCookieMethodAccess extends MethodAccess { SetCookieMethodAccess() { @@ -64,6 +43,22 @@ class SetCookieMethodAccess extends MethodAccess { } } +/** + * A taint configuration tracking flow from the text `httponly` to argument 1 of + * `SetCookieMethodAccess`. + */ +class MatchesHttpOnlyConfiguration extends TaintTracking2::Configuration { + MatchesHttpOnlyConfiguration() { this = "MatchesHttpOnlyConfiguration" } + + override predicate isSource(DataFlow::Node source) { + source.asExpr().(CompileTimeConstantExpr).getStringValue().toLowerCase().matches("%httponly%") + } + + override predicate isSink(DataFlow::Node sink) { + sink.asExpr() = any(SetCookieMethodAccess ma).getArgument(1) + } +} + /** The cookie class of Java EE. */ class CookieClass extends RefType { CookieClass() { @@ -79,7 +74,7 @@ predicate isBooleanTrue(Expr expr) { true } -/** Holds if the method or a wrapper method sets the `HttpOnly` flag. */ +/** Holds if the method call sets the `HttpOnly` flag. */ predicate setHttpOnlyInCookie(MethodAccess ma) { ma.getMethod().getName() = "setHttpOnly" and ( @@ -93,14 +88,24 @@ predicate setHttpOnlyInCookie(MethodAccess ma) { isBooleanTrue(mpa.getArgument(i)) ) ) - or - exists(MethodAccess mca | - ma.getMethod().calls(mca.getMethod()) and - setHttpOnlyInCookie(mca) - ) } -/** Holds if the method or a wrapper method removes a cookie. */ +/** + * A taint configuration tracking flow of a method or a wrapper method that sets + * the `HttpOnly` flag. + */ +class SetHttpOnlyInCookieConfiguration extends TaintTracking2::Configuration { + SetHttpOnlyInCookieConfiguration() { this = "SetHttpOnlyInCookieConfiguration" } + + override predicate isSource(DataFlow::Node source) { any() } + + override predicate isSink(DataFlow::Node sink) { + sink.asExpr() = + any(MethodAccess ma | ma.getMethod() instanceof ResponseAddCookieMethod).getArgument(0) + } +} + +/** Holds if the method call removes a cookie. */ predicate removeCookie(MethodAccess ma) { ma.getMethod().getName() = "setMaxAge" and ma.getArgument(0).(IntegerLiteral).getIntValue() = 0 @@ -125,15 +130,14 @@ class CookieResponseSink extends DataFlow::ExprNode { setHttpOnlyInCookie(ma2) or removeCookie(ma2) ) and - ( - DataFlow::localExprFlow(ma2.getQualifier(), this.getExpr()) or - DataFlow::localExprFlow(ma2, this.getExpr()) + exists(SetHttpOnlyInCookieConfiguration cc | + cc.hasFlow(DataFlow::exprNode(ma2.getQualifier()), this) ) ) or ma instanceof SetCookieMethodAccess and this.getExpr() = ma.getArgument(1) and - not hasHttpOnlyExpr(this.getExpr()) // response.addHeader("Set-Cookie", "token=" +authId + ";HttpOnly;Secure") + not exists(MatchesHttpOnlyConfiguration cc | cc.hasFlowToExpr(ma.getArgument(1))) // response.addHeader("Set-Cookie", "token=" +authId + ";HttpOnly;Secure") ) and not isTestMethod(ma) // Test class or method ) diff --git a/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.expected b/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.expected index dae98e92e67..a9d126ca4a9 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.expected @@ -8,8 +8,8 @@ edges | SensitiveCookieNotHttpOnly.java:70:28:70:43 | ... + ... : String | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | | SensitiveCookieNotHttpOnly.java:70:28:70:55 | ... + ... : String | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | | SensitiveCookieNotHttpOnly.java:88:35:88:51 | "Presto-UI-Token" : String | SensitiveCookieNotHttpOnly.java:91:16:91:21 | cookie : Cookie | -| SensitiveCookieNotHttpOnly.java:91:16:91:21 | cookie : Cookie | SensitiveCookieNotHttpOnly.java:102:25:102:64 | createAuthenticationCookie(...) : Cookie | -| SensitiveCookieNotHttpOnly.java:102:25:102:64 | createAuthenticationCookie(...) : Cookie | SensitiveCookieNotHttpOnly.java:103:28:103:33 | cookie | +| SensitiveCookieNotHttpOnly.java:91:16:91:21 | cookie : Cookie | SensitiveCookieNotHttpOnly.java:110:25:110:64 | createAuthenticationCookie(...) : Cookie | +| SensitiveCookieNotHttpOnly.java:110:25:110:64 | createAuthenticationCookie(...) : Cookie | SensitiveCookieNotHttpOnly.java:111:28:111:33 | cookie | nodes | SensitiveCookieNotHttpOnly.java:24:33:24:43 | "jwt_token" : String | semmle.label | "jwt_token" : String | | SensitiveCookieNotHttpOnly.java:31:28:31:36 | jwtCookie | semmle.label | jwtCookie | @@ -26,8 +26,8 @@ nodes | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | semmle.label | secString | | SensitiveCookieNotHttpOnly.java:88:35:88:51 | "Presto-UI-Token" : String | semmle.label | "Presto-UI-Token" : String | | SensitiveCookieNotHttpOnly.java:91:16:91:21 | cookie : Cookie | semmle.label | cookie : Cookie | -| SensitiveCookieNotHttpOnly.java:102:25:102:64 | createAuthenticationCookie(...) : Cookie | semmle.label | createAuthenticationCookie(...) : Cookie | -| SensitiveCookieNotHttpOnly.java:103:28:103:33 | cookie | semmle.label | cookie | +| SensitiveCookieNotHttpOnly.java:110:25:110:64 | createAuthenticationCookie(...) : Cookie | semmle.label | createAuthenticationCookie(...) : Cookie | +| SensitiveCookieNotHttpOnly.java:111:28:111:33 | cookie | semmle.label | cookie | #select | SensitiveCookieNotHttpOnly.java:31:28:31:36 | jwtCookie | SensitiveCookieNotHttpOnly.java:24:33:24:43 | "jwt_token" : String | SensitiveCookieNotHttpOnly.java:31:28:31:36 | jwtCookie | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:24:33:24:43 | "jwt_token" | This sensitive cookie | | SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... | SensitiveCookieNotHttpOnly.java:42:42:42:49 | "token=" : String | SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:42:42:42:49 | "token=" | This sensitive cookie | @@ -38,4 +38,4 @@ nodes | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | SensitiveCookieNotHttpOnly.java:70:28:70:35 | "token=" : String | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:70:28:70:35 | "token=" | This sensitive cookie | | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | SensitiveCookieNotHttpOnly.java:70:28:70:43 | ... + ... : String | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:70:28:70:43 | ... + ... | This sensitive cookie | | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | SensitiveCookieNotHttpOnly.java:70:28:70:55 | ... + ... : String | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:70:28:70:55 | ... + ... | This sensitive cookie | -| SensitiveCookieNotHttpOnly.java:103:28:103:33 | cookie | SensitiveCookieNotHttpOnly.java:88:35:88:51 | "Presto-UI-Token" : String | SensitiveCookieNotHttpOnly.java:103:28:103:33 | cookie | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:88:35:88:51 | "Presto-UI-Token" | This sensitive cookie | +| SensitiveCookieNotHttpOnly.java:111:28:111:33 | cookie | SensitiveCookieNotHttpOnly.java:88:35:88:51 | "Presto-UI-Token" : String | SensitiveCookieNotHttpOnly.java:111:28:111:33 | cookie | $@ doesn't have the HttpOnly flag set. | SensitiveCookieNotHttpOnly.java:88:35:88:51 | "Presto-UI-Token" | This sensitive cookie | diff --git a/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.java b/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.java index fdc831d7836..0bb912f6ce6 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.java +++ b/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.java @@ -91,6 +91,14 @@ class SensitiveCookieNotHttpOnly { return cookie; } + public Cookie removeAuthenticationCookie(HttpServletRequest request, String jwt) { + String PRESTO_UI_COOKIE = "Presto-UI-Token"; + Cookie cookie = new Cookie(PRESTO_UI_COOKIE, jwt); + cookie.setPath("/ui"); + cookie.setMaxAge(0); + return cookie; + } + // GOOD - Tests set a sensitive cookie header with the `HttpOnly` flag set using a wrapper method. public void addCookie11(HttpServletRequest request, HttpServletResponse response, String jwt) { Cookie cookie = createHttpOnlyAuthenticationCookie(request, jwt); @@ -103,6 +111,12 @@ class SensitiveCookieNotHttpOnly { response.addCookie(cookie); } + // GOOD - Tests remove a sensitive cookie header without the `HttpOnly` flag set using a wrapper method. + public void addCookie13(HttpServletRequest request, HttpServletResponse response, String jwt) { + Cookie cookie = removeAuthenticationCookie(request, jwt); + response.addCookie(cookie); + } + private Cookie createCookie(String name, String value, Boolean httpOnly){ Cookie cookie = null; cookie = new Cookie(name, value); @@ -119,12 +133,12 @@ class SensitiveCookieNotHttpOnly { } // GOOD - Tests set a sensitive cookie header with the `HttpOnly` flag set through a boolean variable using a wrapper method. - public void addCookie13(HttpServletRequest request, HttpServletResponse response, String refreshToken) { + public void addCookie14(HttpServletRequest request, HttpServletResponse response, String refreshToken) { response.addCookie(createCookie("refresh_token", refreshToken, true)); } // BAD - Tests set a sensitive cookie header with the `HttpOnly` flag not set through a boolean variable using a wrapper method. - public void addCookie14(HttpServletRequest request, HttpServletResponse response, String refreshToken) { + public void addCookie15(HttpServletRequest request, HttpServletResponse response, String refreshToken) { response.addCookie(createCookie("refresh_token", refreshToken, false)); } From 70824b3f0b696874b0b4dd33ccb4942d1f9a2b18 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Thu, 25 Mar 2021 09:47:31 +0100 Subject: [PATCH 343/725] Java: Delete filter queries. --- java/ql/src/external/DefectFilter.qll | 55 -------------------- java/ql/src/external/MetricFilter.qll | 44 ---------------- java/ql/src/filters/FromSource.ql | 15 ------ java/ql/src/filters/NotGenerated.ql | 13 ----- java/ql/src/filters/NotGeneratedForMetric.ql | 13 ----- java/ql/src/filters/SuppressionComment.ql | 52 ------------------ 6 files changed, 192 deletions(-) delete mode 100644 java/ql/src/external/DefectFilter.qll delete mode 100644 java/ql/src/external/MetricFilter.qll delete mode 100644 java/ql/src/filters/FromSource.ql delete mode 100644 java/ql/src/filters/NotGenerated.ql delete mode 100644 java/ql/src/filters/NotGeneratedForMetric.ql delete mode 100644 java/ql/src/filters/SuppressionComment.ql diff --git a/java/ql/src/external/DefectFilter.qll b/java/ql/src/external/DefectFilter.qll deleted file mode 100644 index d3296315f65..00000000000 --- a/java/ql/src/external/DefectFilter.qll +++ /dev/null @@ -1,55 +0,0 @@ -/** Provides a class for working with defect query results stored in dashboard databases. */ - -import java - -/** - * Holds if `id` in the opaque identifier of a result reported by query `queryPath`, - * such that `message` is the associated message and the location of the result spans - * column `startcolumn` of line `startline` to column `endcolumn` of line `endline` - * in file `filepath`. - * - * For more information, see [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). - */ -external predicate defectResults( - int id, string queryPath, string file, int startline, int startcol, int endline, int endcol, - string message -); - -/** - * A defect query result stored in a dashboard database. - */ -class DefectResult extends int { - DefectResult() { defectResults(this, _, _, _, _, _, _, _) } - - /** Gets the path of the query that reported the result. */ - string getQueryPath() { defectResults(this, result, _, _, _, _, _, _) } - - /** Gets the file in which this query result was reported. */ - File getFile() { - exists(string path | defectResults(this, _, path, _, _, _, _, _) | - result.getAbsolutePath() = path - ) - } - - /** Gets the line on which the location of this query result starts. */ - int getStartLine() { defectResults(this, _, _, result, _, _, _, _) } - - /** Gets the column on which the location of this query result starts. */ - int getStartColumn() { defectResults(this, _, _, _, result, _, _, _) } - - /** Gets the line on which the location of this query result ends. */ - int getEndLine() { defectResults(this, _, _, _, _, result, _, _) } - - /** Gets the column on which the location of this query result ends. */ - int getEndColumn() { defectResults(this, _, _, _, _, _, result, _) } - - /** Gets the message associated with this query result. */ - string getMessage() { defectResults(this, _, _, _, _, _, _, result) } - - /** Gets the URL corresponding to the location of this query result. */ - string getURL() { - result = - "file://" + getFile().getAbsolutePath() + ":" + getStartLine() + ":" + getStartColumn() + ":" + - getEndLine() + ":" + getEndColumn() - } -} diff --git a/java/ql/src/external/MetricFilter.qll b/java/ql/src/external/MetricFilter.qll deleted file mode 100644 index cffcae2e425..00000000000 --- a/java/ql/src/external/MetricFilter.qll +++ /dev/null @@ -1,44 +0,0 @@ -import java - -external predicate metricResults( - int id, string queryPath, string file, int startline, int startcol, int endline, int endcol, - float value -); - -class MetricResult extends int { - MetricResult() { metricResults(this, _, _, _, _, _, _, _) } - - string getQueryPath() { metricResults(this, result, _, _, _, _, _, _) } - - File getFile() { - exists(string path | - metricResults(this, _, path, _, _, _, _, _) and result.getAbsolutePath() = path - ) - } - - int getStartLine() { metricResults(this, _, _, result, _, _, _, _) } - - int getStartColumn() { metricResults(this, _, _, _, result, _, _, _) } - - int getEndLine() { metricResults(this, _, _, _, _, result, _, _) } - - int getEndColumn() { metricResults(this, _, _, _, _, _, result, _) } - - predicate hasMatchingLocation() { exists(this.getMatchingLocation()) } - - Location getMatchingLocation() { - result.getFile() = this.getFile() and - result.getStartLine() = this.getStartLine() and - result.getEndLine() = this.getEndLine() and - result.getStartColumn() = this.getStartColumn() and - result.getEndColumn() = this.getEndColumn() - } - - float getValue() { metricResults(this, _, _, _, _, _, _, result) } - - string getURL() { - result = - "file://" + getFile().getAbsolutePath() + ":" + getStartLine() + ":" + getStartColumn() + ":" + - getEndLine() + ":" + getEndColumn() - } -} diff --git a/java/ql/src/filters/FromSource.ql b/java/ql/src/filters/FromSource.ql deleted file mode 100644 index 5d655c4954e..00000000000 --- a/java/ql/src/filters/FromSource.ql +++ /dev/null @@ -1,15 +0,0 @@ -/** - * @name Filter: only keep results from source - * @description Shows how to filter for only certain files - * @kind problem - * @id java/source-filter - */ - -import java -import external.DefectFilter - -from DefectResult res, CompilationUnit cu -where - cu = res.getFile() and - cu.fromSource() -select res, res.getMessage() diff --git a/java/ql/src/filters/NotGenerated.ql b/java/ql/src/filters/NotGenerated.ql deleted file mode 100644 index d20e8ca5e58..00000000000 --- a/java/ql/src/filters/NotGenerated.ql +++ /dev/null @@ -1,13 +0,0 @@ -/** - * @name Filter: non-generated files - * @description Only keep results that aren't in generated files - * @kind problem - * @id java/not-generated-file-filter - */ - -import java -import external.DefectFilter - -from DefectResult res -where not res.getFile() instanceof GeneratedFile -select res, res.getMessage() diff --git a/java/ql/src/filters/NotGeneratedForMetric.ql b/java/ql/src/filters/NotGeneratedForMetric.ql deleted file mode 100644 index 8d424cea687..00000000000 --- a/java/ql/src/filters/NotGeneratedForMetric.ql +++ /dev/null @@ -1,13 +0,0 @@ -/** - * @name Metric Filter: non-generated files - * @description Only keep metric results that aren't in generated files - * @kind treemap - * @id java/not-generated-file-metric-filter - */ - -import java -import external.MetricFilter - -from MetricResult res -where not res.getFile() instanceof GeneratedFile -select res, res.getValue() diff --git a/java/ql/src/filters/SuppressionComment.ql b/java/ql/src/filters/SuppressionComment.ql deleted file mode 100644 index 85bb2627c5e..00000000000 --- a/java/ql/src/filters/SuppressionComment.ql +++ /dev/null @@ -1,52 +0,0 @@ -/** - * @name Filter: Suppression comments - * @description Recognise comments containing `NOSEMMLE` as suppression comments - * when they appear on a line containing an alert or the - * immediately preceding line. As further customisations, - * `NOSEMMLE(some text)` will only suppress alerts where the - * message contains "some text", and `NOSEMMLE/some regex/` will - * only suppress alerts where the message contains a match of the - * regex. No special way of escaping `)` or `/` in the suppression - * comment argument is provided. - * @kind problem - * @id java/nosemmle-suppression-comment-filter - */ - -import java -import external.DefectFilter - -class SuppressionComment extends Javadoc { - SuppressionComment() { this.getAChild*().getText().matches("%NOSEMMLE%") } - - private string getASuppressionDirective() { - result = this.getAChild*().getText().regexpFind("\\bNOSEMMLE\\b(\\([^)]+?\\)|/[^/]+?/|)", _, 0) - } - - private string getAnActualSubstringArg() { - result = this.getASuppressionDirective().regexpCapture("NOSEMMLE\\((.*)\\)", 1) - } - - private string getAnActualRegexArg() { - result = ".*" + this.getASuppressionDirective().regexpCapture("NOSEMMLE/(.*)/", 1) + ".*" - } - - private string getASuppressionRegex() { - result = getAnActualRegexArg() - or - exists(string substring | substring = getAnActualSubstringArg() | - result = "\\Q" + substring.replaceAll("\\E", "\\E\\\\E\\Q") + "\\E" - ) - or - result = ".*" and getASuppressionDirective() = "NOSEMMLE" - } - - predicate suppresses(DefectResult res) { - this.getFile() = res.getFile() and - res.getEndLine() - this.getLocation().getEndLine() in [0 .. 2] and - res.getMessage().regexpMatch(this.getASuppressionRegex()) - } -} - -from DefectResult res -where not exists(SuppressionComment s | s.suppresses(res)) -select res, res.getMessage() From eeb8c7466697fe5271e674c9d53332ac3ad0dc96 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 24 Mar 2021 20:10:04 +0100 Subject: [PATCH 344/725] C#: Remove `filter` and `external` queries These are legacy queries that are no longer used. --- config/identical-files.json | 3 +- .../Files/DuplicationProblems.inc.qhelp | 16 - .../Files/FLinesOfDuplicatedCode.qhelp | 30 -- .../Metrics/Files/FLinesOfDuplicatedCode.ql | 27 -- csharp/ql/src/external/CodeDuplication.qll | 305 ------------------ csharp/ql/src/external/DefectFilter.qll | 34 -- csharp/ql/src/external/DuplicateMethod.cs | 22 -- csharp/ql/src/external/DuplicateMethod.qhelp | 35 -- csharp/ql/src/external/DuplicateMethod.ql | 41 --- csharp/ql/src/external/DuplicateMethodFix.cs | 18 -- csharp/ql/src/external/ExternalArtifact.qll | 79 ----- csharp/ql/src/external/MetricFilter.qll | 44 --- .../src/external/MostlyDuplicateClass.qhelp | 20 -- .../ql/src/external/MostlyDuplicateClass.ql | 24 -- .../ql/src/external/MostlyDuplicateFile.qhelp | 31 -- csharp/ql/src/external/MostlyDuplicateFile.ql | 23 -- .../src/external/MostlyDuplicateMethod.qhelp | 48 --- .../ql/src/external/MostlyDuplicateMethod.ql | 30 -- .../ql/src/external/MostlySimilarFile.qhelp | 24 -- csharp/ql/src/external/MostlySimilarFile.ql | 31 -- csharp/ql/src/filters/ChangedLines.ql | 20 -- csharp/ql/src/filters/ChangedLines.qll | 12 - .../ql/src/filters/ChangedLinesForMetric.ql | 15 - csharp/ql/src/filters/ClassifyFiles.ql | 2 + csharp/ql/src/filters/FromSource.ql | 13 - csharp/ql/src/filters/FromSourceForMetric.ql | 13 - csharp/ql/src/filters/NotGenerated.ql | 13 - .../ql/src/filters/NotGeneratedForMetric.ql | 13 - csharp/ql/src/filters/NotInTestFile.ql | 14 - .../ql/src/filters/NotInTestFileForMetric.ql | 14 - csharp/ql/src/filters/NotInTestMethod.ql | 17 - .../NotInTestMethodExpectingException.ql | 24 -- csharp/ql/src/filters/UnchangedLines.ql | 22 -- .../ql/src/filters/UnchangedLinesForMetric.ql | 15 - .../ExternalDependencies/File1.cs | 30 -- .../ExternalDependencies/File2.cs | 5 - .../Files/FLinesOfDuplicatedCode/file1.cs | 48 --- .../Files/FLinesOfDuplicatedCode/file2.cs | 30 -- 38 files changed, 3 insertions(+), 1202 deletions(-) delete mode 100644 csharp/ql/src/Metrics/Files/DuplicationProblems.inc.qhelp delete mode 100644 csharp/ql/src/Metrics/Files/FLinesOfDuplicatedCode.qhelp delete mode 100644 csharp/ql/src/Metrics/Files/FLinesOfDuplicatedCode.ql delete mode 100644 csharp/ql/src/external/CodeDuplication.qll delete mode 100644 csharp/ql/src/external/DefectFilter.qll delete mode 100644 csharp/ql/src/external/DuplicateMethod.cs delete mode 100644 csharp/ql/src/external/DuplicateMethod.qhelp delete mode 100644 csharp/ql/src/external/DuplicateMethod.ql delete mode 100644 csharp/ql/src/external/DuplicateMethodFix.cs delete mode 100644 csharp/ql/src/external/ExternalArtifact.qll delete mode 100644 csharp/ql/src/external/MetricFilter.qll delete mode 100644 csharp/ql/src/external/MostlyDuplicateClass.qhelp delete mode 100644 csharp/ql/src/external/MostlyDuplicateClass.ql delete mode 100644 csharp/ql/src/external/MostlyDuplicateFile.qhelp delete mode 100644 csharp/ql/src/external/MostlyDuplicateFile.ql delete mode 100644 csharp/ql/src/external/MostlyDuplicateMethod.qhelp delete mode 100644 csharp/ql/src/external/MostlyDuplicateMethod.ql delete mode 100644 csharp/ql/src/external/MostlySimilarFile.qhelp delete mode 100644 csharp/ql/src/external/MostlySimilarFile.ql delete mode 100644 csharp/ql/src/filters/ChangedLines.ql delete mode 100644 csharp/ql/src/filters/ChangedLines.qll delete mode 100644 csharp/ql/src/filters/ChangedLinesForMetric.ql delete mode 100644 csharp/ql/src/filters/FromSource.ql delete mode 100644 csharp/ql/src/filters/FromSourceForMetric.ql delete mode 100644 csharp/ql/src/filters/NotGenerated.ql delete mode 100644 csharp/ql/src/filters/NotGeneratedForMetric.ql delete mode 100644 csharp/ql/src/filters/NotInTestFile.ql delete mode 100644 csharp/ql/src/filters/NotInTestFileForMetric.ql delete mode 100644 csharp/ql/src/filters/NotInTestMethod.ql delete mode 100644 csharp/ql/src/filters/NotInTestMethodExpectingException.ql delete mode 100644 csharp/ql/src/filters/UnchangedLines.ql delete mode 100644 csharp/ql/src/filters/UnchangedLinesForMetric.ql delete mode 100644 csharp/ql/test/query-tests/Metrics/Dependencies/ExternalDependencies/File1.cs delete mode 100644 csharp/ql/test/query-tests/Metrics/Dependencies/ExternalDependencies/File2.cs delete mode 100644 csharp/ql/test/query-tests/Metrics/Files/FLinesOfDuplicatedCode/file1.cs delete mode 100644 csharp/ql/test/query-tests/Metrics/Files/FLinesOfDuplicatedCode/file2.cs diff --git a/config/identical-files.json b/config/identical-files.json index b63690c5f1e..6f70e6b6361 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -376,7 +376,6 @@ ], "DuplicationProblems.inc.qhelp": [ "cpp/ql/src/Metrics/Files/DuplicationProblems.inc.qhelp", - "csharp/ql/src/Metrics/Files/DuplicationProblems.inc.qhelp", "javascript/ql/src/Metrics/DuplicationProblems.inc.qhelp", "python/ql/src/Metrics/DuplicationProblems.inc.qhelp" ], @@ -435,4 +434,4 @@ "javascript/ql/src/semmle/javascript/security/CryptoAlgorithms.qll", "python/ql/src/semmle/crypto/Crypto.qll" ] -} +} \ No newline at end of file diff --git a/csharp/ql/src/Metrics/Files/DuplicationProblems.inc.qhelp b/csharp/ql/src/Metrics/Files/DuplicationProblems.inc.qhelp deleted file mode 100644 index 54397da6c99..00000000000 --- a/csharp/ql/src/Metrics/Files/DuplicationProblems.inc.qhelp +++ /dev/null @@ -1,16 +0,0 @@ - - - -

    -Duplicated code increases overall code size, making the code base -harder to maintain and harder to understand. It also becomes harder to fix bugs, -since a programmer applying a fix to one copy has to always remember to update -other copies accordingly. Finally, code duplication is generally an indication of -a poorly designed or hastily written code base, which typically suffers from other -problems as well. -

    - -
    -
    diff --git a/csharp/ql/src/Metrics/Files/FLinesOfDuplicatedCode.qhelp b/csharp/ql/src/Metrics/Files/FLinesOfDuplicatedCode.qhelp deleted file mode 100644 index 3f7b574a4dc..00000000000 --- a/csharp/ql/src/Metrics/Files/FLinesOfDuplicatedCode.qhelp +++ /dev/null @@ -1,30 +0,0 @@ - - - -

    -A file that contains many lines that are duplicated within the code base is problematic -for a number of reasons. -

    - -
    - - - - -

    -Refactor files with lots of duplicated code to extract the common code into -shared classes and assemblies. -

    - -
    - - - -
  • Wikipedia: Duplicate code.
  • -
  • M. Fowler, Refactoring. Addison-Wesley, 1999.
  • - - -
    -
    diff --git a/csharp/ql/src/Metrics/Files/FLinesOfDuplicatedCode.ql b/csharp/ql/src/Metrics/Files/FLinesOfDuplicatedCode.ql deleted file mode 100644 index bf3da5e1f80..00000000000 --- a/csharp/ql/src/Metrics/Files/FLinesOfDuplicatedCode.ql +++ /dev/null @@ -1,27 +0,0 @@ -/** - * @deprecated - * @name Duplicated lines in files - * @description The number of lines in a file, including code, comment and whitespace lines, - * which are duplicated in at least one other place. - * @kind treemap - * @treemap.warnOn highValues - * @metricType file - * @metricAggregate avg sum max - * @precision high - * @id cs/duplicated-lines-in-files - * @tags testability - * modularity - */ - -import external.CodeDuplication - -from SourceFile f, int n -where - n = - count(int line | - exists(DuplicateBlock d | d.sourceFile() = f | - line in [d.sourceStartLine() .. d.sourceEndLine()] and - not whitelistedLineForDuplication(f, line) - ) - ) -select f, n order by n desc diff --git a/csharp/ql/src/external/CodeDuplication.qll b/csharp/ql/src/external/CodeDuplication.qll deleted file mode 100644 index f4165e599e8..00000000000 --- a/csharp/ql/src/external/CodeDuplication.qll +++ /dev/null @@ -1,305 +0,0 @@ -import csharp - -private string relativePath(File file) { result = file.getRelativePath().replaceAll("\\", "/") } - -/** - * Holds if the `index`-th token of block `copy` is in file `file`, spanning - * column `sc` of line `sl` to column `ec` of line `el`. - * - * For more information, see [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). - */ -pragma[nomagic] -predicate tokenLocation(File file, int sl, int sc, int ec, int el, Copy copy, int index) { - file = copy.sourceFile() and - tokens(copy, index, sl, sc, ec, el) -} - -class Copy extends @duplication_or_similarity { - private int lastToken() { result = max(int i | tokens(this, i, _, _, _, _) | i) } - - int tokenStartingAt(Location loc) { - tokenLocation(loc.getFile(), loc.getStartLine(), loc.getStartColumn(), _, _, this, result) - } - - int tokenEndingAt(Location loc) { - tokenLocation(loc.getFile(), _, _, loc.getEndLine(), loc.getEndColumn(), this, result) - } - - int sourceStartLine() { tokens(this, 0, result, _, _, _) } - - int sourceStartColumn() { tokens(this, 0, _, result, _, _) } - - int sourceEndLine() { tokens(this, lastToken(), _, _, result, _) } - - int sourceEndColumn() { tokens(this, lastToken(), _, _, _, result) } - - int sourceLines() { result = this.sourceEndLine() + 1 - this.sourceStartLine() } - - int getEquivalenceClass() { duplicateCode(this, _, result) or similarCode(this, _, result) } - - File sourceFile() { - exists(string name | duplicateCode(this, name, _) or similarCode(this, name, _) | - name.replaceAll("\\", "/") = relativePath(result) - ) - } - - predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - sourceFile().getAbsolutePath() = filepath and - startline = sourceStartLine() and - startcolumn = sourceStartColumn() and - endline = sourceEndLine() and - endcolumn = sourceEndColumn() - } - - string toString() { none() } -} - -class DuplicateBlock extends Copy, @duplication { - override string toString() { result = "Duplicate code: " + sourceLines() + " duplicated lines." } -} - -class SimilarBlock extends Copy, @similarity { - override string toString() { - result = "Similar code: " + sourceLines() + " almost duplicated lines." - } -} - -private Method sourceMethod() { method_location(result, _) and numlines(result, _, _, _) } - -private int numberOfSourceMethods(Class c) { - result = count(Method m | m = sourceMethod() and m.getDeclaringType() = c) -} - -private predicate blockCoversStatement(int equivClass, int first, int last, Stmt stmt) { - exists(DuplicateBlock b, Location loc | - stmt.getLocation() = loc and - first = b.tokenStartingAt(loc) and - last = b.tokenEndingAt(loc) and - b.getEquivalenceClass() = equivClass - ) -} - -private Stmt statementInMethod(Method m) { - result.getEnclosingCallable() = m and - not result instanceof BlockStmt -} - -private predicate duplicateStatement(Method m1, Method m2, Stmt s1, Stmt s2) { - exists(int equivClass, int first, int last | - s1 = statementInMethod(m1) and - s2 = statementInMethod(m2) and - blockCoversStatement(equivClass, first, last, s1) and - blockCoversStatement(equivClass, first, last, s2) and - s1 != s2 and - m1 != m2 - ) -} - -/** Holds if `duplicate` number of statements are duplicated in the methods. */ -predicate duplicateStatements(Method m1, Method m2, int duplicate, int total) { - duplicate = strictcount(Stmt s | duplicateStatement(m1, m2, s, _)) and - total = strictcount(statementInMethod(m1)) -} - -/** - * Find pairs of methods are identical - */ -predicate duplicateMethod(Method m, Method other) { - exists(int total | duplicateStatements(m, other, total, total)) -} - -private predicate similarLines(File f, int line) { - exists(SimilarBlock b | b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()]) -} - -private predicate similarLinesPerEquivalenceClass(int equivClass, int lines, File f) { - lines = - strictsum(SimilarBlock b, int toSum | - (b.sourceFile() = f and b.getEquivalenceClass() = equivClass) and - toSum = b.sourceLines() - | - toSum - ) -} - -pragma[noopt] -private predicate similarLinesCovered(File f, int coveredLines, File otherFile) { - exists(int numLines | numLines = f.getNumberOfLines() | - exists(int coveredApprox | - coveredApprox = - strictsum(int num | - exists(int equivClass | - similarLinesPerEquivalenceClass(equivClass, num, f) and - similarLinesPerEquivalenceClass(equivClass, num, otherFile) and - f != otherFile - ) - ) and - exists(int n, int product | product = coveredApprox * 100 and n = product / numLines | n > 75) - ) and - exists(int notCovered | - notCovered = - count(int j | - j in [1 .. numLines] and - not similarLines(f, j) - ) and - coveredLines = numLines - notCovered - ) - ) -} - -private predicate duplicateLines(File f, int line) { - exists(DuplicateBlock b | - b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()] - ) -} - -private predicate duplicateLinesPerEquivalenceClass(int equivClass, int lines, File f) { - lines = - strictsum(DuplicateBlock b, int toSum | - (b.sourceFile() = f and b.getEquivalenceClass() = equivClass) and - toSum = b.sourceLines() - | - toSum - ) -} - -pragma[noopt] -private predicate duplicateLinesCovered(File f, int coveredLines, File otherFile) { - exists(int numLines | numLines = f.getNumberOfLines() | - exists(int coveredApprox | - coveredApprox = - strictsum(int num | - exists(int equivClass | - duplicateLinesPerEquivalenceClass(equivClass, num, f) and - duplicateLinesPerEquivalenceClass(equivClass, num, otherFile) and - f != otherFile - ) - ) and - exists(int n, int product | product = coveredApprox * 100 and n = product / numLines | n > 75) - ) and - exists(int notCovered | - notCovered = - count(int j | - j in [1 .. numLines] and - not duplicateLines(f, j) - ) and - coveredLines = numLines - notCovered - ) - ) -} - -/** Holds if the two files are not duplicated but have more than 80% similar lines. */ -predicate similarFiles(File f, File other, int percent) { - exists(int covered, int total | - similarLinesCovered(f, covered, other) and - total = f.getNumberOfLines() and - covered * 100 / total = percent and - percent > 80 - ) and - not duplicateFiles(f, other, _) -} - -/** Holds if the two files have more than 70% duplicated lines. */ -predicate duplicateFiles(File f, File other, int percent) { - exists(int covered, int total | - duplicateLinesCovered(f, covered, other) and - total = f.getNumberOfLines() and - covered * 100 / total = percent and - percent > 70 - ) -} - -pragma[noopt] -private predicate duplicateAnonymousClass(AnonymousClass c, AnonymousClass other) { - exists(int numDup | - numDup = - strictcount(Method m1 | - exists(Method m2 | - duplicateMethod(m1, m2) and - m1 = sourceMethod() and - m1.getDeclaringType() = c and - c instanceof AnonymousClass and - m2.getDeclaringType() = other and - other instanceof AnonymousClass and - c != other - ) - ) and - numDup = numberOfSourceMethods(c) and - numDup = numberOfSourceMethods(other) and - forall(Type t | c.getABaseType() = t | t = other.getABaseType()) - ) -} - -pragma[noopt] -private predicate mostlyDuplicateClassBase(Class c, Class other, int numDup, int total) { - numDup = - strictcount(Method m1 | - exists(Method m2 | - duplicateMethod(m1, m2) and - m1 = sourceMethod() and - m1.getDeclaringType() = c and - m2.getDeclaringType() = other and - other instanceof Class and - c != other - ) - ) and - total = numberOfSourceMethods(c) and - exists(int n, int product | product = 100 * numDup and n = product / total | n > 80) and - not c instanceof AnonymousClass and - not other instanceof AnonymousClass -} - -/** Holds if the methods in the two classes are more than 80% duplicated. */ -predicate mostlyDuplicateClass(Class c, Class other, string message) { - exists(int numDup, int total | - mostlyDuplicateClassBase(c, other, numDup, total) and - ( - total != numDup and - exists(string s1, string s2, string s3, string name | - s1 = " out of " and - s2 = " methods in " and - s3 = " are duplicated in $@." and - name = c.getName() - | - message = numDup + s1 + total + s2 + name + s3 - ) - or - total = numDup and - exists(string s1, string s2, string name | - s1 = "All methods in " and s2 = " are identical in $@." and name = c.getName() - | - message = s1 + name + s2 - ) - ) - ) -} - -/** Holds if the two files are similar or duplicated. */ -predicate fileLevelDuplication(File f, File other) { - similarFiles(f, other, _) or duplicateFiles(f, other, _) -} - -/** - * Holds if the two classes are duplicated anonymous classes or more than 80% of - * their methods are duplicated. - */ -predicate classLevelDuplication(Class c, Class other) { - duplicateAnonymousClass(c, other) or mostlyDuplicateClass(c, other, _) -} - -private Element whitelistedDuplicateElement() { - result instanceof UsingNamespaceDirective or - result instanceof UsingStaticDirective -} - -/** - * Holds if the `line` in the `file` contains an element, such as a `using` - * directive, that is not considered for code duplication. - */ -predicate whitelistedLineForDuplication(File file, int line) { - exists(Location loc | loc = whitelistedDuplicateElement().getLocation() | - line = loc.getStartLine() and file = loc.getFile() - ) -} diff --git a/csharp/ql/src/external/DefectFilter.qll b/csharp/ql/src/external/DefectFilter.qll deleted file mode 100644 index 4f4f60b66c1..00000000000 --- a/csharp/ql/src/external/DefectFilter.qll +++ /dev/null @@ -1,34 +0,0 @@ -import csharp - -external predicate defectResults( - int id, string queryPath, string file, int startline, int startcol, int endline, int endcol, - string message -); - -class DefectResult extends int { - DefectResult() { defectResults(this, _, _, _, _, _, _, _) } - - string getQueryPath() { defectResults(this, result, _, _, _, _, _, _) } - - File getFile() { - exists(string path | - defectResults(this, _, path, _, _, _, _, _) and result.getAbsolutePath() = path - ) - } - - int getStartLine() { defectResults(this, _, _, result, _, _, _, _) } - - int getStartColumn() { defectResults(this, _, _, _, result, _, _, _) } - - int getEndLine() { defectResults(this, _, _, _, _, result, _, _) } - - int getEndColumn() { defectResults(this, _, _, _, _, _, result, _) } - - string getMessage() { defectResults(this, _, _, _, _, _, _, result) } - - string getURL() { - result = - "file://" + getFile().getAbsolutePath() + ":" + getStartLine() + ":" + getStartColumn() + ":" + - getEndLine() + ":" + getEndColumn() - } -} diff --git a/csharp/ql/src/external/DuplicateMethod.cs b/csharp/ql/src/external/DuplicateMethod.cs deleted file mode 100644 index 8a963528267..00000000000 --- a/csharp/ql/src/external/DuplicateMethod.cs +++ /dev/null @@ -1,22 +0,0 @@ -class Toolbox -{ - private int x; - private int y; - public void move(int x, int y) - { - this.x = x; - this.y = y; - } - // ... -} -class Window -{ - private int x; - private int y; - public void move(int x, int y) - { - this.x = x; - this.y = y; - } - // ... -} diff --git a/csharp/ql/src/external/DuplicateMethod.qhelp b/csharp/ql/src/external/DuplicateMethod.qhelp deleted file mode 100644 index d42ffb73c64..00000000000 --- a/csharp/ql/src/external/DuplicateMethod.qhelp +++ /dev/null @@ -1,35 +0,0 @@ - - - -

    Methods should not be duplicated at more than one place in the program. Duplicating code makes it harder to update -should a change need to be made. It also makes the code harder to read.

    - -
    - -

    Determining how to address this issue requires some consideration. If the duplicate methods are in the same class -then it is normally possible to just remove one and replace all references to that method by references to the other -method. If the methods are in different classes then there might be a need to create a superclass that -contains the method, which both classes inherit. If it is not logical to create a superclass the method -could be moved into a separate utility class.

    - -
    - -

    In this example the Toolbox and the Window class both have the same move method. In this case it would be logical to -put this method as well as the x and y properties into a new superclass that Toolbox and Window extend.

    - - -
    -
    -

    The example could be easily fixed by moving the x and y properties as well as the move method to a parent class. Note -that the x and y properties have to be changed to protected if they are accessed from the Toolbox and Window classes.

    - - -
    - - -
  • Elmar Juergens, Florian Deissenboeck, Benjamin Hummel and Stefan Wagner. Do Code Clones Matter?. 2009.
  • - -
    -
    diff --git a/csharp/ql/src/external/DuplicateMethod.ql b/csharp/ql/src/external/DuplicateMethod.ql deleted file mode 100644 index 371315cd4e6..00000000000 --- a/csharp/ql/src/external/DuplicateMethod.ql +++ /dev/null @@ -1,41 +0,0 @@ -/** - * @deprecated - * @name Duplicate method - * @description There is another identical implementation of this method. Extract the code to a common superclass or delegate to improve sharing. - * @kind problem - * @problem.severity recommendation - * @precision high - * @id cs/duplicate-method - * @tags testability - * maintainability - * useless-code - * duplicate-code - * statistical - * non-attributable - */ - -import csharp -import CodeDuplication - -predicate relevant(Method m) { - m.getNumberOfLinesOfCode() > 5 and not m.getName().matches("get%") - or - m.getNumberOfLinesOfCode() > 10 -} - -pragma[noopt] -predicate query(Method m, Method other) { - duplicateMethod(m, other) and - relevant(m) and - not exists(File f1, File f2 | - m.getFile() = f1 and fileLevelDuplication(f1, f2) and other.getFile() = f2 - ) and - not exists(Type t1, Type t2 | - m.getDeclaringType() = t1 and classLevelDuplication(t1, t2) and other.getDeclaringType() = t2 - ) -} - -from Method m, Method other -where query(m, other) -select m, "Method " + m.getName() + " is duplicated in $@.", other, - other.getDeclaringType().getName() + "." + other.getName() diff --git a/csharp/ql/src/external/DuplicateMethodFix.cs b/csharp/ql/src/external/DuplicateMethodFix.cs deleted file mode 100644 index 5fb9864de99..00000000000 --- a/csharp/ql/src/external/DuplicateMethodFix.cs +++ /dev/null @@ -1,18 +0,0 @@ -class Container -{ - protected int x; - protected int y; - public void move(int x, int y) - { - this.x = x; - this.y = y; - } -} -class Toolbox : Container -{ - // ... -} -class Window : Container -{ - // ... -} diff --git a/csharp/ql/src/external/ExternalArtifact.qll b/csharp/ql/src/external/ExternalArtifact.qll deleted file mode 100644 index 15be44b15bd..00000000000 --- a/csharp/ql/src/external/ExternalArtifact.qll +++ /dev/null @@ -1,79 +0,0 @@ -import csharp - -class ExternalElement extends @external_element { - /** Gets a textual representation of this element. */ - string toString() { none() } - - /** Gets the location of this element. */ - Location getLocation() { none() } - - /** Gets the file containing this element. */ - File getFile() { result = getLocation().getFile() } -} - -class ExternalDefect extends ExternalElement, @externalDefect { - string getQueryPath() { - exists(string path | - externalDefects(this, path, _, _, _) and - result = path.replaceAll("\\", "/") - ) - } - - string getMessage() { externalDefects(this, _, _, result, _) } - - float getSeverity() { externalDefects(this, _, _, _, result) } - - override Location getLocation() { externalDefects(this, _, result, _, _) } - - override string toString() { - result = getQueryPath() + ": " + getLocation() + " - " + getMessage() - } -} - -class ExternalMetric extends ExternalElement, @externalMetric { - string getQueryPath() { externalMetrics(this, result, _, _) } - - float getValue() { externalMetrics(this, _, _, result) } - - override Location getLocation() { externalMetrics(this, _, result, _) } - - override string toString() { result = getQueryPath() + ": " + getLocation() + " - " + getValue() } -} - -class ExternalData extends ExternalElement, @externalDataElement { - string getDataPath() { externalData(this, result, _, _) } - - string getQueryPath() { result = getDataPath().regexpReplaceAll("\\.[^.]*$", ".ql") } - - int getNumFields() { result = 1 + max(int i | externalData(this, _, i, _) | i) } - - string getField(int index) { externalData(this, _, index, result) } - - int getFieldAsInt(int index) { result = getField(index).toInt() } - - float getFieldAsFloat(int index) { result = getField(index).toFloat() } - - date getFieldAsDate(int index) { result = getField(index).toDate() } - - override string toString() { result = getQueryPath() + ": " + buildTupleString(0) } - - private string buildTupleString(int start) { - start = getNumFields() - 1 and result = getField(start) - or - start < getNumFields() - 1 and result = getField(start) + "," + buildTupleString(start + 1) - } -} - -/** - * External data with a location, and a message, as produced by tools that used to produce QLDs. - */ -class DefectExternalData extends ExternalData { - DefectExternalData() { - this.getField(0).regexpMatch("\\w+://.*:[0-9]+:[0-9]+:[0-9]+:[0-9]+$") and - this.getNumFields() = 2 - } - - string getURL() { result = getField(0) } - - string getMessage() { result = getField(1) } -} diff --git a/csharp/ql/src/external/MetricFilter.qll b/csharp/ql/src/external/MetricFilter.qll deleted file mode 100644 index 6d7197662c0..00000000000 --- a/csharp/ql/src/external/MetricFilter.qll +++ /dev/null @@ -1,44 +0,0 @@ -import csharp - -external predicate metricResults( - int id, string queryPath, string file, int startline, int startcol, int endline, int endcol, - float value -); - -class MetricResult extends int { - MetricResult() { metricResults(this, _, _, _, _, _, _, _) } - - string getQueryPath() { metricResults(this, result, _, _, _, _, _, _) } - - File getFile() { - exists(string path | - metricResults(this, _, path, _, _, _, _, _) and result.getAbsolutePath() = path - ) - } - - int getStartLine() { metricResults(this, _, _, result, _, _, _, _) } - - int getStartColumn() { metricResults(this, _, _, _, result, _, _, _) } - - int getEndLine() { metricResults(this, _, _, _, _, result, _, _) } - - int getEndColumn() { metricResults(this, _, _, _, _, _, result, _) } - - predicate hasMatchingLocation() { exists(this.getMatchingLocation()) } - - Location getMatchingLocation() { - result.getFile() = this.getFile() and - result.getStartLine() = this.getStartLine() and - result.getEndLine() = this.getEndLine() and - result.getStartColumn() = this.getStartColumn() and - result.getEndColumn() = this.getEndColumn() - } - - float getValue() { metricResults(this, _, _, _, _, _, _, result) } - - string getURL() { - result = - "file://" + getFile().getAbsolutePath() + ":" + getStartLine() + ":" + getStartColumn() + ":" + - getEndLine() + ":" + getEndColumn() - } -} diff --git a/csharp/ql/src/external/MostlyDuplicateClass.qhelp b/csharp/ql/src/external/MostlyDuplicateClass.qhelp deleted file mode 100644 index 2e053657d0a..00000000000 --- a/csharp/ql/src/external/MostlyDuplicateClass.qhelp +++ /dev/null @@ -1,20 +0,0 @@ - - - -

    If two classes share a lot of each other's methods then there is a lot of unnecessary code duplication. -This makes it difficult to make changes in future and makes the code harder to read.

    - -
    - -

    If a duplicate class has been included by mistake then remove it. Otherwise consider making a common -superclass for both classes or even making one of the classes a superclass of the other.

    - -
    - - -
  • Elmar Juergens, Florian Deissenboeck, Benjamin Hummel and Stefan Wagner. Do Code Clones Matter?. 2009.
  • - -
    -
    diff --git a/csharp/ql/src/external/MostlyDuplicateClass.ql b/csharp/ql/src/external/MostlyDuplicateClass.ql deleted file mode 100644 index 7b7d5ef3eff..00000000000 --- a/csharp/ql/src/external/MostlyDuplicateClass.ql +++ /dev/null @@ -1,24 +0,0 @@ -/** - * @deprecated - * @name Duplicate class - * @description More than 80% of the methods in this class are duplicated in another class. Create a common supertype to improve code sharing. - * @kind problem - * @problem.severity recommendation - * @precision high - * @id cs/duplicate-class - * @tags testability - * maintainability - * useless-code - * duplicate-code - * statistical - * non-attributable - */ - -import csharp -import CodeDuplication - -from Class c, string message, Class link -where - mostlyDuplicateClass(c, link, message) and - not fileLevelDuplication(c.getFile(), _) -select c, message, link, link.getName() diff --git a/csharp/ql/src/external/MostlyDuplicateFile.qhelp b/csharp/ql/src/external/MostlyDuplicateFile.qhelp deleted file mode 100644 index 9cfe21f43cf..00000000000 --- a/csharp/ql/src/external/MostlyDuplicateFile.qhelp +++ /dev/null @@ -1,31 +0,0 @@ - - - -

    If two files share a lot of each other's code then there is a lot of unnecessary code duplication. -This makes it difficult to make changes in future and makes the code harder to read.

    - -
    - -

    While completely duplicated files are rare, they are usually a sign of a simple oversight. -Usually the required action is to remove all but one of them. A common exception to this rule may arise -from generated code that simply occurs in several places in the source tree; the check can be -adapted to exclude such results.

    - -

    It is far more common to see duplication of many lines between two files, leaving just a few that -are actually different. Consider such situations carefully. Are the differences deliberate or -a result of an inconsistent update to one of the clones? If the latter, then treating the files as -completely duplicate and eliminating one (while preserving any corrections or new features that -may have been introduced) is the best course. If two files serve genuinely different purposes but almost -all of their lines are the same, that can be a sign that there is a missing level of abstraction. Look -for ways to share the functionality, either by creating a utility class for the common parts or by -encapsulating the common parts into a new super class of any classes involved.

    - -
    - - -
  • Elmar Juergens, Florian Deissenboeck, Benjamin Hummel and Stefan Wagner. Do Code Clones Matter?. 2009.
  • - -
    -
    diff --git a/csharp/ql/src/external/MostlyDuplicateFile.ql b/csharp/ql/src/external/MostlyDuplicateFile.ql deleted file mode 100644 index 2dbc2e17ffb..00000000000 --- a/csharp/ql/src/external/MostlyDuplicateFile.ql +++ /dev/null @@ -1,23 +0,0 @@ -/** - * @deprecated - * @name Mostly duplicate file - * @description There is another file that shares a lot of the code with this file. Merge the two files to improve maintainability. - * @kind problem - * @problem.severity recommendation - * @precision high - * @id cs/duplicate-file - * @tags testability - * maintainability - * useless-code - * duplicate-code - * statistical - * non-attributable - */ - -import csharp -import CodeDuplication - -from File f, File other, int percent -where duplicateFiles(f, other, percent) -select f, percent + "% of the lines in " + f.getBaseName() + " are copies of lines in $@.", other, - other.getBaseName() diff --git a/csharp/ql/src/external/MostlyDuplicateMethod.qhelp b/csharp/ql/src/external/MostlyDuplicateMethod.qhelp deleted file mode 100644 index 8388520189d..00000000000 --- a/csharp/ql/src/external/MostlyDuplicateMethod.qhelp +++ /dev/null @@ -1,48 +0,0 @@ - - - - -

    When most of the lines in one method are duplicated in one or more other -methods, the methods themselves are regarded as mostly duplicate or similar.

    - -

    Code duplication in general is highly undesirable for a range of reasons. The artificially -inflated amount of code is more difficult to understand, and sequences of similar but subtly different lines -can mask the real purpose or intention behind them. Also, there is always a risk that only one -of several copies of the code is updated to address a defect or add a feature.

    - -
    - -

    Although completely duplicated methods are rare, they are usually a sign of a simple -oversight (or deliberate copy/paste) by a developer. Usually the required solution -is to remove all but one of them.

    - -

    It is more common to see duplication of many lines between two methods, leaving just -a few that are actually different. Decide whether the differences are -intended or the result of an inconsistent update to one of the copies.

    -
      -
    • If the two methods serve different purposes but many of their lines are duplicated, this indicates -that there is a missing level of abstraction. Look for ways of encapsulating the commonality and sharing it while -retaining the differences in functionality. Perhaps the method can be moved to a single place -and given an additional parameter, allowing it to cover all use cases. Alternatively, there -may be a common pre-processing or post-processing step that can be extracted to its own (shared) -method, leaving only the specific parts in the existing methods. Modern IDEs may provide -refactoring support for this sort of issue, usually with the names "Extract method", "Change method signature", -"Pull up" or "Extract supertype".
    • -
    • If the two methods serve the same purpose and are different only as a result of inconsistent updates -then treat the methods as completely duplicate. Determine -the most up-to-date and correct version of the code and eliminate all near duplicates. Callers of the -removed methods should be updated to call the remaining method instead.
    - -
    - - -
  • E. Juergens, F. Deissenboeck, B. Hummel, S. Wagner. -Do code clones matter? Proceedings of the 31st International Conference on -Software Engineering, -485-495, 2009.
  • - - -
    -
    diff --git a/csharp/ql/src/external/MostlyDuplicateMethod.ql b/csharp/ql/src/external/MostlyDuplicateMethod.ql deleted file mode 100644 index aa0003c113b..00000000000 --- a/csharp/ql/src/external/MostlyDuplicateMethod.ql +++ /dev/null @@ -1,30 +0,0 @@ -/** - * @deprecated - * @name Mostly duplicate method - * @description There is another method that shares a lot of the code with this method. Extract the code to a common superclass or delegate to improve sharing. - * @kind problem - * @problem.severity recommendation - * @precision high - * @id cs/similar-method - * @tags testability - * maintainability - * useless-code - * statistical - * non-attributable - */ - -import csharp -import CodeDuplication - -from Method m, int covered, int total, Method other, int percent -where - duplicateStatements(m, other, covered, total) and - covered != total and - m.getNumberOfLinesOfCode() > 5 and - covered * 100 / total = percent and - percent > 80 and - not duplicateMethod(m, other) and - not classLevelDuplication(m.getDeclaringType(), other.getDeclaringType()) and - not fileLevelDuplication(m.getFile(), other.getFile()) -select m, percent + "% of the statements in " + m.getName() + " are duplicated in $@.", other, - other.getDeclaringType().getName() + "." + other.getName() diff --git a/csharp/ql/src/external/MostlySimilarFile.qhelp b/csharp/ql/src/external/MostlySimilarFile.qhelp deleted file mode 100644 index f0fd64c99ad..00000000000 --- a/csharp/ql/src/external/MostlySimilarFile.qhelp +++ /dev/null @@ -1,24 +0,0 @@ - - - -

    This rule identifies two files that have a lot of the same lines but with different variable and method -names. This makes it difficult to make changes in future and makes the code harder to read.

    - -
    - -

    It is important to determine why there are small differences in the files. Sometimes the files might have -been duplicates but an update was only applied to one copy. If this is the case it should be simple to merge -the files, preserving any changes.

    - -

    If the files are intentionally different then it could be a good idea to consider extracting some of the -shared code into a superclass or a separate utility class.

    - -
    - - -
  • Elmar Juergens, Florian Deissenboeck, Benjamin Hummel and Stefan Wagner. Do Code Clones Matter?. 2009.
  • - -
    -
    diff --git a/csharp/ql/src/external/MostlySimilarFile.ql b/csharp/ql/src/external/MostlySimilarFile.ql deleted file mode 100644 index a66df834aca..00000000000 --- a/csharp/ql/src/external/MostlySimilarFile.ql +++ /dev/null @@ -1,31 +0,0 @@ -/** - * @deprecated - * @name Mostly similar file - * @description There is another file that shares a lot of the code with this file. Notice that names of variables and types may have been changed. Merge the two files to improve maintainability. - * @kind problem - * @problem.severity recommendation - * @precision high - * @id cs/similar-file - * @tags testability - * maintainability - * useless-code - * duplicate-code - * statistical - * non-attributable - */ - -import csharp -import CodeDuplication - -predicate irrelevant(File f) { - f.getStem() = "AssemblyInfo" or - f.getStem().matches("%.Designer") -} - -from File f, File other, int percent -where - similarFiles(f, other, percent) and - not irrelevant(f) and - not irrelevant(other) -select f, percent + "% of the lines in " + f.getBaseName() + " are similar to lines in $@.", other, - other.getBaseName() diff --git a/csharp/ql/src/filters/ChangedLines.ql b/csharp/ql/src/filters/ChangedLines.ql deleted file mode 100644 index f97e60d4faf..00000000000 --- a/csharp/ql/src/filters/ChangedLines.ql +++ /dev/null @@ -1,20 +0,0 @@ -/** - * @name Filter: only keep results from source that have been changed since the base line - * @description Exclude results that have not changed since the base line. - * @id cs/changed-lines-filter - * @kind problem - */ - -import csharp -import external.ExternalArtifact -import external.DefectFilter -import ChangedLines - -from DefectResult res -where - changedLine(res.getFile(), res.getStartLine()) - or - changedLine(res.getFile(), res.getEndLine()) - or - res.getStartLine() = 0 and changedLine(res.getFile(), _) -select res, res.getMessage() diff --git a/csharp/ql/src/filters/ChangedLines.qll b/csharp/ql/src/filters/ChangedLines.qll deleted file mode 100644 index 75628dab020..00000000000 --- a/csharp/ql/src/filters/ChangedLines.qll +++ /dev/null @@ -1,12 +0,0 @@ -import csharp -import external.ExternalArtifact - -pragma[noopt] -predicate changedLine(File f, int line) { - exists(ExternalMetric metric, Location l | - exists(string s | s = "changedLines.ql" and metric.getQueryPath() = s) and - l = metric.getLocation() and - f = l.getFile() and - line = l.getStartLine() - ) -} diff --git a/csharp/ql/src/filters/ChangedLinesForMetric.ql b/csharp/ql/src/filters/ChangedLinesForMetric.ql deleted file mode 100644 index d04cc681a37..00000000000 --- a/csharp/ql/src/filters/ChangedLinesForMetric.ql +++ /dev/null @@ -1,15 +0,0 @@ -/** - * @name Filter: only keep results from source that have been changed since the base line - * @description Exclude results that have not changed since the base line. - * @id cs/changed-lines-metric-filter - * @kind treemap - */ - -import csharp -import external.ExternalArtifact -import external.MetricFilter -import ChangedLines - -from MetricResult res -where changedLine(res.getFile(), _) -select res, res.getValue() diff --git a/csharp/ql/src/filters/ClassifyFiles.ql b/csharp/ql/src/filters/ClassifyFiles.ql index 4277e321a1c..23b0994dcfa 100644 --- a/csharp/ql/src/filters/ClassifyFiles.ql +++ b/csharp/ql/src/filters/ClassifyFiles.ql @@ -2,6 +2,8 @@ * @name Classify files * @description This query produces a list of all files in a snapshot * that are classified as generated code or test code. + * + * Used by LGTM. * @kind file-classifier * @id cs/file-classifier */ diff --git a/csharp/ql/src/filters/FromSource.ql b/csharp/ql/src/filters/FromSource.ql deleted file mode 100644 index e19785afad9..00000000000 --- a/csharp/ql/src/filters/FromSource.ql +++ /dev/null @@ -1,13 +0,0 @@ -/** - * @name Filter: only keep results from source - * @description Exclude results that do not come from source code files. - * @kind problem - * @id cs/source-filter - */ - -import csharp -import external.DefectFilter - -from DefectResult res -where res.getFile().fromSource() -select res, res.getMessage() diff --git a/csharp/ql/src/filters/FromSourceForMetric.ql b/csharp/ql/src/filters/FromSourceForMetric.ql deleted file mode 100644 index 49e1d4a2f3c..00000000000 --- a/csharp/ql/src/filters/FromSourceForMetric.ql +++ /dev/null @@ -1,13 +0,0 @@ -/** - * @name Filter: only keep metric results from source - * @description Exclude results that do not come from source code files. - * @kind treemap - * @id cs/source-metric-filter - */ - -import csharp -import external.MetricFilter - -from MetricResult res -where res.getFile().fromSource() -select res, res.getValue() diff --git a/csharp/ql/src/filters/NotGenerated.ql b/csharp/ql/src/filters/NotGenerated.ql deleted file mode 100644 index 5e80ffe8e2e..00000000000 --- a/csharp/ql/src/filters/NotGenerated.ql +++ /dev/null @@ -1,13 +0,0 @@ -/** - * @name Filter: only keep results in non-generated files - * @description Exclude results that come from generated code. - * @kind problem - * @id cs/not-generated-file-filter - */ - -import semmle.code.csharp.commons.GeneratedCode -import external.DefectFilter - -from DefectResult res -where not isGeneratedCode(res.getFile()) -select res, res.getMessage() diff --git a/csharp/ql/src/filters/NotGeneratedForMetric.ql b/csharp/ql/src/filters/NotGeneratedForMetric.ql deleted file mode 100644 index ca6e7f8080f..00000000000 --- a/csharp/ql/src/filters/NotGeneratedForMetric.ql +++ /dev/null @@ -1,13 +0,0 @@ -/** - * @name Filter: only keep metric results in non-generated files - * @description Exclude results that come from generated code. - * @kind treemap - * @id cs/not-generated-file-metric-filter - */ - -import semmle.code.csharp.commons.GeneratedCode -import external.MetricFilter - -from MetricResult res -where not isGeneratedCode(res.getFile()) -select res, res.getValue() diff --git a/csharp/ql/src/filters/NotInTestFile.ql b/csharp/ql/src/filters/NotInTestFile.ql deleted file mode 100644 index 041163ef946..00000000000 --- a/csharp/ql/src/filters/NotInTestFile.ql +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @name Filter: only keep results that are outside of test files - * @description Exclude results in test files. - * @kind problem - * @id cs/test-file-filter - */ - -import csharp -import semmle.code.csharp.frameworks.Test -import external.DefectFilter - -from DefectResult res -where not res.getFile() instanceof TestFile -select res, res.getMessage() diff --git a/csharp/ql/src/filters/NotInTestFileForMetric.ql b/csharp/ql/src/filters/NotInTestFileForMetric.ql deleted file mode 100644 index 47b8e71253f..00000000000 --- a/csharp/ql/src/filters/NotInTestFileForMetric.ql +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @name Filter: only keep results that are outside of test files - * @description Exclude results in test files. - * @kind treemap - * @id cs/test-file-metric-filter - */ - -import csharp -import semmle.code.csharp.frameworks.Test -import external.MetricFilter - -from MetricResult res -where not res.getFile() instanceof TestFile -select res, res.getValue() diff --git a/csharp/ql/src/filters/NotInTestMethod.ql b/csharp/ql/src/filters/NotInTestMethod.ql deleted file mode 100644 index 2981b891380..00000000000 --- a/csharp/ql/src/filters/NotInTestMethod.ql +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @name Filter: only keep results that are outside of test methods - * @description Exclude results in test methods. - * @kind problem - * @id cs/test-method-filter - */ - -import csharp -import semmle.code.csharp.frameworks.Test -import external.DefectFilter - -from DefectResult res -where - not res.getFile() instanceof TestFile - or - not res.getStartLine() = res.getFile().(TestFile).lineInTestMethod() -select res, res.getMessage() diff --git a/csharp/ql/src/filters/NotInTestMethodExpectingException.ql b/csharp/ql/src/filters/NotInTestMethodExpectingException.ql deleted file mode 100644 index f4879211484..00000000000 --- a/csharp/ql/src/filters/NotInTestMethodExpectingException.ql +++ /dev/null @@ -1,24 +0,0 @@ -/** - * @name Filter: only keep results that are outside of a test method expecting an exception - * @description Exclude results in test methods expecting exceptions. - * @kind problem - * @id cs/test-method-exception-filter - */ - -import csharp -import semmle.code.csharp.frameworks.Test -import external.DefectFilter - -predicate ignoredLine(File f, int line) { - exists(TestMethod m | m.expectsException() | - f = m.getFile() and - line in [m.getLocation().getStartLine() .. m.getBody().getLocation().getEndLine()] - ) -} - -from DefectResult res -where - not res.getFile() instanceof TestFile - or - not ignoredLine(res.getFile(), res.getStartLine()) -select res, res.getMessage() diff --git a/csharp/ql/src/filters/UnchangedLines.ql b/csharp/ql/src/filters/UnchangedLines.ql deleted file mode 100644 index 89d43ac2561..00000000000 --- a/csharp/ql/src/filters/UnchangedLines.ql +++ /dev/null @@ -1,22 +0,0 @@ -/** - * @name Filter: only keep results from source that have not changed since the base line - * @description Complement of ChangedLines.ql. - * @kind problem - * @id cs/unchanged-lines-filter - */ - -import csharp -import external.ExternalArtifact -import external.DefectFilter -import ChangedLines - -from DefectResult res -where - not ( - changedLine(res.getFile(), res.getStartLine()) - or - changedLine(res.getFile(), res.getEndLine()) - or - res.getStartLine() = 0 and changedLine(res.getFile(), _) - ) -select res, res.getMessage() diff --git a/csharp/ql/src/filters/UnchangedLinesForMetric.ql b/csharp/ql/src/filters/UnchangedLinesForMetric.ql deleted file mode 100644 index b31b4cb5d56..00000000000 --- a/csharp/ql/src/filters/UnchangedLinesForMetric.ql +++ /dev/null @@ -1,15 +0,0 @@ -/** - * @name Filter: only keep results from source that have not changed since the base line - * @description Complement of ChangedLinesForMetric.ql. - * @kind treemap - * @id cs/unchanged-lines-metric-filter - */ - -import csharp -import external.ExternalArtifact -import external.MetricFilter -import ChangedLines - -from MetricResult res -where not changedLine(res.getFile(), _) -select res, res.getValue() diff --git a/csharp/ql/test/query-tests/Metrics/Dependencies/ExternalDependencies/File1.cs b/csharp/ql/test/query-tests/Metrics/Dependencies/ExternalDependencies/File1.cs deleted file mode 100644 index aff76d83b3f..00000000000 --- a/csharp/ql/test/query-tests/Metrics/Dependencies/ExternalDependencies/File1.cs +++ /dev/null @@ -1,30 +0,0 @@ -// semmle-extractor-options: /r:System.Collections.dll /r:System.Data.Common.dll /r:System.Runtime.Serialization.Primitives.dll /r:System.Private.Xml.dll /r:System.Xml.ReaderWriter.dll /r:System.Net.Primitives.dll /r:System.Net.Http.dll /r:System.Private.DataContractSerialization.dll /r:System.Runtime.Serialization.dll /r:System.ComponentModel.Primitives.dll - -using System.Collections.Generic; -using System.Net.Http; -using System.Xml; -using System.Runtime.Serialization.Json; -using System.Data; - -class C -{ - System.Net.Http.HttpClient client; - System.Xml.XmlReader reader; - IXmlJsonReaderInitializer init; - - [DataSysDescription("")] - void Test() - { - client = new HttpClient(); - var request = new HttpRequestMessage(); - client.SendAsync(request); - - Method(); - } - - List initializerList; - - void Method() - { - } -} diff --git a/csharp/ql/test/query-tests/Metrics/Dependencies/ExternalDependencies/File2.cs b/csharp/ql/test/query-tests/Metrics/Dependencies/ExternalDependencies/File2.cs deleted file mode 100644 index 8df4d961b26..00000000000 --- a/csharp/ql/test/query-tests/Metrics/Dependencies/ExternalDependencies/File2.cs +++ /dev/null @@ -1,5 +0,0 @@ - -class D -{ - System.Net.Http.HttpClient client; -} diff --git a/csharp/ql/test/query-tests/Metrics/Files/FLinesOfDuplicatedCode/file1.cs b/csharp/ql/test/query-tests/Metrics/Files/FLinesOfDuplicatedCode/file1.cs deleted file mode 100644 index a1af845b74d..00000000000 --- a/csharp/ql/test/query-tests/Metrics/Files/FLinesOfDuplicatedCode/file1.cs +++ /dev/null @@ -1,48 +0,0 @@ -// These are not counted as duplicates: - -using System; -using System; -using System; -using System; -using System; -using System; -using System; -using System; -using System; -using System; - -class C1 -{ - void f() - { - int a; - int b; - int c; - int d; - int e; - int f; - int g; - int h; - int i; - int j; - int k; - } -} - -class C2 -{ - void f() - { - int a; - int b; - int c; - int d; - int e; - int f; - int g; - int h; - int i; - int j; - int k; - } -} diff --git a/csharp/ql/test/query-tests/Metrics/Files/FLinesOfDuplicatedCode/file2.cs b/csharp/ql/test/query-tests/Metrics/Files/FLinesOfDuplicatedCode/file2.cs deleted file mode 100644 index 2ac99295c6b..00000000000 --- a/csharp/ql/test/query-tests/Metrics/Files/FLinesOfDuplicatedCode/file2.cs +++ /dev/null @@ -1,30 +0,0 @@ -// These are not counted as duplicates: - -using System; -using System; -using System; -using System; -using System; -using System; -using System; -using System; -using System; - -class C3 -{ - void f() - { - int a; - int b; - int c; - int d; - int e; - int f; - int g; - int h; - int i; - int j; - int k; - } -} - From 7e33b571c96b48afb1ae954e62277dd3d58dabc1 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 24 Mar 2021 20:18:24 +0100 Subject: [PATCH 345/725] C#: Add change note --- csharp/change-notes/2021-03-24-remove-legacy-queries.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 csharp/change-notes/2021-03-24-remove-legacy-queries.md diff --git a/csharp/change-notes/2021-03-24-remove-legacy-queries.md b/csharp/change-notes/2021-03-24-remove-legacy-queries.md new file mode 100644 index 00000000000..1cbcbb6a1a0 --- /dev/null +++ b/csharp/change-notes/2021-03-24-remove-legacy-queries.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* Legacy queries in the folders `external` and `filters` have all been removed. \ No newline at end of file From b94c189946e610ce5440d03c37030708dc614c68 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 24 Mar 2021 20:20:23 +0100 Subject: [PATCH 346/725] C#: Remove `VulnerablePackage.ql` query --- .../CWE-937/Vulnerabilities.qll | 335 ------------------ .../CWE-937/Vulnerability.qll | 93 ----- .../CWE-937/VulnerablePackage.qhelp | 43 --- .../CWE-937/VulnerablePackage.ql | 20 -- .../CWE-937/VulnerablePackageBAD.csproj | 15 - .../CWE-937/VulnerablePackageGOOD.csproj | 15 - .../Security Features/CWE-937/Program.cs | 0 .../CWE-937/VulnerablePackage.expected | 12 - .../CWE-937/VulnerablePackage.qlref | 1 - .../Security Features/CWE-937/csproj.config | 22 -- .../Security Features/CWE-937/packages.config | 13 - 11 files changed, 569 deletions(-) delete mode 100644 csharp/ql/src/Security Features/CWE-937/Vulnerabilities.qll delete mode 100644 csharp/ql/src/Security Features/CWE-937/Vulnerability.qll delete mode 100644 csharp/ql/src/Security Features/CWE-937/VulnerablePackage.qhelp delete mode 100644 csharp/ql/src/Security Features/CWE-937/VulnerablePackage.ql delete mode 100644 csharp/ql/src/Security Features/CWE-937/VulnerablePackageBAD.csproj delete mode 100644 csharp/ql/src/Security Features/CWE-937/VulnerablePackageGOOD.csproj delete mode 100644 csharp/ql/test/query-tests/Security Features/CWE-937/Program.cs delete mode 100644 csharp/ql/test/query-tests/Security Features/CWE-937/VulnerablePackage.expected delete mode 100644 csharp/ql/test/query-tests/Security Features/CWE-937/VulnerablePackage.qlref delete mode 100644 csharp/ql/test/query-tests/Security Features/CWE-937/csproj.config delete mode 100644 csharp/ql/test/query-tests/Security Features/CWE-937/packages.config diff --git a/csharp/ql/src/Security Features/CWE-937/Vulnerabilities.qll b/csharp/ql/src/Security Features/CWE-937/Vulnerabilities.qll deleted file mode 100644 index 86f32443cdb..00000000000 --- a/csharp/ql/src/Security Features/CWE-937/Vulnerabilities.qll +++ /dev/null @@ -1,335 +0,0 @@ -/** - * Provides a list of NuGet packages with known vulnerabilities. - * - * To add a new vulnerability follow the existing pattern. - * Create a new class that extends the abstract class `Vulnerability`, - * supplying the name and the URL, and override one (or both) of - * `matchesRange` and `matchesVersion`. - */ - -import csharp -import Vulnerability - -class MicrosoftAdvisory4021279 extends Vulnerability { - MicrosoftAdvisory4021279() { this = "Microsoft Security Advisory 4021279" } - - override string getUrl() { result = "https://github.com/dotnet/corefx/issues/19535" } - - override predicate matchesRange(string name, Version affected, Version fixed) { - name = "System.Text.Encodings.Web" and - ( - affected = "4.0.0" and fixed = "4.0.1" - or - affected = "4.3.0" and fixed = "4.3.1" - ) - or - name = "System.Net.Http" and - ( - affected = "4.1.1" and fixed = "4.1.2" - or - affected = "4.3.1" and fixed = "4.3.2" - ) - or - name = "System.Net.Http.WinHttpHandler" and - ( - affected = "4.0.1" and fixed = "4.0.2" - or - affected = "4.3.0" and fixed = "4.3.1" - ) - or - name = "System.Net.Security" and - ( - affected = "4.0.0" and fixed = "4.0.1" - or - affected = "4.3.0" and fixed = "4.3.1" - ) - or - ( - name = "Microsoft.AspNetCore.Mvc" - or - name = "Microsoft.AspNetCore.Mvc.Core" - or - name = "Microsoft.AspNetCore.Mvc.Abstractions" - or - name = "Microsoft.AspNetCore.Mvc.ApiExplorer" - or - name = "Microsoft.AspNetCore.Mvc.Cors" - or - name = "Microsoft.AspNetCore.Mvc.DataAnnotations" - or - name = "Microsoft.AspNetCore.Mvc.Formatters.Json" - or - name = "Microsoft.AspNetCore.Mvc.Formatters.Xml" - or - name = "Microsoft.AspNetCore.Mvc.Localization" - or - name = "Microsoft.AspNetCore.Mvc.Razor.Host" - or - name = "Microsoft.AspNetCore.Mvc.Razor" - or - name = "Microsoft.AspNetCore.Mvc.TagHelpers" - or - name = "Microsoft.AspNetCore.Mvc.ViewFeatures" - or - name = "Microsoft.AspNetCore.Mvc.WebApiCompatShim" - ) and - ( - affected = "1.0.0" and fixed = "1.0.4" - or - affected = "1.1.0" and fixed = "1.1.3" - ) - } -} - -class CVE_2017_8700 extends Vulnerability { - CVE_2017_8700() { this = "CVE-2017-8700" } - - override string getUrl() { result = "https://github.com/aspnet/Announcements/issues/279" } - - override predicate matchesRange(string name, Version affected, Version fixed) { - ( - name = "Microsoft.AspNetCore.Mvc.Core" - or - name = "Microsoft.AspNetCore.Mvc.Cors" - ) and - ( - affected = "1.0.0" and fixed = "1.0.6" - or - affected = "1.1.0" and fixed = "1.1.6" - ) - } -} - -class CVE_2018_0765 extends Vulnerability { - CVE_2018_0765() { this = "CVE-2018-0765" } - - override string getUrl() { result = "https://github.com/dotnet/announcements/issues/67" } - - override predicate matchesRange(string name, Version affected, Version fixed) { - name = "System.Security.Cryptography.Xml" and - affected = "0.0.0" and - fixed = "4.4.2" - } -} - -class AspNetCore_Mar18 extends Vulnerability { - AspNetCore_Mar18() { this = "ASPNETCore-Mar18" } - - override string getUrl() { result = "https://github.com/aspnet/Announcements/issues/300" } - - override predicate matchesRange(string name, Version affected, Version fixed) { - ( - name = "Microsoft.AspNetCore.Server.Kestrel.Core" - or - name = "Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions" - or - name = "Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv" - ) and - affected = "2.0.0" and - fixed = "2.0.3" - or - name = "Microsoft.AspNetCore.All" and - affected = "2.0.0" and - fixed = "2.0.8" - } -} - -class CVE_2018_8409 extends Vulnerability { - CVE_2018_8409() { this = "CVE-2018-8409" } - - override string getUrl() { result = "https://github.com/aspnet/Announcements/issues/316" } - - override predicate matchesRange(string name, Version affected, Version fixed) { - name = "System.IO.Pipelines" and affected = "4.5.0" and fixed = "4.5.1" - or - (name = "Microsoft.AspNetCore.All" or name = "Microsoft.AspNetCore.App") and - affected = "2.1.0" and - fixed = "2.1.4" - } -} - -class CVE_2018_8171 extends Vulnerability { - CVE_2018_8171() { this = "CVE-2018-8171" } - - override string getUrl() { result = "https://github.com/aspnet/Announcements/issues/310" } - - override predicate matchesRange(string name, Version affected, Version fixed) { - name = "Microsoft.AspNetCore.Identity" and - ( - affected = "1.0.0" and fixed = "1.0.6" - or - affected = "1.1.0" and fixed = "1.1.6" - or - affected = "2.0.0" and fixed = "2.0.4" - or - affected = "2.1.0" and fixed = "2.1.2" - ) - } -} - -class CVE_2018_8356 extends Vulnerability { - CVE_2018_8356() { this = "CVE-2018-8356" } - - override string getUrl() { result = "https://github.com/dotnet/announcements/issues/73" } - - override predicate matchesRange(string name, Version affected, Version fixed) { - ( - name = "System.Private.ServiceModel" - or - name = "System.ServiceModel.Http" - or - name = "System.ServiceModel.NetTcp" - ) and - ( - affected = "4.0.0" and fixed = "4.1.3" - or - affected = "4.3.0" and fixed = "4.3.3" - or - affected = "4.4.0" and fixed = "4.4.4" - or - affected = "4.5.0" and fixed = "4.5.3" - ) - or - ( - name = "System.ServiceModel.Duplex" - or - name = "System.ServiceModel.Security" - ) and - ( - affected = "4.0.0" and fixed = "4.0.4" - or - affected = "4.3.0" and fixed = "4.3.3" - or - affected = "4.4.0" and fixed = "4.4.4" - or - affected = "4.5.0" and fixed = "4.5.3" - ) - or - name = "System.ServiceModel.NetTcp" and - ( - affected = "4.0.0" and fixed = "4.1.3" - or - affected = "4.3.0" and fixed = "4.3.3" - or - affected = "4.4.0" and fixed = "4.4.4" - or - affected = "4.5.0" and fixed = "4.5.1" - ) - } -} - -class ASPNETCore_Jul18 extends Vulnerability { - ASPNETCore_Jul18() { this = "ASPNETCore-July18" } - - override string getUrl() { result = "https://github.com/aspnet/Announcements/issues/311" } - - override predicate matchesRange(string name, Version affected, Version fixed) { - name = "Microsoft.AspNetCore.Server.Kestrel.Core" and - ( - affected = "2.0.0" and fixed = "2.0.4" - or - affected = "2.1.0" and fixed = "2.1.2" - ) - or - name = "Microsoft.AspNetCore.All" and - ( - affected = "2.0.0" and fixed = "2.0.9" - or - affected = "2.1.0" and fixed = "2.1.2" - ) - or - name = "Microsoft.AspNetCore.App" and - affected = "2.1.0" and - fixed = "2.1.2" - } -} - -class CVE_2018_8292 extends Vulnerability { - CVE_2018_8292() { this = "CVE-2018-8292" } - - override string getUrl() { result = "https://github.com/dotnet/announcements/issues/88" } - - override predicate matchesVersion(string name, Version affected, Version fixed) { - name = "System.Net.Http" and - ( - affected = "2.0" or - affected = "4.0.0" or - affected = "4.1.0" or - affected = "1.1.1" or - affected = "4.1.2" or - affected = "4.3.0" or - affected = "4.3.1" or - affected = "4.3.2" or - affected = "4.3.3" - ) and - fixed = "4.3.4" - } -} - -class CVE_2018_0786 extends Vulnerability { - CVE_2018_0786() { this = "CVE-2018-0786" } - - override string getUrl() { result = "https://github.com/dotnet/announcements/issues/51" } - - override predicate matchesRange(string name, Version affected, Version fixed) { - ( - name = "System.ServiceModel.Primitives" - or - name = "System.ServiceModel.Http" - or - name = "System.ServiceModel.NetTcp" - or - name = "System.ServiceModel.Duplex" - or - name = "System.ServiceModel.Security" - or - name = "System.Private.ServiceModel" - ) and - ( - affected = "4.4.0" and fixed = "4.4.1" - or - affected = "4.3.0" and fixed = "4.3.1" - ) - or - ( - name = "System.ServiceModel.Primitives" - or - name = "System.ServiceModel.Http" - or - name = "System.ServiceModel.NetTcp" - or - name = "System.Private.ServiceModel" - ) and - affected = "4.1.0" and - fixed = "4.1.1" - or - ( - name = "System.ServiceModel.Duplex" - or - name = "System.ServiceModel.Security" - ) and - affected = "4.0.1" and - fixed = "4.0.2" - } -} - -class CVE_2019_0657 extends Vulnerability { - CVE_2019_0657() { this = "CVE-2019-0657" } - - override predicate matchesRange(string name, Version affected, Version fixed) { - name = "Microsoft.NETCore.App" and - ( - affected = "2.1.0" and fixed = "2.1.8" - or - affected = "2.2.0" and fixed = "2.2.2" - ) - } - - override predicate matchesVersion(string name, Version affected, Version fixed) { - name = "System.Private.Uri" and - affected = "4.3.0" and - fixed = "4.3.1" - } - - override string getUrl() { result = "https://github.com/dotnet/announcements/issues/97" } -} diff --git a/csharp/ql/src/Security Features/CWE-937/Vulnerability.qll b/csharp/ql/src/Security Features/CWE-937/Vulnerability.qll deleted file mode 100644 index a2c6d482c1c..00000000000 --- a/csharp/ql/src/Security Features/CWE-937/Vulnerability.qll +++ /dev/null @@ -1,93 +0,0 @@ -import csharp - -/** - * A package reference in an XML file, for example in a - * `.csproj` file, a `.props` file, or a `packages.config` file. - */ -class Package extends XMLElement { - string name; - Version version; - - Package() { - (this.getName() = "PackageManagement" or this.getName() = "PackageReference") and - name = this.getAttributeValue("Include") and - version = this.getAttributeValue("Version") - or - this.getName() = "package" and - name = this.getAttributeValue("id") and - version = this.getAttributeValue("version") - } - - /** Gets the name of the package, for example `System.IO.Pipelines`. */ - string getPackageName() { result = name } - - /** Gets the version of the package, for example `4.5.1`. */ - Version getVersion() { result = version } - - override string toString() { result = name + " " + version } -} - -/** - * A vulnerability, where the name of the vulnerability is this string. - * One of `matchesRange` or `matchesVersion` must be overridden in order to - * specify which packages are vulnerable. - */ -abstract class Vulnerability extends string { - bindingset[this] - Vulnerability() { any() } - - /** - * Holds if a package with name `name` is vulnerable from version `affected` - * until version `fixed`. - */ - predicate matchesRange(string name, Version affected, Version fixed) { none() } - - /** - * Holds if a package with name `name` is vulnerable in version `affected`, and - * is fixed by version `fixed`. - */ - predicate matchesVersion(string name, Version affected, Version fixed) { none() } - - /** Gets the URL describing the vulnerability. */ - abstract string getUrl(); - - /** - * Holds if a package with name `name` and version `version` - * has this vulnerability. The fixed version is given by `fixed`. - */ - bindingset[name, version] - predicate isVulnerable(string name, Version version, Version fixed) { - exists(Version affected, string n | name.toLowerCase() = n.toLowerCase() | - matchesRange(n, affected, fixed) and - version.compareTo(fixed) < 0 and - version.compareTo(affected) >= 0 - or - matchesVersion(n, affected, fixed) and - version.compareTo(affected) = 0 - ) - } -} - -bindingset[name, version] -private Version getUltimateFix(string name, Version version) { - result = max(Version fix | any(Vulnerability v).isVulnerable(name, version, fix)) -} - -/** - * A package with a vulnerability. - */ -class VulnerablePackage extends Package { - Vulnerability vuln; - - VulnerablePackage() { vuln.isVulnerable(this.getPackageName(), this.getVersion(), _) } - - /** Gets the vulnerability of this package. */ - Vulnerability getVulnerability() { result = vuln } - - /** Gets the version of this package where the vulnerability is fixed. */ - Version getFixedVersion() { - // This is needed because sometimes the "fixed" version of some - // vulnerabilities are themselves vulnerable to other vulnerabilities. - result = getUltimateFix(this.getPackageName(), this.getVersion()) - } -} diff --git a/csharp/ql/src/Security Features/CWE-937/VulnerablePackage.qhelp b/csharp/ql/src/Security Features/CWE-937/VulnerablePackage.qhelp deleted file mode 100644 index 112642c7958..00000000000 --- a/csharp/ql/src/Security Features/CWE-937/VulnerablePackage.qhelp +++ /dev/null @@ -1,43 +0,0 @@ - - - - -

    -Using a package with a known vulnerability is a security risk that could leave the -software vulnerable to attack. -

    -

    -This query reads the packages imported by the project build files and -.config files, and checks them against a list of packages with known -vulnerabilities. -

    -
    - - -

    -Upgrade the package to the recommended version using, for example, the NuGet package manager, -or by editing the project files directly. -

    -
    - - -

    -The following example shows a C# project file referencing package System.Net.Http -version 4.3.1, which is vulnerable to CVE-2018-8292. -

    - -

    -The project file can be fixed by changing the version of the package to 4.3.4. -

    - -
    - - -
  • -OWASP: A9-Using Components with Known Vulnerabilities. -
  • -
    - -
    diff --git a/csharp/ql/src/Security Features/CWE-937/VulnerablePackage.ql b/csharp/ql/src/Security Features/CWE-937/VulnerablePackage.ql deleted file mode 100644 index 4be7c76dd7b..00000000000 --- a/csharp/ql/src/Security Features/CWE-937/VulnerablePackage.ql +++ /dev/null @@ -1,20 +0,0 @@ -/** - * @name Using a package with a known vulnerability - * @description Using a package with a known vulnerability is a security risk. - * Upgrade the package to a version that does not contain the vulnerability. - * @kind problem - * @problem.severity error - * @precision high - * @id cs/use-of-vulnerable-package - * @tags security - * external/cwe/cwe-937 - */ - -import csharp -import Vulnerabilities - -from Vulnerability vuln, VulnerablePackage package -where vuln = package.getVulnerability() -select package, - "Package '" + package + "' has vulnerability $@, and should be upgraded to version " + - package.getFixedVersion() + ".", vuln.getUrl(), vuln.toString() diff --git a/csharp/ql/src/Security Features/CWE-937/VulnerablePackageBAD.csproj b/csharp/ql/src/Security Features/CWE-937/VulnerablePackageBAD.csproj deleted file mode 100644 index b13494984ec..00000000000 --- a/csharp/ql/src/Security Features/CWE-937/VulnerablePackageBAD.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - - netcoreapp2.0 - Semmle.Autobuild - Semmle.Autobuild - Exe - - - - - - - - diff --git a/csharp/ql/src/Security Features/CWE-937/VulnerablePackageGOOD.csproj b/csharp/ql/src/Security Features/CWE-937/VulnerablePackageGOOD.csproj deleted file mode 100644 index 98275b86a6f..00000000000 --- a/csharp/ql/src/Security Features/CWE-937/VulnerablePackageGOOD.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - - netcoreapp2.0 - Semmle.Autobuild - Semmle.Autobuild - Exe - - - - - - - - diff --git a/csharp/ql/test/query-tests/Security Features/CWE-937/Program.cs b/csharp/ql/test/query-tests/Security Features/CWE-937/Program.cs deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/csharp/ql/test/query-tests/Security Features/CWE-937/VulnerablePackage.expected b/csharp/ql/test/query-tests/Security Features/CWE-937/VulnerablePackage.expected deleted file mode 100644 index 8aeb3d517e0..00000000000 --- a/csharp/ql/test/query-tests/Security Features/CWE-937/VulnerablePackage.expected +++ /dev/null @@ -1,12 +0,0 @@ -| csproj.config:4:5:4:77 | System.Text.Encodings.Web 4.3.0 | Package 'System.Text.Encodings.Web 4.3.0' has vulnerability $@, and should be upgraded to version 4.3.1. | https://github.com/dotnet/corefx/issues/19535 | Microsoft Security Advisory 4021279 | -| csproj.config:5:5:5:75 | system.text.encodings.web 4.3 | Package 'system.text.encodings.web 4.3' has vulnerability $@, and should be upgraded to version 4.3.1. | https://github.com/dotnet/corefx/issues/19535 | Microsoft Security Advisory 4021279 | -| csproj.config:6:5:6:67 | System.Net.Http 4.1.1 | Package 'System.Net.Http 4.1.1' has vulnerability $@, and should be upgraded to version 4.1.2. | https://github.com/dotnet/corefx/issues/19535 | Microsoft Security Advisory 4021279 | -| csproj.config:7:5:7:67 | System.Net.Http 4.1.2 | Package 'System.Net.Http 4.1.2' has vulnerability $@, and should be upgraded to version 4.3.4. | https://github.com/dotnet/announcements/issues/88 | CVE-2018-8292 | -| csproj.config:8:5:8:70 | System.Private.Uri 4.3.0 | Package 'System.Private.Uri 4.3.0' has vulnerability $@, and should be upgraded to version 4.3.1. | https://github.com/dotnet/announcements/issues/97 | CVE-2019-0657 | -| csproj.config:9:5:9:73 | Microsoft.NETCore.App 2.1.0 | Package 'Microsoft.NETCore.App 2.1.0' has vulnerability $@, and should be upgraded to version 2.1.8. | https://github.com/dotnet/announcements/issues/97 | CVE-2019-0657 | -| csproj.config:10:5:10:73 | Microsoft.NETCore.App 2.2.1 | Package 'Microsoft.NETCore.App 2.2.1' has vulnerability $@, and should be upgraded to version 2.2.2. | https://github.com/dotnet/announcements/issues/97 | CVE-2019-0657 | -| packages.config:9:3:9:79 | System.IO.Pipelines 4.5.0 | Package 'System.IO.Pipelines 4.5.0' has vulnerability $@, and should be upgraded to version 4.5.1. | https://github.com/aspnet/Announcements/issues/316 | CVE-2018-8409 | -| packages.config:10:3:10:81 | System.IO.Pipelines 4.5.0.0 | Package 'System.IO.Pipelines 4.5.0.0' has vulnerability $@, and should be upgraded to version 4.5.1. | https://github.com/aspnet/Announcements/issues/316 | CVE-2018-8409 | -| packages.config:11:3:11:84 | microsoft.aspnetcore.all 2.0.0 | Package 'microsoft.aspnetcore.all 2.0.0' has vulnerability $@, and should be upgraded to version 2.0.9. | https://github.com/aspnet/Announcements/issues/300 | ASPNETCore-Mar18 | -| packages.config:11:3:11:84 | microsoft.aspnetcore.all 2.0.0 | Package 'microsoft.aspnetcore.all 2.0.0' has vulnerability $@, and should be upgraded to version 2.0.9. | https://github.com/aspnet/Announcements/issues/311 | ASPNETCore-July18 | -| packages.config:12:3:12:84 | Microsoft.AspNetCore.All 2.0.8 | Package 'Microsoft.AspNetCore.All 2.0.8' has vulnerability $@, and should be upgraded to version 2.0.9. | https://github.com/aspnet/Announcements/issues/311 | ASPNETCore-July18 | diff --git a/csharp/ql/test/query-tests/Security Features/CWE-937/VulnerablePackage.qlref b/csharp/ql/test/query-tests/Security Features/CWE-937/VulnerablePackage.qlref deleted file mode 100644 index fb8a73b25f9..00000000000 --- a/csharp/ql/test/query-tests/Security Features/CWE-937/VulnerablePackage.qlref +++ /dev/null @@ -1 +0,0 @@ -Security Features/CWE-937/VulnerablePackage.ql \ No newline at end of file diff --git a/csharp/ql/test/query-tests/Security Features/CWE-937/csproj.config b/csharp/ql/test/query-tests/Security Features/CWE-937/csproj.config deleted file mode 100644 index 114d0631ba3..00000000000 --- a/csharp/ql/test/query-tests/Security Features/CWE-937/csproj.config +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/csharp/ql/test/query-tests/Security Features/CWE-937/packages.config b/csharp/ql/test/query-tests/Security Features/CWE-937/packages.config deleted file mode 100644 index 12f63f71043..00000000000 --- a/csharp/ql/test/query-tests/Security Features/CWE-937/packages.config +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - From b83da2255c47de55cfac531748eae4d535f6af7e Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 24 Mar 2021 20:22:01 +0100 Subject: [PATCH 347/725] C#: Add change note --- csharp/change-notes/2021-03-24-remove-vuln-package-query.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 csharp/change-notes/2021-03-24-remove-vuln-package-query.md diff --git a/csharp/change-notes/2021-03-24-remove-vuln-package-query.md b/csharp/change-notes/2021-03-24-remove-vuln-package-query.md new file mode 100644 index 00000000000..2a211823b39 --- /dev/null +++ b/csharp/change-notes/2021-03-24-remove-vuln-package-query.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* The query `VulnerablePackage.ql` has been removed. \ No newline at end of file From 419fbe77abf2df7f9430f3ff96ca32722ad2074c Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 24 Mar 2021 20:31:02 +0100 Subject: [PATCH 348/725] C#: Remove `@precision` tags from metric queries --- csharp/ql/src/Metrics/Dependencies/ExternalDependencies.ql | 1 - csharp/ql/src/Metrics/Files/FLinesOfCode.ql | 1 - csharp/ql/src/Metrics/Files/FLinesOfComment.ql | 1 - csharp/ql/src/Metrics/Files/FLinesOfCommentedCode.ql | 1 - csharp/ql/src/Metrics/Files/FNumberOfTests.ql | 1 - 5 files changed, 5 deletions(-) diff --git a/csharp/ql/src/Metrics/Dependencies/ExternalDependencies.ql b/csharp/ql/src/Metrics/Dependencies/ExternalDependencies.ql index 6139262afd3..87e7d3a5cf6 100644 --- a/csharp/ql/src/Metrics/Dependencies/ExternalDependencies.ql +++ b/csharp/ql/src/Metrics/Dependencies/ExternalDependencies.ql @@ -5,7 +5,6 @@ * @kind treemap * @treemap.warnOn highValues * @metricType externalDependency - * @precision medium * @id cs/external-dependencies */ diff --git a/csharp/ql/src/Metrics/Files/FLinesOfCode.ql b/csharp/ql/src/Metrics/Files/FLinesOfCode.ql index 7aa709b2579..93f426d6329 100644 --- a/csharp/ql/src/Metrics/Files/FLinesOfCode.ql +++ b/csharp/ql/src/Metrics/Files/FLinesOfCode.ql @@ -5,7 +5,6 @@ * @treemap.warnOn highValues * @metricType file * @metricAggregate avg sum max - * @precision very-high * @id cs/lines-of-code-in-files * @tags maintainability * complexity diff --git a/csharp/ql/src/Metrics/Files/FLinesOfComment.ql b/csharp/ql/src/Metrics/Files/FLinesOfComment.ql index 2071b86ad7a..0686268169f 100644 --- a/csharp/ql/src/Metrics/Files/FLinesOfComment.ql +++ b/csharp/ql/src/Metrics/Files/FLinesOfComment.ql @@ -5,7 +5,6 @@ * @treemap.warnOn lowValues * @metricType file * @metricAggregate avg sum max - * @precision very-high * @id cs/lines-of-comments-in-files * @tags maintainability * documentation diff --git a/csharp/ql/src/Metrics/Files/FLinesOfCommentedCode.ql b/csharp/ql/src/Metrics/Files/FLinesOfCommentedCode.ql index 7e88ef5e91b..e84100b8928 100644 --- a/csharp/ql/src/Metrics/Files/FLinesOfCommentedCode.ql +++ b/csharp/ql/src/Metrics/Files/FLinesOfCommentedCode.ql @@ -5,7 +5,6 @@ * @treemap.warnOn highValues * @metricType file * @metricAggregate avg sum max - * @precision high * @id cs/lines-of-commented-out-code-in-files * @tags maintainability * documentation diff --git a/csharp/ql/src/Metrics/Files/FNumberOfTests.ql b/csharp/ql/src/Metrics/Files/FNumberOfTests.ql index 613c76c68af..f7abfc24a91 100644 --- a/csharp/ql/src/Metrics/Files/FNumberOfTests.ql +++ b/csharp/ql/src/Metrics/Files/FNumberOfTests.ql @@ -5,7 +5,6 @@ * @treemap.warnOn highValues * @metricType file * @metricAggregate avg sum max - * @precision medium * @id cs/tests-in-files * @tags maintainability */ From 4b7440d4d5f410b6e7aa37b2fb2c74c16ac829ce Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Thu, 25 Mar 2021 09:52:05 +0100 Subject: [PATCH 349/725] Java: Remove precision tag from metric queries. --- java/ql/src/Metrics/Dependencies/ExternalDependencies.ql | 1 - java/ql/src/Metrics/Files/FLinesOfCode.ql | 1 - java/ql/src/Metrics/Files/FLinesOfComment.ql | 1 - java/ql/src/Metrics/Files/FLinesOfCommentedCode.ql | 1 - java/ql/src/Metrics/Files/FLinesOfDuplicatedCode.ql | 1 - java/ql/src/Metrics/Files/FNumberOfTests.ql | 1 - 6 files changed, 6 deletions(-) diff --git a/java/ql/src/Metrics/Dependencies/ExternalDependencies.ql b/java/ql/src/Metrics/Dependencies/ExternalDependencies.ql index 79fd9db7557..f3cb1b5ce9a 100644 --- a/java/ql/src/Metrics/Dependencies/ExternalDependencies.ql +++ b/java/ql/src/Metrics/Dependencies/ExternalDependencies.ql @@ -5,7 +5,6 @@ * @kind treemap * @treemap.warnOn highValues * @metricType externalDependency - * @precision medium * @id java/external-dependencies */ diff --git a/java/ql/src/Metrics/Files/FLinesOfCode.ql b/java/ql/src/Metrics/Files/FLinesOfCode.ql index 45bea0faf4c..5c8436a18d8 100644 --- a/java/ql/src/Metrics/Files/FLinesOfCode.ql +++ b/java/ql/src/Metrics/Files/FLinesOfCode.ql @@ -5,7 +5,6 @@ * @treemap.warnOn highValues * @metricType file * @metricAggregate avg sum max - * @precision very-high * @id java/lines-of-code-in-files * @tags maintainability * complexity diff --git a/java/ql/src/Metrics/Files/FLinesOfComment.ql b/java/ql/src/Metrics/Files/FLinesOfComment.ql index ee2c21f0d9f..da9560516a3 100644 --- a/java/ql/src/Metrics/Files/FLinesOfComment.ql +++ b/java/ql/src/Metrics/Files/FLinesOfComment.ql @@ -5,7 +5,6 @@ * @treemap.warnOn lowValues * @metricType file * @metricAggregate avg sum max - * @precision very-high * @id java/lines-of-comments-in-files * @tags maintainability * documentation diff --git a/java/ql/src/Metrics/Files/FLinesOfCommentedCode.ql b/java/ql/src/Metrics/Files/FLinesOfCommentedCode.ql index d6fd316a2d9..62054ccfb87 100644 --- a/java/ql/src/Metrics/Files/FLinesOfCommentedCode.ql +++ b/java/ql/src/Metrics/Files/FLinesOfCommentedCode.ql @@ -5,7 +5,6 @@ * @treemap.warnOn highValues * @metricType file * @metricAggregate avg sum max - * @precision high * @id java/lines-of-commented-out-code-in-files * @tags maintainability * documentation diff --git a/java/ql/src/Metrics/Files/FLinesOfDuplicatedCode.ql b/java/ql/src/Metrics/Files/FLinesOfDuplicatedCode.ql index f6e99fa6b4b..2dda34289d7 100644 --- a/java/ql/src/Metrics/Files/FLinesOfDuplicatedCode.ql +++ b/java/ql/src/Metrics/Files/FLinesOfDuplicatedCode.ql @@ -7,7 +7,6 @@ * @treemap.warnOn highValues * @metricType file * @metricAggregate avg sum max - * @precision high * @id java/duplicated-lines-in-files * @tags testability * modularity diff --git a/java/ql/src/Metrics/Files/FNumberOfTests.ql b/java/ql/src/Metrics/Files/FNumberOfTests.ql index dc9ed989ef8..c37a4f88298 100644 --- a/java/ql/src/Metrics/Files/FNumberOfTests.ql +++ b/java/ql/src/Metrics/Files/FNumberOfTests.ql @@ -5,7 +5,6 @@ * @treemap.warnOn lowValues * @metricType file * @metricAggregate avg sum max - * @precision medium * @id java/tests-in-files * @tags maintainability */ From 3e67ebacb085a27c0a461be727a342c1da616c16 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 13 Nov 2020 21:14:56 +0000 Subject: [PATCH 350/725] JS: Support lodash-es --- .../src/semmle/javascript/frameworks/LodashUnderscore.qll | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/LodashUnderscore.qll b/javascript/ql/src/semmle/javascript/frameworks/LodashUnderscore.qll index bca3c7b606b..c05dbc3a8d6 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/LodashUnderscore.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/LodashUnderscore.qll @@ -21,11 +21,9 @@ module LodashUnderscore { string name; DefaultMember() { - this = DataFlow::moduleMember("underscore", name) + this = DataFlow::moduleMember(["underscore", "lodash", "lodash-es"], name) or - this = DataFlow::moduleMember("lodash", name) - or - this = DataFlow::moduleImport("lodash/" + name) + this = DataFlow::moduleImport(["lodash/", "lodash-es/"] + name) or this = DataFlow::moduleImport("lodash." + name.toLowerCase()) and isLodashMember(name) or From 5d9778c64dd9b58b4e946206f775eb74effe5017 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 22 Jan 2021 16:05:55 +0000 Subject: [PATCH 351/725] JS: Step through babel.transform --- .../src/semmle/javascript/frameworks/Babel.qll | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Babel.qll b/javascript/ql/src/semmle/javascript/frameworks/Babel.qll index 4a66fdd6d10..02a57d25a37 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Babel.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Babel.qll @@ -188,4 +188,20 @@ module Babel { /** Gets the name of the variable used to create JSX elements. */ string getJsxFactoryVariableName() { result = getOption("pragma").(JSONString).getValue() } } + + /** + * A taint step through a call to the Babel `transform` function. + */ + private class TransformTaintStep extends TaintTracking::SharedTaintStep { + override predicate step(DataFlow::Node pred, DataFlow::Node succ) { + exists(DataFlow::CallNode call | + call = + API::moduleImport(["@babel/standalone", "@babel/core"]) + .getMember(["transform", "transformSync"]) + .getACall() and + pred = call.getArgument(0) and + succ = call + ) + } + } } From 51f489211bd834ca18dee72b6cafb858c8125e08 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 25 Jan 2021 15:01:04 +0000 Subject: [PATCH 352/725] JS: Support react-native-base64 --- javascript/ql/src/semmle/javascript/Base64.qll | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Base64.qll b/javascript/ql/src/semmle/javascript/Base64.qll index 639dab85b29..f2e91a7060c 100644 --- a/javascript/ql/src/semmle/javascript/Base64.qll +++ b/javascript/ql/src/semmle/javascript/Base64.qll @@ -150,7 +150,8 @@ private class NpmBase64Encode extends Base64::Encode::Range, DataFlow::CallNode enc = DataFlow::moduleMember("base64url", "toBase64") or enc = DataFlow::moduleMember("js-base64", "Base64").getAPropertyRead("encode") or enc = DataFlow::moduleMember("js-base64", "Base64").getAPropertyRead("encodeURI") or - enc = DataFlow::moduleMember("urlsafe-base64", "encode") + enc = DataFlow::moduleMember("urlsafe-base64", "encode") or + enc = DataFlow::moduleMember("react-native-base64", ["encode", "encodeFromByteArray"]) | this = enc.getACall() ) @@ -186,7 +187,8 @@ private class NpmBase64Decode extends Base64::Decode::Range, DataFlow::CallNode dec = DataFlow::moduleMember("base64url", "decode") or dec = DataFlow::moduleMember("base64url", "fromBase64") or dec = DataFlow::moduleMember("js-base64", "Base64").getAPropertyRead("decode") or - dec = DataFlow::moduleMember("urlsafe-base64", "decode") + dec = DataFlow::moduleMember("urlsafe-base64", "decode") or + dec = DataFlow::moduleMember("react-native-base64", "decode") | this = dec.getACall() ) From bd3f6d12345a2abee4e49e752be1db9adebb956a Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Sat, 23 Jan 2021 10:07:00 +0000 Subject: [PATCH 353/725] JS: Add `o[o.length] = y` taint step --- .../javascript/dataflow/TaintTracking.qll | 20 +++++++++++-------- .../TaintTracking/BasicTaintTracking.expected | 1 + .../TaintTracking/array-mutation.js | 4 ++++ 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll index 805f3a832a6..d5bea527183 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll @@ -584,22 +584,26 @@ module TaintTracking { /** * A taint propagating data flow edge for assignments of the form `o[k] = v`, where - * `k` is not a constant and `o` refers to some object literal; in this case, we consider - * taint to flow from `v` to that object literal. + * one of the following holds: * - * The rationale for this heuristic is that if properties of `o` are accessed by - * computed (that is, non-constant) names, then `o` is most likely being treated as - * a map, not as a real object. In this case, it makes sense to consider the entire - * map to be tainted as soon as one of its entries is. + * - `k` is not a constant and `o` refers to some object literal. The rationale + * here is that `o` is most likely being used like a dictionary object. + * + * - `k` refers to `o.length`, that is, the assignment is of form `o[o.length] = v`. + * In this case, the assignment behaves like `o.push(v)`. */ - private class DictionaryTaintStep extends SharedTaintStep { + private class ComputedPropWriteTaintStep extends SharedTaintStep { override predicate heapStep(DataFlow::Node pred, DataFlow::Node succ) { - exists(AssignExpr assgn, IndexExpr idx, DataFlow::ObjectLiteralNode obj | + exists(AssignExpr assgn, IndexExpr idx, DataFlow::SourceNode obj | assgn.getTarget() = idx and obj.flowsToExpr(idx.getBase()) and not exists(idx.getPropertyName()) and pred = DataFlow::valueNode(assgn.getRhs()) and succ = obj + | + obj instanceof DataFlow::ObjectLiteralNode + or + obj.getAPropertyRead("length").flowsToExpr(idx.getPropertyNameExpr()) ) } } diff --git a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected index 5814218864b..fe0663b2ada 100644 --- a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected @@ -11,6 +11,7 @@ typeInferenceMismatch | array-mutation.js:27:16:27:23 | source() | array-mutation.js:28:8:28:8 | g | | array-mutation.js:31:33:31:40 | source() | array-mutation.js:32:8:32:8 | h | | array-mutation.js:35:36:35:43 | source() | array-mutation.js:36:8:36:8 | i | +| array-mutation.js:39:17:39:24 | source() | array-mutation.js:40:8:40:8 | j | | booleanOps.js:2:11:2:18 | source() | booleanOps.js:4:8:4:8 | x | | booleanOps.js:2:11:2:18 | source() | booleanOps.js:13:10:13:10 | x | | booleanOps.js:2:11:2:18 | source() | booleanOps.js:19:10:19:10 | x | diff --git a/javascript/ql/test/library-tests/TaintTracking/array-mutation.js b/javascript/ql/test/library-tests/TaintTracking/array-mutation.js index 17657915625..cc581d34a25 100644 --- a/javascript/ql/test/library-tests/TaintTracking/array-mutation.js +++ b/javascript/ql/test/library-tests/TaintTracking/array-mutation.js @@ -34,4 +34,8 @@ function test(x, y) { let i = []; Array.prototype.unshift.apply(i, source()); sink(i); // NOT OK + + let j = []; + j[j.length] = source(); + sink(j); // NOT OK } From dbc6cf63c20783606f4cc0f703ba69cba92c1e4b Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 25 Mar 2021 08:58:28 +0000 Subject: [PATCH 354/725] JS: Fix bad join order in PropertyProjection --- .../frameworks/PropertyProjection.qll | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/PropertyProjection.qll b/javascript/ql/src/semmle/javascript/frameworks/PropertyProjection.qll index 1217c8de3db..e3fe62be164 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/PropertyProjection.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/PropertyProjection.qll @@ -75,10 +75,6 @@ private DataFlow::SourceNode getASimplePropertyProjectionCallee( ) { singleton = false and ( - result = LodashUnderscore::member("pick") and - objectIndex = 0 and - selectorIndex = [1 .. max(result.getACall().getNumArgument())] - or result = LodashUnderscore::member("pickBy") and objectIndex = 0 and selectorIndex = 1 @@ -131,6 +127,19 @@ private class SimplePropertyProjection extends PropertyProjection::Range { override predicate isSingletonProjection() { singleton = true } } +/** + * A property projection with a variable number of selector indices. + */ +private class VarArgsPropertyProjection extends PropertyProjection::Range { + VarArgsPropertyProjection() { this = LodashUnderscore::member("pick").getACall() } + + override DataFlow::Node getObject() { result = getArgument(0) } + + override DataFlow::Node getASelector() { result = getArgument(any(int i | i > 0)) } + + override predicate isSingletonProjection() { none() } +} + /** * A taint step for a property projection. */ From c82b5eb040a469ddaf82f48e67a7d555341641f1 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Thu, 25 Mar 2021 10:06:10 +0100 Subject: [PATCH 355/725] Java: Remove code duplication library. --- .../Metrics/Files/FLinesOfDuplicatedCode.ql | 11 +- .../src/Metrics/Files/FLinesOfSimilarCode.ql | 11 +- java/ql/src/external/CodeDuplication.qll | 268 ------------------ java/ql/src/external/DuplicateAnonymous.ql | 5 +- java/ql/src/external/DuplicateBlock.ql | 12 +- java/ql/src/external/DuplicateMethod.ql | 13 +- java/ql/src/external/MostlyDuplicateClass.ql | 5 +- java/ql/src/external/MostlyDuplicateFile.ql | 3 +- java/ql/src/external/MostlyDuplicateMethod.ql | 13 +- java/ql/src/external/MostlySimilarFile.ql | 3 +- 10 files changed, 14 insertions(+), 330 deletions(-) delete mode 100644 java/ql/src/external/CodeDuplication.qll diff --git a/java/ql/src/Metrics/Files/FLinesOfDuplicatedCode.ql b/java/ql/src/Metrics/Files/FLinesOfDuplicatedCode.ql index 2dda34289d7..89277750efb 100644 --- a/java/ql/src/Metrics/Files/FLinesOfDuplicatedCode.ql +++ b/java/ql/src/Metrics/Files/FLinesOfDuplicatedCode.ql @@ -12,15 +12,8 @@ * modularity */ -import external.CodeDuplication +import java from File f, int n -where - n = - count(int line | - exists(DuplicateBlock d | d.sourceFile() = f | - line in [d.sourceStartLine() .. d.sourceEndLine()] and - not whitelistedLineForDuplication(f, line) - ) - ) +where none() select f, n order by n desc diff --git a/java/ql/src/Metrics/Files/FLinesOfSimilarCode.ql b/java/ql/src/Metrics/Files/FLinesOfSimilarCode.ql index f7de197055f..a15d673612a 100644 --- a/java/ql/src/Metrics/Files/FLinesOfSimilarCode.ql +++ b/java/ql/src/Metrics/Files/FLinesOfSimilarCode.ql @@ -11,15 +11,8 @@ * @tags testability */ -import external.CodeDuplication +import java from File f, int n -where - n = - count(int line | - exists(SimilarBlock d | d.sourceFile() = f | - line in [d.sourceStartLine() .. d.sourceEndLine()] and - not whitelistedLineForDuplication(f, line) - ) - ) +where none() select f, n order by n desc diff --git a/java/ql/src/external/CodeDuplication.qll b/java/ql/src/external/CodeDuplication.qll deleted file mode 100644 index 98782463a0e..00000000000 --- a/java/ql/src/external/CodeDuplication.qll +++ /dev/null @@ -1,268 +0,0 @@ -import java - -private string relativePath(File file) { result = file.getRelativePath().replaceAll("\\", "/") } - -cached -private predicate tokenLocation(File file, int sl, int sc, int ec, int el, Copy copy, int index) { - file = copy.sourceFile() and - tokens(copy, index, sl, sc, ec, el) -} - -class Copy extends @duplication_or_similarity { - private int lastToken() { result = max(int i | tokens(this, i, _, _, _, _) | i) } - - int tokenStartingAt(Location loc) { - tokenLocation(loc.getFile(), loc.getStartLine(), loc.getStartColumn(), _, _, this, result) - } - - int tokenEndingAt(Location loc) { - tokenLocation(loc.getFile(), _, _, loc.getEndLine(), loc.getEndColumn(), this, result) - } - - int sourceStartLine() { tokens(this, 0, result, _, _, _) } - - int sourceStartColumn() { tokens(this, 0, _, result, _, _) } - - int sourceEndLine() { tokens(this, lastToken(), _, _, result, _) } - - int sourceEndColumn() { tokens(this, lastToken(), _, _, _, result) } - - int sourceLines() { result = this.sourceEndLine() + 1 - this.sourceStartLine() } - - int getEquivalenceClass() { duplicateCode(this, _, result) or similarCode(this, _, result) } - - File sourceFile() { - exists(string name | duplicateCode(this, name, _) or similarCode(this, name, _) | - name.replaceAll("\\", "/") = relativePath(result) - ) - } - - predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - sourceFile().getAbsolutePath() = filepath and - startline = sourceStartLine() and - startcolumn = sourceStartColumn() and - endline = sourceEndLine() and - endcolumn = sourceEndColumn() - } - - string toString() { none() } -} - -class DuplicateBlock extends Copy, @duplication { - override string toString() { result = "Duplicate code: " + sourceLines() + " duplicated lines." } -} - -class SimilarBlock extends Copy, @similarity { - override string toString() { - result = "Similar code: " + sourceLines() + " almost duplicated lines." - } -} - -Method sourceMethod() { hasLocation(result, _) and numlines(result, _, _, _) } - -int numberOfSourceMethods(Class c) { - result = count(Method m | m = sourceMethod() and m.getDeclaringType() = c) -} - -private predicate blockCoversStatement(int equivClass, int first, int last, Stmt stmt) { - exists(DuplicateBlock b, Location loc | - stmt.getLocation() = loc and - first = b.tokenStartingAt(loc) and - last = b.tokenEndingAt(loc) and - b.getEquivalenceClass() = equivClass - ) -} - -private Stmt statementInMethod(Method m) { - result.getEnclosingCallable() = m and - not result instanceof BlockStmt -} - -private predicate duplicateStatement(Method m1, Method m2, Stmt s1, Stmt s2) { - exists(int equivClass, int first, int last | - s1 = statementInMethod(m1) and - s2 = statementInMethod(m2) and - blockCoversStatement(equivClass, first, last, s1) and - blockCoversStatement(equivClass, first, last, s2) and - s1 != s2 and - m1 != m2 - ) -} - -predicate duplicateStatements(Method m1, Method m2, int duplicate, int total) { - duplicate = strictcount(Stmt s | duplicateStatement(m1, m2, s, _)) and - total = strictcount(statementInMethod(m1)) -} - -/** - * Pairs of methods that are identical. - */ -predicate duplicateMethod(Method m, Method other) { - exists(int total | duplicateStatements(m, other, total, total)) -} - -predicate similarLines(File f, int line) { - exists(SimilarBlock b | b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()]) -} - -private predicate similarLinesPerEquivalenceClass(int equivClass, int lines, File f) { - lines = - strictsum(SimilarBlock b, int toSum | - (b.sourceFile() = f and b.getEquivalenceClass() = equivClass) and - toSum = b.sourceLines() - | - toSum - ) -} - -pragma[noopt] -private predicate similarLinesCovered(File f, int coveredLines, File otherFile) { - exists(int numLines | numLines = f.getTotalNumberOfLines() | - exists(int coveredApprox | - coveredApprox = - strictsum(int num | - exists(int equivClass | - similarLinesPerEquivalenceClass(equivClass, num, f) and - similarLinesPerEquivalenceClass(equivClass, num, otherFile) and - f != otherFile - ) - ) and - exists(int n, int product | product = coveredApprox * 100 and n = product / numLines | n > 75) - ) and - exists(int notCovered | - notCovered = count(int j | j in [1 .. numLines] and not similarLines(f, j)) and - coveredLines = numLines - notCovered - ) - ) -} - -predicate duplicateLines(File f, int line) { - exists(DuplicateBlock b | - b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()] - ) -} - -private predicate duplicateLinesPerEquivalenceClass(int equivClass, int lines, File f) { - lines = - strictsum(DuplicateBlock b, int toSum | - (b.sourceFile() = f and b.getEquivalenceClass() = equivClass) and - toSum = b.sourceLines() - | - toSum - ) -} - -pragma[noopt] -private predicate duplicateLinesCovered(File f, int coveredLines, File otherFile) { - exists(int numLines | numLines = f.getTotalNumberOfLines() | - exists(int coveredApprox | - coveredApprox = - strictsum(int num | - exists(int equivClass | - duplicateLinesPerEquivalenceClass(equivClass, num, f) and - duplicateLinesPerEquivalenceClass(equivClass, num, otherFile) and - f != otherFile - ) - ) and - exists(int n, int product | product = coveredApprox * 100 and n = product / numLines | n > 75) - ) and - exists(int notCovered | - notCovered = count(int j | j in [1 .. numLines] and not duplicateLines(f, j)) and - coveredLines = numLines - notCovered - ) - ) -} - -predicate similarFiles(File f, File other, int percent) { - exists(int covered, int total | - similarLinesCovered(f, covered, other) and - total = f.getTotalNumberOfLines() and - covered * 100 / total = percent and - percent > 80 - ) and - not duplicateFiles(f, other, _) -} - -predicate duplicateFiles(File f, File other, int percent) { - exists(int covered, int total | - duplicateLinesCovered(f, covered, other) and - total = f.getTotalNumberOfLines() and - covered * 100 / total = percent and - percent > 70 - ) -} - -predicate duplicateAnonymousClass(AnonymousClass c, AnonymousClass other) { - exists(int numDup | - numDup = - strictcount(Method m1 | - exists(Method m2 | - duplicateMethod(m1, m2) and - m1 = sourceMethod() and - m1.getDeclaringType() = c and - m2.getDeclaringType() = other and - c != other - ) - ) and - numDup = numberOfSourceMethods(c) and - numDup = numberOfSourceMethods(other) and - forall(Type t | c.getASupertype() = t | t = other.getASupertype()) - ) -} - -pragma[noopt] -predicate mostlyDuplicateClassBase(Class c, Class other, int numDup, int total) { - numDup = - strictcount(Method m1 | - exists(Method m2 | - duplicateMethod(m1, m2) and - m1 = sourceMethod() and - m1.getDeclaringType() = c and - m2.getDeclaringType() = other and - other instanceof Class and - c != other - ) - ) and - total = numberOfSourceMethods(c) and - exists(int n, int product | product = 100 * numDup and n = product / total | n > 80) -} - -predicate mostlyDuplicateClass(Class c, Class other, string message) { - exists(int numDup, int total | - mostlyDuplicateClassBase(c, other, numDup, total) and - not c instanceof AnonymousClass and - not other instanceof AnonymousClass and - ( - total != numDup and - exists(string s1, string s2, string s3, string name | - s1 = " out of " and - s2 = " methods in " and - s3 = " are duplicated in $@." and - name = c.getName() - | - message = numDup + s1 + total + s2 + name + s3 - ) - or - total = numDup and - exists(string s1, string s2, string name | - s1 = "All methods in " and s2 = " are identical in $@." and name = c.getName() - | - message = s1 + name + s2 - ) - ) - ) -} - -predicate fileLevelDuplication(File f, File other) { - similarFiles(f, other, _) or duplicateFiles(f, other, _) -} - -predicate classLevelDuplication(Class c, Class other) { - duplicateAnonymousClass(c, other) or mostlyDuplicateClass(c, other, _) -} - -predicate whitelistedLineForDuplication(File f, int line) { - exists(Import i | i.getFile() = f and i.getLocation().getStartLine() = line) -} diff --git a/java/ql/src/external/DuplicateAnonymous.ql b/java/ql/src/external/DuplicateAnonymous.ql index 1be9ff3922f..880abfc3a69 100644 --- a/java/ql/src/external/DuplicateAnonymous.ql +++ b/java/ql/src/external/DuplicateAnonymous.ql @@ -15,11 +15,8 @@ */ import java -import CodeDuplication from AnonymousClass c, AnonymousClass other -where - duplicateAnonymousClass(c, other) and - not fileLevelDuplication(c.getCompilationUnit(), other.getCompilationUnit()) +where none() select c, "Anonymous class is identical to $@.", other, "another anonymous class in " + other.getFile().getStem() diff --git a/java/ql/src/external/DuplicateBlock.ql b/java/ql/src/external/DuplicateBlock.ql index 0e4c5d7eb93..cc515904039 100644 --- a/java/ql/src/external/DuplicateBlock.ql +++ b/java/ql/src/external/DuplicateBlock.ql @@ -8,16 +8,10 @@ * @id java/duplicate-block */ -import CodeDuplication +import java -from DuplicateBlock d, DuplicateBlock other, int lines, File otherFile, int otherLine -where - lines = d.sourceLines() and - lines > 10 and - other.getEquivalenceClass() = d.getEquivalenceClass() and - other != d and - otherFile = other.sourceFile() and - otherLine = other.sourceStartLine() +from BlockStmt d, int lines, File otherFile, int otherLine +where none() select d, "Duplicate code: " + lines + " lines are duplicated at " + otherFile.getStem() + ":" + otherLine + "." diff --git a/java/ql/src/external/DuplicateMethod.ql b/java/ql/src/external/DuplicateMethod.ql index 4ec8740e475..f7fc59e7fda 100644 --- a/java/ql/src/external/DuplicateMethod.ql +++ b/java/ql/src/external/DuplicateMethod.ql @@ -16,19 +16,8 @@ */ import java -import CodeDuplication - -predicate relevant(Method m) { - m.getNumberOfLinesOfCode() > 5 and not m.getName().matches("get%") - or - m.getNumberOfLinesOfCode() > 10 -} from Method m, Method other -where - duplicateMethod(m, other) and - relevant(m) and - not fileLevelDuplication(m.getCompilationUnit(), other.getCompilationUnit()) and - not classLevelDuplication(m.getDeclaringType(), other.getDeclaringType()) +where none() select m, "Method " + m.getName() + " is duplicated in $@.", other, other.getDeclaringType().getQualifiedName() diff --git a/java/ql/src/external/MostlyDuplicateClass.ql b/java/ql/src/external/MostlyDuplicateClass.ql index 864c44384c6..d5683a5fbba 100644 --- a/java/ql/src/external/MostlyDuplicateClass.ql +++ b/java/ql/src/external/MostlyDuplicateClass.ql @@ -16,10 +16,7 @@ */ import java -import CodeDuplication from Class c, string message, Class link -where - mostlyDuplicateClass(c, link, message) and - not fileLevelDuplication(c.getCompilationUnit(), _) +where none() select c, message, link, link.getQualifiedName() diff --git a/java/ql/src/external/MostlyDuplicateFile.ql b/java/ql/src/external/MostlyDuplicateFile.ql index 86dfa725c25..ccdeddf1890 100644 --- a/java/ql/src/external/MostlyDuplicateFile.ql +++ b/java/ql/src/external/MostlyDuplicateFile.ql @@ -16,9 +16,8 @@ */ import java -import CodeDuplication from File f, File other, int percent -where duplicateFiles(f, other, percent) +where none() select f, percent + "% of the lines in " + f.getStem() + " are copies of lines in $@.", other, other.getStem() diff --git a/java/ql/src/external/MostlyDuplicateMethod.ql b/java/ql/src/external/MostlyDuplicateMethod.ql index 2f47c9ea373..db576ad9696 100644 --- a/java/ql/src/external/MostlyDuplicateMethod.ql +++ b/java/ql/src/external/MostlyDuplicateMethod.ql @@ -16,17 +16,8 @@ */ import java -import CodeDuplication -from Method m, int covered, int total, Method other, int percent -where - duplicateStatements(m, other, covered, total) and - covered != total and - m.getMetrics().getNumberOfLinesOfCode() > 5 and - covered * 100 / total = percent and - percent > 80 and - not duplicateMethod(m, other) and - not classLevelDuplication(m.getDeclaringType(), other.getDeclaringType()) and - not fileLevelDuplication(m.getCompilationUnit(), other.getCompilationUnit()) +from Method m, Method other, int percent +where none() select m, percent + "% of the statements in " + m.getName() + " are duplicated in $@.", other, other.getDeclaringType().getName() + "." + other.getStringSignature() diff --git a/java/ql/src/external/MostlySimilarFile.ql b/java/ql/src/external/MostlySimilarFile.ql index 5b0ab87c91a..4b56a09a4de 100644 --- a/java/ql/src/external/MostlySimilarFile.ql +++ b/java/ql/src/external/MostlySimilarFile.ql @@ -16,9 +16,8 @@ */ import java -import CodeDuplication from File f, File other, int percent -where similarFiles(f, other, percent) +where none() select f, percent + "% of the lines in " + f.getStem() + " are similar to lines in $@.", other, other.getStem() From 1564aee57a881ce70b5cccd83fdb60041e01d77f Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Thu, 25 Mar 2021 10:11:30 +0100 Subject: [PATCH 356/725] Java: Add change note for filter query removal. --- java/change-notes/2021-03-25-remove-legacy-filter-queries.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 java/change-notes/2021-03-25-remove-legacy-filter-queries.md diff --git a/java/change-notes/2021-03-25-remove-legacy-filter-queries.md b/java/change-notes/2021-03-25-remove-legacy-filter-queries.md new file mode 100644 index 00000000000..e3e4b9b4b1e --- /dev/null +++ b/java/change-notes/2021-03-25-remove-legacy-filter-queries.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* Legacy filter queries have been removed. From 5b905cfe18c3b2bc667dcc4291656661b5a2a874 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Thu, 25 Mar 2021 10:12:58 +0100 Subject: [PATCH 357/725] Java: Add change note for code duplication library removal. --- .../2021-03-25-remove-legacy-code-duplication-library.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 java/change-notes/2021-03-25-remove-legacy-code-duplication-library.md diff --git a/java/change-notes/2021-03-25-remove-legacy-code-duplication-library.md b/java/change-notes/2021-03-25-remove-legacy-code-duplication-library.md new file mode 100644 index 00000000000..2a4ac2033ea --- /dev/null +++ b/java/change-notes/2021-03-25-remove-legacy-code-duplication-library.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* The legacy code duplication library has been removed. From 867471b1225aa23b357c6f6a2302b7d670d66c7c Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Thu, 25 Mar 2021 10:23:17 +0100 Subject: [PATCH 358/725] C++: Delete old queries. --- cpp/ql/src/external/tests/DefectFilter.ql | 12 ------ .../external/tests/DefectFromExternalData.ql | 19 ---------- cpp/ql/src/external/tests/MetricFilter.ql | 12 ------ cpp/ql/src/filters/FilterAutogenerated.ql | 17 --------- .../filters/FilterAutogeneratedForMetric.ql | 16 -------- cpp/ql/src/filters/FromSource.ql | 17 --------- cpp/ql/src/filters/Macros.ql | 37 ------------------- 7 files changed, 130 deletions(-) delete mode 100644 cpp/ql/src/external/tests/DefectFilter.ql delete mode 100644 cpp/ql/src/external/tests/DefectFromExternalData.ql delete mode 100644 cpp/ql/src/external/tests/MetricFilter.ql delete mode 100644 cpp/ql/src/filters/FilterAutogenerated.ql delete mode 100644 cpp/ql/src/filters/FilterAutogeneratedForMetric.ql delete mode 100644 cpp/ql/src/filters/FromSource.ql delete mode 100644 cpp/ql/src/filters/Macros.ql diff --git a/cpp/ql/src/external/tests/DefectFilter.ql b/cpp/ql/src/external/tests/DefectFilter.ql deleted file mode 100644 index 88da84e1a52..00000000000 --- a/cpp/ql/src/external/tests/DefectFilter.ql +++ /dev/null @@ -1,12 +0,0 @@ -/** - * @name Defect filter - * @description Only include results in large files (200) lines of code, and change the message. - * @tags filter - */ - -import cpp -import external.DefectFilter - -from DefectResult res -where res.getFile().getMetrics().getNumberOfLinesOfCode() > 200 -select res, "Large files: " + res.getMessage() diff --git a/cpp/ql/src/external/tests/DefectFromExternalData.ql b/cpp/ql/src/external/tests/DefectFromExternalData.ql deleted file mode 100644 index 35bf494b9d4..00000000000 --- a/cpp/ql/src/external/tests/DefectFromExternalData.ql +++ /dev/null @@ -1,19 +0,0 @@ -/** - * @name Defect from external data - * @id cpp/external/tests/defects-from-external-data - * @description Insert description here... - * @kind problem - * @problem.severity warning - * @tags external-data - */ - -import cpp -import external.ExternalArtifact - -from ExternalData d, File u -where - d.getQueryPath() = "external-data.ql" and - u.getShortName() = d.getField(0) -select u, - d.getField(5) + ", " + d.getFieldAsDate(1) + ", " + d.getField(2) + ", " + d.getFieldAsFloat(3) + - ", " + d.getFieldAsInt(4) + ": " + d.getNumFields() diff --git a/cpp/ql/src/external/tests/MetricFilter.ql b/cpp/ql/src/external/tests/MetricFilter.ql deleted file mode 100644 index ba2868254ef..00000000000 --- a/cpp/ql/src/external/tests/MetricFilter.ql +++ /dev/null @@ -1,12 +0,0 @@ -/** - * @name Metric filter - * @description Only include results in large files (200) lines of code. - * @tags filter - */ - -import cpp -import external.MetricFilter - -from MetricResult res -where res.getFile().getMetrics().getNumberOfLinesOfCode() > 200 -select res, res.getValue() diff --git a/cpp/ql/src/filters/FilterAutogenerated.ql b/cpp/ql/src/filters/FilterAutogenerated.ql deleted file mode 100644 index 90df03add5c..00000000000 --- a/cpp/ql/src/filters/FilterAutogenerated.ql +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @name Filter: exclude results from files that are autogenerated - * @description Use this filter to return results only if they are - * located in files that are maintained manually. - * @kind problem - * @problem.severity recommendation - * @id cpp/autogenerated-filter - * @tags filter - */ - -import cpp -import semmle.code.cpp.AutogeneratedFile -import external.DefectFilter - -from DefectResult res -where not res.getFile() instanceof AutogeneratedFile -select res, res.getMessage() diff --git a/cpp/ql/src/filters/FilterAutogeneratedForMetric.ql b/cpp/ql/src/filters/FilterAutogeneratedForMetric.ql deleted file mode 100644 index 6cc6833f7f8..00000000000 --- a/cpp/ql/src/filters/FilterAutogeneratedForMetric.ql +++ /dev/null @@ -1,16 +0,0 @@ -/** - * @name Metric filter: exclude results from files that are autogenerated - * @description Use this filter to return results only if they are - * located in files that are maintained manually. - * @kind treemap - * @id cpp/autogenerated-for-metric-filter - * @tags filter - */ - -import cpp -import semmle.code.cpp.AutogeneratedFile -import external.MetricFilter - -from MetricResult res -where not res.getFile() instanceof AutogeneratedFile -select res, res.getValue() diff --git a/cpp/ql/src/filters/FromSource.ql b/cpp/ql/src/filters/FromSource.ql deleted file mode 100644 index b0213721d0b..00000000000 --- a/cpp/ql/src/filters/FromSource.ql +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @name Filter: exclude results from files for which we do not have - * source code - * @description Use this filter to return results only if they are - * located in files for which we have source code. - * @kind problem - * @problem.severity recommendation - * @id cpp/from-source-filter - * @tags filter - */ - -import cpp -import external.DefectFilter - -from DefectResult res -where res.getFile().fromSource() -select res, res.getMessage() diff --git a/cpp/ql/src/filters/Macros.ql b/cpp/ql/src/filters/Macros.ql deleted file mode 100644 index 5191171196a..00000000000 --- a/cpp/ql/src/filters/Macros.ql +++ /dev/null @@ -1,37 +0,0 @@ -/** - * @name Filter: exclude results on lines covered by a macro expansion - * @description Use this filter to return results only when there is no - * macro expansion whose location spans all the lines of - * the result's location. - * @kind problem - * @problem.severity recommendation - * @id cpp/macros-filter - * @tags filter - */ - -import cpp -import external.DefectFilter - -predicate macroLocation(File f, int startLine, int endLine) { - exists(MacroInvocation mi, Location l | - l = mi.getLocation() and - l.getFile() = f and - l.getStartLine() = startLine and - l.getEndLine() = endLine - ) -} - -predicate macroCovering(DefectResult r) { - exists(File f, int macroStart, int macroEnd, int defectStart, int defectEnd | - f = r.getFile() and - defectStart = r.getStartLine() and - defectEnd = r.getEndLine() and - macroLocation(f, macroStart, macroEnd) and - macroStart <= defectStart and - macroEnd >= defectEnd - ) -} - -from DefectResult res -where not macroCovering(res) -select res, res.getMessage() From 28ff3f412d39047f7f3cf0be011b744163a07a3c Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Thu, 25 Mar 2021 10:29:47 +0100 Subject: [PATCH 359/725] Java: Add severity and precision metadata to experimental queries. --- .../src/experimental/Security/CWE/CWE-036/OpenStream.ql | 7 ++++++- .../experimental/Security/CWE/CWE-273/UnsafeCertTrust.ql | 7 ++++++- .../CWE/CWE-295/JxBrowserWithoutCertValidation.ql | 6 +++++- .../experimental/Security/CWE/CWE-297/InsecureJavaMail.ql | 8 ++++++-- .../Security/CWE/CWE-312/CleartextStorageSharedPrefs.ql | 6 +++++- .../Security/CWE/CWE-326/InsufficientKeySize.ql | 2 ++ java/ql/src/experimental/Security/CWE/CWE-489/EJBMain.ql | 2 ++ .../experimental/Security/CWE/CWE-489/WebComponentMain.ql | 2 ++ .../Security/CWE/CWE-548/InsecureDirectoryConfig.ql | 7 ++++++- .../Security/CWE/CWE-555/PasswordInConfigurationFile.ql | 2 ++ .../Security/CWE/CWE-939/IncorrectURLVerification.ql | 8 ++++++-- 11 files changed, 48 insertions(+), 9 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-036/OpenStream.ql b/java/ql/src/experimental/Security/CWE/CWE-036/OpenStream.ql index 5835c3f17ef..871d6bb4737 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-036/OpenStream.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-036/OpenStream.ql @@ -1,8 +1,13 @@ /** * @name openStream called on URLs created from remote source * @description Calling openStream on URLs created from remote source - * can lead to local file disclosure. + * can lead to local file disclosure. * @kind path-problem + * @problem.severity warning + * @precision medium + * @id java/openstream-called-on-tainted-url + * @tags security + * external/cwe/cwe-036 */ import java diff --git a/java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.ql b/java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.ql index 3dca54a8de6..9efdcbf4c6e 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.ql @@ -1,7 +1,12 @@ /** * @name Unsafe certificate trust - * @description Unsafe implementation of the interface X509TrustManager and SSLSocket/SSLEngine ignores all SSL certificate validation errors when establishing an HTTPS connection, thereby making the app vulnerable to man-in-the-middle attacks. + * @description Unsafe implementation of the interface X509TrustManager and + * SSLSocket/SSLEngine ignores all SSL certificate validation + * errors when establishing an HTTPS connection, thereby making + * the app vulnerable to man-in-the-middle attacks. * @kind problem + * @problem.severity warning + * @precision medium * @id java/unsafe-cert-trust * @tags security * external/cwe-273 diff --git a/java/ql/src/experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.ql b/java/ql/src/experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.ql index aecffaf3f3b..f664f4ce953 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.ql @@ -1,7 +1,11 @@ /** * @name JxBrowser with disabled certificate validation - * @description Insecure configuration of JxBrowser disables certificate validation making the app vulnerable to man-in-the-middle attacks. + * @description Insecure configuration of JxBrowser disables certificate + * validation making the app vulnerable to man-in-the-middle + * attacks. * @kind problem + * @problem.severity warning + * @precision medium * @id java/jxbrowser/disabled-certificate-validation * @tags security * external/cwe/cwe-295 diff --git a/java/ql/src/experimental/Security/CWE/CWE-297/InsecureJavaMail.ql b/java/ql/src/experimental/Security/CWE/CWE-297/InsecureJavaMail.ql index 6b9176ce034..c17c83448cb 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-297/InsecureJavaMail.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-297/InsecureJavaMail.ql @@ -1,8 +1,12 @@ /** - * @id java/insecure-smtp-ssl * @name Insecure JavaMail SSL Configuration - * @description Java application configured to use authenticated mail session over SSL does not validate the SSL certificate to properly ensure that it is actually associated with that host. + * @description Java application configured to use authenticated mail session + * over SSL does not validate the SSL certificate to properly + * ensure that it is actually associated with that host. * @kind problem + * @problem.severity warning + * @precision medium + * @id java/insecure-smtp-ssl * @tags security * external/cwe-297 */ diff --git a/java/ql/src/experimental/Security/CWE/CWE-312/CleartextStorageSharedPrefs.ql b/java/ql/src/experimental/Security/CWE/CWE-312/CleartextStorageSharedPrefs.ql index fcfe3f82651..b10741c2048 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-312/CleartextStorageSharedPrefs.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-312/CleartextStorageSharedPrefs.ql @@ -1,7 +1,11 @@ /** * @name Cleartext storage of sensitive information using `SharedPreferences` on Android - * @description Cleartext Storage of Sensitive Information using SharedPreferences on Android allows access for users with root privileges or unexpected exposure from chained vulnerabilities. + * @description Cleartext Storage of Sensitive Information using + * SharedPreferences on Android allows access for users with root + * privileges or unexpected exposure from chained vulnerabilities. * @kind problem + * @problem.severity warning + * @precision medium * @id java/android/cleartext-storage-shared-prefs * @tags security * external/cwe/cwe-312 diff --git a/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.ql b/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.ql index 41242a44805..155d05abfae 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.ql @@ -2,6 +2,8 @@ * @name Weak encryption: Insufficient key size * @description Finds uses of encryption algorithms with too small a key size * @kind problem + * @problem.severity warning + * @precision medium * @id java/insufficient-key-size * @tags security * external/cwe/cwe-326 diff --git a/java/ql/src/experimental/Security/CWE/CWE-489/EJBMain.ql b/java/ql/src/experimental/Security/CWE/CWE-489/EJBMain.ql index 7723aea9ee2..6771311094b 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-489/EJBMain.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-489/EJBMain.ql @@ -2,6 +2,8 @@ * @name Main Method in Enterprise Java Bean * @description Java EE applications with a main method. * @kind problem + * @problem.severity warning + * @precision medium * @id java/main-method-in-enterprise-bean * @tags security * external/cwe-489 diff --git a/java/ql/src/experimental/Security/CWE/CWE-489/WebComponentMain.ql b/java/ql/src/experimental/Security/CWE/CWE-489/WebComponentMain.ql index bb96c726147..2a3dfcbd3ac 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-489/WebComponentMain.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-489/WebComponentMain.ql @@ -2,6 +2,8 @@ * @name Main Method in Java EE Web Components * @description Java EE web applications with a main method. * @kind problem + * @problem.severity warning + * @precision medium * @id java/main-method-in-web-components * @tags security * external/cwe-489 diff --git a/java/ql/src/experimental/Security/CWE/CWE-548/InsecureDirectoryConfig.ql b/java/ql/src/experimental/Security/CWE/CWE-548/InsecureDirectoryConfig.ql index 08a456137d0..912df87c0b7 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-548/InsecureDirectoryConfig.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-548/InsecureDirectoryConfig.ql @@ -1,7 +1,12 @@ /** * @name Directories and files exposure - * @description A directory listing provides an attacker with the complete index of all the resources located inside of the complete web directory, which could yield files containing sensitive information like source code and credentials to the attacker. + * @description A directory listing provides an attacker with the complete + * index of all the resources located inside of the complete web + * directory, which could yield files containing sensitive + * information like source code and credentials to the attacker. * @kind problem + * @problem.severity warning + * @precision medium * @id java/server-directory-listing * @tags security * external/cwe-548 diff --git a/java/ql/src/experimental/Security/CWE/CWE-555/PasswordInConfigurationFile.ql b/java/ql/src/experimental/Security/CWE/CWE-555/PasswordInConfigurationFile.ql index a8ed7ec538e..a50b02a908f 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-555/PasswordInConfigurationFile.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-555/PasswordInConfigurationFile.ql @@ -2,6 +2,8 @@ * @name Password in configuration file * @description Finds passwords in configuration files. * @kind problem + * @problem.severity warning + * @precision medium * @id java/password-in-configuration * @tags security * external/cwe/cwe-555 diff --git a/java/ql/src/experimental/Security/CWE/CWE-939/IncorrectURLVerification.ql b/java/ql/src/experimental/Security/CWE/CWE-939/IncorrectURLVerification.ql index 87b87b029f4..70156684b41 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-939/IncorrectURLVerification.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-939/IncorrectURLVerification.ql @@ -1,8 +1,12 @@ /** - * @id java/incorrect-url-verification * @name Incorrect URL verification - * @description Apps that rely on URL parsing to verify that a given URL is pointing to a trusted server are susceptible to wrong ways of URL parsing and verification. + * @description Apps that rely on URL parsing to verify that a given URL is + * pointing to a trusted server are susceptible to wrong ways of + * URL parsing and verification. * @kind problem + * @problem.severity warning + * @precision medium + * @id java/incorrect-url-verification * @tags security * external/cwe-939 */ From 32b264bdee364b21f6ac04d9115fbc7514cc25bb Mon Sep 17 00:00:00 2001 From: yoff Date: Thu, 25 Mar 2021 10:48:59 +0100 Subject: [PATCH 360/725] Apply suggestions from code review Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com> --- .../codeql-language-guides/using-api-graphs-in-python.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/codeql/codeql-language-guides/using-api-graphs-in-python.rst b/docs/codeql/codeql-language-guides/using-api-graphs-in-python.rst index ba274933d0f..24be065c912 100644 --- a/docs/codeql/codeql-language-guides/using-api-graphs-in-python.rst +++ b/docs/codeql/codeql-language-guides/using-api-graphs-in-python.rst @@ -31,9 +31,9 @@ following snippet demonstrates. ➤ `See this in the query console on LGTM.com `__. -This query selects the API graph node corresponding to the ``re`` module. This node represent the fact that the ``re`` module has been imported rather than a specific place in the program where the import happens. Therefore, there will be at most one result per project, and it will not have a useful location, so you have to click `Show 1 non-source result` in order to see it. +This query selects the API graph node corresponding to the ``re`` module. This node represents the fact that the ``re`` module has been imported rather than a specific location in the program where the import happens. Therefore, there will be at most one result per project, and it will not have a useful location, so you'll have to click `Show 1 non-source result` in order to see it. -To find places in the program where the ``re`` module is referenced, you can use the ``getAUse`` method. The following query selects all references to the ``re`` module in the current database. +To find where the ``re`` module is referenced in the program, you can use the ``getAUse`` method. The following query selects all references to the ``re`` module in the current database. .. code-block:: ql From 6bfc49c069e6f8e193061879d2c53e35986f9543 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 25 Mar 2021 11:43:25 +0100 Subject: [PATCH 361/725] C#: Address review comments --- .../internal/pressa/SsaImplCommon.qll | 2 +- .../code/csharp/dataflow/FlowSummary.qll | 14 +++++----- .../dataflow/internal/FlowSummaryImpl.qll | 28 +++++++++---------- .../internal/FlowSummaryImplSpecific.qll | 2 +- .../dataflow/internal/SsaImplCommon.qll | 2 +- .../internal/basessa/SsaImplCommon.qll | 2 +- 6 files changed, 25 insertions(+), 25 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/internal/pressa/SsaImplCommon.qll b/csharp/ql/src/semmle/code/csharp/controlflow/internal/pressa/SsaImplCommon.qll index be01c05b8fa..7a1879059c3 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/internal/pressa/SsaImplCommon.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/internal/pressa/SsaImplCommon.qll @@ -1,5 +1,5 @@ /** - * Provides a language-independant implementation of static single assignment + * Provides a language-independent implementation of static single assignment * (SSA) form. */ diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/FlowSummary.qll b/csharp/ql/src/semmle/code/csharp/dataflow/FlowSummary.qll index 054131d2c06..65b1cc2928f 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/FlowSummary.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/FlowSummary.qll @@ -1,4 +1,4 @@ -/** Provides classes and predicates for definining flow summaries. */ +/** Provides classes and predicates for defining flow summaries. */ import csharp private import internal.FlowSummaryImpl as Impl @@ -70,14 +70,14 @@ module SummaryComponentStack { /** Gets a singleton stack representing a qualifier. */ SummaryComponentStack qualifier() { result = singleton(SummaryComponent::qualifier()) } - /** Gets a stack representing an element of `of`. */ - SummaryComponentStack elementOf(SummaryComponentStack of) { - result = push(SummaryComponent::element(), of) + /** Gets a stack representing an element of `container`. */ + SummaryComponentStack elementOf(SummaryComponentStack container) { + result = push(SummaryComponent::element(), container) } - /** Gets a stack representing a propery `p` of `of`. */ - SummaryComponentStack propertyOf(Property p, SummaryComponentStack of) { - result = push(SummaryComponent::property(p), of) + /** Gets a stack representing a propery `p` of `object`. */ + SummaryComponentStack propertyOf(Property p, SummaryComponentStack object) { + result = push(SummaryComponent::property(p), object) } /** Gets a stack representing a field `f` of `of`. */ diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll index 850ba6a7aa5..7ed8b1f7e05 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll @@ -1,7 +1,7 @@ /** - * Provides classes and predicates for definining flow summaries. + * Provides classes and predicates for defining flow summaries. * - * The definitions in this file are language-independant, and language-specific + * The definitions in this file are language-independent, and language-specific * definitions are passed in via the `DataFlowImplSpecific` and * `FlowSummaryImplSpecific` modules. */ @@ -10,10 +10,12 @@ private import FlowSummaryImplSpecific private import DataFlowImplSpecific::Private private import DataFlowImplSpecific::Public -/** Provides classes and predicates for definining flow summaries. */ +/** Provides classes and predicates for defining flow summaries. */ module Public { + private import Private + /** - * A compontent used in a flow summary. + * A component used in a flow summary. * * Either a parameter or an argument at a given position, a specific * content type, or a return kind. @@ -21,7 +23,7 @@ module Public { class SummaryComponent extends TSummaryComponent { /** Gets a textual representation of this summary component. */ string toString() { - exists(Content c | this = TContantSummaryComponent(c) and result = c.toString()) + exists(Content c | this = TContentSummaryComponent(c) and result = c.toString()) or exists(int i | this = TParameterSummaryComponent(i) and result = "parameter " + i) or @@ -34,7 +36,7 @@ module Public { /** Provides predicates for constructing summary components. */ module SummaryComponent { /** Gets a summary component for content `c`. */ - SummaryComponent content(Content c) { result = TContantSummaryComponent(c) } + SummaryComponent content(Content c) { result = TContentSummaryComponent(c) } /** Gets a summary component for parameter `i`. */ SummaryComponent parameter(int i) { result = TParameterSummaryComponent(i) } @@ -105,7 +107,7 @@ module Public { } /** - * Gets the stack obtained by push `head` onto `tail`. + * Gets the stack obtained by pushing `head` onto `tail`. * * Make sure to override `RequiredSummaryComponentStack::required()` in order * to ensure that the constructed stack exists. @@ -140,11 +142,11 @@ module Public { * `preservesValue` indicates whether this is a value-preserving step * or a taint-step. * - * Input specications are restricted to stacks that end with + * Input specifications are restricted to stacks that end with * `SummaryComponent::argument(_)`, preceded by zero or more * `SummaryComponent::return(_)` or `SummaryComponent::content(_)` components. * - * Output specications are restricted to stacks that end with + * Output specifications are restricted to stacks that end with * `SummaryComponent::return(_)` or `SummaryComponent::argument(_)`. * * Output stacks ending with `SummaryComponent::return(_)` can be preceded by zero @@ -179,7 +181,7 @@ module Private { private import DataFlowImplCommon as DataFlowImplCommon newtype TSummaryComponent = - TContantSummaryComponent(Content c) or + TContentSummaryComponent(Content c) or TParameterSummaryComponent(int i) { parameterPosition(i) } or TArgumentSummaryComponent(int i) { parameterPosition(i) } or TReturnSummaryComponent(ReturnKind rk) @@ -368,7 +370,7 @@ module Private { n = summaryNodeInputState(c, s) and ( exists(Content cont | - head = TContantSummaryComponent(cont) and result = getContentType(cont) + head = TContentSummaryComponent(cont) and result = getContentType(cont) ) or exists(ReturnKind rk | @@ -380,7 +382,7 @@ module Private { n = summaryNodeOutputState(c, s) and ( exists(Content cont | - head = TContantSummaryComponent(cont) and result = getContentType(cont) + head = TContentSummaryComponent(cont) and result = getContentType(cont) ) or s.length() = 1 and @@ -670,5 +672,3 @@ module Private { } } } - -private import Private diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummaryImplSpecific.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummaryImplSpecific.qll index cb38cd18ad4..01e3a2e1633 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummaryImplSpecific.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummaryImplSpecific.qll @@ -1,5 +1,5 @@ /** - * Provides C# specific classes and predicates for definining flow summaries. + * Provides C# specific classes and predicates for defining flow summaries. */ private import csharp diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll index be01c05b8fa..7a1879059c3 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll @@ -1,5 +1,5 @@ /** - * Provides a language-independant implementation of static single assignment + * Provides a language-independent implementation of static single assignment * (SSA) form. */ diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll index be01c05b8fa..7a1879059c3 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll @@ -1,5 +1,5 @@ /** - * Provides a language-independant implementation of static single assignment + * Provides a language-independent implementation of static single assignment * (SSA) form. */ From 57bd3f3c1459c04aa0098a254522bcc405f86d80 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Thu, 25 Mar 2021 10:44:26 +0000 Subject: [PATCH 362/725] Optimize the taint flow source --- .../CWE-1004/SensitiveCookieNotHttpOnly.ql | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql b/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql index db9adc2ee09..f1bc7879b8a 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql @@ -97,7 +97,10 @@ predicate setHttpOnlyInCookie(MethodAccess ma) { class SetHttpOnlyInCookieConfiguration extends TaintTracking2::Configuration { SetHttpOnlyInCookieConfiguration() { this = "SetHttpOnlyInCookieConfiguration" } - override predicate isSource(DataFlow::Node source) { any() } + override predicate isSource(DataFlow::Node source) { + source.asExpr() = + any(MethodAccess ma | setHttpOnlyInCookie(ma) or removeCookie(ma)).getQualifier() + } override predicate isSink(DataFlow::Node sink) { sink.asExpr() = @@ -123,21 +126,11 @@ class CookieResponseSink extends DataFlow::ExprNode { ( ma.getMethod() instanceof ResponseAddCookieMethod and this.getExpr() = ma.getArgument(0) and - not exists( - MethodAccess ma2 // a method or wrapper method that invokes cookie.setHttpOnly(true) - | - ( - setHttpOnlyInCookie(ma2) or - removeCookie(ma2) - ) and - exists(SetHttpOnlyInCookieConfiguration cc | - cc.hasFlow(DataFlow::exprNode(ma2.getQualifier()), this) - ) - ) + not exists(SetHttpOnlyInCookieConfiguration cc | cc.hasFlowTo(this)) or ma instanceof SetCookieMethodAccess and this.getExpr() = ma.getArgument(1) and - not exists(MatchesHttpOnlyConfiguration cc | cc.hasFlowToExpr(ma.getArgument(1))) // response.addHeader("Set-Cookie", "token=" +authId + ";HttpOnly;Secure") + not exists(MatchesHttpOnlyConfiguration cc | cc.hasFlowTo(this)) // response.addHeader("Set-Cookie", "token=" +authId + ";HttpOnly;Secure") ) and not isTestMethod(ma) // Test class or method ) From 24360d3a4c31dbc2cad55725a3993b780f28eacd Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 25 Mar 2021 12:00:49 +0100 Subject: [PATCH 363/725] C++: Fix join order in AV rule 79 by joining with GVN after the recursive call. --- cpp/ql/src/jsf/4.10 Classes/AV Rule 79.ql | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cpp/ql/src/jsf/4.10 Classes/AV Rule 79.ql b/cpp/ql/src/jsf/4.10 Classes/AV Rule 79.ql index d582cfa4224..3ae7bc65b45 100644 --- a/cpp/ql/src/jsf/4.10 Classes/AV Rule 79.ql +++ b/cpp/ql/src/jsf/4.10 Classes/AV Rule 79.ql @@ -91,16 +91,17 @@ private predicate exprReleases(Expr e, Expr released, string kind) { // `e` is a call to a release function and `released` is the released argument releaseExpr(e, released, kind) or - exists(Function f, int arg | + exists(int arg, VariableAccess access, Function f | // `e` is a call to a function that releases one of it's parameters, // and `released` is the corresponding argument ( e.(FunctionCall).getTarget() = f or e.(FunctionCall).getTarget().(MemberFunction).getAnOverridingFunction+() = f ) and + access = f.getParameter(arg).getAnAccess() and e.(FunctionCall).getArgument(arg) = released and exprReleases(_, - exprOrDereference(globalValueNumber(f.getParameter(arg).getAnAccess()).getAnExpr()), kind) + pragma[only_bind_into](exprOrDereference(globalValueNumber(access).getAnExpr())), kind) ) or exists(Function f, ThisExpr innerThis | @@ -112,7 +113,7 @@ private predicate exprReleases(Expr e, Expr released, string kind) { ) and e.(FunctionCall).getQualifier() = exprOrDereference(released) and innerThis.getEnclosingFunction() = f and - exprReleases(_, globalValueNumber(innerThis).getAnExpr(), kind) + exprReleases(_, pragma[only_bind_into](globalValueNumber(innerThis).getAnExpr()), kind) ) } From 75afa011ffcb595918bcb6e62259f7fda217d81d Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Thu, 25 Mar 2021 11:20:36 +0100 Subject: [PATCH 364/725] Java: Add metadata to several more experimental queries. --- .../Security/CWE/CWE-297/InsecureLdapEndpoint.ql | 7 +++++-- .../Security/CWE/CWE-522/InsecureBasicAuth.ql | 7 ++++++- .../Security/CWE/CWE-522/InsecureLdapAuth.ql | 2 ++ .../Security/CWE/CWE-532/SensitiveInfoLog.ql | 7 +++++-- .../Security/CWE/CWE-598/SensitiveGetQuery.ql | 2 ++ .../Security/CWE/CWE-600/UncaughtServletException.ql | 7 ++++++- .../Security/CWE/CWE-749/UnsafeAndroidAccess.ql | 7 +++++-- .../experimental/Security/CWE/CWE-755/NFEAndroidDoS.ql | 9 +++++++-- .../Security/CWE/CWE-927/SensitiveBroadcast.ql | 8 ++++++-- 9 files changed, 44 insertions(+), 12 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.ql b/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.ql index 7780d2a0248..467d78ae1c4 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.ql @@ -1,8 +1,11 @@ /** * @name Insecure LDAPS Endpoint Configuration - * @description Java application configured to disable LDAPS endpoint identification does not validate - * the SSL certificate to properly ensure that it is actually associated with that host. + * @description Java application configured to disable LDAPS endpoint + * identification does not validate the SSL certificate to + * properly ensure that it is actually associated with that host. * @kind problem + * @problem.severity warning + * @precision medium * @id java/insecure-ldaps-endpoint * @tags security * external/cwe-297 diff --git a/java/ql/src/experimental/Security/CWE/CWE-522/InsecureBasicAuth.ql b/java/ql/src/experimental/Security/CWE/CWE-522/InsecureBasicAuth.ql index 3ec836a0117..97d2f6dad33 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-522/InsecureBasicAuth.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-522/InsecureBasicAuth.ql @@ -1,7 +1,12 @@ /** * @name Insecure basic authentication - * @description Basic authentication only obfuscates username/password in Base64 encoding, which can be easily recognized and reversed. Transmission of sensitive information not over HTTPS is vulnerable to packet sniffing. + * @description Basic authentication only obfuscates username/password in + * Base64 encoding, which can be easily recognized and reversed. + * Transmission of sensitive information not over HTTPS is + * vulnerable to packet sniffing. * @kind path-problem + * @problem.severity warning + * @precision medium * @id java/insecure-basic-auth * @tags security * external/cwe-522 diff --git a/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql b/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql index 8411a128c9c..4ce2b8b7134 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql @@ -2,6 +2,8 @@ * @name Insecure LDAP authentication * @description LDAP authentication with credentials sent in cleartext. * @kind path-problem + * @problem.severity warning + * @precision medium * @id java/insecure-ldap-auth * @tags security * external/cwe-522 diff --git a/java/ql/src/experimental/Security/CWE/CWE-532/SensitiveInfoLog.ql b/java/ql/src/experimental/Security/CWE/CWE-532/SensitiveInfoLog.ql index 853bbb6bace..968009d6fa1 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-532/SensitiveInfoLog.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-532/SensitiveInfoLog.ql @@ -1,8 +1,11 @@ /** - * @id java/sensitiveinfo-in-logfile * @name Insertion of sensitive information into log files - * @description Writing sensitive information to log files can give valuable guidance to an attacker or expose sensitive user information. + * @description Writing sensitive information to log files can give valuable + * guidance to an attacker or expose sensitive user information. * @kind path-problem + * @problem.severity warning + * @precision medium + * @id java/sensitiveinfo-in-logfile * @tags security * external/cwe-532 */ diff --git a/java/ql/src/experimental/Security/CWE/CWE-598/SensitiveGetQuery.ql b/java/ql/src/experimental/Security/CWE/CWE-598/SensitiveGetQuery.ql index bc9850cfddb..a9528ee2f9b 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-598/SensitiveGetQuery.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-598/SensitiveGetQuery.ql @@ -2,6 +2,8 @@ * @name Sensitive GET Query * @description Use of GET request method with sensitive query strings. * @kind path-problem + * @problem.severity warning + * @precision medium * @id java/sensitive-query-with-get * @tags security * external/cwe-598 diff --git a/java/ql/src/experimental/Security/CWE/CWE-600/UncaughtServletException.ql b/java/ql/src/experimental/Security/CWE/CWE-600/UncaughtServletException.ql index 1cab7856672..f3472e97be0 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-600/UncaughtServletException.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-600/UncaughtServletException.ql @@ -1,7 +1,12 @@ /** * @name Uncaught Servlet Exception - * @description Uncaught exceptions in a servlet could leave a system in an unexpected state, possibly resulting in denial-of-service attacks or the exposure of sensitive information disclosed in stack traces. + * @description Uncaught exceptions in a servlet could leave a system in an + * unexpected state, possibly resulting in denial-of-service + * attacks or the exposure of sensitive information disclosed in + * stack traces. * @kind path-problem + * @problem.severity warning + * @precision medium * @id java/uncaught-servlet-exception * @tags security * external/cwe-600 diff --git a/java/ql/src/experimental/Security/CWE/CWE-749/UnsafeAndroidAccess.ql b/java/ql/src/experimental/Security/CWE/CWE-749/UnsafeAndroidAccess.ql index bd69eecf2c4..24755e64f13 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-749/UnsafeAndroidAccess.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-749/UnsafeAndroidAccess.ql @@ -1,8 +1,11 @@ /** * @name Unsafe resource fetching in Android webview - * @id java/android/unsafe-android-webview-fetch - * @description JavaScript rendered inside WebViews can access any protected application file and web resource from any origin + * @description JavaScript rendered inside WebViews can access any protected + * application file and web resource from any origin * @kind path-problem + * @problem.severity warning + * @precision medium + * @id java/android/unsafe-android-webview-fetch * @tags security * external/cwe/cwe-749 * external/cwe/cwe-079 diff --git a/java/ql/src/experimental/Security/CWE/CWE-755/NFEAndroidDoS.ql b/java/ql/src/experimental/Security/CWE/CWE-755/NFEAndroidDoS.ql index 879399be26c..b737c460fa9 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-755/NFEAndroidDoS.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-755/NFEAndroidDoS.ql @@ -1,8 +1,13 @@ /** * @name Local Android DoS Caused By NumberFormatException - * @id java/android/nfe-local-android-dos - * @description NumberFormatException thrown but not caught by an Android application that allows external inputs can crash the application, constituting a local Denial of Service (DoS) attack. + * @description NumberFormatException thrown but not caught by an Android + * application that allows external inputs can crash the + * application, constituting a local Denial of Service (DoS) + * attack. * @kind path-problem + * @problem.severity warning + * @precision medium + * @id java/android/nfe-local-android-dos * @tags security * external/cwe/cwe-755 */ diff --git a/java/ql/src/experimental/Security/CWE/CWE-927/SensitiveBroadcast.ql b/java/ql/src/experimental/Security/CWE/CWE-927/SensitiveBroadcast.ql index 785a0f5c91c..2396392f6c9 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-927/SensitiveBroadcast.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-927/SensitiveBroadcast.ql @@ -1,8 +1,12 @@ /** * @name Broadcasting sensitive data to all Android applications - * @id java/sensitive-broadcast - * @description An Android application uses implicit intents to broadcast sensitive data to all applications without specifying any receiver permission. + * @description An Android application uses implicit intents to broadcast + * sensitive data to all applications without specifying any + * receiver permission. * @kind path-problem + * @problem.severity warning + * @precision medium + * @id java/sensitive-broadcast * @tags security * external/cwe-927 */ From 3b82452d76585755c092f0baa00dd7b7a322b6c7 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 25 Mar 2021 14:47:43 +0100 Subject: [PATCH 365/725] detect fs modules that pass through a reduce call --- .../javascript/frameworks/NodeJSLib.qll | 22 ++ .../CWE-022/TaintedPath/TaintedPath.expected | 249 ++++++++++++++++++ .../CWE-022/TaintedPath/my-async-fs-module.js | 14 + .../CWE-022/TaintedPath/other-fs-libraries.js | 10 + 4 files changed, 295 insertions(+) create mode 100644 javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/my-async-fs-module.js diff --git a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll index 9894dd119df..20ccf86d47c 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll @@ -478,6 +478,28 @@ module NodeJSLib { DataFlow::moduleImport("util-promisifyall") ].getACall() ) + or + // const fs = require('fs'); + // module.exports = methods.reduce((obj, method) => { + // obj[method] = fs[method]; + // return obj; + // }, {}); + t.continue() = t2 and + exists( + DataFlow::MethodCallNode call, DataFlow::ParameterNode obj, DataFlow::SourceNode method + | + call.getMethodName() = "reduce" and + result = call and + obj = call.getABoundCallbackParameter(0, 0) and + obj.flowsTo(any(DataFlow::FunctionNode f).getAReturn()) and + exists(DataFlow::PropWrite write, DataFlow::PropRead read | + write = obj.getAPropertyWrite() and + method.flowsToExpr(write.getPropertyNameExpr()) and + method.flowsToExpr(read.getPropertyNameExpr()) and + read.getBase().getALocalSource() = fsModule(t2) and + write.getRhs() = maybePromisified(read) + ) + ) ) } } diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected index 0b1fe929968..5d8806c0501 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected @@ -2168,6 +2168,109 @@ nodes | other-fs-libraries.js:42:53:42:56 | path | | other-fs-libraries.js:42:53:42:56 | path | | other-fs-libraries.js:42:53:42:56 | path | +| other-fs-libraries.js:49:7:49:48 | path | +| other-fs-libraries.js:49:7:49:48 | path | +| other-fs-libraries.js:49:7:49:48 | path | +| other-fs-libraries.js:49:7:49:48 | path | +| other-fs-libraries.js:49:7:49:48 | path | +| other-fs-libraries.js:49:7:49:48 | path | +| other-fs-libraries.js:49:7:49:48 | path | +| other-fs-libraries.js:49:7:49:48 | path | +| other-fs-libraries.js:49:7:49:48 | path | +| other-fs-libraries.js:49:7:49:48 | path | +| other-fs-libraries.js:49:7:49:48 | path | +| other-fs-libraries.js:49:7:49:48 | path | +| other-fs-libraries.js:49:7:49:48 | path | +| other-fs-libraries.js:49:7:49:48 | path | +| other-fs-libraries.js:49:7:49:48 | path | +| other-fs-libraries.js:49:7:49:48 | path | +| other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:14:49:43 | url.par ... ).query | +| other-fs-libraries.js:49:14:49:43 | url.par ... ).query | +| other-fs-libraries.js:49:14:49:43 | url.par ... ).query | +| other-fs-libraries.js:49:14:49:43 | url.par ... ).query | +| other-fs-libraries.js:49:14:49:43 | url.par ... ).query | +| other-fs-libraries.js:49:14:49:43 | url.par ... ).query | +| other-fs-libraries.js:49:14:49:43 | url.par ... ).query | +| other-fs-libraries.js:49:14:49:43 | url.par ... ).query | +| other-fs-libraries.js:49:14:49:43 | url.par ... ).query | +| other-fs-libraries.js:49:14:49:43 | url.par ... ).query | +| other-fs-libraries.js:49:14:49:43 | url.par ... ).query | +| other-fs-libraries.js:49:14:49:43 | url.par ... ).query | +| other-fs-libraries.js:49:14:49:43 | url.par ... ).query | +| other-fs-libraries.js:49:14:49:43 | url.par ... ).query | +| other-fs-libraries.js:49:14:49:43 | url.par ... ).query | +| other-fs-libraries.js:49:14:49:43 | url.par ... ).query | +| other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | +| other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | +| other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | +| other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | +| other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | +| other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | +| other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | +| other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | +| other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | +| other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | +| other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | +| other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | +| other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | +| other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | +| other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | +| other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | +| other-fs-libraries.js:49:24:49:30 | req.url | +| other-fs-libraries.js:49:24:49:30 | req.url | +| other-fs-libraries.js:49:24:49:30 | req.url | +| other-fs-libraries.js:49:24:49:30 | req.url | +| other-fs-libraries.js:49:24:49:30 | req.url | +| other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:52:24:52:27 | path | | pupeteer.js:5:9:5:71 | tainted | | pupeteer.js:5:9:5:71 | tainted | | pupeteer.js:5:9:5:71 | tainted | @@ -6421,6 +6524,150 @@ edges | other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | | other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | | other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:51:19:51:22 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:49:7:49:48 | path | other-fs-libraries.js:52:24:52:27 | path | +| other-fs-libraries.js:49:14:49:37 | url.par ... , true) | other-fs-libraries.js:49:14:49:43 | url.par ... ).query | +| other-fs-libraries.js:49:14:49:37 | url.par ... , true) | other-fs-libraries.js:49:14:49:43 | url.par ... ).query | +| other-fs-libraries.js:49:14:49:37 | url.par ... , true) | other-fs-libraries.js:49:14:49:43 | url.par ... ).query | +| other-fs-libraries.js:49:14:49:37 | url.par ... , true) | other-fs-libraries.js:49:14:49:43 | url.par ... ).query | +| other-fs-libraries.js:49:14:49:37 | url.par ... , true) | other-fs-libraries.js:49:14:49:43 | url.par ... ).query | +| other-fs-libraries.js:49:14:49:37 | url.par ... , true) | other-fs-libraries.js:49:14:49:43 | url.par ... ).query | +| other-fs-libraries.js:49:14:49:37 | url.par ... , true) | other-fs-libraries.js:49:14:49:43 | url.par ... ).query | +| other-fs-libraries.js:49:14:49:37 | url.par ... , true) | other-fs-libraries.js:49:14:49:43 | url.par ... ).query | +| other-fs-libraries.js:49:14:49:37 | url.par ... , true) | other-fs-libraries.js:49:14:49:43 | url.par ... ).query | +| other-fs-libraries.js:49:14:49:37 | url.par ... , true) | other-fs-libraries.js:49:14:49:43 | url.par ... ).query | +| other-fs-libraries.js:49:14:49:37 | url.par ... , true) | other-fs-libraries.js:49:14:49:43 | url.par ... ).query | +| other-fs-libraries.js:49:14:49:37 | url.par ... , true) | other-fs-libraries.js:49:14:49:43 | url.par ... ).query | +| other-fs-libraries.js:49:14:49:37 | url.par ... , true) | other-fs-libraries.js:49:14:49:43 | url.par ... ).query | +| other-fs-libraries.js:49:14:49:37 | url.par ... , true) | other-fs-libraries.js:49:14:49:43 | url.par ... ).query | +| other-fs-libraries.js:49:14:49:37 | url.par ... , true) | other-fs-libraries.js:49:14:49:43 | url.par ... ).query | +| other-fs-libraries.js:49:14:49:37 | url.par ... , true) | other-fs-libraries.js:49:14:49:43 | url.par ... ).query | +| other-fs-libraries.js:49:14:49:43 | url.par ... ).query | other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | +| other-fs-libraries.js:49:14:49:43 | url.par ... ).query | other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | +| other-fs-libraries.js:49:14:49:43 | url.par ... ).query | other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | +| other-fs-libraries.js:49:14:49:43 | url.par ... ).query | other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | +| other-fs-libraries.js:49:14:49:43 | url.par ... ).query | other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | +| other-fs-libraries.js:49:14:49:43 | url.par ... ).query | other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | +| other-fs-libraries.js:49:14:49:43 | url.par ... ).query | other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | +| other-fs-libraries.js:49:14:49:43 | url.par ... ).query | other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | +| other-fs-libraries.js:49:14:49:43 | url.par ... ).query | other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | +| other-fs-libraries.js:49:14:49:43 | url.par ... ).query | other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | +| other-fs-libraries.js:49:14:49:43 | url.par ... ).query | other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | +| other-fs-libraries.js:49:14:49:43 | url.par ... ).query | other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | +| other-fs-libraries.js:49:14:49:43 | url.par ... ).query | other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | +| other-fs-libraries.js:49:14:49:43 | url.par ... ).query | other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | +| other-fs-libraries.js:49:14:49:43 | url.par ... ).query | other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | +| other-fs-libraries.js:49:14:49:43 | url.par ... ).query | other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | +| other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | other-fs-libraries.js:49:7:49:48 | path | +| other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | other-fs-libraries.js:49:7:49:48 | path | +| other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | other-fs-libraries.js:49:7:49:48 | path | +| other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | other-fs-libraries.js:49:7:49:48 | path | +| other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | other-fs-libraries.js:49:7:49:48 | path | +| other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | other-fs-libraries.js:49:7:49:48 | path | +| other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | other-fs-libraries.js:49:7:49:48 | path | +| other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | other-fs-libraries.js:49:7:49:48 | path | +| other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | other-fs-libraries.js:49:7:49:48 | path | +| other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | other-fs-libraries.js:49:7:49:48 | path | +| other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | other-fs-libraries.js:49:7:49:48 | path | +| other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | other-fs-libraries.js:49:7:49:48 | path | +| other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | other-fs-libraries.js:49:7:49:48 | path | +| other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | other-fs-libraries.js:49:7:49:48 | path | +| other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | other-fs-libraries.js:49:7:49:48 | path | +| other-fs-libraries.js:49:14:49:48 | url.par ... ry.path | other-fs-libraries.js:49:7:49:48 | path | +| other-fs-libraries.js:49:24:49:30 | req.url | other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:24:49:30 | req.url | other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:24:49:30 | req.url | other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:24:49:30 | req.url | other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:24:49:30 | req.url | other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:24:49:30 | req.url | other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:24:49:30 | req.url | other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:24:49:30 | req.url | other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:24:49:30 | req.url | other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:24:49:30 | req.url | other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:24:49:30 | req.url | other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:24:49:30 | req.url | other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:24:49:30 | req.url | other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:24:49:30 | req.url | other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:24:49:30 | req.url | other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:24:49:30 | req.url | other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:24:49:30 | req.url | other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:24:49:30 | req.url | other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:24:49:30 | req.url | other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:24:49:30 | req.url | other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:24:49:30 | req.url | other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:24:49:30 | req.url | other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:24:49:30 | req.url | other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:24:49:30 | req.url | other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:24:49:30 | req.url | other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:24:49:30 | req.url | other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:24:49:30 | req.url | other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:24:49:30 | req.url | other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:24:49:30 | req.url | other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:24:49:30 | req.url | other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:24:49:30 | req.url | other-fs-libraries.js:49:14:49:37 | url.par ... , true) | +| other-fs-libraries.js:49:24:49:30 | req.url | other-fs-libraries.js:49:14:49:37 | url.par ... , true) | | pupeteer.js:5:9:5:71 | tainted | pupeteer.js:9:28:9:34 | tainted | | pupeteer.js:5:9:5:71 | tainted | pupeteer.js:9:28:9:34 | tainted | | pupeteer.js:5:9:5:71 | tainted | pupeteer.js:9:28:9:34 | tainted | @@ -8046,6 +8293,8 @@ edges | other-fs-libraries.js:40:35:40:38 | path | other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:40:35:40:38 | path | This path depends on $@. | other-fs-libraries.js:38:24:38:30 | req.url | a user-provided value | | other-fs-libraries.js:41:50:41:53 | path | other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:41:50:41:53 | path | This path depends on $@. | other-fs-libraries.js:38:24:38:30 | req.url | a user-provided value | | other-fs-libraries.js:42:53:42:56 | path | other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:42:53:42:56 | path | This path depends on $@. | other-fs-libraries.js:38:24:38:30 | req.url | a user-provided value | +| other-fs-libraries.js:51:19:51:22 | path | other-fs-libraries.js:49:24:49:30 | req.url | other-fs-libraries.js:51:19:51:22 | path | This path depends on $@. | other-fs-libraries.js:49:24:49:30 | req.url | a user-provided value | +| other-fs-libraries.js:52:24:52:27 | path | other-fs-libraries.js:49:24:49:30 | req.url | other-fs-libraries.js:52:24:52:27 | path | This path depends on $@. | other-fs-libraries.js:49:24:49:30 | req.url | a user-provided value | | pupeteer.js:9:28:9:34 | tainted | pupeteer.js:5:28:5:53 | parseTo ... t).name | pupeteer.js:9:28:9:34 | tainted | This path depends on $@. | pupeteer.js:5:28:5:53 | parseTo ... t).name | a user-provided value | | pupeteer.js:13:37:13:43 | tainted | pupeteer.js:5:28:5:53 | parseTo ... t).name | pupeteer.js:13:37:13:43 | tainted | This path depends on $@. | pupeteer.js:5:28:5:53 | parseTo ... t).name | a user-provided value | | tainted-access-paths.js:8:19:8:22 | path | tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:8:19:8:22 | path | This path depends on $@. | tainted-access-paths.js:6:24:6:30 | req.url | a user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/my-async-fs-module.js b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/my-async-fs-module.js new file mode 100644 index 00000000000..f39b9a4efe8 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/my-async-fs-module.js @@ -0,0 +1,14 @@ +const fs = require('fs'); +const {promisify} = require('bluebird'); + +const methods = [ + 'readFile', + 'writeFile', + 'readFileSync', + 'writeFileSync' +]; + +module.exports = methods.reduce((obj, method) => { + obj[method] = promisify(fs[method]); + return obj; +}, {}); diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/other-fs-libraries.js b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/other-fs-libraries.js index 793cfd53142..14c9e357492 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/other-fs-libraries.js +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/other-fs-libraries.js @@ -41,3 +41,13 @@ http.createServer(function(req, res) { require("bluebird").promisify(fs.readFileSync)(path); // NOT OK require("bluebird").promisifyAll(fs).readFileSync(path); // NOT OK }); + + +const asyncFS = require("./my-async-fs-module"); + +http.createServer(function(req, res) { + var path = url.parse(req.url, true).query.path; + + fs.readFileSync(path); // NOT OK + asyncFS.readFileSync(path); // NOT OK +}); From e3b2e0a1dedacaf5be6da16c041af417e8300d20 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 25 Mar 2021 15:06:32 +0100 Subject: [PATCH 366/725] Python: Delete filter queries --- python/ql/src/Filters/NotGenerated.ql | 14 -------------- python/ql/src/Filters/NotTest.ql | 14 -------------- 2 files changed, 28 deletions(-) delete mode 100644 python/ql/src/Filters/NotGenerated.ql delete mode 100644 python/ql/src/Filters/NotTest.ql diff --git a/python/ql/src/Filters/NotGenerated.ql b/python/ql/src/Filters/NotGenerated.ql deleted file mode 100644 index e1efbfd42e3..00000000000 --- a/python/ql/src/Filters/NotGenerated.ql +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @name Filter: non-generated files - * @description Only keep results that aren't (or don't appear to be) generated. - * @kind problem - * @id py/not-generated-file-filter - */ - -import python -import external.DefectFilter -import semmle.python.filters.GeneratedCode - -from DefectResult res -where not exists(GeneratedFile f | res.getFile() = f) -select res, res.getMessage() diff --git a/python/ql/src/Filters/NotTest.ql b/python/ql/src/Filters/NotTest.ql deleted file mode 100644 index 56650e4ff15..00000000000 --- a/python/ql/src/Filters/NotTest.ql +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @name Filter: non-test files - * @description Only keep results that aren't in tests - * @kind problem - * @id py/not-test-file-filter - */ - -import python -import external.DefectFilter -import semmle.python.filters.Tests - -from DefectResult res -where not exists(TestScope s | contains(s.getLocation(), res)) -select res, res.getMessage() From 09fbf480dbb9f85d690274a0fe5e6582e5443c51 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 25 Mar 2021 15:04:41 +0100 Subject: [PATCH 367/725] Python: Remove precision tag from metric queries --- python/ql/src/Lexical/FCommentedOutCode.ql | 1 - python/ql/src/Metrics/Dependencies/ExternalDependencies.ql | 1 - python/ql/src/Metrics/FLinesOfCode.ql | 1 - python/ql/src/Metrics/FLinesOfComments.ql | 1 - python/ql/src/Metrics/FLinesOfDuplicatedCode.ql | 1 - python/ql/src/Metrics/FLinesOfSimilarCode.ql | 1 - python/ql/src/Metrics/FNumberOfTests.ql | 1 - 7 files changed, 7 deletions(-) diff --git a/python/ql/src/Lexical/FCommentedOutCode.ql b/python/ql/src/Lexical/FCommentedOutCode.ql index e988f4074c7..a0ab7f01c99 100644 --- a/python/ql/src/Lexical/FCommentedOutCode.ql +++ b/python/ql/src/Lexical/FCommentedOutCode.ql @@ -4,7 +4,6 @@ * @kind treemap * @treemap.warnOn highValues * @metricType file - * @precision high * @tags maintainability * @id py/lines-of-commented-out-code-in-files */ diff --git a/python/ql/src/Metrics/Dependencies/ExternalDependencies.ql b/python/ql/src/Metrics/Dependencies/ExternalDependencies.ql index 5efec24c7b6..a810211e631 100644 --- a/python/ql/src/Metrics/Dependencies/ExternalDependencies.ql +++ b/python/ql/src/Metrics/Dependencies/ExternalDependencies.ql @@ -5,7 +5,6 @@ * @kind treemap * @treemap.warnOn highValues * @metricType externalDependency - * @precision medium * @id py/external-dependencies */ diff --git a/python/ql/src/Metrics/FLinesOfCode.ql b/python/ql/src/Metrics/FLinesOfCode.ql index a46698c7087..84c952f9267 100644 --- a/python/ql/src/Metrics/FLinesOfCode.ql +++ b/python/ql/src/Metrics/FLinesOfCode.ql @@ -6,7 +6,6 @@ * @treemap.warnOn highValues * @metricType file * @metricAggregate avg sum max - * @precision very-high * @tags maintainability * @id py/lines-of-code-in-files */ diff --git a/python/ql/src/Metrics/FLinesOfComments.ql b/python/ql/src/Metrics/FLinesOfComments.ql index b426a0b25f3..18a234eef67 100644 --- a/python/ql/src/Metrics/FLinesOfComments.ql +++ b/python/ql/src/Metrics/FLinesOfComments.ql @@ -6,7 +6,6 @@ * @treemap.warnOn lowValues * @metricType file * @metricAggregate avg sum max - * @precision very-high * @id py/lines-of-comments-in-files */ diff --git a/python/ql/src/Metrics/FLinesOfDuplicatedCode.ql b/python/ql/src/Metrics/FLinesOfDuplicatedCode.ql index 3b503f697d1..957d9042e9e 100644 --- a/python/ql/src/Metrics/FLinesOfDuplicatedCode.ql +++ b/python/ql/src/Metrics/FLinesOfDuplicatedCode.ql @@ -7,7 +7,6 @@ * @treemap.warnOn highValues * @metricType file * @metricAggregate avg sum max - * @precision high * @tags testability * @id py/duplicated-lines-in-files */ diff --git a/python/ql/src/Metrics/FLinesOfSimilarCode.ql b/python/ql/src/Metrics/FLinesOfSimilarCode.ql index 714286a8047..b8d7adf7376 100644 --- a/python/ql/src/Metrics/FLinesOfSimilarCode.ql +++ b/python/ql/src/Metrics/FLinesOfSimilarCode.ql @@ -7,7 +7,6 @@ * @treemap.warnOn highValues * @metricType file * @metricAggregate avg sum max - * @precision high * @tags testability * @id py/similar-lines-in-files */ diff --git a/python/ql/src/Metrics/FNumberOfTests.ql b/python/ql/src/Metrics/FNumberOfTests.ql index 34a76c70d33..65711993bb1 100644 --- a/python/ql/src/Metrics/FNumberOfTests.ql +++ b/python/ql/src/Metrics/FNumberOfTests.ql @@ -5,7 +5,6 @@ * @treemap.warnOn lowValues * @metricType file * @metricAggregate avg sum max - * @precision medium * @id py/tests-in-files */ From 3d49b8cb916f8eed2d6442a5283de29a987b2690 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 25 Mar 2021 10:17:30 +0100 Subject: [PATCH 368/725] consider quoted string concatenations as sanitizers for js/shell-command-injection-from-environment --- ...llCommandInjectionFromEnvironmentCustomizations.qll | 10 ++++++++++ .../Security/CWE-078/UselessUseOfCat.expected | 1 + .../tst_shell-command-injection-from-environment.js | 3 +++ 3 files changed, 14 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ShellCommandInjectionFromEnvironmentCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ShellCommandInjectionFromEnvironmentCustomizations.qll index 4528376b1c8..29e0afa39b2 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/ShellCommandInjectionFromEnvironmentCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/ShellCommandInjectionFromEnvironmentCustomizations.qll @@ -55,4 +55,14 @@ module ShellCommandInjectionFromEnvironment { class ShellCommandSink extends Sink, DataFlow::ValueNode { ShellCommandSink() { any(SystemCommandExecution sys).isShellInterpreted(this) } } + + /** + * A string-concatenation leaf that is sorounded by quotes, seen as a sanitizer for command-injection. + */ + class QuotingConcatSanitizer extends Sanitizer, StringOps::ConcatenationLeaf { + QuotingConcatSanitizer() { + this.getNextLeaf().getStringValue().regexpMatch("(\"|').*") and + this.getPreviousLeaf().getStringValue().regexpMatch(".*(\"|')") + } + } } diff --git a/javascript/ql/test/query-tests/Security/CWE-078/UselessUseOfCat.expected b/javascript/ql/test/query-tests/Security/CWE-078/UselessUseOfCat.expected index 7a7e22fb332..3410fd0a815 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/UselessUseOfCat.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/UselessUseOfCat.expected @@ -61,6 +61,7 @@ syncCommand | tst_shell-command-injection-from-environment.js:5:2:5:62 | cp.exec ... emp")]) | | tst_shell-command-injection-from-environment.js:6:2:6:54 | cp.exec ... temp")) | | tst_shell-command-injection-from-environment.js:9:2:9:58 | execa.s ... temp")) | +| tst_shell-command-injection-from-environment.js:12:2:12:34 | execa.s ... + safe) | | uselesscat.js:16:1:16:29 | execSyn ... uinfo') | | uselesscat.js:18:1:18:26 | execSyn ... path}`) | | uselesscat.js:20:1:20:36 | execSyn ... wc -l') | diff --git a/javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js b/javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js index a4c7860993f..0d610b1e9dd 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js +++ b/javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js @@ -7,4 +7,7 @@ var cp = require('child_process'), execa.shell('rm -rf ' + path.join(__dirname, "temp")); // NOT OK execa.shellSync('rm -rf ' + path.join(__dirname, "temp")); // NOT OK + + const safe = "\"" + path.join(__dirname, "temp") + "\""; + execa.shellSync('rm -rf ' + safe); // OK }); From bd4934380a78a7d484888d6b403dd7749b4d2cad Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 25 Mar 2021 15:27:55 +0100 Subject: [PATCH 369/725] Python: Remove code duplication library --- .../ql/src/Metrics/FLinesOfDuplicatedCode.ql | 10 +- python/ql/src/Metrics/FLinesOfSimilarCode.ql | 10 +- python/ql/src/external/CodeDuplication.qll | 273 ------------- python/ql/src/external/DuplicateBlock.ql | 18 +- python/ql/src/external/DuplicateFunction.ql | 12 +- .../ql/src/external/MostlyDuplicateClass.ql | 6 +- python/ql/src/external/MostlyDuplicateFile.ql | 5 +- python/ql/src/external/MostlySimilarFile.ql | 3 +- python/ql/src/external/SimilarFunction.ql | 13 +- .../DuplicateCode/Duplicate.expected | 2 - .../library-tests/DuplicateCode/Duplicate.ql | 23 -- .../DuplicateStatements.expected | 0 .../DuplicateCode/DuplicateStatements.ql | 26 -- .../DuplicateCode/Similar.expected | 23 -- .../library-tests/DuplicateCode/Similar.ql | 22 -- .../DuplicateCode/duplicate_test.py | 321 ---------------- .../DuplicateCode/DuplicateBlock.expected | 8 - .../DuplicateCode/DuplicateBlock.qlref | 1 - .../DuplicateCode/DuplicateFunction.expected | 4 - .../DuplicateCode/DuplicateFunction.qlref | 1 - .../MostlyDuplicateClass.expected | 2 - .../DuplicateCode/MostlyDuplicateClass.qlref | 1 - .../MostlyDuplicateFile.expected | 0 .../DuplicateCode/MostlyDuplicateFile.qlref | 1 - .../DuplicateCode/MostlySimilarFile.expected | 0 .../DuplicateCode/MostlySimilarFile.qlref | 1 - .../DuplicateCode/SimilarFunction.expected | 12 - .../DuplicateCode/SimilarFunction.qlref | 1 - .../DuplicateCode/duplicate_test.py | 358 ------------------ .../UselessCode/DuplicateCode/similar.py | 63 --- 30 files changed, 13 insertions(+), 1207 deletions(-) delete mode 100644 python/ql/src/external/CodeDuplication.qll delete mode 100644 python/ql/test/library-tests/DuplicateCode/Duplicate.expected delete mode 100644 python/ql/test/library-tests/DuplicateCode/Duplicate.ql delete mode 100644 python/ql/test/library-tests/DuplicateCode/DuplicateStatements.expected delete mode 100644 python/ql/test/library-tests/DuplicateCode/DuplicateStatements.ql delete mode 100644 python/ql/test/library-tests/DuplicateCode/Similar.expected delete mode 100644 python/ql/test/library-tests/DuplicateCode/Similar.ql delete mode 100644 python/ql/test/library-tests/DuplicateCode/duplicate_test.py delete mode 100644 python/ql/test/query-tests/UselessCode/DuplicateCode/DuplicateBlock.expected delete mode 100644 python/ql/test/query-tests/UselessCode/DuplicateCode/DuplicateBlock.qlref delete mode 100644 python/ql/test/query-tests/UselessCode/DuplicateCode/DuplicateFunction.expected delete mode 100644 python/ql/test/query-tests/UselessCode/DuplicateCode/DuplicateFunction.qlref delete mode 100644 python/ql/test/query-tests/UselessCode/DuplicateCode/MostlyDuplicateClass.expected delete mode 100644 python/ql/test/query-tests/UselessCode/DuplicateCode/MostlyDuplicateClass.qlref delete mode 100644 python/ql/test/query-tests/UselessCode/DuplicateCode/MostlyDuplicateFile.expected delete mode 100644 python/ql/test/query-tests/UselessCode/DuplicateCode/MostlyDuplicateFile.qlref delete mode 100644 python/ql/test/query-tests/UselessCode/DuplicateCode/MostlySimilarFile.expected delete mode 100644 python/ql/test/query-tests/UselessCode/DuplicateCode/MostlySimilarFile.qlref delete mode 100644 python/ql/test/query-tests/UselessCode/DuplicateCode/SimilarFunction.expected delete mode 100644 python/ql/test/query-tests/UselessCode/DuplicateCode/SimilarFunction.qlref delete mode 100644 python/ql/test/query-tests/UselessCode/DuplicateCode/duplicate_test.py delete mode 100644 python/ql/test/query-tests/UselessCode/DuplicateCode/similar.py diff --git a/python/ql/src/Metrics/FLinesOfDuplicatedCode.ql b/python/ql/src/Metrics/FLinesOfDuplicatedCode.ql index 957d9042e9e..54a45e986df 100644 --- a/python/ql/src/Metrics/FLinesOfDuplicatedCode.ql +++ b/python/ql/src/Metrics/FLinesOfDuplicatedCode.ql @@ -12,15 +12,7 @@ */ import python -import external.CodeDuplication from File f, int n -where - n = - count(int line | - exists(DuplicateBlock d | d.sourceFile() = f | - line in [d.sourceStartLine() .. d.sourceEndLine()] and - not allowlistedLineForDuplication(f, line) - ) - ) +where none() select f, n order by n desc diff --git a/python/ql/src/Metrics/FLinesOfSimilarCode.ql b/python/ql/src/Metrics/FLinesOfSimilarCode.ql index b8d7adf7376..354d3d2644b 100644 --- a/python/ql/src/Metrics/FLinesOfSimilarCode.ql +++ b/python/ql/src/Metrics/FLinesOfSimilarCode.ql @@ -12,15 +12,7 @@ */ import python -import external.CodeDuplication from File f, int n -where - n = - count(int line | - exists(SimilarBlock d | d.sourceFile() = f | - line in [d.sourceStartLine() .. d.sourceEndLine()] and - not allowlistedLineForDuplication(f, line) - ) - ) +where none() select f, n order by n desc diff --git a/python/ql/src/external/CodeDuplication.qll b/python/ql/src/external/CodeDuplication.qll deleted file mode 100644 index 01ab28d955b..00000000000 --- a/python/ql/src/external/CodeDuplication.qll +++ /dev/null @@ -1,273 +0,0 @@ -/** Provides classes for detecting duplicate or similar code. */ - -import python - -/** Gets the relative path of `file`, with backslashes replaced by forward slashes. */ -private string relativePath(File file) { result = file.getRelativePath().replaceAll("\\", "/") } - -/** - * Holds if the `index`-th token of block `copy` is in file `file`, spanning - * column `sc` of line `sl` to column `ec` of line `el`. - * - * For more information, see [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). - */ -pragma[noinline, nomagic] -private predicate tokenLocation(File file, int sl, int sc, int ec, int el, Copy copy, int index) { - file = copy.sourceFile() and - tokens(copy, index, sl, sc, ec, el) -} - -/** A token block used for detection of duplicate and similar code. */ -class Copy extends @duplication_or_similarity { - private int lastToken() { result = max(int i | tokens(this, i, _, _, _, _) | i) } - - /** Gets the index of the token in this block starting at the location `loc`, if any. */ - int tokenStartingAt(Location loc) { - tokenLocation(loc.getFile(), loc.getStartLine(), loc.getStartColumn(), _, _, this, result) - } - - /** Gets the index of the token in this block ending at the location `loc`, if any. */ - int tokenEndingAt(Location loc) { - tokenLocation(loc.getFile(), _, _, loc.getEndLine(), loc.getEndColumn(), this, result) - } - - /** Gets the line on which the first token in this block starts. */ - int sourceStartLine() { tokens(this, 0, result, _, _, _) } - - /** Gets the column on which the first token in this block starts. */ - int sourceStartColumn() { tokens(this, 0, _, result, _, _) } - - /** Gets the line on which the last token in this block ends. */ - int sourceEndLine() { tokens(this, this.lastToken(), _, _, result, _) } - - /** Gets the column on which the last token in this block ends. */ - int sourceEndColumn() { tokens(this, this.lastToken(), _, _, _, result) } - - /** Gets the number of lines containing at least (part of) one token in this block. */ - int sourceLines() { result = this.sourceEndLine() + 1 - this.sourceStartLine() } - - /** Gets an opaque identifier for the equivalence class of this block. */ - int getEquivalenceClass() { duplicateCode(this, _, result) or similarCode(this, _, result) } - - /** Gets the source file in which this block appears. */ - File sourceFile() { - exists(string name | duplicateCode(this, name, _) or similarCode(this, name, _) | - name.replaceAll("\\", "/") = relativePath(result) - ) - } - - /** - * Holds if this element is at the specified location. - * The location spans column `startcolumn` of line `startline` to - * column `endcolumn` of line `endline` in file `filepath`. - * For more information, see - * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). - */ - predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - sourceFile().getAbsolutePath() = filepath and - startline = sourceStartLine() and - startcolumn = sourceStartColumn() and - endline = sourceEndLine() and - endcolumn = sourceEndColumn() - } - - /** Gets a textual representation of this element. */ - string toString() { result = "Copy" } - - /** - * Gets a block that extends this one, that is, its first token is also - * covered by this block, but they are not the same block. - */ - Copy extendingBlock() { - exists(File file, int sl, int sc, int ec, int el | - tokenLocation(file, sl, sc, ec, el, this, _) and - tokenLocation(file, sl, sc, ec, el, result, 0) - ) and - this != result - } -} - -/** - * Holds if there is a sequence of `SimilarBlock`s `start1, ..., end1` and another sequence - * `start2, ..., end2` such that each block extends the previous one and corresponding blocks - * have the same equivalence class, with `start` being the equivalence class of `start1` and - * `start2`, and `end` the equivalence class of `end1` and `end2`. - */ -predicate similar_extension( - SimilarBlock start1, SimilarBlock start2, SimilarBlock ext1, SimilarBlock ext2, int start, int ext -) { - start1.getEquivalenceClass() = start and - start2.getEquivalenceClass() = start and - ext1.getEquivalenceClass() = ext and - ext2.getEquivalenceClass() = ext and - start1 != start2 and - ( - ext1 = start1 and ext2 = start2 - or - similar_extension(start1.extendingBlock(), start2.extendingBlock(), ext1, ext2, _, ext) - ) -} - -/** - * Holds if there is a sequence of `DuplicateBlock`s `start1, ..., end1` and another sequence - * `start2, ..., end2` such that each block extends the previous one and corresponding blocks - * have the same equivalence class, with `start` being the equivalence class of `start1` and - * `start2`, and `end` the equivalence class of `end1` and `end2`. - */ -predicate duplicate_extension( - DuplicateBlock start1, DuplicateBlock start2, DuplicateBlock ext1, DuplicateBlock ext2, int start, - int ext -) { - start1.getEquivalenceClass() = start and - start2.getEquivalenceClass() = start and - ext1.getEquivalenceClass() = ext and - ext2.getEquivalenceClass() = ext and - start1 != start2 and - ( - ext1 = start1 and ext2 = start2 - or - duplicate_extension(start1.extendingBlock(), start2.extendingBlock(), ext1, ext2, _, ext) - ) -} - -/** A block of duplicated code. */ -class DuplicateBlock extends Copy, @duplication { - override string toString() { result = "Duplicate code: " + sourceLines() + " duplicated lines." } -} - -/** A block of similar code. */ -class SimilarBlock extends Copy, @similarity { - override string toString() { - result = "Similar code: " + sourceLines() + " almost duplicated lines." - } -} - -/** - * Holds if `stmt1` and `stmt2` are duplicate statements in function or toplevel `sc1` and `sc2`, - * respectively, where `scope1` and `scope2` are not the same. - */ -predicate duplicateStatement(Scope scope1, Scope scope2, Stmt stmt1, Stmt stmt2) { - exists(int equivstart, int equivend, int first, int last | - scope1.contains(stmt1) and - scope2.contains(stmt2) and - duplicateCoversStatement(equivstart, equivend, first, last, stmt1) and - duplicateCoversStatement(equivstart, equivend, first, last, stmt2) and - stmt1 != stmt2 and - scope1 != scope2 - ) -} - -/** - * Holds if statement `stmt` is covered by a sequence of `DuplicateBlock`s, where `first` - * is the index of the token in the first block that starts at the beginning of `stmt`, - * while `last` is the index of the token in the last block that ends at the end of `stmt`, - * and `equivstart` and `equivend` are the equivalence classes of the first and the last - * block, respectively. - */ -private predicate duplicateCoversStatement( - int equivstart, int equivend, int first, int last, Stmt stmt -) { - exists(DuplicateBlock b1, DuplicateBlock b2, Location startloc, Location endloc | - stmt.getLocation() = startloc and - stmt.getLastStatement().getLocation() = endloc and - first = b1.tokenStartingAt(startloc) and - last = b2.tokenEndingAt(endloc) and - b1.getEquivalenceClass() = equivstart and - b2.getEquivalenceClass() = equivend and - duplicate_extension(b1, _, b2, _, equivstart, equivend) - ) -} - -/** - * Holds if `sc1` is a function or toplevel with `total` lines, and `scope2` is a function or - * toplevel that has `duplicate` lines in common with `scope1`. - */ -predicate duplicateStatements(Scope scope1, Scope scope2, int duplicate, int total) { - duplicate = strictcount(Stmt stmt | duplicateStatement(scope1, scope2, stmt, _)) and - total = strictcount(Stmt stmt | scope1.contains(stmt)) -} - -/** - * Find pairs of scopes that are identical or almost identical - */ -predicate duplicateScopes(Scope s, Scope other, float percent, string message) { - exists(int total, int duplicate | duplicateStatements(s, other, duplicate, total) | - percent = 100.0 * duplicate / total and - percent >= 80.0 and - if duplicate = total - then message = "All " + total + " statements in " + s.getName() + " are identical in $@." - else - message = - duplicate + " out of " + total + " statements in " + s.getName() + " are duplicated in $@." - ) -} - -/** - * Holds if `stmt1` and `stmt2` are similar statements in function or toplevel `scope1` and `scope2`, - * respectively, where `scope1` and `scope2` are not the same. - */ -private predicate similarStatement(Scope scope1, Scope scope2, Stmt stmt1, Stmt stmt2) { - exists(int start, int end, int first, int last | - scope1.contains(stmt1) and - scope2.contains(stmt2) and - similarCoversStatement(start, end, first, last, stmt1) and - similarCoversStatement(start, end, first, last, stmt2) and - stmt1 != stmt2 and - scope1 != scope2 - ) -} - -/** - * Holds if statement `stmt` is covered by a sequence of `SimilarBlock`s, where `first` - * is the index of the token in the first block that starts at the beginning of `stmt`, - * while `last` is the index of the token in the last block that ends at the end of `stmt`, - * and `equivstart` and `equivend` are the equivalence classes of the first and the last - * block, respectively. - */ -private predicate similarCoversStatement( - int equivstart, int equivend, int first, int last, Stmt stmt -) { - exists(SimilarBlock b1, SimilarBlock b2, Location startloc, Location endloc | - stmt.getLocation() = startloc and - stmt.getLastStatement().getLocation() = endloc and - first = b1.tokenStartingAt(startloc) and - last = b2.tokenEndingAt(endloc) and - b1.getEquivalenceClass() = equivstart and - b2.getEquivalenceClass() = equivend and - similar_extension(b1, _, b2, _, equivstart, equivend) - ) -} - -/** - * Holds if `sc1` is a function or toplevel with `total` lines, and `scope2` is a function or - * toplevel that has `similar` similar lines to `scope1`. - */ -private predicate similarStatements(Scope scope1, Scope scope2, int similar, int total) { - similar = strictcount(Stmt stmt | similarStatement(scope1, scope2, stmt, _)) and - total = strictcount(Stmt stmt | scope1.contains(stmt)) -} - -/** - * Find pairs of scopes that are similar - */ -predicate similarScopes(Scope s, Scope other, float percent, string message) { - exists(int total, int similar | similarStatements(s, other, similar, total) | - percent = 100.0 * similar / total and - percent >= 80.0 and - if similar = total - then message = "All statements in " + s.getName() + " are similar in $@." - else - message = - similar + " out of " + total + " statements in " + s.getName() + " are similar in $@." - ) -} - -/** - * Holds if the line is acceptable as a duplicate. - * This is true for blocks of import statements. - */ -predicate allowlistedLineForDuplication(File f, int line) { - exists(ImportingStmt i | i.getLocation().getFile() = f and i.getLocation().getStartLine() = line) -} diff --git a/python/ql/src/external/DuplicateBlock.ql b/python/ql/src/external/DuplicateBlock.ql index 90067fa834c..89c61040cc2 100644 --- a/python/ql/src/external/DuplicateBlock.ql +++ b/python/ql/src/external/DuplicateBlock.ql @@ -16,19 +16,7 @@ */ import python -import CodeDuplication -predicate sorted_by_location(DuplicateBlock x, DuplicateBlock y) { - if x.sourceFile() = y.sourceFile() - then x.sourceStartLine() < y.sourceStartLine() - else x.sourceFile().getAbsolutePath() < y.sourceFile().getAbsolutePath() -} - -from DuplicateBlock d, DuplicateBlock other -where - d.sourceLines() > 10 and - other.getEquivalenceClass() = d.getEquivalenceClass() and - sorted_by_location(other, d) -select d, - "Duplicate code: " + d.sourceLines() + " lines are duplicated at " + - other.sourceFile().getShortName() + ":" + other.sourceStartLine().toString() +from BasicBlock d +where none() +select d, "Duplicate code: " + "-1" + " lines are duplicated at " + "" + ":" + "-1" diff --git a/python/ql/src/external/DuplicateFunction.ql b/python/ql/src/external/DuplicateFunction.ql index 4583eede278..56f0c0761ae 100644 --- a/python/ql/src/external/DuplicateFunction.ql +++ b/python/ql/src/external/DuplicateFunction.ql @@ -16,15 +16,7 @@ */ import python -import CodeDuplication -predicate relevant(Function m) { m.getMetrics().getNumberOfLinesOfCode() > 5 } - -from Function m, Function other, string message, int percent -where - duplicateScopes(m, other, percent, message) and - relevant(m) and - percent > 95.0 and - not duplicateScopes(m.getEnclosingModule(), other.getEnclosingModule(), _, _) and - not duplicateScopes(m.getScope(), other.getScope(), _, _) +from Function m, Function other, string message +where none() select m, message, other, other.getName() diff --git a/python/ql/src/external/MostlyDuplicateClass.ql b/python/ql/src/external/MostlyDuplicateClass.ql index 2e530fef4d0..2932611ba6f 100644 --- a/python/ql/src/external/MostlyDuplicateClass.ql +++ b/python/ql/src/external/MostlyDuplicateClass.ql @@ -16,11 +16,7 @@ */ import python -import CodeDuplication from Class c, Class other, string message -where - duplicateScopes(c, other, _, message) and - count(c.getAStmt()) > 3 and - not duplicateScopes(c.getEnclosingModule(), _, _, _) +where none() select c, message, other, other.getName() diff --git a/python/ql/src/external/MostlyDuplicateFile.ql b/python/ql/src/external/MostlyDuplicateFile.ql index 274d3758b1d..c11c21dba87 100644 --- a/python/ql/src/external/MostlyDuplicateFile.ql +++ b/python/ql/src/external/MostlyDuplicateFile.ql @@ -16,8 +16,7 @@ */ import python -import CodeDuplication -from Module m, Module other, int percent, string message -where duplicateScopes(m, other, percent, message) +from Module m, Module other, string message +where none() select m, message, other, other.getName() diff --git a/python/ql/src/external/MostlySimilarFile.ql b/python/ql/src/external/MostlySimilarFile.ql index bad174f8fc5..eae859aaecf 100644 --- a/python/ql/src/external/MostlySimilarFile.ql +++ b/python/ql/src/external/MostlySimilarFile.ql @@ -16,8 +16,7 @@ */ import python -import CodeDuplication from Module m, Module other, string message -where similarScopes(m, other, _, message) +where none() select m, message, other, other.getName() diff --git a/python/ql/src/external/SimilarFunction.ql b/python/ql/src/external/SimilarFunction.ql index 509790c89af..84f75c9a489 100644 --- a/python/ql/src/external/SimilarFunction.ql +++ b/python/ql/src/external/SimilarFunction.ql @@ -16,16 +16,7 @@ */ import python -import CodeDuplication -predicate relevant(Function m) { m.getMetrics().getNumberOfLinesOfCode() > 10 } - -from Function m, Function other, string message, int percent -where - similarScopes(m, other, percent, message) and - relevant(m) and - percent > 95.0 and - not duplicateScopes(m, other, _, _) and - not duplicateScopes(m.getEnclosingModule(), other.getEnclosingModule(), _, _) and - not duplicateScopes(m.getScope(), other.getScope(), _, _) +from Function m, Function other, string message +where none() select m, message, other, other.getName() diff --git a/python/ql/test/library-tests/DuplicateCode/Duplicate.expected b/python/ql/test/library-tests/DuplicateCode/Duplicate.expected deleted file mode 100644 index 5c7717546d6..00000000000 --- a/python/ql/test/library-tests/DuplicateCode/Duplicate.expected +++ /dev/null @@ -1,2 +0,0 @@ -| Duplicate code: 34 duplicated lines. | Duplicate code: 34 duplicated lines. | duplicate_test.py | 9 | 42 | -| Duplicate code: 80 duplicated lines. | Duplicate code: 80 duplicated lines. | duplicate_test.py | 84 | 163 | diff --git a/python/ql/test/library-tests/DuplicateCode/Duplicate.ql b/python/ql/test/library-tests/DuplicateCode/Duplicate.ql deleted file mode 100644 index a8f04593ea3..00000000000 --- a/python/ql/test/library-tests/DuplicateCode/Duplicate.ql +++ /dev/null @@ -1,23 +0,0 @@ -/** - * @name Duplicate - * @description Insert description here... - * @kind table - * @problem.severity warning - */ - -import python -import external.CodeDuplication - -predicate lexically_sorted(DuplicateBlock dup1, DuplicateBlock dup2) { - dup1.sourceFile().getAbsolutePath() < dup2.sourceFile().getAbsolutePath() - or - dup1.sourceFile().getAbsolutePath() = dup2.sourceFile().getAbsolutePath() and - dup1.sourceStartLine() < dup2.sourceStartLine() -} - -from DuplicateBlock dup1, DuplicateBlock dup2 -where - dup1.getEquivalenceClass() = dup2.getEquivalenceClass() and - lexically_sorted(dup1, dup2) -select dup1.toString(), dup2.toString(), dup1.sourceFile().getShortName(), dup1.sourceStartLine(), - dup1.sourceEndLine() diff --git a/python/ql/test/library-tests/DuplicateCode/DuplicateStatements.expected b/python/ql/test/library-tests/DuplicateCode/DuplicateStatements.expected deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/python/ql/test/library-tests/DuplicateCode/DuplicateStatements.ql b/python/ql/test/library-tests/DuplicateCode/DuplicateStatements.ql deleted file mode 100644 index ca297eb3718..00000000000 --- a/python/ql/test/library-tests/DuplicateCode/DuplicateStatements.ql +++ /dev/null @@ -1,26 +0,0 @@ -/** - * @name DuplicateStatements - * @description Insert description here... - * @kind problem - * @problem.severity warning - */ - -import python -import external.CodeDuplication - -predicate mostlyDuplicateFunction(Function f) { - exists(int covered, int total, Function other, int percent | - duplicateStatements(f, other, covered, total) and - covered != total and - total > 5 and - covered * 100 / total = percent and - percent > 80 and - not exists(Scope s | s = f.getScope*() | duplicateScopes(s, _, _, _)) - ) -} - -from Stmt s -where - mostlyDuplicateFunction(s.getScope()) and - not duplicateStatement(s.getScope(), _, s, _) -select s.toString(), s.getLocation().toString() diff --git a/python/ql/test/library-tests/DuplicateCode/Similar.expected b/python/ql/test/library-tests/DuplicateCode/Similar.expected deleted file mode 100644 index 34e0b8f745c..00000000000 --- a/python/ql/test/library-tests/DuplicateCode/Similar.expected +++ /dev/null @@ -1,23 +0,0 @@ -| duplicate_test.py:9:1:20:17 | Similar code: 12 almost duplicated lines. | duplicate_test.py:47:1:58:17 | Similar code: 12 almost duplicated lines. | duplicate_test.py | 9 | 20 | -| duplicate_test.py:9:1:20:17 | Similar code: 12 almost duplicated lines. | duplicate_test.py:249:1:260:17 | Similar code: 12 almost duplicated lines. | duplicate_test.py | 9 | 20 | -| duplicate_test.py:9:1:20:17 | Similar code: 12 almost duplicated lines. | duplicate_test.py:287:1:298:17 | Similar code: 12 almost duplicated lines. | duplicate_test.py | 9 | 20 | -| duplicate_test.py:14:8:25:13 | Similar code: 12 almost duplicated lines. | duplicate_test.py:52:8:63:13 | Similar code: 12 almost duplicated lines. | duplicate_test.py | 14 | 25 | -| duplicate_test.py:14:8:25:13 | Similar code: 12 almost duplicated lines. | duplicate_test.py:254:8:265:13 | Similar code: 12 almost duplicated lines. | duplicate_test.py | 14 | 25 | -| duplicate_test.py:20:28:42:31 | Similar code: 23 almost duplicated lines. | duplicate_test.py:58:28:80:31 | Similar code: 23 almost duplicated lines. | duplicate_test.py | 20 | 42 | -| duplicate_test.py:20:28:42:31 | Similar code: 23 almost duplicated lines. | duplicate_test.py:260:28:282:31 | Similar code: 23 almost duplicated lines. | duplicate_test.py | 20 | 42 | -| duplicate_test.py:20:28:42:31 | Similar code: 23 almost duplicated lines. | duplicate_test.py:296:40:318:31 | Similar code: 23 almost duplicated lines. | duplicate_test.py | 20 | 42 | -| duplicate_test.py:36:1:47:0 | Similar code: 12 almost duplicated lines. | duplicate_test.py:74:1:84:0 | Similar code: 11 almost duplicated lines. | duplicate_test.py | 36 | 47 | -| duplicate_test.py:36:1:47:0 | Similar code: 12 almost duplicated lines. | duplicate_test.py:276:1:287:0 | Similar code: 12 almost duplicated lines. | duplicate_test.py | 36 | 47 | -| duplicate_test.py:36:22:56:26 | Similar code: 21 almost duplicated lines. | duplicate_test.py:276:21:296:26 | Similar code: 21 almost duplicated lines. | duplicate_test.py | 36 | 56 | -| duplicate_test.py:42:22:57:9 | Similar code: 16 almost duplicated lines. | duplicate_test.py:245:20:259:9 | Similar code: 15 almost duplicated lines. | duplicate_test.py | 42 | 57 | -| duplicate_test.py:42:22:57:9 | Similar code: 16 almost duplicated lines. | duplicate_test.py:282:22:297:9 | Similar code: 16 almost duplicated lines. | duplicate_test.py | 42 | 57 | -| duplicate_test.py:47:1:58:17 | Similar code: 12 almost duplicated lines. | duplicate_test.py:249:1:260:17 | Similar code: 12 almost duplicated lines. | duplicate_test.py | 47 | 58 | -| duplicate_test.py:47:1:58:17 | Similar code: 12 almost duplicated lines. | duplicate_test.py:287:1:298:17 | Similar code: 12 almost duplicated lines. | duplicate_test.py | 47 | 58 | -| duplicate_test.py:52:8:63:13 | Similar code: 12 almost duplicated lines. | duplicate_test.py:254:8:265:13 | Similar code: 12 almost duplicated lines. | duplicate_test.py | 52 | 63 | -| duplicate_test.py:58:28:80:31 | Similar code: 23 almost duplicated lines. | duplicate_test.py:260:28:282:31 | Similar code: 23 almost duplicated lines. | duplicate_test.py | 58 | 80 | -| duplicate_test.py:58:28:80:31 | Similar code: 23 almost duplicated lines. | duplicate_test.py:296:40:318:31 | Similar code: 23 almost duplicated lines. | duplicate_test.py | 58 | 80 | -| duplicate_test.py:74:1:84:0 | Similar code: 11 almost duplicated lines. | duplicate_test.py:276:1:287:0 | Similar code: 12 almost duplicated lines. | duplicate_test.py | 74 | 84 | -| duplicate_test.py:82:25:163:24 | Similar code: 82 almost duplicated lines. | duplicate_test.py:163:24:245:24 | Similar code: 83 almost duplicated lines. | duplicate_test.py | 82 | 163 | -| duplicate_test.py:245:20:259:9 | Similar code: 15 almost duplicated lines. | duplicate_test.py:282:22:297:9 | Similar code: 16 almost duplicated lines. | duplicate_test.py | 245 | 259 | -| duplicate_test.py:249:1:260:17 | Similar code: 12 almost duplicated lines. | duplicate_test.py:287:1:298:17 | Similar code: 12 almost duplicated lines. | duplicate_test.py | 249 | 260 | -| duplicate_test.py:260:28:282:31 | Similar code: 23 almost duplicated lines. | duplicate_test.py:296:40:318:31 | Similar code: 23 almost duplicated lines. | duplicate_test.py | 260 | 282 | diff --git a/python/ql/test/library-tests/DuplicateCode/Similar.ql b/python/ql/test/library-tests/DuplicateCode/Similar.ql deleted file mode 100644 index 3f9a99c8ecf..00000000000 --- a/python/ql/test/library-tests/DuplicateCode/Similar.ql +++ /dev/null @@ -1,22 +0,0 @@ -/** - * @name Similar - * @description Insert description here... - * @kind table - * @problem.severity warning - */ - -import python -import external.CodeDuplication - -predicate lexically_sorted(SimilarBlock dup1, SimilarBlock dup2) { - dup1.sourceFile().getAbsolutePath() < dup2.sourceFile().getAbsolutePath() - or - dup1.sourceFile().getAbsolutePath() = dup2.sourceFile().getAbsolutePath() and - dup1.sourceStartLine() < dup2.sourceStartLine() -} - -from SimilarBlock dup1, SimilarBlock dup2 -where - dup1.getEquivalenceClass() = dup2.getEquivalenceClass() and - lexically_sorted(dup1, dup2) -select dup1, dup2, dup1.sourceFile().getShortName(), dup1.sourceStartLine(), dup1.sourceEndLine() diff --git a/python/ql/test/library-tests/DuplicateCode/duplicate_test.py b/python/ql/test/library-tests/DuplicateCode/duplicate_test.py deleted file mode 100644 index a382fdefcef..00000000000 --- a/python/ql/test/library-tests/DuplicateCode/duplicate_test.py +++ /dev/null @@ -1,321 +0,0 @@ -#Code Duplication - - -#Exact duplication of function - -#Code copied from stdlib, copyright PSF. -#See http://www.python.org/download/releases/2.7/license/ - -def dis(x=None): - """Disassemble classes, methods, functions, or code. - - With no argument, disassemble the last traceback. - - """ - if x is None: - distb() - return - if isinstance(x, types.InstanceType): - x = x.__class__ - if hasattr(x, 'im_func'): - x = x.im_func - if hasattr(x, 'func_code'): - x = x.func_code - if hasattr(x, '__dict__'): - items = x.__dict__.items() - items.sort() - for name, x1 in items: - if isinstance(x1, _have_code): - print "Disassembly of %s:" % name - try: - dis(x1) - except TypeError, msg: - print "Sorry:", msg - print - elif hasattr(x, 'co_code'): - disassemble(x) - elif isinstance(x, str): - disassemble_string(x) - else: - raise TypeError, \ - "don't know how to disassemble %s objects" % \ - type(x).__name__ - - -#And duplicate version - -def dis2(x=None): - """Disassemble classes, methods, functions, or code. - - With no argument, disassemble the last traceback. - - """ - if x is None: - distb() - return - if isinstance(x, types.InstanceType): - x = x.__class__ - if hasattr(x, 'im_func'): - x = x.im_func - if hasattr(x, 'func_code'): - x = x.func_code - if hasattr(x, '__dict__'): - items = x.__dict__.items() - items.sort() - for name, x1 in items: - if isinstance(x1, _have_code): - print "Disassembly of %s:" % name - try: - dis(x1) - except TypeError, msg: - print "Sorry:", msg - print - elif hasattr(x, 'co_code'): - disassemble(x) - elif isinstance(x, str): - disassemble_string(x) - else: - raise TypeError, \ - "don't know how to disassemble %s objects" % \ - type(x).__name__ - -#Exactly duplicate class - -class Popen3: - """Class representing a child process. Normally, instances are created - internally by the functions popen2() and popen3().""" - - sts = -1 # Child not completed yet - - def __init__(self, cmd, capturestderr=False, bufsize=-1): - """The parameter 'cmd' is the shell command to execute in a - sub-process. On UNIX, 'cmd' may be a sequence, in which case arguments - will be passed directly to the program without shell intervention (as - with os.spawnv()). If 'cmd' is a string it will be passed to the shell - (as with os.system()). The 'capturestderr' flag, if true, specifies - that the object should capture standard error output of the child - process. The default is false. If the 'bufsize' parameter is - specified, it specifies the size of the I/O buffers to/from the child - process.""" - _cleanup() - self.cmd = cmd - p2cread, p2cwrite = os.pipe() - c2pread, c2pwrite = os.pipe() - if capturestderr: - errout, errin = os.pipe() - self.pid = os.fork() - if self.pid == 0: - # Child - os.dup2(p2cread, 0) - os.dup2(c2pwrite, 1) - if capturestderr: - os.dup2(errin, 2) - self._run_child(cmd) - os.close(p2cread) - self.tochild = os.fdopen(p2cwrite, 'w', bufsize) - os.close(c2pwrite) - self.fromchild = os.fdopen(c2pread, 'r', bufsize) - if capturestderr: - os.close(errin) - self.childerr = os.fdopen(errout, 'r', bufsize) - else: - self.childerr = None - - def __del__(self): - # In case the child hasn't been waited on, check if it's done. - self.poll(_deadstate=sys.maxint) - if self.sts < 0: - if _active is not None: - # Child is still running, keep us alive until we can wait on it. - _active.append(self) - - def _run_child(self, cmd): - if isinstance(cmd, basestring): - cmd = ['/bin/sh', '-c', cmd] - os.closerange(3, MAXFD) - try: - os.execvp(cmd[0], cmd) - finally: - os._exit(1) - - def poll(self, _deadstate=None): - """Return the exit status of the child process if it has finished, - or -1 if it hasn't finished yet.""" - if self.sts < 0: - try: - pid, sts = os.waitpid(self.pid, os.WNOHANG) - # pid will be 0 if self.pid hasn't terminated - if pid == self.pid: - self.sts = sts - except os.error: - if _deadstate is not None: - self.sts = _deadstate - return self.sts - - def wait(self): - """Wait for and return the exit status of the child process.""" - if self.sts < 0: - pid, sts = os.waitpid(self.pid, 0) - # This used to be a test, but it is believed to be - # always true, so I changed it to an assertion - mvl - assert pid == self.pid - self.sts = sts - return self.sts - - -class Popen3Again: - """Class representing a child process. Normally, instances are created - internally by the functions popen2() and popen3().""" - - sts = -1 # Child not completed yet - - def __init__(self, cmd, capturestderr=False, bufsize=-1): - """The parameter 'cmd' is the shell command to execute in a - sub-process. On UNIX, 'cmd' may be a sequence, in which case arguments - will be passed directly to the program without shell intervention (as - with os.spawnv()). If 'cmd' is a string it will be passed to the shell - (as with os.system()). The 'capturestderr' flag, if true, specifies - that the object should capture standard error output of the child - process. The default is false. If the 'bufsize' parameter is - specified, it specifies the size of the I/O buffers to/from the child - process.""" - _cleanup() - self.cmd = cmd - p2cread, p2cwrite = os.pipe() - c2pread, c2pwrite = os.pipe() - if capturestderr: - errout, errin = os.pipe() - self.pid = os.fork() - if self.pid == 0: - # Child - os.dup2(p2cread, 0) - os.dup2(c2pwrite, 1) - if capturestderr: - os.dup2(errin, 2) - self._run_child(cmd) - os.close(p2cread) - self.tochild = os.fdopen(p2cwrite, 'w', bufsize) - os.close(c2pwrite) - self.fromchild = os.fdopen(c2pread, 'r', bufsize) - if capturestderr: - os.close(errin) - self.childerr = os.fdopen(errout, 'r', bufsize) - else: - self.childerr = None - - def __del__(self): - # In case the child hasn't been waited on, check if it's done. - self.poll(_deadstate=sys.maxint) - if self.sts < 0: - if _active is not None: - # Child is still running, keep us alive until we can wait on it. - _active.append(self) - - def _run_child(self, cmd): - if isinstance(cmd, basestring): - cmd = ['/bin/sh', '-c', cmd] - os.closerange(3, MAXFD) - try: - os.execvp(cmd[0], cmd) - finally: - os._exit(1) - - def poll(self, _deadstate=None): - """Return the exit status of the child process if it has finished, - or -1 if it hasn't finished yet.""" - if self.sts < 0: - try: - pid, sts = os.waitpid(self.pid, os.WNOHANG) - # pid will be 0 if self.pid hasn't terminated - if pid == self.pid: - self.sts = sts - except os.error: - if _deadstate is not None: - self.sts = _deadstate - return self.sts - - def wait(self): - """Wait for and return the exit status of the child process.""" - if self.sts < 0: - pid, sts = os.waitpid(self.pid, 0) - # This used to be a test, but it is believed to be - # always true, so I changed it to an assertion - mvl - assert pid == self.pid - self.sts = sts - return self.sts - -#Duplicate function with identifiers changed - -def dis3(y=None): - """frobnicate classes, methods, functions, or code. - - With no argument, frobnicate the last traceback. - - """ - if y is None: - distb() - return - if isinstance(y, types.InstanceType): - y = y.__class__ - if hasattr(y, 'im_func'): - y = y.im_func - if hasattr(y, 'func_code'): - y = y.func_code - if hasattr(y, '__dict__'): - items = y.__dict__.items() - items.sort() - for name, y1 in items: - if isinstance(y1, _have_code): - print "Disassembly of %s:" % name - try: - dis(y1) - except TypeError, msg: - print "Sorry:", msg - print - elif hasattr(y, 'co_code'): - frobnicate(y) - elif isinstance(y, str): - frobnicate_string(y) - else: - raise TypeError, \ - "don't know how to frobnicate %s objects" % \ - type(y).__name__ - - -#Mostly similar function with changed identifiers - -def dis5(z=None): - """splat classes, methods, functions, or code. - - With no argument, splat the last traceback. - - """ - if z is None: - distb() - return - if isinstance(z, types.InstanceType): - z = z.__class__ - if hasattr(y, 'func_code'): - y = y.func_code - if hasattr(z, '__dict__'): - items = z.__dict__.items() - items.sort() - for name, z1 in items: - if isinstance(z1, _have_code): - print "Disassembly of %s:" % name - try: - dis(z1) - except TypeError, msg: - print "Sorry:", msg - print - elif hasattr(z, 'co_code'): - splat(z) - elif isinstance(z, str): - splat_string(z) - else: - raise TypeError, \ - "don't know how to splat %s objects" % \ - type(z).__name__ - - - diff --git a/python/ql/test/query-tests/UselessCode/DuplicateCode/DuplicateBlock.expected b/python/ql/test/query-tests/UselessCode/DuplicateCode/DuplicateBlock.expected deleted file mode 100644 index 9234fea78c7..00000000000 --- a/python/ql/test/query-tests/UselessCode/DuplicateCode/DuplicateBlock.expected +++ /dev/null @@ -1,8 +0,0 @@ -| duplicate_test.py:47:9:60:17 | Duplicate code: 14 duplicated lines. | Duplicate code: 14 lines are duplicated at duplicate_test.py:9 | -| duplicate_test.py:56:18:66:25 | Duplicate code: 11 duplicated lines. | Duplicate code: 11 lines are duplicated at duplicate_test.py:18 | -| duplicate_test.py:61:24:80:32 | Duplicate code: 20 duplicated lines. | Duplicate code: 20 lines are duplicated at duplicate_test.py:23 | -| duplicate_test.py:166:18:245:24 | Duplicate code: 80 duplicated lines. | Duplicate code: 80 lines are duplicated at duplicate_test.py:84 | -| duplicate_test.py:287:9:300:17 | Duplicate code: 14 duplicated lines. | Duplicate code: 14 lines are duplicated at duplicate_test.py:9 | -| duplicate_test.py:287:9:300:17 | Duplicate code: 14 duplicated lines. | Duplicate code: 14 lines are duplicated at duplicate_test.py:47 | -| duplicate_test.py:299:22:318:32 | Duplicate code: 20 duplicated lines. | Duplicate code: 20 lines are duplicated at duplicate_test.py:23 | -| duplicate_test.py:299:22:318:32 | Duplicate code: 20 duplicated lines. | Duplicate code: 20 lines are duplicated at duplicate_test.py:61 | diff --git a/python/ql/test/query-tests/UselessCode/DuplicateCode/DuplicateBlock.qlref b/python/ql/test/query-tests/UselessCode/DuplicateCode/DuplicateBlock.qlref deleted file mode 100644 index 6e6d439a040..00000000000 --- a/python/ql/test/query-tests/UselessCode/DuplicateCode/DuplicateBlock.qlref +++ /dev/null @@ -1 +0,0 @@ -external/DuplicateBlock.ql diff --git a/python/ql/test/query-tests/UselessCode/DuplicateCode/DuplicateFunction.expected b/python/ql/test/query-tests/UselessCode/DuplicateCode/DuplicateFunction.expected deleted file mode 100644 index c85079e3811..00000000000 --- a/python/ql/test/query-tests/UselessCode/DuplicateCode/DuplicateFunction.expected +++ /dev/null @@ -1,4 +0,0 @@ -| duplicate_test.py:9:1:9:16 | Function dis | All 26 statements in dis are identical in $@. | duplicate_test.py:47:1:47:17 | Function dis2 | dis2 | -| duplicate_test.py:47:1:47:17 | Function dis2 | All 26 statements in dis2 are identical in $@. | duplicate_test.py:9:1:9:16 | Function dis | dis | -| duplicate_test.py:287:1:287:17 | Function dis4 | All 24 statements in dis4 are identical in $@. | duplicate_test.py:9:1:9:16 | Function dis | dis | -| duplicate_test.py:287:1:287:17 | Function dis4 | All 24 statements in dis4 are identical in $@. | duplicate_test.py:47:1:47:17 | Function dis2 | dis2 | diff --git a/python/ql/test/query-tests/UselessCode/DuplicateCode/DuplicateFunction.qlref b/python/ql/test/query-tests/UselessCode/DuplicateCode/DuplicateFunction.qlref deleted file mode 100644 index bb7e3a45417..00000000000 --- a/python/ql/test/query-tests/UselessCode/DuplicateCode/DuplicateFunction.qlref +++ /dev/null @@ -1 +0,0 @@ -external/DuplicateFunction.ql diff --git a/python/ql/test/query-tests/UselessCode/DuplicateCode/MostlyDuplicateClass.expected b/python/ql/test/query-tests/UselessCode/DuplicateCode/MostlyDuplicateClass.expected deleted file mode 100644 index e628b371944..00000000000 --- a/python/ql/test/query-tests/UselessCode/DuplicateCode/MostlyDuplicateClass.expected +++ /dev/null @@ -1,2 +0,0 @@ -| duplicate_test.py:84:1:84:13 | Class Popen3 | All 55 statements in Popen3 are identical in $@. | duplicate_test.py:166:1:166:18 | Class Popen3Again | Popen3Again | -| duplicate_test.py:166:1:166:18 | Class Popen3Again | All 55 statements in Popen3Again are identical in $@. | duplicate_test.py:84:1:84:13 | Class Popen3 | Popen3 | diff --git a/python/ql/test/query-tests/UselessCode/DuplicateCode/MostlyDuplicateClass.qlref b/python/ql/test/query-tests/UselessCode/DuplicateCode/MostlyDuplicateClass.qlref deleted file mode 100644 index 4af1d7b760b..00000000000 --- a/python/ql/test/query-tests/UselessCode/DuplicateCode/MostlyDuplicateClass.qlref +++ /dev/null @@ -1 +0,0 @@ -external/MostlyDuplicateClass.ql diff --git a/python/ql/test/query-tests/UselessCode/DuplicateCode/MostlyDuplicateFile.expected b/python/ql/test/query-tests/UselessCode/DuplicateCode/MostlyDuplicateFile.expected deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/python/ql/test/query-tests/UselessCode/DuplicateCode/MostlyDuplicateFile.qlref b/python/ql/test/query-tests/UselessCode/DuplicateCode/MostlyDuplicateFile.qlref deleted file mode 100644 index ae06f160dec..00000000000 --- a/python/ql/test/query-tests/UselessCode/DuplicateCode/MostlyDuplicateFile.qlref +++ /dev/null @@ -1 +0,0 @@ -external/MostlyDuplicateFile.ql diff --git a/python/ql/test/query-tests/UselessCode/DuplicateCode/MostlySimilarFile.expected b/python/ql/test/query-tests/UselessCode/DuplicateCode/MostlySimilarFile.expected deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/python/ql/test/query-tests/UselessCode/DuplicateCode/MostlySimilarFile.qlref b/python/ql/test/query-tests/UselessCode/DuplicateCode/MostlySimilarFile.qlref deleted file mode 100644 index f8d493b0a55..00000000000 --- a/python/ql/test/query-tests/UselessCode/DuplicateCode/MostlySimilarFile.qlref +++ /dev/null @@ -1 +0,0 @@ -external/MostlySimilarFile.ql diff --git a/python/ql/test/query-tests/UselessCode/DuplicateCode/SimilarFunction.expected b/python/ql/test/query-tests/UselessCode/DuplicateCode/SimilarFunction.expected deleted file mode 100644 index 55408a91345..00000000000 --- a/python/ql/test/query-tests/UselessCode/DuplicateCode/SimilarFunction.expected +++ /dev/null @@ -1,12 +0,0 @@ -| duplicate_test.py:9:1:9:16 | Function dis | All statements in dis are similar in $@. | duplicate_test.py:249:1:249:17 | Function dis3 | dis3 | -| duplicate_test.py:9:1:9:16 | Function dis | All statements in dis are similar in $@. | duplicate_test.py:323:1:323:17 | Function dis5 | dis5 | -| duplicate_test.py:47:1:47:17 | Function dis2 | All statements in dis2 are similar in $@. | duplicate_test.py:249:1:249:17 | Function dis3 | dis3 | -| duplicate_test.py:47:1:47:17 | Function dis2 | All statements in dis2 are similar in $@. | duplicate_test.py:323:1:323:17 | Function dis5 | dis5 | -| duplicate_test.py:249:1:249:17 | Function dis3 | All statements in dis3 are similar in $@. | duplicate_test.py:9:1:9:16 | Function dis | dis | -| duplicate_test.py:249:1:249:17 | Function dis3 | All statements in dis3 are similar in $@. | duplicate_test.py:47:1:47:17 | Function dis2 | dis2 | -| duplicate_test.py:249:1:249:17 | Function dis3 | All statements in dis3 are similar in $@. | duplicate_test.py:323:1:323:17 | Function dis5 | dis5 | -| duplicate_test.py:287:1:287:17 | Function dis4 | All statements in dis4 are similar in $@. | duplicate_test.py:249:1:249:17 | Function dis3 | dis3 | -| duplicate_test.py:287:1:287:17 | Function dis4 | All statements in dis4 are similar in $@. | duplicate_test.py:323:1:323:17 | Function dis5 | dis5 | -| duplicate_test.py:323:1:323:17 | Function dis5 | All statements in dis5 are similar in $@. | duplicate_test.py:9:1:9:16 | Function dis | dis | -| duplicate_test.py:323:1:323:17 | Function dis5 | All statements in dis5 are similar in $@. | duplicate_test.py:47:1:47:17 | Function dis2 | dis2 | -| duplicate_test.py:323:1:323:17 | Function dis5 | All statements in dis5 are similar in $@. | duplicate_test.py:249:1:249:17 | Function dis3 | dis3 | diff --git a/python/ql/test/query-tests/UselessCode/DuplicateCode/SimilarFunction.qlref b/python/ql/test/query-tests/UselessCode/DuplicateCode/SimilarFunction.qlref deleted file mode 100644 index 665253817d7..00000000000 --- a/python/ql/test/query-tests/UselessCode/DuplicateCode/SimilarFunction.qlref +++ /dev/null @@ -1 +0,0 @@ -external/SimilarFunction.ql diff --git a/python/ql/test/query-tests/UselessCode/DuplicateCode/duplicate_test.py b/python/ql/test/query-tests/UselessCode/DuplicateCode/duplicate_test.py deleted file mode 100644 index cebfd7aca8a..00000000000 --- a/python/ql/test/query-tests/UselessCode/DuplicateCode/duplicate_test.py +++ /dev/null @@ -1,358 +0,0 @@ -#Code Duplication - - -#Exact duplication of function - -#Code copied from stdlib, copyright PSF. -#See http://www.python.org/download/releases/2.7/license/ - -def dis(x=None): - """Disassemble classes, methods, functions, or code. - - With no argument, disassemble the last traceback. - - """ - if x is None: - distb() - return - if isinstance(x, types.InstanceType): - x = x.__class__ - if hasattr(x, 'im_func'): - x = x.im_func - if hasattr(x, 'func_code'): - x = x.func_code - if hasattr(x, '__dict__'): - items = x.__dict__.items() - items.sort() - for name, x1 in items: - if isinstance(x1, _have_code): - print("Disassembly of %s:" % name) - try: - dis(x1) - except TypeError(msg): - print("Sorry:", msg) - print() - elif hasattr(x, 'co_code'): - disassemble(x) - elif isinstance(x, str): - disassemble_string(x) - else: - raise TypeError( - "don't know how to disassemble %s objects" % - type(x).__name__) - - -#And duplicate version - -def dis2(x=None): - """Disassemble classes, methods, functions, or code. - - With no argument, disassemble the last traceback. - - """ - if x is None: - distb() - return - if isinstance(x, types.InstanceType): - x = x.__class__ - if hasattr(x, 'im_func'): - x = x.im_func - if hasattr(x, 'func_code'): - x = x.func_code - if hasattr(x, '__dict__'): - items = x.__dict__.items() - items.sort() - for name, x1 in items: - if isinstance(x1, _have_code): - print("Disassembly of %s:" % name) - try: - dis(x1) - except TypeError(msg): - print("Sorry:", msg) - print() - elif hasattr(x, 'co_code'): - disassemble(x) - elif isinstance(x, str): - disassemble_string(x) - else: - raise TypeError( - "don't know how to disassemble %s objects" % - type(x).__name__) - -#Exactly duplicate class - -class Popen3: - """Class representing a child process. Normally, instances are created - internally by the functions popen2() and popen3().""" - - sts = -1 # Child not completed yet - - def __init__(self, cmd, capturestderr=False, bufsize=-1): - """The parameter 'cmd' is the shell command to execute in a - sub-process. On UNIX, 'cmd' may be a sequence, in which case arguments - will be passed directly to the program without shell intervention (as - with os.spawnv()). If 'cmd' is a string it will be passed to the shell - (as with os.system()). The 'capturestderr' flag, if true, specifies - that the object should capture standard error output of the child - process. The default is false. If the 'bufsize' parameter is - specified, it specifies the size of the I/O buffers to/from the child - process.""" - _cleanup() - self.cmd = cmd - p2cread, p2cwrite = os.pipe() - c2pread, c2pwrite = os.pipe() - if capturestderr: - errout, errin = os.pipe() - self.pid = os.fork() - if self.pid == 0: - # Child - os.dup2(p2cread, 0) - os.dup2(c2pwrite, 1) - if capturestderr: - os.dup2(errin, 2) - self._run_child(cmd) - os.close(p2cread) - self.tochild = os.fdopen(p2cwrite, 'w', bufsize) - os.close(c2pwrite) - self.fromchild = os.fdopen(c2pread, 'r', bufsize) - if capturestderr: - os.close(errin) - self.childerr = os.fdopen(errout, 'r', bufsize) - else: - self.childerr = None - - def __del__(self): - # In case the child hasn't been waited on, check if it's done. - self.poll(_deadstate=sys.maxint) - if self.sts < 0: - if _active is not None: - # Child is still running, keep us alive until we can wait on it. - _active.append(self) - - def _run_child(self, cmd): - if isinstance(cmd, basestring): - cmd = ['/bin/sh', '-c', cmd] - os.closerange(3, MAXFD) - try: - os.execvp(cmd[0], cmd) - finally: - os._exit(1) - - def poll(self, _deadstate=None): - """Return the exit status of the child process if it has finished, - or -1 if it hasn't finished yet.""" - if self.sts < 0: - try: - pid, sts = os.waitpid(self.pid, os.WNOHANG) - # pid will be 0 if self.pid hasn't terminated - if pid == self.pid: - self.sts = sts - except os.error: - if _deadstate is not None: - self.sts = _deadstate - return self.sts - - def wait(self): - """Wait for and return the exit status of the child process.""" - if self.sts < 0: - pid, sts = os.waitpid(self.pid, 0) - # This used to be a test, but it is believed to be - # always true, so I changed it to an assertion - mvl - assert pid == self.pid - self.sts = sts - return self.sts - - -class Popen3Again: - """Class representing a child process. Normally, instances are created - internally by the functions popen2() and popen3().""" - - sts = -1 # Child not completed yet - - def __init__(self, cmd, capturestderr=False, bufsize=-1): - """The parameter 'cmd' is the shell command to execute in a - sub-process. On UNIX, 'cmd' may be a sequence, in which case arguments - will be passed directly to the program without shell intervention (as - with os.spawnv()). If 'cmd' is a string it will be passed to the shell - (as with os.system()). The 'capturestderr' flag, if true, specifies - that the object should capture standard error output of the child - process. The default is false. If the 'bufsize' parameter is - specified, it specifies the size of the I/O buffers to/from the child - process.""" - _cleanup() - self.cmd = cmd - p2cread, p2cwrite = os.pipe() - c2pread, c2pwrite = os.pipe() - if capturestderr: - errout, errin = os.pipe() - self.pid = os.fork() - if self.pid == 0: - # Child - os.dup2(p2cread, 0) - os.dup2(c2pwrite, 1) - if capturestderr: - os.dup2(errin, 2) - self._run_child(cmd) - os.close(p2cread) - self.tochild = os.fdopen(p2cwrite, 'w', bufsize) - os.close(c2pwrite) - self.fromchild = os.fdopen(c2pread, 'r', bufsize) - if capturestderr: - os.close(errin) - self.childerr = os.fdopen(errout, 'r', bufsize) - else: - self.childerr = None - - def __del__(self): - # In case the child hasn't been waited on, check if it's done. - self.poll(_deadstate=sys.maxint) - if self.sts < 0: - if _active is not None: - # Child is still running, keep us alive until we can wait on it. - _active.append(self) - - def _run_child(self, cmd): - if isinstance(cmd, basestring): - cmd = ['/bin/sh', '-c', cmd] - os.closerange(3, MAXFD) - try: - os.execvp(cmd[0], cmd) - finally: - os._exit(1) - - def poll(self, _deadstate=None): - """Return the exit status of the child process if it has finished, - or -1 if it hasn't finished yet.""" - if self.sts < 0: - try: - pid, sts = os.waitpid(self.pid, os.WNOHANG) - # pid will be 0 if self.pid hasn't terminated - if pid == self.pid: - self.sts = sts - except os.error: - if _deadstate is not None: - self.sts = _deadstate - return self.sts - - def wait(self): - """Wait for and return the exit status of the child process.""" - if self.sts < 0: - pid, sts = os.waitpid(self.pid, 0) - # This used to be a test, but it is believed to be - # always true, so I changed it to an assertion - mvl - assert pid == self.pid - self.sts = sts - return self.sts - -#Duplicate function with identifiers changed - -def dis3(y=None): - """frobnicate classes, methods, functions, or code. - - With no argument, frobnicate the last traceback. - - """ - if y is None: - distb() - return - if isinstance(y, types.InstanceType): - y = y.__class__ - if hasattr(y, 'im_func'): - y = y.im_func - if hasattr(y, 'func_code'): - y = y.func_code - if hasattr(y, '__dict__'): - items = y.__dict__.items() - items.sort() - for name, y1 in items: - if isinstance(y1, _have_code): - print("Disassembly of %s:" % name) - try: - dis(y1) - except TypeError(msg): - print("Sorry:", msg) - print() - elif hasattr(y, 'co_code'): - frobnicate(y) - elif isinstance(y, str): - frobnicate_string(y) - else: - raise TypeError( - "don't know how to frobnicate %s objects" % - type(y).__name__) - - -#Mostly similar function - -def dis4(x=None): - """Disassemble classes, methods, functions, or code. - - With no argument, disassemble the last traceback. - - """ - if x is None: - distb() - return - if isinstance(x, types.InstanceType): - x = x.__class__ - if hasattr(x, 'im_func'): - x = x.im_func - if hasattr(x, '__dict__'): - items = x.__dict__.items() - items.sort() - for name, x1 in items: - if isinstance(x1, _have_code): - print("Disassembly of %s:" % name) - try: - dis(x1) - except TypeError(msg): - print("Sorry:", msg) - print() - elif hasattr(x, 'co_code'): - disassemble(x) - elif isinstance(x, str): - disassemble_string(x) - else: - raise TypeError( - "don't know how to disassemble %s objects" % - type(x).__name__) - - -#Similar function with changed identifiers - -def dis5(z=None): - """splat classes, methods, functions, or code. - - With no argument, splat the last traceback. - - """ - if z is None: - distb() - return - if isinstance(z, types.InstanceType): - z = z.__class__ - if hasattr(z, 'im_func'): - z = z.im_func - if hasattr(y, 'func_code'): - y = y.func_code - if hasattr(z, '__dict__'): - items = z.__dict__.items() - items.sort() - for name, z1 in items: - if isinstance(z1, _have_code): - print("Disassembly of %s:" % name) - try: - dis(z1) - except TypeError(msg): - print("Sorry:", msg) - print() - elif hasattr(z, 'co_code'): - splat(z) - elif isinstance(z, str): - splat_string(z) - else: - raise TypeError( - "don't know how to splat %s objects" % - type(z).__name__) - - diff --git a/python/ql/test/query-tests/UselessCode/DuplicateCode/similar.py b/python/ql/test/query-tests/UselessCode/DuplicateCode/similar.py deleted file mode 100644 index 8f36c5e65ed..00000000000 --- a/python/ql/test/query-tests/UselessCode/DuplicateCode/similar.py +++ /dev/null @@ -1,63 +0,0 @@ - - -def original(the_ast): - def walk(node, in_function, in_name_main): - def flags(): - return in_function * 2 + in_name_main - if isinstance(node, ast.Module): - for import_node in walk(node.body, in_function, in_name_main): - yield import_node - elif isinstance(node, ast.ImportFrom): - aliases = [ Alias(a.name, a.asname) for a in node.names] - yield FromImport(node.level, node.module, aliases, flags()) - elif isinstance(node, ast.Import): - aliases = [ Alias(a.name, a.asname) for a in node.names] - yield Import(aliases, flags()) - elif isinstance(node, ast.FunctionDef): - for _, child in ast.iter_fields(node): - for import_node in walk(child, True, in_name_main): - yield import_node - elif isinstance(node, list): - for n in node: - for import_node in walk(n, in_function, in_name_main): - yield import_node - return list(walk(the_ast, False, False)) - -def similar_1(the_ast): - def walk(node, in_function, in_name_main): - def flags(): - return in_function * 2 + in_name_main - if isinstance(node, ast.Module): - for import_node in walk(node.body, in_function, in_name_main): - yield import_node - elif isinstance(node, ast.ImportFrom): - aliases = [ Alias(a.name, a.asname) for a in node.names] - yield FromImport(node.level, node.module, aliases, flags()) - elif isinstance(node, ast.Import): - aliases = [ Alias(a.name, a.asname) for a in node.names] - yield Import(aliases, flags()) - elif isinstance(node, ast.FunctionDef): - for _, child in ast.iter_fields(node): - for import_node in walk(child, True, in_name_main): - yield import_node - return list(walk(the_ast, False, False)) - -def similar_2(the_ast): - def walk(node, in_function, in_name_main): - def flags(): - return in_function * 2 + in_name_main - if isinstance(node, ast.Module): - for import_node in walk(node.body, in_function, in_name_main): - yield import_node - elif isinstance(node, ast.Import): - aliases = [ Alias(a.name, a.asname) for a in node.names] - yield Import(aliases, flags()) - elif isinstance(node, ast.FunctionDef): - for _, child in ast.iter_fields(node): - for import_node in walk(child, True, in_name_main): - yield import_node - elif isinstance(node, list): - for n in node: - for import_node in walk(n, in_function, in_name_main): - yield import_node - return list(walk(the_ast, False, False)) From 6a3859fc83b8b46d8714ffa0a42ca372c3ca92c9 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 25 Mar 2021 15:31:43 +0100 Subject: [PATCH 370/725] C#: Remove unnecessary `pre` call in `FlowSummaryImpl.qll` --- .../csharp/dataflow/internal/FlowSummaryImpl.qll | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll index 7ed8b1f7e05..3c8c94c913c 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll @@ -323,19 +323,19 @@ module Private { isParameterPostUpdate(_, c, i) } - private Node pre(Node post) { - summaryPostUpdateNode(post, result) - or - not summaryPostUpdateNode(post, _) and - result = post - } - private predicate callbackOutput( SummarizedCallable c, SummaryComponentStack s, Node receiver, ReturnKind rk ) { any(SummaryNodeState state).isInputState(c, s) and s.head() = TReturnSummaryComponent(rk) and - receiver = pre(summaryNodeInputState(c, s.drop(1))) + receiver = summaryNodeInputState(c, s.drop(1)) + } + + private Node pre(Node post) { + summaryPostUpdateNode(post, result) + or + not summaryPostUpdateNode(post, _) and + result = post } private predicate callbackInput( From cdd613358bb8d22ffc1893db7d55041bdd51db12 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 25 Mar 2021 15:33:06 +0100 Subject: [PATCH 371/725] C#: Sync SSA files --- csharp/ql/src/semmle/code/cil/internal/SsaImplCommon.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/ql/src/semmle/code/cil/internal/SsaImplCommon.qll b/csharp/ql/src/semmle/code/cil/internal/SsaImplCommon.qll index be01c05b8fa..7a1879059c3 100644 --- a/csharp/ql/src/semmle/code/cil/internal/SsaImplCommon.qll +++ b/csharp/ql/src/semmle/code/cil/internal/SsaImplCommon.qll @@ -1,5 +1,5 @@ /** - * Provides a language-independant implementation of static single assignment + * Provides a language-independent implementation of static single assignment * (SSA) form. */ From 203b0e3d884edd7e3eaedee58f8c2d6b1b000a89 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 25 Mar 2021 15:32:57 +0100 Subject: [PATCH 372/725] Python: Add change note --- python/change-notes/2021-03-25-remove-legacy.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 python/change-notes/2021-03-25-remove-legacy.md diff --git a/python/change-notes/2021-03-25-remove-legacy.md b/python/change-notes/2021-03-25-remove-legacy.md new file mode 100644 index 00000000000..32ef43e9216 --- /dev/null +++ b/python/change-notes/2021-03-25-remove-legacy.md @@ -0,0 +1,3 @@ +lgtm,codescanning +* The legacy code duplication library has been removed. +* Legacy filter queries have been removed. From 344c2d3c3d475b64bd166d9ead1ff07382b5cd3b Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Thu, 25 Mar 2021 15:42:57 +0100 Subject: [PATCH 373/725] Update java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql --- .../ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql | 2 ++ 1 file changed, 2 insertions(+) diff --git a/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql b/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql index 343a073a27b..736fe100c39 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql @@ -2,6 +2,8 @@ * @name Use of a hash function without a salt * @description Hashed passwords without a salt are vulnerable to dictionary attacks. * @kind path-problem + * @problem.severity warning + * @precision low * @id java/hash-without-salt * @tags security * external/cwe-759 From 9abe02f419d4341a601b7f963ec7b1f0c8c68898 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 25 Mar 2021 16:00:18 +0100 Subject: [PATCH 374/725] Python: Fix query metadata for old queries that have been ported I'm not sure even I want to keep these around much longer. They seem to be causing more problem than they are doing good. --- .../CVE-2018-1281/BindToAllInterfaces.ql | 2 ++ .../Security-old-dataflow/CWE-022/PathInjection.ql | 2 ++ .../Security-old-dataflow/CWE-078/CommandInjection.ql | 2 ++ .../Security-old-dataflow/CWE-079/ReflectedXss.ql | 2 ++ .../Security-old-dataflow/CWE-089/SqlInjection.ql | 2 ++ .../Security-old-dataflow/CWE-094/CodeInjection.ql | 2 ++ .../Security-old-dataflow/CWE-326/WeakCrypto.ql | 7 ++----- .../Security-old-dataflow/CWE-502/UnsafeDeserialization.ql | 2 ++ .../Security-old-dataflow/CWE-601/UrlRedirect.ql | 2 ++ 9 files changed, 18 insertions(+), 5 deletions(-) diff --git a/python/ql/src/experimental/Security-old-dataflow/CVE-2018-1281/BindToAllInterfaces.ql b/python/ql/src/experimental/Security-old-dataflow/CVE-2018-1281/BindToAllInterfaces.ql index 012e606f6e2..e7c25b02e41 100644 --- a/python/ql/src/experimental/Security-old-dataflow/CVE-2018-1281/BindToAllInterfaces.ql +++ b/python/ql/src/experimental/Security-old-dataflow/CVE-2018-1281/BindToAllInterfaces.ql @@ -3,6 +3,8 @@ * @description Binding a socket to all interfaces opens it up to traffic from any IPv4 address * and is therefore associated with security risks. * @kind problem + * @id py/old/bind-socket-all-network-interfaces + * @problem.severity error */ import python diff --git a/python/ql/src/experimental/Security-old-dataflow/CWE-022/PathInjection.ql b/python/ql/src/experimental/Security-old-dataflow/CWE-022/PathInjection.ql index 10dc5a8353b..f14473e3268 100644 --- a/python/ql/src/experimental/Security-old-dataflow/CWE-022/PathInjection.ql +++ b/python/ql/src/experimental/Security-old-dataflow/CWE-022/PathInjection.ql @@ -2,6 +2,8 @@ * @name OLD QUERY: Uncontrolled data used in path expression * @description Accessing paths influenced by users can allow an attacker to access unexpected resources. * @kind path-problem + * @problem.severity error + * @id py/old/path-injection */ import python diff --git a/python/ql/src/experimental/Security-old-dataflow/CWE-078/CommandInjection.ql b/python/ql/src/experimental/Security-old-dataflow/CWE-078/CommandInjection.ql index 71c836ba8dc..8a7e8d96012 100755 --- a/python/ql/src/experimental/Security-old-dataflow/CWE-078/CommandInjection.ql +++ b/python/ql/src/experimental/Security-old-dataflow/CWE-078/CommandInjection.ql @@ -3,6 +3,8 @@ * @description Using externally controlled strings in a command line may allow a malicious * user to change the meaning of the command. * @kind path-problem + * @problem.severity error + * @id py/old/command-line-injection */ import python diff --git a/python/ql/src/experimental/Security-old-dataflow/CWE-079/ReflectedXss.ql b/python/ql/src/experimental/Security-old-dataflow/CWE-079/ReflectedXss.ql index a3d5b6ed9fc..5301920a779 100644 --- a/python/ql/src/experimental/Security-old-dataflow/CWE-079/ReflectedXss.ql +++ b/python/ql/src/experimental/Security-old-dataflow/CWE-079/ReflectedXss.ql @@ -3,6 +3,8 @@ * @description Writing user input directly to a web page * allows for a cross-site scripting vulnerability. * @kind path-problem + * @problem.severity error + * @id py/old/reflective-xss */ import python diff --git a/python/ql/src/experimental/Security-old-dataflow/CWE-089/SqlInjection.ql b/python/ql/src/experimental/Security-old-dataflow/CWE-089/SqlInjection.ql index 821b52235e1..303391d34ff 100755 --- a/python/ql/src/experimental/Security-old-dataflow/CWE-089/SqlInjection.ql +++ b/python/ql/src/experimental/Security-old-dataflow/CWE-089/SqlInjection.ql @@ -3,6 +3,8 @@ * @description Building a SQL query from user-controlled sources is vulnerable to insertion of * malicious SQL code by the user. * @kind path-problem + * @problem.severity error + * @id py/old/sql-injection */ import python diff --git a/python/ql/src/experimental/Security-old-dataflow/CWE-094/CodeInjection.ql b/python/ql/src/experimental/Security-old-dataflow/CWE-094/CodeInjection.ql index 697f6616997..50dd501c476 100644 --- a/python/ql/src/experimental/Security-old-dataflow/CWE-094/CodeInjection.ql +++ b/python/ql/src/experimental/Security-old-dataflow/CWE-094/CodeInjection.ql @@ -3,6 +3,8 @@ * @description Interpreting unsanitized user input as code allows a malicious user arbitrary * code execution. * @kind path-problem + * @problem.severity error + * @id py/old/code-injection */ import python diff --git a/python/ql/src/experimental/Security-old-dataflow/CWE-326/WeakCrypto.ql b/python/ql/src/experimental/Security-old-dataflow/CWE-326/WeakCrypto.ql index 27c1fcce429..efd9e968bda 100644 --- a/python/ql/src/experimental/Security-old-dataflow/CWE-326/WeakCrypto.ql +++ b/python/ql/src/experimental/Security-old-dataflow/CWE-326/WeakCrypto.ql @@ -1,12 +1,9 @@ /** - * @name Use of weak cryptographic key + * @name OLD QUERY: Use of weak cryptographic key * @description Use of a cryptographic key that is too small may allow the encryption to be broken. * @kind problem * @problem.severity error - * @precision high - * @id py/weak-crypto-key - * @tags security - * external/cwe/cwe-326 + * @id py/old/weak-crypto-key */ import python diff --git a/python/ql/src/experimental/Security-old-dataflow/CWE-502/UnsafeDeserialization.ql b/python/ql/src/experimental/Security-old-dataflow/CWE-502/UnsafeDeserialization.ql index 7e43c3b1497..32f01f7e3b6 100644 --- a/python/ql/src/experimental/Security-old-dataflow/CWE-502/UnsafeDeserialization.ql +++ b/python/ql/src/experimental/Security-old-dataflow/CWE-502/UnsafeDeserialization.ql @@ -2,6 +2,8 @@ * @name OLD QUERY: Deserializing untrusted input * @description Deserializing user-controlled data may allow attackers to execute arbitrary code. * @kind path-problem + * @id py/old/unsafe-deserialization + * @problem.severity error */ import python diff --git a/python/ql/src/experimental/Security-old-dataflow/CWE-601/UrlRedirect.ql b/python/ql/src/experimental/Security-old-dataflow/CWE-601/UrlRedirect.ql index f5c5491608d..91c422cd327 100644 --- a/python/ql/src/experimental/Security-old-dataflow/CWE-601/UrlRedirect.ql +++ b/python/ql/src/experimental/Security-old-dataflow/CWE-601/UrlRedirect.ql @@ -3,6 +3,8 @@ * @description URL redirection based on unvalidated user input * may cause redirection to malicious web sites. * @kind path-problem + * @problem.severity error + * @id py/old/url-redirection */ import python From 7fb5bd0cabae990ada21230304e5604e6173db6d Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Wed, 10 Mar 2021 11:51:59 +0000 Subject: [PATCH 375/725] Add tests for and slightly expand models of Commons Lang's ArrayUtils class --- .../code/java/frameworks/apache/Lang.qll | 16 +- .../apache-commons-lang3/ArrayUtilsTest.java | 75 + .../org/apache/commons/lang3/ArrayUtils.java | 1383 +++++++++++++++++ 3 files changed, 1470 insertions(+), 4 deletions(-) create mode 100644 java/ql/test/library-tests/frameworks/apache-commons-lang3/ArrayUtilsTest.java create mode 100644 java/ql/test/stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/ArrayUtils.java diff --git a/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll b/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll index 0b64361c018..7b37cc3b31e 100644 --- a/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll +++ b/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll @@ -49,19 +49,27 @@ private class ApacheLangArrayUtilsTaintPreservingMethod extends TaintPreservingC src = [0 .. getNumberOfParameters() - 1] or this.hasName([ - "clone", "nullToEmpty", "remove", "removeAll", "removeElement", "removeElements", "reverse", - "shift", "shuffle", "subarray", "swap", "toArray", "toMap", "toObject", "toPrimitive", - "toString", "toStringArray" + "clone", "nullToEmpty", "remove", "removeAll", "removeElement", "removeElements", + "subarray", "toArray", "toMap", "toObject", "removeAllOccurences", "removeAllOccurrences" ]) and src = 0 or + this.hasName("toPrimitive") and + src = [0, 1] + or this.hasName("add") and this.getNumberOfParameters() = 2 and src = [0, 1] or - this.hasName("add") and + this.hasName(["add"]) and this.getNumberOfParameters() = 3 and src = [0, 2] + or + this.hasName("insert") and + src = [1, 2] + or + this.hasName("get") and + src = [0, 2] } } diff --git a/java/ql/test/library-tests/frameworks/apache-commons-lang3/ArrayUtilsTest.java b/java/ql/test/library-tests/frameworks/apache-commons-lang3/ArrayUtilsTest.java new file mode 100644 index 00000000000..73773a8d61c --- /dev/null +++ b/java/ql/test/library-tests/frameworks/apache-commons-lang3/ArrayUtilsTest.java @@ -0,0 +1,75 @@ +import org.apache.commons.lang3.ArrayUtils; +import java.io.StringReader; +import java.nio.CharBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +class ArrayUtilsTest { + String taint() { return "tainted"; } + + private static class IntSource { + static int taint() { return 0; } + } + + void sink(Object o) {} + + void test() throws Exception { + + // All methods of this class copy the input array, so the incoming array should not be assigned taint. + String[] alreadyTainted = new String[] { taint() }; + String[] clean = new String[] { "Untainted" }; + + sink(ArrayUtils.add(clean, 0, taint())); // $hasTaintFlow + sink(ArrayUtils.add(alreadyTainted, 0, "clean")); // $hasTaintFlow + sink(ArrayUtils.add(clean, IntSource.taint(), "clean")); // Index argument does not contribute taint + sink(ArrayUtils.add(clean, taint())); // $hasTaintFlow + sink(ArrayUtils.add(alreadyTainted, "clean")); // $hasTaintFlow + sink(ArrayUtils.addAll(clean, "clean", taint())); // $hasTaintFlow + sink(ArrayUtils.addAll(clean, taint(), "clean")); // $hasTaintFlow + sink(ArrayUtils.addAll(alreadyTainted, "clean", "also clean")); // $hasTaintFlow + sink(ArrayUtils.addFirst(clean, taint())); // $hasTaintFlow + sink(ArrayUtils.addFirst(alreadyTainted, "clean")); // $hasTaintFlow + sink(ArrayUtils.clone(alreadyTainted)); // $hasTaintFlow + sink(ArrayUtils.get(alreadyTainted, 0)); // $hasTaintFlow + sink(ArrayUtils.get(clean, IntSource.taint())); // Index argument does not contribute taint + sink(ArrayUtils.get(alreadyTainted, 0, "default value")); // $hasTaintFlow + sink(ArrayUtils.get(clean, IntSource.taint(), "default value")); // Index argument does not contribute taint + sink(ArrayUtils.get(clean, 0, taint())); // $hasTaintFlow + sink(ArrayUtils.insert(IntSource.taint(), clean, "value1", "value2")); // Index argument does not contribute taint + sink(ArrayUtils.insert(0, alreadyTainted, "value1", "value2")); // $hasTaintFlow + sink(ArrayUtils.insert(0, clean, taint(), "value2")); // $hasTaintFlow + sink(ArrayUtils.insert(0, clean, "value1", taint())); // $hasTaintFlow + sink(ArrayUtils.nullToEmpty(alreadyTainted)); // $hasTaintFlow + sink(ArrayUtils.nullToEmpty(alreadyTainted, String[].class)); // $hasTaintFlow + sink(ArrayUtils.remove(alreadyTainted, 0)); // $hasTaintFlow + sink(ArrayUtils.remove(clean, IntSource.taint())); // Index argument does not contribute taint + sink(ArrayUtils.removeAll(alreadyTainted, 0, 1)); // $hasTaintFlow + sink(ArrayUtils.removeAll(clean, IntSource.taint(), 1)); // Index argument does not contribute taint + sink(ArrayUtils.removeAll(clean, 0, IntSource.taint())); // Index argument does not contribute taint + sink(ArrayUtils.removeAllOccurences(clean, taint())); // Removed argument does not contribute taint + sink(ArrayUtils.removeAllOccurences(alreadyTainted, "value to remove")); // $hasTaintFlow + sink(ArrayUtils.removeAllOccurrences(clean, taint())); // Removed argument does not contribute taint + sink(ArrayUtils.removeAllOccurrences(alreadyTainted, "value to remove")); // $hasTaintFlow + sink(ArrayUtils.removeElement(clean, taint())); // Removed argument does not contribute taint + sink(ArrayUtils.removeElement(alreadyTainted, "value to remove")); // $hasTaintFlow + sink(ArrayUtils.removeElements(alreadyTainted, 0, 1)); // $hasTaintFlow + sink(ArrayUtils.removeElements(clean, IntSource.taint(), 1)); // Index argument does not contribute taint + sink(ArrayUtils.removeElements(clean, 0, IntSource.taint())); // Index argument does not contribute taint + sink(ArrayUtils.subarray(alreadyTainted, 0, 0)); // $hasTaintFlow + sink(ArrayUtils.subarray(clean, IntSource.taint(), IntSource.taint())); // Index arguments do not contribute taint + sink(ArrayUtils.toArray("clean", taint())); // $hasTaintFlow + sink(ArrayUtils.toArray(taint(), "clean")); // $hasTaintFlow + sink(ArrayUtils.toMap(alreadyTainted).get("key")); // $hasTaintFlow + + // Check that none of the above had an effect on `clean`: + sink(clean); + + int[] taintedInts = new int[] { IntSource.taint() }; + Integer[] taintedBoxedInts = ArrayUtils.toObject(taintedInts); + sink(taintedBoxedInts); // $hasTaintFlow + sink(ArrayUtils.toPrimitive(taintedBoxedInts)); // $hasTaintFlow + sink(ArrayUtils.toPrimitive(new Integer[] {}, IntSource.taint())); // $hasTaintFlow + + } + } \ No newline at end of file diff --git a/java/ql/test/stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/ArrayUtils.java b/java/ql/test/stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/ArrayUtils.java new file mode 100644 index 00000000000..d57fe87b9a8 --- /dev/null +++ b/java/ql/test/stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/ArrayUtils.java @@ -0,0 +1,1383 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3; + +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.BitSet; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; + + +public class ArrayUtils { + public static boolean[] add(final boolean[] array, final boolean element) { + return null; + } + + public static boolean[] add(final boolean[] array, final int index, final boolean element) { + return null; + } + + public static byte[] add(final byte[] array, final byte element) { + return null; + } + + public static byte[] add(final byte[] array, final int index, final byte element) { + return null; + } + + public static char[] add(final char[] array, final char element) { + return null; + } + + public static char[] add(final char[] array, final int index, final char element) { + return null; + } + + public static double[] add(final double[] array, final double element) { + return null; + } + + public static double[] add(final double[] array, final int index, final double element) { + return null; + } + + public static float[] add(final float[] array, final float element) { + return null; + } + + public static float[] add(final float[] array, final int index, final float element) { + return null; + } + + public static int[] add(final int[] array, final int element) { + return null; + } + + public static int[] add(final int[] array, final int index, final int element) { + return null; + } + + public static long[] add(final long[] array, final int index, final long element) { + return null; + } + + public static long[] add(final long[] array, final long element) { + return null; + } + + public static short[] add(final short[] array, final int index, final short element) { + return null; + } + + public static short[] add(final short[] array, final short element) { + return null; + } + + public static T[] add(final T[] array, final int index, final T element) { + return null; + } + + public static T[] add(final T[] array, final T element) { + return null; + } + + public static boolean[] addAll(final boolean[] array1, final boolean... array2) { + return null; + } + + public static byte[] addAll(final byte[] array1, final byte... array2) { + return null; + } + + public static char[] addAll(final char[] array1, final char... array2) { + return null; + } + + public static double[] addAll(final double[] array1, final double... array2) { + return null; + } + + public static float[] addAll(final float[] array1, final float... array2) { + return null; + } + + public static int[] addAll(final int[] array1, final int... array2) { + return null; + } + + public static long[] addAll(final long[] array1, final long... array2) { + return null; + } + + public static short[] addAll(final short[] array1, final short... array2) { + return null; + } + + public static T[] addAll(final T[] array1, @SuppressWarnings("unchecked") final T... array2) { + return null; + } + + public static boolean[] addFirst(final boolean[] array, final boolean element) { + return null; + } + + public static byte[] addFirst(final byte[] array, final byte element) { + return null; + } + + public static char[] addFirst(final char[] array, final char element) { + return null; + } + + public static double[] addFirst(final double[] array, final double element) { + return null; + } + + public static float[] addFirst(final float[] array, final float element) { + return null; + } + + public static int[] addFirst(final int[] array, final int element) { + return null; + } + + public static long[] addFirst(final long[] array, final long element) { + return null; + } + + public static short[] addFirst(final short[] array, final short element) { + return null; + } + + public static T[] addFirst(final T[] array, final T element) { + return null; + } + + public static boolean[] clone(final boolean[] array) { + return null; + } + + public static byte[] clone(final byte[] array) { + return null; + } + + public static char[] clone(final char[] array) { + return null; + } + + public static double[] clone(final double[] array) { + return null; + } + + public static float[] clone(final float[] array) { + return null; + } + + public static int[] clone(final int[] array) { + return null; + } + + public static long[] clone(final long[] array) { + return null; + } + + public static short[] clone(final short[] array) { + return null; + } + + public static T[] clone(final T[] array) { + return null; + } + + public static boolean contains(final boolean[] array, final boolean valueToFind) { + return false; + } + + public static boolean contains(final byte[] array, final byte valueToFind) { + return false; + } + + public static boolean contains(final char[] array, final char valueToFind) { + return false; + } + + public static boolean contains(final double[] array, final double valueToFind) { + return false; + } + + public static boolean contains(final double[] array, final double valueToFind, final double tolerance) { + return false; + } + + public static boolean contains(final float[] array, final float valueToFind) { + return false; + } + + public static boolean contains(final int[] array, final int valueToFind) { + return false; + } + + public static boolean contains(final long[] array, final long valueToFind) { + return false; + } + + public static boolean contains(final Object[] array, final Object objectToFind) { + return false; + } + + public static boolean contains(final short[] array, final short valueToFind) { + return false; + } + + public static T get(final T[] array, final int index) { + return null; + } + + public static T get(final T[] array, final int index, final T defaultValue) { + return null; + } + + public static int getLength(final Object array) { + return 0; + } + + public static int hashCode(final Object array) { + return 0; + } + + public static BitSet indexesOf(final boolean[] array, final boolean valueToFind) { + return null; + } + + public static BitSet indexesOf(final boolean[] array, final boolean valueToFind, int startIndex) { + return null; + } + + public static BitSet indexesOf(final byte[] array, final byte valueToFind) { + return null; + } + + public static BitSet indexesOf(final byte[] array, final byte valueToFind, int startIndex) { + return null; + } + + public static BitSet indexesOf(final char[] array, final char valueToFind) { + return null; + } + + public static BitSet indexesOf(final char[] array, final char valueToFind, int startIndex) { + return null; + } + + public static BitSet indexesOf(final double[] array, final double valueToFind) { + return null; + } + + public static BitSet indexesOf(final double[] array, final double valueToFind, final double tolerance) { + return null; + } + + public static BitSet indexesOf(final double[] array, final double valueToFind, int startIndex) { + return null; + } + + public static BitSet indexesOf(final double[] array, final double valueToFind, int startIndex, final double tolerance) { + return null; + } + + public static BitSet indexesOf(final float[] array, final float valueToFind) { + return null; + } + + public static BitSet indexesOf(final float[] array, final float valueToFind, int startIndex) { + return null; + } + + public static BitSet indexesOf(final int[] array, final int valueToFind) { + return null; + } + + public static BitSet indexesOf(final int[] array, final int valueToFind, int startIndex) { + return null; + } + + public static BitSet indexesOf(final long[] array, final long valueToFind) { + return null; + } + + public static BitSet indexesOf(final long[] array, final long valueToFind, int startIndex) { + return null; + } + + public static BitSet indexesOf(final Object[] array, final Object objectToFind) { + return null; + } + + public static BitSet indexesOf(final Object[] array, final Object objectToFind, int startIndex) { + return null; + } + + public static BitSet indexesOf(final short[] array, final short valueToFind) { + return null; + } + + public static BitSet indexesOf(final short[] array, final short valueToFind, int startIndex) { + return null; + } + + public static int indexOf(final boolean[] array, final boolean valueToFind) { + return 0; + } + + public static int indexOf(final boolean[] array, final boolean valueToFind, int startIndex) { + return 0; + } + + public static int indexOf(final byte[] array, final byte valueToFind) { + return 0; + } + + public static int indexOf(final byte[] array, final byte valueToFind, int startIndex) { + return 0; + } + + public static int indexOf(final char[] array, final char valueToFind) { + return 0; + } + + public static int indexOf(final char[] array, final char valueToFind, int startIndex) { + return 0; + } + + public static int indexOf(final double[] array, final double valueToFind) { + return 0; + } + + public static int indexOf(final double[] array, final double valueToFind, final double tolerance) { + return 0; + } + + public static int indexOf(final double[] array, final double valueToFind, int startIndex) { + return 0; + } + + public static int indexOf(final double[] array, final double valueToFind, int startIndex, final double tolerance) { + return 0; + } + + public static int indexOf(final float[] array, final float valueToFind) { + return 0; + } + + public static int indexOf(final float[] array, final float valueToFind, int startIndex) { + return 0; + } + + public static int indexOf(final int[] array, final int valueToFind) { + return 0; + } + +public static int indexOf(final int[] array, final int valueToFind, int startIndex) { + return 0; +} + + public static int indexOf(final long[] array, final long valueToFind) { + return 0; + } + + public static int indexOf(final long[] array, final long valueToFind, int startIndex) { + return 0; + } + + public static int indexOf(final Object[] array, final Object objectToFind) { + return 0; + } + + public static int indexOf(final Object[] array, final Object objectToFind, int startIndex) { + return 0; + } + + public static int indexOf(final short[] array, final short valueToFind) { + return 0; + } + + public static int indexOf(final short[] array, final short valueToFind, int startIndex) { + return 0; + } + + public static boolean[] insert(final int index, final boolean[] array, final boolean... values) { + return null; + } + + public static byte[] insert(final int index, final byte[] array, final byte... values) { + return null; + } + + public static char[] insert(final int index, final char[] array, final char... values) { + return null; + } + + public static double[] insert(final int index, final double[] array, final double... values) { + return null; + } + + public static float[] insert(final int index, final float[] array, final float... values) { + return null; + } + + public static int[] insert(final int index, final int[] array, final int... values) { + return null; + } + + public static long[] insert(final int index, final long[] array, final long... values) { + return null; + } + + public static short[] insert(final int index, final short[] array, final short... values) { + return null; + } + + public static T[] insert(final int index, final T[] array, final T... values) { + return null; + } + + public static boolean isArrayIndexValid(final T[] array, final int index) { + return false; + } + + public static boolean isEmpty(final boolean[] array) { + return false; + } + + public static boolean isEmpty(final byte[] array) { + return false; + } + + public static boolean isEmpty(final char[] array) { + return false; + } + + public static boolean isEmpty(final double[] array) { + return false; + } + + public static boolean isEmpty(final float[] array) { + return false; + } + + public static boolean isEmpty(final int[] array) { + return false; + } + + public static boolean isEmpty(final long[] array) { + return false; + } + + public static boolean isEmpty(final Object[] array) { + return false; + } + + public static boolean isEmpty(final short[] array) { + return false; + } + + public static boolean isEquals(final Object array1, final Object array2) { + return false; + } + + public static boolean isNotEmpty(final boolean[] array) { + return false; + } + + public static boolean isNotEmpty(final byte[] array) { + return false; + } + + public static boolean isNotEmpty(final char[] array) { + return false; + } + + public static boolean isNotEmpty(final double[] array) { + return false; + } + + public static boolean isNotEmpty(final float[] array) { + return false; + } + + public static boolean isNotEmpty(final int[] array) { + return false; + } + + public static boolean isNotEmpty(final long[] array) { + return false; + } + + public static boolean isNotEmpty(final short[] array) { + return false; + } + + public static boolean isNotEmpty(final T[] array) { + return false; + } + + public static boolean isSameLength(final boolean[] array1, final boolean[] array2) { + return false; + } + + public static boolean isSameLength(final byte[] array1, final byte[] array2) { + return false; + } + + public static boolean isSameLength(final char[] array1, final char[] array2) { + return false; + } + + public static boolean isSameLength(final double[] array1, final double[] array2) { + return false; + } + + public static boolean isSameLength(final float[] array1, final float[] array2) { + return false; + } + + public static boolean isSameLength(final int[] array1, final int[] array2) { + return false; + } + + public static boolean isSameLength(final long[] array1, final long[] array2) { + return false; + } + + public static boolean isSameLength(final Object array1, final Object array2) { + return false; + } + + public static boolean isSameLength(final Object[] array1, final Object[] array2) { + return false; + } + + public static boolean isSameLength(final short[] array1, final short[] array2) { + return false; + } + + public static boolean isSameType(final Object array1, final Object array2) { + return false; + } + + public static boolean isSorted(final boolean[] array) { + return false; + } + + public static boolean isSorted(final byte[] array) { + return false; + } + + public static boolean isSorted(final char[] array) { + return false; + } + + public static boolean isSorted(final double[] array) { + return false; + } + + public static boolean isSorted(final float[] array) { + return false; + } + + public static boolean isSorted(final int[] array) { + return false; + } + + public static boolean isSorted(final long[] array) { + return false; + } + + public static boolean isSorted(final short[] array) { + return false; + } + + public static > boolean isSorted(final T[] array) { + return false; + } + + public static boolean isSorted(final T[] array, final Comparator comparator) { + return false; + } + + public static int lastIndexOf(final boolean[] array, final boolean valueToFind) { + return 0; + } + + public static int lastIndexOf(final boolean[] array, final boolean valueToFind, int startIndex) { + return 0; + } + + public static int lastIndexOf(final byte[] array, final byte valueToFind) { + return 0; + } + + public static int lastIndexOf(final byte[] array, final byte valueToFind, int startIndex) { + return 0; + } + + public static int lastIndexOf(final char[] array, final char valueToFind) { + return 0; + } + + public static int lastIndexOf(final char[] array, final char valueToFind, int startIndex) { + return 0; + } + + public static int lastIndexOf(final double[] array, final double valueToFind) { + return 0; + } + + public static int lastIndexOf(final double[] array, final double valueToFind, final double tolerance) { + return 0; + } + + public static int lastIndexOf(final double[] array, final double valueToFind, int startIndex) { + return 0; + } + + public static int lastIndexOf(final double[] array, final double valueToFind, int startIndex, final double tolerance) { + return 0; + } + + public static int lastIndexOf(final float[] array, final float valueToFind) { + return 0; + } + + public static int lastIndexOf(final float[] array, final float valueToFind, int startIndex) { + return 0; + } + + public static int lastIndexOf(final int[] array, final int valueToFind) { + return 0; + } + + public static int lastIndexOf(final int[] array, final int valueToFind, int startIndex) { + return 0; + } + + public static int lastIndexOf(final long[] array, final long valueToFind) { + return 0; + } + + public static int lastIndexOf(final long[] array, final long valueToFind, int startIndex) { + return 0; + } + + public static int lastIndexOf(final Object[] array, final Object objectToFind) { + return 0; + } + + public static int lastIndexOf(final Object[] array, final Object objectToFind, int startIndex) { + return 0; + } + + public static int lastIndexOf(final short[] array, final short valueToFind) { + return 0; + } + + public static int lastIndexOf(final short[] array, final short valueToFind, int startIndex) { + return 0; + } + + public static boolean[] nullToEmpty(final boolean[] array) { + return null; + } + + public static Boolean[] nullToEmpty(final Boolean[] array) { + return null; + } + + public static byte[] nullToEmpty(final byte[] array) { + return null; + } + + public static Byte[] nullToEmpty(final Byte[] array) { + return null; + } + + public static char[] nullToEmpty(final char[] array) { + return null; + } + + public static Character[] nullToEmpty(final Character[] array) { + return null; + } + + public static Class[] nullToEmpty(final Class[] array) { + return null; + } + + public static double[] nullToEmpty(final double[] array) { + return null; + } + + public static Double[] nullToEmpty(final Double[] array) { + return null; + } + + public static float[] nullToEmpty(final float[] array) { + return null; + } + + public static Float[] nullToEmpty(final Float[] array) { + return null; + } + + public static int[] nullToEmpty(final int[] array) { + return null; + } + + public static Integer[] nullToEmpty(final Integer[] array) { + return null; + } + + public static long[] nullToEmpty(final long[] array) { + return null; + } + + public static Long[] nullToEmpty(final Long[] array) { + return null; + } + + public static Object[] nullToEmpty(final Object[] array) { + return null; + } + + public static short[] nullToEmpty(final short[] array) { + return null; + } + + public static Short[] nullToEmpty(final Short[] array) { + return null; + } + + public static String[] nullToEmpty(final String[] array) { + return null; + } + + public static T[] nullToEmpty(final T[] array, final Class type) { + return null; + } + + public static boolean[] remove(final boolean[] array, final int index) { + return null; + } + + public static byte[] remove(final byte[] array, final int index) { + return null; + } + + public static char[] remove(final char[] array, final int index) { + return null; + } + + public static double[] remove(final double[] array, final int index) { + return null; + } + + public static float[] remove(final float[] array, final int index) { + return null; + } + + public static int[] remove(final int[] array, final int index) { + return null; + } + + public static long[] remove(final long[] array, final int index) { + return null; + } + + public static short[] remove(final short[] array, final int index) { + return null; + } + + public static T[] remove(final T[] array, final int index) { + return null; + } + + public static boolean[] removeAll(final boolean[] array, final int... indices) { + return null; + } + + public static byte[] removeAll(final byte[] array, final int... indices) { + return null; + } + + public static char[] removeAll(final char[] array, final int... indices) { + return null; + } + + public static double[] removeAll(final double[] array, final int... indices) { + return null; + } + + public static float[] removeAll(final float[] array, final int... indices) { + return null; + } + + public static int[] removeAll(final int[] array, final int... indices) { + return null; + } + + public static long[] removeAll(final long[] array, final int... indices) { + return null; + } + + public static short[] removeAll(final short[] array, final int... indices) { + return null; + } + + public static T[] removeAll(final T[] array, final int... indices) { + return null; + } + + public static boolean[] removeAllOccurences(final boolean[] array, final boolean element) { + return null; + } + + public static byte[] removeAllOccurences(final byte[] array, final byte element) { + return null; + } + + public static char[] removeAllOccurences(final char[] array, final char element) { + return null; + } + + public static double[] removeAllOccurences(final double[] array, final double element) { + return null; + } + + public static float[] removeAllOccurences(final float[] array, final float element) { + return null; + } + + public static int[] removeAllOccurences(final int[] array, final int element) { + return null; + } + + public static long[] removeAllOccurences(final long[] array, final long element) { + return null; + } + + public static short[] removeAllOccurences(final short[] array, final short element) { + return null; + } + + public static T[] removeAllOccurences(final T[] array, final T element) { + return null; + } + + public static boolean[] removeAllOccurrences(final boolean[] array, final boolean element) { + return null; + } + + public static byte[] removeAllOccurrences(final byte[] array, final byte element) { + return null; + } + + public static char[] removeAllOccurrences(final char[] array, final char element) { + return null; + } + + public static double[] removeAllOccurrences(final double[] array, final double element) { + return null; + } + + public static float[] removeAllOccurrences(final float[] array, final float element) { + return null; + } + + public static int[] removeAllOccurrences(final int[] array, final int element) { + return null; + } + + public static long[] removeAllOccurrences(final long[] array, final long element) { + return null; + } + + public static short[] removeAllOccurrences(final short[] array, final short element) { + return null; + } + + public static T[] removeAllOccurrences(final T[] array, final T element) { + return null; + } + + public static boolean[] removeElement(final boolean[] array, final boolean element) { + return null; + } + + public static byte[] removeElement(final byte[] array, final byte element) { + return null; + } + + public static char[] removeElement(final char[] array, final char element) { + return null; + } + + public static double[] removeElement(final double[] array, final double element) { + return null; + } + + public static float[] removeElement(final float[] array, final float element) { + return null; + } + + public static int[] removeElement(final int[] array, final int element) { + return null; + } + + public static long[] removeElement(final long[] array, final long element) { + return null; + } + + public static short[] removeElement(final short[] array, final short element) { + return null; + } + + public static T[] removeElement(final T[] array, final Object element) { + return null; + } + + public static boolean[] removeElements(final boolean[] array, final boolean... values) { + return null; + } + + public static byte[] removeElements(final byte[] array, final byte... values) { + return null; + } + + public static char[] removeElements(final char[] array, final char... values) { + return null; + } + + public static double[] removeElements(final double[] array, final double... values) { + return null; + } + + public static float[] removeElements(final float[] array, final float... values) { + return null; + } + + public static int[] removeElements(final int[] array, final int... values) { + return null; + } + + public static long[] removeElements(final long[] array, final long... values) { + return null; + } + + public static short[] removeElements(final short[] array, final short... values) { + return null; + } + + public static T[] removeElements(final T[] array, final T... values) { + return null; + } + + public static void reverse(final boolean[] array) { + } + + public static void reverse(final boolean[] array, final int startIndexInclusive, final int endIndexExclusive) { + } + + public static void reverse(final byte[] array) { + } + + public static void reverse(final byte[] array, final int startIndexInclusive, final int endIndexExclusive) { + } + + public static void reverse(final char[] array) { + } + + public static void reverse(final char[] array, final int startIndexInclusive, final int endIndexExclusive) { + } + + public static void reverse(final double[] array) { + } + + public static void reverse(final double[] array, final int startIndexInclusive, final int endIndexExclusive) { + } + + public static void reverse(final float[] array) { + } + + public static void reverse(final float[] array, final int startIndexInclusive, final int endIndexExclusive) { + } + + public static void reverse(final int[] array) { + } + + public static void reverse(final int[] array, final int startIndexInclusive, final int endIndexExclusive) { + } + + public static void reverse(final long[] array) { + } + + public static void reverse(final long[] array, final int startIndexInclusive, final int endIndexExclusive) { + } + + public static void reverse(final Object[] array) { + } + + public static void reverse(final Object[] array, final int startIndexInclusive, final int endIndexExclusive) { + } + + public static void reverse(final short[] array) { + } + + public static void reverse(final short[] array, final int startIndexInclusive, final int endIndexExclusive) { + } + + public static void shift(final boolean[] array, final int offset) { + } + + public static void shift(final boolean[] array, int startIndexInclusive, int endIndexExclusive, int offset) { + } + + public static void shift(final byte[] array, final int offset) { + } + + public static void shift(final byte[] array, int startIndexInclusive, int endIndexExclusive, int offset) { + } + + public static void shift(final char[] array, final int offset) { + } + + public static void shift(final char[] array, int startIndexInclusive, int endIndexExclusive, int offset) { + } + + public static void shift(final double[] array, final int offset) { + } + + public static void shift(final double[] array, int startIndexInclusive, int endIndexExclusive, int offset) { + } + + public static void shift(final float[] array, final int offset) { + } + + public static void shift(final float[] array, int startIndexInclusive, int endIndexExclusive, int offset) { + } + + public static void shift(final int[] array, final int offset) { + } + + public static void shift(final int[] array, int startIndexInclusive, int endIndexExclusive, int offset) { + } + + public static void shift(final long[] array, final int offset) { + } + + public static void shift(final long[] array, int startIndexInclusive, int endIndexExclusive, int offset) { + } + + public static void shift(final Object[] array, final int offset) { + } + + public static void shift(final Object[] array, int startIndexInclusive, int endIndexExclusive, int offset) { + } + + public static void shift(final short[] array, final int offset) { + } + + public static void shift(final short[] array, int startIndexInclusive, int endIndexExclusive, int offset) { + } + + public static void shuffle(final boolean[] array) { + } + + public static void shuffle(final boolean[] array, final Random random) { + } + + public static void shuffle(final byte[] array) { + } + + public static void shuffle(final byte[] array, final Random random) { + } + + public static void shuffle(final char[] array) { + } + + public static void shuffle(final char[] array, final Random random) { + } + + public static void shuffle(final double[] array) { + } + + public static void shuffle(final double[] array, final Random random) { + } + + public static void shuffle(final float[] array) { + } + + public static void shuffle(final float[] array, final Random random) { + } + + public static void shuffle(final int[] array) { + } + + public static void shuffle(final int[] array, final Random random) { + } + + public static void shuffle(final long[] array) { + } + + public static void shuffle(final long[] array, final Random random) { + } + + public static void shuffle(final Object[] array) { + } + + public static void shuffle(final Object[] array, final Random random) { + } + + public static void shuffle(final short[] array) { + } + + public static void shuffle(final short[] array, final Random random) { + } + + public static boolean[] subarray(final boolean[] array, int startIndexInclusive, int endIndexExclusive) { + return null; + } + + public static byte[] subarray(final byte[] array, int startIndexInclusive, int endIndexExclusive) { + return null; + } + + public static char[] subarray(final char[] array, int startIndexInclusive, int endIndexExclusive) { + return null; + } + + public static double[] subarray(final double[] array, int startIndexInclusive, int endIndexExclusive) { + return null; + } + + public static float[] subarray(final float[] array, int startIndexInclusive, int endIndexExclusive) { + return null; + } + + public static int[] subarray(final int[] array, int startIndexInclusive, int endIndexExclusive) { + return null; + } + + public static long[] subarray(final long[] array, int startIndexInclusive, int endIndexExclusive) { + return null; + } + + public static short[] subarray(final short[] array, int startIndexInclusive, int endIndexExclusive) { + return null; + } + + public static T[] subarray(final T[] array, int startIndexInclusive, int endIndexExclusive) { + return null; + } + + public static void swap(final boolean[] array, final int offset1, final int offset2) { + } + + public static void swap(final boolean[] array, int offset1, int offset2, int len) { + } + + public static void swap(final byte[] array, final int offset1, final int offset2) { + } + + public static void swap(final byte[] array, int offset1, int offset2, int len) { + } + + public static void swap(final char[] array, final int offset1, final int offset2) { + } + + public static void swap(final char[] array, int offset1, int offset2, int len) { + } + + public static void swap(final double[] array, final int offset1, final int offset2) { + } + + public static void swap(final double[] array, int offset1, int offset2, int len) { + } + + public static void swap(final float[] array, final int offset1, final int offset2) { + } + + public static void swap(final float[] array, int offset1, int offset2, int len) { + } + + public static void swap(final int[] array, final int offset1, final int offset2) { + } + + public static void swap(final int[] array, int offset1, int offset2, int len) { + } + + public static void swap(final long[] array, final int offset1, final int offset2) { + } + + public static void swap(final long[] array, int offset1, int offset2, int len) { + } + + public static void swap(final Object[] array, final int offset1, final int offset2) { + } + + public static void swap(final Object[] array, int offset1, int offset2, int len) { + } + + public static void swap(final short[] array, final int offset1, final int offset2) { + } + + public static void swap(final short[] array, int offset1, int offset2, int len) { + } + + public static T[] toArray(@SuppressWarnings("unchecked") final T... items) { + return null; + } + + public static Map toMap(final Object[] array) { + return null; + } + + public static Boolean[] toObject(final boolean[] array) { + return null; + } + + public static Byte[] toObject(final byte[] array) { + return null; + } + + public static Character[] toObject(final char[] array) { + return null; + } + + public static Double[] toObject(final double[] array) { + return null; + } + + public static Float[] toObject(final float[] array) { + return null; + } + + public static Integer[] toObject(final int[] array) { + return null; + } + + public static Long[] toObject(final long[] array) { + return null; + } + + public static Short[] toObject(final short[] array) { + return null; + } + + public static boolean[] toPrimitive(final Boolean[] array) { + return null; + } + + public static boolean[] toPrimitive(final Boolean[] array, final boolean valueForNull) { + return null; + } + + public static byte[] toPrimitive(final Byte[] array) { + return null; + } + + public static byte[] toPrimitive(final Byte[] array, final byte valueForNull) { + return null; + } + + public static char[] toPrimitive(final Character[] array) { + return null; + } + + public static char[] toPrimitive(final Character[] array, final char valueForNull) { + return null; + } + + public static double[] toPrimitive(final Double[] array) { + return null; + } + + public static double[] toPrimitive(final Double[] array, final double valueForNull) { + return null; + } + + public static float[] toPrimitive(final Float[] array) { + return null; + } + + public static float[] toPrimitive(final Float[] array, final float valueForNull) { + return null; + } + + public static int[] toPrimitive(final Integer[] array) { + return null; + } + + public static int[] toPrimitive(final Integer[] array, final int valueForNull) { + return null; + } + + public static long[] toPrimitive(final Long[] array) { + return null; + } + + public static long[] toPrimitive(final Long[] array, final long valueForNull) { + return null; + } + + public static Object toPrimitive(final Object array) { + return null; + } + + public static short[] toPrimitive(final Short[] array) { + return null; + } + + public static short[] toPrimitive(final Short[] array, final short valueForNull) { + return null; + } + + public static String toString(final Object array) { + return null; + } + + public static String toString(final Object array, final String stringIfNull) { + return null; + } + + public static String[] toStringArray(final Object[] array) { + return null; + } + + public static String[] toStringArray(final Object[] array, final String valueForNullElements) { + return null; + } + + public ArrayUtils() { + } + +} From 1beac06236d195ba394dbc57561c8c0d042c8d90 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Wed, 10 Mar 2021 12:41:28 +0000 Subject: [PATCH 376/725] Translate ArrayUtils models to CSV --- .../code/java/frameworks/apache/Lang.qll | 79 +++++++++---------- 1 file changed, 38 insertions(+), 41 deletions(-) diff --git a/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll b/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll index 7b37cc3b31e..eda817026b3 100644 --- a/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll +++ b/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll @@ -14,15 +14,6 @@ class TypeApacheRandomStringUtils extends Class { } } -/** - * The class `org.apache.commons.lang.ArrayUtils` or `org.apache.commons.lang3.ArrayUtils`. - */ -class TypeApacheArrayUtils extends Class { - TypeApacheArrayUtils() { - hasQualifiedName(["org.apache.commons.lang", "org.apache.commons.lang3"], "ArrayUtils") - } -} - /** * The method `deserialize` in either `org.apache.commons.lang.SerializationUtils` * or `org.apache.commons.lang3.SerializationUtils`. @@ -37,39 +28,45 @@ class MethodApacheSerializationUtilsDeserialize extends Method { } /** - * A taint preserving method on `org.apache.commons.lang.ArrayUtils` or `org.apache.commons.lang3.ArrayUtils` + * Taint-propagating models for `ArrayUtils`. */ -private class ApacheLangArrayUtilsTaintPreservingMethod extends TaintPreservingCallable { - ApacheLangArrayUtilsTaintPreservingMethod() { - this.getDeclaringType() instanceof TypeApacheArrayUtils - } - - override predicate returnsTaintFrom(int src) { - this.hasName(["addAll", "addFirst"]) and - src = [0 .. getNumberOfParameters() - 1] - or - this.hasName([ - "clone", "nullToEmpty", "remove", "removeAll", "removeElement", "removeElements", - "subarray", "toArray", "toMap", "toObject", "removeAllOccurences", "removeAllOccurrences" - ]) and - src = 0 - or - this.hasName("toPrimitive") and - src = [0, 1] - or - this.hasName("add") and - this.getNumberOfParameters() = 2 and - src = [0, 1] - or - this.hasName(["add"]) and - this.getNumberOfParameters() = 3 and - src = [0, 2] - or - this.hasName("insert") and - src = [1, 2] - or - this.hasName("get") and - src = [0, 2] +private class ApacheArrayUtilsModel extends SummaryModelCsv { + override predicate row(string row) { + row = + [ + "org.apache.commons.lang3;ArrayUtils;false;add;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;ArrayUtils;false;add;;;Argument[2];ReturnValue;taint", + "org.apache.commons.lang3;ArrayUtils;false;add;(java.lang.Object[],java.lang.Object);;Argument[1];ReturnValue;taint", + "org.apache.commons.lang3;ArrayUtils;false;add;(boolean[],boolean);;Argument[1];ReturnValue;taint", + "org.apache.commons.lang3;ArrayUtils;false;add;(byte[],byte);;Argument[1];ReturnValue;taint", + "org.apache.commons.lang3;ArrayUtils;false;add;(char[],char);;Argument[1];ReturnValue;taint", + "org.apache.commons.lang3;ArrayUtils;false;add;(double[],double);;Argument[1];ReturnValue;taint", + "org.apache.commons.lang3;ArrayUtils;false;add;(float[],float);;Argument[1];ReturnValue;taint", + "org.apache.commons.lang3;ArrayUtils;false;add;(int[],int);;Argument[1];ReturnValue;taint", + "org.apache.commons.lang3;ArrayUtils;false;add;(long[],long);;Argument[1];ReturnValue;taint", + "org.apache.commons.lang3;ArrayUtils;false;add;(short[],short);;Argument[1];ReturnValue;taint", + "org.apache.commons.lang3;ArrayUtils;false;addAll;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;ArrayUtils;false;addFirst;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;ArrayUtils;false;clone;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;ArrayUtils;false;get;(java.lang.Object[],int,java.lang.Object);;Argument[2];ReturnValue;taint", + "org.apache.commons.lang3;ArrayUtils;false;get;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;ArrayUtils;false;insert;;;Argument[1];ReturnValue;taint", + "org.apache.commons.lang3;ArrayUtils;false;insert;;;Argument[2];ReturnValue;taint", + "org.apache.commons.lang3;ArrayUtils;false;insert;;;Argument[3];ReturnValue;taint", + "org.apache.commons.lang3;ArrayUtils;false;nullToEmpty;(java.lang.Object[],java.lang.Class);;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;ArrayUtils;false;nullToEmpty;(java.lang.String[]);;Argument;ReturnValue;taint", + "org.apache.commons.lang3;ArrayUtils;false;remove;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;ArrayUtils;false;removeAll;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;ArrayUtils;false;removeAllOccurences;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;ArrayUtils;false;removeAllOccurrences;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;ArrayUtils;false;removeElement;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;ArrayUtils;false;removeElements;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;ArrayUtils;false;subarray;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;ArrayUtils;false;toArray;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;ArrayUtils;false;toMap;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;ArrayUtils;false;toObject;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;ArrayUtils;false;toPrimitive;;;Argument;ReturnValue;taint" + ] } } From 25a0e091309c9441bffb5a1bae1c0ad87aa05ac0 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Wed, 10 Mar 2021 12:45:59 +0000 Subject: [PATCH 377/725] Convert StringUtils models to CSV --- .../code/java/frameworks/apache/Lang.qll | 196 +++++++++++++----- 1 file changed, 144 insertions(+), 52 deletions(-) diff --git a/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll b/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll index eda817026b3..404a8e77de4 100644 --- a/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll +++ b/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll @@ -70,58 +70,150 @@ private class ApacheArrayUtilsModel extends SummaryModelCsv { } } -private Type getAnExcludedParameterType() { - result instanceof PrimitiveType or - result.(RefType).hasQualifiedName("java.nio.charset", "Charset") or - result.(RefType).hasQualifiedName("java.util", "Locale") -} - -private class ApacheStringUtilsTaintPreservingMethod extends TaintPreservingCallable { - ApacheStringUtilsTaintPreservingMethod() { - this.getDeclaringType().hasQualifiedName("org.apache.commons.lang3", "StringUtils") and - this.hasName([ - "abbreviate", "abbreviateMiddle", "appendIfMissing", "appendIfMissingIgnoreCase", - "capitalize", "center", "chomp", "chop", "defaultIfBlank", "defaultIfEmpty", - "defaultString", "deleteWhitespace", "difference", "firstNonBlank", "firstNonEmpty", - "getBytes", "getCommonPrefix", "getDigits", "getIfBlank", "getIfEmpty", "join", "joinWith", - "left", "leftPad", "lowerCase", "mid", "normalizeSpace", "overlay", "prependIfMissing", - "prependIfMissingIgnoreCase", "remove", "removeAll", "removeEnd", "removeEndIgnoreCase", - "removeFirst", "removeIgnoreCase", "removePattern", "removeStart", "removeStartIgnoreCase", - "repeat", "replace", "replaceAll", "replaceChars", "replaceEach", "replaceEachRepeatedly", - "replaceFirst", "replaceIgnoreCase", "replaceOnce", "replaceOnceIgnoreCase", - "replacePattern", "reverse", "reverseDelimited", "right", "rightPad", "rotate", "split", - "splitByCharacterType", "splitByCharacterTypeCamelCase", "splitByWholeSeparator", - "splitByWholeSeparatorPreserveAllTokens", "splitPreserveAllTokens", "strip", "stripAccents", - "stripAll", "stripEnd", "stripStart", "stripToEmpty", "stripToNull", "substring", - "substringAfter", "substringAfterLast", "substringBefore", "substringBeforeLast", - "substringBetween", "substringsBetween", "swapCase", "toCodePoints", "toEncodedString", - "toRootLowerCase", "toRootUpperCase", "toString", "trim", "trimToEmpty", "trimToNull", - "truncate", "uncapitalize", "unwrap", "upperCase", "valueOf", "wrap", "wrapIfMissing" - ]) - } - - private predicate isExcludedParameter(int arg) { - this.getName().matches(["appendIfMissing%", "prependIfMissing%"]) and arg = [2, 3] - or - this.getName().matches(["remove%", "split%", "substring%", "strip%"]) and - arg = [1 .. getNumberOfParameters() - 1] - or - this.getName().matches(["chomp", "getBytes", "replace%", "toString", "unwrap"]) and arg = 1 - or - this.getName() = "join" and - // Exclude joins of types that render numerically (char[] and non-primitive arrays - // are still considered taint sources) - exists(PrimitiveType pt | - this.getParameterType(arg).(Array).getComponentType() = pt and - not pt instanceof CharacterType - ) and - arg = 0 - } - - override predicate returnsTaintFrom(int arg) { - arg = [0 .. getNumberOfParameters() - 1] and - not this.getParameterType(arg) = getAnExcludedParameterType() and - not isExcludedParameter(arg) +private class ApacheStringUtilsModel extends SummaryModelCsv { + override predicate row(string row) { + row = + [ + "org.apache.commons.lang3;StringUtils;false;abbreviate;(java.lang.String,java.lang.String,int);;Argument[1];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;abbreviate;(java.lang.String,java.lang.String,int,int);;Argument[1];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;abbreviate;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;abbreviateMiddle;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;abbreviateMiddle;;;Argument[1];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;appendIfMissing;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;appendIfMissing;;;Argument[1];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;appendIfMissingIgnoreCase;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;appendIfMissingIgnoreCase;;;Argument[1];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;capitalize;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;center;(java.lang.String,int,java.lang.String);;Argument[2];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;center;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;chomp;(java.lang.String);;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;chomp;(java.lang.String,java.lang.String);;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;chop;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;defaultIfBlank;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;defaultIfEmpty;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;defaultString;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;deleteWhitespace;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;difference;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;firstNonBlank;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;firstNonEmpty;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;getBytes;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;getCommonPrefix;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;getDigits;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;getIfBlank;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;getIfEmpty;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;join;(char[],char);;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;join;(char[],char,int,int);;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;join;(java.lang.Iterable,char);;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;join;(java.lang.Iterable,java.lang.String);;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;join;(java.lang.Object[]);;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;join;(java.lang.Object[],char);;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;join;(java.lang.Object[],char,int,int);;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;join;(java.lang.Object[],java.lang.String);;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;join;(java.lang.Object[],java.lang.String,int,int);;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;join;(java.lang.Object[],java.lang.String,int,int);;Argument[1];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;join;(java.util.Iterator,char);;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;join;(java.util.Iterator,java.lang.String);;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;join;(java.util.List,char,int,int);;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;join;(java.util.List,java.lang.String,int,int);;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;join;(java.util.List,java.lang.String,int,int);;Argument[1];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;joinWith;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;left;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;leftPad;(java.lang.String,int,java.lang.String);;Argument[2];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;leftPad;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;lowerCase;(java.lang.String);;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;lowerCase;(java.lang.String,java.util.Locale);;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;mid;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;normalizeSpace;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;overlay;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;overlay;;;Argument[1];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;prependIfMissing;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;prependIfMissing;;;Argument[1];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;prependIfMissingIgnoreCase;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;prependIfMissingIgnoreCase;;;Argument[1];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;remove;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;removeAll;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;removeEnd;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;removeEndIgnoreCase;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;removeFirst;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;removeIgnoreCase;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;removePattern;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;removeStart;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;removeStartIgnoreCase;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;repeat;(java.lang.String,java.lang.String,int);;Argument[1];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;repeat;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;replace;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;replace;;;Argument[2];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;replaceAll;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;replaceAll;;;Argument[2];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;replaceChars;(java.lang.String,java.lang.String,java.lang.String);;Argument[2];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;replaceChars;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;replaceEach;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;replaceEach;;;Argument[2];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;replaceEachRepeatedly;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;replaceEachRepeatedly;;;Argument[2];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;replaceFirst;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;replaceFirst;;;Argument[2];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;replaceIgnoreCase;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;replaceIgnoreCase;;;Argument[2];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;replaceOnce;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;replaceOnce;;;Argument[2];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;replaceOnceIgnoreCase;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;replaceOnceIgnoreCase;;;Argument[2];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;replacePattern;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;replacePattern;;;Argument[2];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;reverse;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;reverseDelimited;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;right;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;rightPad;(java.lang.String,int,java.lang.String);;Argument[2];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;rightPad;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;rotate;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;split;(java.lang.String);;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;split;(java.lang.String,char);;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;split;(java.lang.String,java.lang.String);;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;split;(java.lang.String,java.lang.String,int);;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;splitByCharacterType;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;splitByCharacterTypeCamelCase;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;splitByWholeSeparator;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;splitByWholeSeparatorPreserveAllTokens;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;splitPreserveAllTokens;(java.lang.String);;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;splitPreserveAllTokens;(java.lang.String,char);;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;splitPreserveAllTokens;(java.lang.String,java.lang.String);;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;splitPreserveAllTokens;(java.lang.String,java.lang.String,int);;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;strip;(java.lang.String);;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;strip;(java.lang.String,java.lang.String);;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;stripAccents;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;stripAll;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;stripEnd;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;stripStart;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;stripToEmpty;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;stripToNull;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;substring;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;substringAfter;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;substringAfterLast;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;substringBefore;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;substringBeforeLast;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;substringBetween;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;substringsBetween;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;swapCase;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;toCodePoints;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;toEncodedString;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;toRootLowerCase;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;toRootUpperCase;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;toString;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;trim;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;trimToEmpty;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;trimToNull;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;truncate;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;uncapitalize;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;unwrap;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;upperCase;(java.lang.String);;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;upperCase;(java.lang.String,java.util.Locale);;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;valueOf;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;wrap;(java.lang.String,char);;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;wrap;(java.lang.String,java.lang.String);;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;wrapIfMissing;(java.lang.String,char);;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;wrapIfMissing;(java.lang.String,java.lang.String);;Argument;ReturnValue;taint" + ] } } From a5220bf6163a006d3101594a98eba232df06278b Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Wed, 10 Mar 2021 12:57:28 +0000 Subject: [PATCH 378/725] Convert StrBuilder models to CSV --- .../code/java/frameworks/apache/Lang.qll | 297 ++++++++++++------ 1 file changed, 207 insertions(+), 90 deletions(-) diff --git a/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll b/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll index 404a8e77de4..93d3b496ba5 100644 --- a/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll +++ b/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll @@ -217,96 +217,213 @@ private class ApacheStringUtilsModel extends SummaryModelCsv { } } -/** - * A method declared on Apache Commons Lang's `StrBuilder`, or the same class or its - * renamed version `TextStringBuilder` in Commons Text. - */ -class ApacheStrBuilderCallable extends Callable { - ApacheStrBuilderCallable() { - this.getDeclaringType().hasQualifiedName("org.apache.commons.lang3.text", "StrBuilder") or - this.getDeclaringType() - .hasQualifiedName("org.apache.commons.text", ["StrBuilder", "TextStringBuilder"]) - } -} - -/** - * An Apache Commons Lang `StrBuilder` method that adds taint to the `StrBuilder`. - */ -private class ApacheStrBuilderTaintingMethod extends ApacheStrBuilderCallable, - TaintPreservingCallable { - ApacheStrBuilderTaintingMethod() { - this instanceof Constructor - or - this.hasName([ - "append", "appendAll", "appendFixedWidthPadLeft", "appendFixedWidthPadRight", "appendln", - "appendSeparator", "appendWithSeparators", "insert", "readFrom", "replace", "replaceAll", - "replaceFirst" - ]) - } - - private predicate consumesTaintFromAllArgs() { - // Specifically the append[ln](String, Object...) overloads also consume taint from their other arguments: - this.getName() in ["appendAll", "appendWithSeparators"] - or - this.getName() = ["append", "appendln"] and this.getAParameter().isVarargs() - or - this.getName() = "appendSeparator" and this.getParameterType(1) instanceof TypeString - } - - override predicate transfersTaint(int fromArg, int toArg) { - // Taint the qualifier - toArg = -1 and - ( - this.getName().matches(["append%", "readFrom"]) and fromArg = 0 - or - this.getName() = "insert" and fromArg = 1 - or - this.getName().matches("replace%") and - ( - if this.getParameterType(0).(PrimitiveType).getName() = "int" - then fromArg = 2 - else fromArg = 1 - ) - or - this.consumesTaintFromAllArgs() and fromArg in [0 .. this.getNumberOfParameters() - 1] - ) - } - - override predicate returnsTaintFrom(int arg) { this instanceof Constructor and arg = 0 } -} - -/** - * An Apache Commons Lang `StrBuilder` method that returns taint from the `StrBuilder`. - */ -private class ApacheStrBuilderTaintGetter extends ApacheStrBuilderCallable, TaintPreservingCallable { - ApacheStrBuilderTaintGetter() { - // Taint getters: - this.hasName([ - "asReader", "asTokenizer", "build", "getChars", "leftString", "midString", "rightString", - "subSequence", "substring", "toCharArray", "toString", "toStringBuffer", "toStringBuilder" - ]) - or - // Fluent methods that return an alias of `this`: - this.getReturnType() = this.getDeclaringType() - } - - override predicate returnsTaintFrom(int arg) { arg = -1 } -} - -/** - * An Apache Commons Lang `StrBuilder` method that writes taint from the `StrBuilder` to some parameter. - */ -private class ApacheStrBuilderTaintWriter extends ApacheStrBuilderCallable, TaintPreservingCallable { - ApacheStrBuilderTaintWriter() { this.hasName(["appendTo", "getChars"]) } - - override predicate transfersTaint(int fromArg, int toArg) { - fromArg = -1 and - // appendTo(Readable) and getChars(char[]) - if this.getNumberOfParameters() = 1 - then toArg = 0 - else - // getChars(int, int, char[], int) - toArg = 2 +private class ApacheStrBuilderModel extends SummaryModelCsv { + override predicate row(string row) { + row = + [ + "org.apache.commons.lang3.text;StrBuilder;false;StrBuilder;(java.lang.String);;Argument;ReturnValue;taint", + "org.apache.commons.lang3.text;StrBuilder;false;append;(char[]);;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;append;(char[],int,int);;Argument[0];Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;append;(java.lang.CharSequence);;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;append;(java.lang.CharSequence,int,int);;Argument[0];Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;append;(java.lang.Object);;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;append;(java.lang.String);;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;append;(java.lang.String,int,int);;Argument[0];Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;append;(java.lang.String,java.lang.Object[]);;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;append;(java.lang.StringBuffer);;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;append;(java.lang.StringBuffer,int,int);;Argument[0];Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;append;(java.lang.StringBuilder);;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;append;(java.lang.StringBuilder,int,int);;Argument[0];Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;append;(java.nio.CharBuffer);;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;append;(java.nio.CharBuffer,int,int);;Argument[0];Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;append;(org.apache.commons.lang3.text.StrBuilder);;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;append;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.lang3.text;StrBuilder;false;appendAll;;;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;appendAll;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.lang3.text;StrBuilder;false;appendFixedWidthPadLeft;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.lang3.text;StrBuilder;false;appendFixedWidthPadLeft;;;Argument[0];Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;appendFixedWidthPadRight;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.lang3.text;StrBuilder;false;appendFixedWidthPadRight;;;Argument[0];Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;appendSeparator;(java.lang.String);;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;appendSeparator;(java.lang.String,int);;Argument[0];Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;appendSeparator;(java.lang.String,java.lang.String);;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;appendSeparator;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.lang3.text;StrBuilder;false;appendTo;;;Argument[-1];Argument;taint", + "org.apache.commons.lang3.text;StrBuilder;false;appendWithSeparators;;;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;appendWithSeparators;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.lang3.text;StrBuilder;false;appendln;(char[]);;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;appendln;(char[],int,int);;Argument[0];Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;appendln;(java.lang.Object);;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;appendln;(java.lang.String);;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;appendln;(java.lang.String,int,int);;Argument[0];Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;appendln;(java.lang.String,java.lang.Object[]);;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;appendln;(java.lang.StringBuffer);;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;appendln;(java.lang.StringBuffer,int,int);;Argument[0];Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;appendln;(java.lang.StringBuilder);;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;appendln;(java.lang.StringBuilder,int,int);;Argument[0];Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;appendln;(org.apache.commons.lang3.text.StrBuilder);;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;appendln;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.lang3.text;StrBuilder;false;asReader;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.lang3.text;StrBuilder;false;asTokenizer;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.lang3.text;StrBuilder;false;build;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.lang3.text;StrBuilder;false;getChars;(char[]);;Argument[-1];Argument;taint", + "org.apache.commons.lang3.text;StrBuilder;false;getChars;(char[]);;Argument[-1];ReturnValue;taint", + "org.apache.commons.lang3.text;StrBuilder;false;getChars;(int,int,char[],int);;Argument[-1];Argument[2];taint", + "org.apache.commons.lang3.text;StrBuilder;false;insert;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.lang3.text;StrBuilder;false;insert;;;Argument[1];Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;leftString;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.lang3.text;StrBuilder;false;midString;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.lang3.text;StrBuilder;false;readFrom;;;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;replace;(int,int,java.lang.String);;Argument[2];Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;replace;(org.apache.commons.lang3.text.StrMatcher,java.lang.String,int,int,int);;Argument[1];Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;replace;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.lang3.text;StrBuilder;false;replaceAll;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.lang3.text;StrBuilder;false;replaceAll;;;Argument[1];Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;replaceFirst;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.lang3.text;StrBuilder;false;replaceFirst;;;Argument[1];Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;rightString;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.lang3.text;StrBuilder;false;subSequence;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.lang3.text;StrBuilder;false;substring;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.lang3.text;StrBuilder;false;toCharArray;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.lang3.text;StrBuilder;false;toString;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.lang3.text;StrBuilder;false;toStringBuffer;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.lang3.text;StrBuilder;false;toStringBuilder;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;StrBuilder;false;StrBuilder;(java.lang.String);;Argument;ReturnValue;taint", + "org.apache.commons.text;StrBuilder;false;append;(char[]);;Argument;Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;append;(char[],int,int);;Argument[0];Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;append;(java.lang.CharSequence);;Argument;Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;append;(java.lang.CharSequence,int,int);;Argument[0];Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;append;(java.lang.Object);;Argument;Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;append;(java.lang.String);;Argument;Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;append;(java.lang.String,int,int);;Argument[0];Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;append;(java.lang.String,java.lang.Object[]);;Argument;Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;append;(java.lang.StringBuffer);;Argument;Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;append;(java.lang.StringBuffer,int,int);;Argument[0];Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;append;(java.lang.StringBuilder);;Argument;Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;append;(java.lang.StringBuilder,int,int);;Argument[0];Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;append;(java.nio.CharBuffer);;Argument;Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;append;(java.nio.CharBuffer,int,int);;Argument[0];Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;append;(org.apache.commons.text.StrBuilder);;Argument;Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;append;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;StrBuilder;false;appendAll;;;Argument;Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;appendAll;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;StrBuilder;false;appendFixedWidthPadLeft;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;StrBuilder;false;appendFixedWidthPadLeft;;;Argument[0];Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;appendFixedWidthPadRight;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;StrBuilder;false;appendFixedWidthPadRight;;;Argument[0];Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;appendSeparator;(java.lang.String);;Argument;Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;appendSeparator;(java.lang.String,int);;Argument[0];Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;appendSeparator;(java.lang.String,java.lang.String);;Argument;Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;appendSeparator;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;StrBuilder;false;appendTo;;;Argument[-1];Argument;taint", + "org.apache.commons.text;StrBuilder;false;appendWithSeparators;;;Argument;Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;appendWithSeparators;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;StrBuilder;false;appendln;(char[]);;Argument;Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;appendln;(char[],int,int);;Argument[0];Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;appendln;(java.lang.Object);;Argument;Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;appendln;(java.lang.String);;Argument;Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;appendln;(java.lang.String,int,int);;Argument[0];Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;appendln;(java.lang.String,java.lang.Object[]);;Argument;Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;appendln;(java.lang.StringBuffer);;Argument;Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;appendln;(java.lang.StringBuffer,int,int);;Argument[0];Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;appendln;(java.lang.StringBuilder);;Argument;Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;appendln;(java.lang.StringBuilder,int,int);;Argument[0];Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;appendln;(org.apache.commons.text.StrBuilder);;Argument;Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;appendln;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;StrBuilder;false;asReader;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;StrBuilder;false;asTokenizer;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;StrBuilder;false;build;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;StrBuilder;false;getChars;(char[]);;Argument[-1];Argument;taint", + "org.apache.commons.text;StrBuilder;false;getChars;(char[]);;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;StrBuilder;false;getChars;(int,int,char[],int);;Argument[-1];Argument[2];taint", + "org.apache.commons.text;StrBuilder;false;insert;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;StrBuilder;false;insert;;;Argument[1];Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;leftString;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;StrBuilder;false;midString;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;StrBuilder;false;readFrom;;;Argument;Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;replace;(int,int,java.lang.String);;Argument[2];Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;replace;(org.apache.commons.text.StrMatcher,java.lang.String,int,int,int);;Argument[1];Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;replace;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;StrBuilder;false;replaceAll;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;StrBuilder;false;replaceAll;;;Argument[1];Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;replaceFirst;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;StrBuilder;false;replaceFirst;;;Argument[1];Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;rightString;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;StrBuilder;false;subSequence;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;StrBuilder;false;substring;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;StrBuilder;false;toCharArray;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;StrBuilder;false;toString;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;StrBuilder;false;toStringBuffer;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;StrBuilder;false;toStringBuilder;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;TextStringBuilder;false;TextStringBuilder;(java.lang.String);;Argument;ReturnValue;taint", + "org.apache.commons.text;TextStringBuilder;false;TextStringBuilder;(java.lang.CharSequence);;Argument;ReturnValue;taint", + "org.apache.commons.text;TextStringBuilder;false;append;(char[]);;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;append;(char[],int,int);;Argument[0];Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;append;(java.lang.CharSequence);;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;append;(java.lang.CharSequence,int,int);;Argument[0];Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;append;(java.lang.Object);;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;append;(java.lang.String);;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;append;(java.lang.String,int,int);;Argument[0];Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;append;(java.lang.String,java.lang.Object[]);;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;append;(java.lang.StringBuffer);;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;append;(java.lang.StringBuffer,int,int);;Argument[0];Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;append;(java.lang.StringBuilder);;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;append;(java.lang.StringBuilder,int,int);;Argument[0];Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;append;(java.nio.CharBuffer);;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;append;(java.nio.CharBuffer,int,int);;Argument[0];Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;append;(org.apache.commons.text.TextStringBuilder);;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;append;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;TextStringBuilder;false;appendAll;;;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;appendAll;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;TextStringBuilder;false;appendFixedWidthPadLeft;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;TextStringBuilder;false;appendFixedWidthPadLeft;;;Argument[0];Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;appendFixedWidthPadRight;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;TextStringBuilder;false;appendFixedWidthPadRight;;;Argument[0];Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;appendSeparator;(java.lang.String);;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;appendSeparator;(java.lang.String,int);;Argument[0];Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;appendSeparator;(java.lang.String,java.lang.String);;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;appendSeparator;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;TextStringBuilder;false;appendTo;;;Argument[-1];Argument;taint", + "org.apache.commons.text;TextStringBuilder;false;appendWithSeparators;;;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;appendWithSeparators;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;TextStringBuilder;false;appendln;(char[]);;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;appendln;(char[],int,int);;Argument[0];Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;appendln;(java.lang.Object);;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;appendln;(java.lang.String);;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;appendln;(java.lang.String,int,int);;Argument[0];Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;appendln;(java.lang.String,java.lang.Object[]);;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;appendln;(java.lang.StringBuffer);;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;appendln;(java.lang.StringBuffer,int,int);;Argument[0];Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;appendln;(java.lang.StringBuilder);;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;appendln;(java.lang.StringBuilder,int,int);;Argument[0];Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;appendln;(org.apache.commons.text.TextStringBuilder);;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;appendln;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;TextStringBuilder;false;asReader;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;TextStringBuilder;false;asTokenizer;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;TextStringBuilder;false;build;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;TextStringBuilder;false;getChars;(char[]);;Argument[-1];Argument;taint", + "org.apache.commons.text;TextStringBuilder;false;getChars;(char[]);;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;TextStringBuilder;false;getChars;(int,int,char[],int);;Argument[-1];Argument[2];taint", + "org.apache.commons.text;TextStringBuilder;false;insert;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;TextStringBuilder;false;insert;;;Argument[1];Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;leftString;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;TextStringBuilder;false;midString;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;TextStringBuilder;false;readFrom;;;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;replace;(int,int,java.lang.String);;Argument[2];Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;replace;(org.apache.commons.text.matcher.StringMatcher,java.lang.String,int,int,int);;Argument[1];Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;replace;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;TextStringBuilder;false;replaceAll;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;TextStringBuilder;false;replaceAll;;;Argument[1];Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;replaceFirst;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;TextStringBuilder;false;replaceFirst;;;Argument[1];Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;rightString;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;TextStringBuilder;false;subSequence;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;TextStringBuilder;false;substring;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;TextStringBuilder;false;toCharArray;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;TextStringBuilder;false;toString;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;TextStringBuilder;false;toStringBuffer;;;Argument[-1];ReturnValue;taint", + "org.apache.commons.text;TextStringBuilder;false;toStringBuilder;;;Argument[-1];ReturnValue;taint" + ] } } From 1c27ca610abe4ba32fcf66818e35a8fe6b5d5c7d Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 25 Mar 2021 15:12:09 +0000 Subject: [PATCH 379/725] JS: Remove precision atags from metric queries --- javascript/ql/src/Comments/FCommentedOutCode.ql | 1 - javascript/ql/src/Metrics/FCommentRatio.ql | 1 - javascript/ql/src/Metrics/FCyclomaticComplexity.ql | 1 - javascript/ql/src/Metrics/FFunctions.ql | 1 - javascript/ql/src/Metrics/FLines.ql | 1 - javascript/ql/src/Metrics/FLinesOfCode.ql | 1 - javascript/ql/src/Metrics/FLinesOfComment.ql | 1 - javascript/ql/src/Metrics/FLinesOfDuplicatedCode.ql | 1 - javascript/ql/src/Metrics/FLinesOfSimilarCode.ql | 1 - javascript/ql/src/Metrics/FNumberOfStatements.ql | 1 - javascript/ql/src/Metrics/FNumberOfTests.ql | 1 - javascript/ql/src/Metrics/FUseOfES6.ql | 1 - javascript/ql/src/Metrics/FunCyclomaticComplexity.ql | 1 - javascript/ql/src/Metrics/FunLinesOfCode.ql | 1 - 14 files changed, 14 deletions(-) diff --git a/javascript/ql/src/Comments/FCommentedOutCode.ql b/javascript/ql/src/Comments/FCommentedOutCode.ql index a8364bb55fe..d18abda9648 100644 --- a/javascript/ql/src/Comments/FCommentedOutCode.ql +++ b/javascript/ql/src/Comments/FCommentedOutCode.ql @@ -5,7 +5,6 @@ * @treemap.warnOn highValues * @metricType file * @metricAggregate avg sum max - * @precision high * @id js/lines-of-commented-out-code-in-files * @tags maintainability */ diff --git a/javascript/ql/src/Metrics/FCommentRatio.ql b/javascript/ql/src/Metrics/FCommentRatio.ql index cf0d4201c05..c87b78b05a6 100644 --- a/javascript/ql/src/Metrics/FCommentRatio.ql +++ b/javascript/ql/src/Metrics/FCommentRatio.ql @@ -5,7 +5,6 @@ * @treemap.warnOn lowValues * @metricType file * @metricAggregate avg max - * @precision very-high * @tags maintainability * @id js/comment-ratio-per-file */ diff --git a/javascript/ql/src/Metrics/FCyclomaticComplexity.ql b/javascript/ql/src/Metrics/FCyclomaticComplexity.ql index 5c34a1919b7..220122e99bc 100644 --- a/javascript/ql/src/Metrics/FCyclomaticComplexity.ql +++ b/javascript/ql/src/Metrics/FCyclomaticComplexity.ql @@ -5,7 +5,6 @@ * @treemap.warnOn highValues * @metricType file * @metricAggregate avg max - * @precision very-high * @tags testability * @id js/cyclomatic-complexity-per-file */ diff --git a/javascript/ql/src/Metrics/FFunctions.ql b/javascript/ql/src/Metrics/FFunctions.ql index d74cbcde7f3..6ca79978625 100644 --- a/javascript/ql/src/Metrics/FFunctions.ql +++ b/javascript/ql/src/Metrics/FFunctions.ql @@ -5,7 +5,6 @@ * @treemap.warnOn highValues * @metricType file * @metricAggregate avg sum max - * @precision very-high * @id js/functions-per-file */ diff --git a/javascript/ql/src/Metrics/FLines.ql b/javascript/ql/src/Metrics/FLines.ql index 4fdd2ab9458..697e7d8dc78 100644 --- a/javascript/ql/src/Metrics/FLines.ql +++ b/javascript/ql/src/Metrics/FLines.ql @@ -5,7 +5,6 @@ * @treemap.warnOn highValues * @metricType file * @metricAggregate avg sum max - * @precision very-high * @id js/lines-per-file */ diff --git a/javascript/ql/src/Metrics/FLinesOfCode.ql b/javascript/ql/src/Metrics/FLinesOfCode.ql index 52fb8447ef0..69165507f95 100644 --- a/javascript/ql/src/Metrics/FLinesOfCode.ql +++ b/javascript/ql/src/Metrics/FLinesOfCode.ql @@ -6,7 +6,6 @@ * @treemap.warnOn highValues * @metricType file * @metricAggregate avg sum max - * @precision very-high * @id js/lines-of-code-in-files * @tags maintainability */ diff --git a/javascript/ql/src/Metrics/FLinesOfComment.ql b/javascript/ql/src/Metrics/FLinesOfComment.ql index 6eb8b1594c3..34e7ad23931 100644 --- a/javascript/ql/src/Metrics/FLinesOfComment.ql +++ b/javascript/ql/src/Metrics/FLinesOfComment.ql @@ -5,7 +5,6 @@ * @treemap.warnOn lowValues * @metricType file * @metricAggregate avg sum max - * @precision very-high * @id js/lines-of-comments-in-files * @tags documentation */ diff --git a/javascript/ql/src/Metrics/FLinesOfDuplicatedCode.ql b/javascript/ql/src/Metrics/FLinesOfDuplicatedCode.ql index 59bb0b337fb..cd745c71670 100644 --- a/javascript/ql/src/Metrics/FLinesOfDuplicatedCode.ql +++ b/javascript/ql/src/Metrics/FLinesOfDuplicatedCode.ql @@ -7,7 +7,6 @@ * @treemap.warnOn highValues * @metricType file * @metricAggregate avg sum max - * @precision high * @id js/duplicated-lines-in-files * @tags testability * duplicate-code diff --git a/javascript/ql/src/Metrics/FLinesOfSimilarCode.ql b/javascript/ql/src/Metrics/FLinesOfSimilarCode.ql index be6685af968..1c819a56b2d 100644 --- a/javascript/ql/src/Metrics/FLinesOfSimilarCode.ql +++ b/javascript/ql/src/Metrics/FLinesOfSimilarCode.ql @@ -8,7 +8,6 @@ * @treemap.warnOn highValues * @metricType file * @metricAggregate avg sum max - * @precision high * @id js/similar-lines-in-files * @tags testability * duplicate-code diff --git a/javascript/ql/src/Metrics/FNumberOfStatements.ql b/javascript/ql/src/Metrics/FNumberOfStatements.ql index 8346e46b72d..1eaa701ee4e 100644 --- a/javascript/ql/src/Metrics/FNumberOfStatements.ql +++ b/javascript/ql/src/Metrics/FNumberOfStatements.ql @@ -5,7 +5,6 @@ * @treemap.warnOn highValues * @metricType file * @metricAggregate avg sum max - * @precision very-high * @id js/statements-per-file */ diff --git a/javascript/ql/src/Metrics/FNumberOfTests.ql b/javascript/ql/src/Metrics/FNumberOfTests.ql index df1ef983ddc..96e2c52ce19 100644 --- a/javascript/ql/src/Metrics/FNumberOfTests.ql +++ b/javascript/ql/src/Metrics/FNumberOfTests.ql @@ -5,7 +5,6 @@ * @treemap.warnOn lowValues * @metricType file * @metricAggregate avg sum max - * @precision medium * @id js/test-in-files */ diff --git a/javascript/ql/src/Metrics/FUseOfES6.ql b/javascript/ql/src/Metrics/FUseOfES6.ql index 65bcfe84413..e683cc23629 100644 --- a/javascript/ql/src/Metrics/FUseOfES6.ql +++ b/javascript/ql/src/Metrics/FUseOfES6.ql @@ -6,7 +6,6 @@ * @treemap.warnOn highValues * @metricType file * @metricAggregate avg sum max - * @precision very-high * @id js/es20xx-features-per-file */ diff --git a/javascript/ql/src/Metrics/FunCyclomaticComplexity.ql b/javascript/ql/src/Metrics/FunCyclomaticComplexity.ql index 8856f16d29a..12284dfb55c 100644 --- a/javascript/ql/src/Metrics/FunCyclomaticComplexity.ql +++ b/javascript/ql/src/Metrics/FunCyclomaticComplexity.ql @@ -5,7 +5,6 @@ * @treemap.warnOn highValues * @metricType callable * @metricAggregate avg max sum - * @precision very-high * @tags testability * @id js/cyclomatic-complexity-per-function */ diff --git a/javascript/ql/src/Metrics/FunLinesOfCode.ql b/javascript/ql/src/Metrics/FunLinesOfCode.ql index 590ad76c765..5b3dc55cfea 100644 --- a/javascript/ql/src/Metrics/FunLinesOfCode.ql +++ b/javascript/ql/src/Metrics/FunLinesOfCode.ql @@ -5,7 +5,6 @@ * @treemap.warnOn highValues * @metricType callable * @metricAggregate avg sum max - * @precision very-high * @tags maintainability * @id js/lines-of-code-per-function */ From 6cab85712f34b2eaf849616aec149ab383e5c810 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 25 Mar 2021 15:12:35 +0000 Subject: [PATCH 380/725] JS: Delete filter queries --- javascript/ql/src/filters/FilterFrameworks.ql | 14 -------------- javascript/ql/src/filters/FilterFrameworks.qll | 7 ------- .../ql/src/filters/FilterFrameworksForMetric.ql | 14 -------------- javascript/ql/src/filters/FilterGenerated.ql | 15 --------------- .../ql/src/filters/FilterGeneratedForMetric.ql | 16 ---------------- javascript/ql/src/filters/FilterMinified.ql | 13 ------------- .../ql/src/filters/FilterMinifiedForMetric.ql | 14 -------------- 7 files changed, 93 deletions(-) delete mode 100644 javascript/ql/src/filters/FilterFrameworks.ql delete mode 100644 javascript/ql/src/filters/FilterFrameworks.qll delete mode 100644 javascript/ql/src/filters/FilterFrameworksForMetric.ql delete mode 100644 javascript/ql/src/filters/FilterGenerated.ql delete mode 100644 javascript/ql/src/filters/FilterGeneratedForMetric.ql delete mode 100644 javascript/ql/src/filters/FilterMinified.ql delete mode 100644 javascript/ql/src/filters/FilterMinifiedForMetric.ql diff --git a/javascript/ql/src/filters/FilterFrameworks.ql b/javascript/ql/src/filters/FilterFrameworks.ql deleted file mode 100644 index ba21a3f596b..00000000000 --- a/javascript/ql/src/filters/FilterFrameworks.ql +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @name Filter out framework code - * @description Only keep results in non-framework code - * @kind problem - * @problem.severity warning - * @id js/not-framework-file-filter - */ - -import FilterFrameworks -import external.DefectFilter - -from DefectResult defres -where nonFrameworkFile(defres.getFile()) -select defres, defres.getMessage() diff --git a/javascript/ql/src/filters/FilterFrameworks.qll b/javascript/ql/src/filters/FilterFrameworks.qll deleted file mode 100644 index d2e94305a94..00000000000 --- a/javascript/ql/src/filters/FilterFrameworks.qll +++ /dev/null @@ -1,7 +0,0 @@ -import semmle.javascript.dependencies.FrameworkLibraries - -/** - * Holds if file `f` does not contain a framework library. - */ -pragma[nomagic] -predicate nonFrameworkFile(File f) { not exists(FrameworkLibraryInstance fl | fl.getFile() = f) } diff --git a/javascript/ql/src/filters/FilterFrameworksForMetric.ql b/javascript/ql/src/filters/FilterFrameworksForMetric.ql deleted file mode 100644 index 5c65e055614..00000000000 --- a/javascript/ql/src/filters/FilterFrameworksForMetric.ql +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @name Filter out framework code - * @description Only keep results in non-framework code - * @kind treemap - * @id js/not-framework-file-metric-filter - * @metricType file - */ - -import FilterFrameworks -import external.MetricFilter - -from MetricResult res -where nonFrameworkFile(res.getFile()) -select res, res.getValue() diff --git a/javascript/ql/src/filters/FilterGenerated.ql b/javascript/ql/src/filters/FilterGenerated.ql deleted file mode 100644 index 5fe34572f31..00000000000 --- a/javascript/ql/src/filters/FilterGenerated.ql +++ /dev/null @@ -1,15 +0,0 @@ -/** - * @name Filter out generated files - * @description Only keep results from files that do not look like they are minified, - * generated by a module bundler or by Emscripten, or contain a source - * mapping comment. - * @kind problem - * @id js/not-generated-file-filter - */ - -import semmle.javascript.GeneratedCode -import external.DefectFilter - -from DefectResult defres -where not isGeneratedCode(defres.getFile()) -select defres, defres.getMessage() diff --git a/javascript/ql/src/filters/FilterGeneratedForMetric.ql b/javascript/ql/src/filters/FilterGeneratedForMetric.ql deleted file mode 100644 index 71f5026de39..00000000000 --- a/javascript/ql/src/filters/FilterGeneratedForMetric.ql +++ /dev/null @@ -1,16 +0,0 @@ -/** - * @name Filter out generated files - * @description Only keep results from files that do not look like they are minified, - * generated by a module bundler or by Emscripten, or contain a source - * mapping comment. - * @kind treemap - * @id js/not-generated-file-metric-filter - * @metricType file - */ - -import semmle.javascript.GeneratedCode -import external.MetricFilter - -from MetricResult res -where not isGeneratedCode(res.getFile()) -select res, res.getValue() diff --git a/javascript/ql/src/filters/FilterMinified.ql b/javascript/ql/src/filters/FilterMinified.ql deleted file mode 100644 index 8eff17ba7dc..00000000000 --- a/javascript/ql/src/filters/FilterMinified.ql +++ /dev/null @@ -1,13 +0,0 @@ -/** - * @name Filter out minified files - * @description Only keep results from files that are not minified. - * @kind problem - * @id js/not-minified-file-filter - */ - -import javascript -import external.DefectFilter - -from DefectResult defres -where not defres.getFile().getATopLevel().isMinified() -select defres, defres.getMessage() diff --git a/javascript/ql/src/filters/FilterMinifiedForMetric.ql b/javascript/ql/src/filters/FilterMinifiedForMetric.ql deleted file mode 100644 index 002e0b86c54..00000000000 --- a/javascript/ql/src/filters/FilterMinifiedForMetric.ql +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @name Filter out minified files - * @description Only keep results from files that are not minified. - * @kind treemap - * @id js/not-minified-file-metric-filter - * @metricType file - */ - -import javascript -import external.MetricFilter - -from MetricResult res -where not res.getFile().getATopLevel().isMinified() -select res, res.getValue() From 7aae51c876258116b8c873a4b89b03ea8e677471 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 25 Mar 2021 15:13:51 +0000 Subject: [PATCH 381/725] JS: Add change note for filter query removal --- .../change-notes/2021-03-25-remove-legacy-filter-queries.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 javascript/change-notes/2021-03-25-remove-legacy-filter-queries.md diff --git a/javascript/change-notes/2021-03-25-remove-legacy-filter-queries.md b/javascript/change-notes/2021-03-25-remove-legacy-filter-queries.md new file mode 100644 index 00000000000..e3e4b9b4b1e --- /dev/null +++ b/javascript/change-notes/2021-03-25-remove-legacy-filter-queries.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* Legacy filter queries have been removed. From c812bd948a1d843b80721e573ee421f40f66a42b Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 25 Mar 2021 15:14:48 +0000 Subject: [PATCH 382/725] JS: Add @problem.severity to an example query --- javascript/ql/examples/queries/dataflow/EvalTaint/EvalTaint.ql | 1 + 1 file changed, 1 insertion(+) diff --git a/javascript/ql/examples/queries/dataflow/EvalTaint/EvalTaint.ql b/javascript/ql/examples/queries/dataflow/EvalTaint/EvalTaint.ql index 2668fd2c3b1..72208237445 100644 --- a/javascript/ql/examples/queries/dataflow/EvalTaint/EvalTaint.ql +++ b/javascript/ql/examples/queries/dataflow/EvalTaint/EvalTaint.ql @@ -2,6 +2,7 @@ * @name Taint-tracking to 'eval' calls * @description Tracks user-controlled values into 'eval' calls (special case of js/code-injection). * @kind problem + * @problem.severity error * @tags security * @id js/examples/eval-taint */ From 446ad5ec9e274c8672a444380b0fad031069a5dc Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 25 Mar 2021 15:20:59 +0000 Subject: [PATCH 383/725] JS: Remove code duplication library --- .../ql/src/Metrics/FLinesOfDuplicatedCode.ql | 23 +- .../ql/src/Metrics/FLinesOfSimilarCode.ql | 12 +- .../ql/src/external/CodeDuplication.qll | 367 ------------------ .../ql/src/external/DuplicateFunction.ql | 7 +- .../ql/src/external/DuplicateToplevel.ql | 5 +- javascript/ql/src/external/SimilarFunction.ql | 8 +- javascript/ql/src/external/SimilarToplevel.ql | 6 +- .../DuplicateFunction.expected | 6 - .../DuplicateToplevel.expected | 6 - .../SimilarFunction/SimilarFunction.expected | 4 - .../SimilarToplevel/SimilarToplevel.expected | 1 - 11 files changed, 8 insertions(+), 437 deletions(-) delete mode 100644 javascript/ql/src/external/CodeDuplication.qll diff --git a/javascript/ql/src/Metrics/FLinesOfDuplicatedCode.ql b/javascript/ql/src/Metrics/FLinesOfDuplicatedCode.ql index cd745c71670..3789a0508f3 100644 --- a/javascript/ql/src/Metrics/FLinesOfDuplicatedCode.ql +++ b/javascript/ql/src/Metrics/FLinesOfDuplicatedCode.ql @@ -13,27 +13,8 @@ * non-attributable */ -import external.CodeDuplication - -/** - * Holds if line `l` of file `f` should be excluded from duplicated code detection. - * - * Currently, only lines on which an import declaration occurs are excluded. - */ -predicate whitelistedLineForDuplication(File f, int l) { - exists(ImportDeclaration i | i.getFile() = f and i.getLocation().getStartLine() = l) -} - -/** - * Holds if line `l` of file `f` belongs to a block of lines that is duplicated somewhere else. - */ -predicate dupLine(int l, File f) { - exists(DuplicateBlock d | d.sourceFile() = f | - l in [d.sourceStartLine() .. d.sourceEndLine()] and - not whitelistedLineForDuplication(f, l) - ) -} +import javascript from File f, int n -where n = count(int l | dupLine(l, f)) +where none() select f, n order by n desc diff --git a/javascript/ql/src/Metrics/FLinesOfSimilarCode.ql b/javascript/ql/src/Metrics/FLinesOfSimilarCode.ql index 1c819a56b2d..48e0b00449b 100644 --- a/javascript/ql/src/Metrics/FLinesOfSimilarCode.ql +++ b/javascript/ql/src/Metrics/FLinesOfSimilarCode.ql @@ -14,16 +14,8 @@ * non-attributable */ -import external.CodeDuplication - -/** - * Holds if line `l` of file `f` belong to a block of lines that is similar to a block - * of lines appearing somewhere else. - */ -predicate simLine(int l, File f) { - exists(SimilarBlock d | d.sourceFile() = f | l in [d.sourceStartLine() .. d.sourceEndLine()]) -} +import javascript from File f, int n -where n = count(int l | simLine(l, f)) +where none() select f, n order by n desc diff --git a/javascript/ql/src/external/CodeDuplication.qll b/javascript/ql/src/external/CodeDuplication.qll deleted file mode 100644 index bd9a0481a8a..00000000000 --- a/javascript/ql/src/external/CodeDuplication.qll +++ /dev/null @@ -1,367 +0,0 @@ -/** Provides classes for detecting duplicate or similar code. */ - -import semmle.javascript.Files - -/** Gets the relative path of `file`, with backslashes replaced by forward slashes. */ -private string relativePath(File file) { result = file.getRelativePath().replaceAll("\\", "/") } - -/** - * Holds if the `index`-th token of block `copy` is in file `file`, spanning - * column `sc` of line `sl` to column `ec` of line `el`. - * - * For more information, see [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). - */ -pragma[noinline] -private predicate tokenLocation(File file, int sl, int sc, int ec, int el, Copy copy, int index) { - file = copy.sourceFile() and - tokens(copy, index, sl, sc, ec, el) -} - -/** A token block used for detection of duplicate and similar code. */ -class Copy extends @duplication_or_similarity { - /** Gets the index of the last token in this block. */ - private int lastToken() { result = max(int i | tokens(this, i, _, _, _, _) | i) } - - /** Gets the index of the token in this block starting at the location `loc`, if any. */ - int tokenStartingAt(Location loc) { - tokenLocation(loc.getFile(), loc.getStartLine(), loc.getStartColumn(), _, _, this, result) - } - - /** Gets the index of the token in this block ending at the location `loc`, if any. */ - int tokenEndingAt(Location loc) { - tokenLocation(loc.getFile(), _, _, loc.getEndLine(), loc.getEndColumn(), this, result) - } - - /** Gets the line on which the first token in this block starts. */ - int sourceStartLine() { tokens(this, 0, result, _, _, _) } - - /** Gets the column on which the first token in this block starts. */ - int sourceStartColumn() { tokens(this, 0, _, result, _, _) } - - /** Gets the line on which the last token in this block ends. */ - int sourceEndLine() { tokens(this, this.lastToken(), _, _, result, _) } - - /** Gets the column on which the last token in this block ends. */ - int sourceEndColumn() { tokens(this, this.lastToken(), _, _, _, result) } - - /** Gets the number of lines containing at least (part of) one token in this block. */ - int sourceLines() { result = this.sourceEndLine() + 1 - this.sourceStartLine() } - - /** Gets an opaque identifier for the equivalence class of this block. */ - int getEquivalenceClass() { duplicateCode(this, _, result) or similarCode(this, _, result) } - - /** Gets the source file in which this block appears. */ - File sourceFile() { - exists(string name | duplicateCode(this, name, _) or similarCode(this, name, _) | - name.replaceAll("\\", "/") = relativePath(result) - ) - } - - /** - * Holds if this element is at the specified location. - * The location spans column `startcolumn` of line `startline` to - * column `endcolumn` of line `endline` in file `filepath`. - * For more information, see - * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). - */ - predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - sourceFile().getAbsolutePath() = filepath and - startline = sourceStartLine() and - startcolumn = sourceStartColumn() and - endline = sourceEndLine() and - endcolumn = sourceEndColumn() - } - - /** Gets a textual representation of this element. */ - string toString() { none() } - - /** - * Gets a block that extends this one, that is, its first token is also - * covered by this block, but they are not the same block. - */ - Copy extendingBlock() { - exists(File file, int sl, int sc, int ec, int el | - tokenLocation(file, sl, sc, ec, el, this, _) and - tokenLocation(file, sl, sc, ec, el, result, 0) - ) and - this != result - } -} - -/** - * Holds if there is a sequence of `SimilarBlock`s `start1, ..., end1` and another sequence - * `start2, ..., end2` such that each block extends the previous one and corresponding blocks - * have the same equivalence class, with `start` being the equivalence class of `start1` and - * `start2`, and `end` the equivalence class of `end1` and `end2`. - */ -predicate similar_extension( - SimilarBlock start1, SimilarBlock start2, SimilarBlock end1, SimilarBlock end2, int start, int end -) { - start1.getEquivalenceClass() = start and - start2.getEquivalenceClass() = start and - end1.getEquivalenceClass() = end and - end2.getEquivalenceClass() = end and - start1 != start2 and - ( - end1 = start1 and end2 = start2 - or - similar_extension(start1.extendingBlock(), start2.extendingBlock(), end1, end2, _, end) - ) -} - -/** - * Holds if there is a sequence of `DuplicateBlock`s `start1, ..., end1` and another sequence - * `start2, ..., end2` such that each block extends the previous one and corresponding blocks - * have the same equivalence class, with `start` being the equivalence class of `start1` and - * `start2`, and `end` the equivalence class of `end1` and `end2`. - */ -predicate duplicate_extension( - DuplicateBlock start1, DuplicateBlock start2, DuplicateBlock end1, DuplicateBlock end2, int start, - int end -) { - start1.getEquivalenceClass() = start and - start2.getEquivalenceClass() = start and - end1.getEquivalenceClass() = end and - end2.getEquivalenceClass() = end and - start1 != start2 and - ( - end1 = start1 and end2 = start2 - or - duplicate_extension(start1.extendingBlock(), start2.extendingBlock(), end1, end2, _, end) - ) -} - -/** A block of duplicated code. */ -class DuplicateBlock extends Copy, @duplication { - override string toString() { result = "Duplicate code: " + sourceLines() + " duplicated lines." } -} - -/** A block of similar code. */ -class SimilarBlock extends Copy, @similarity { - override string toString() { - result = "Similar code: " + sourceLines() + " almost duplicated lines." - } -} - -/** Holds if statement `s` is in function or toplevel `sc`. */ -private predicate stmtInContainer(Stmt s, StmtContainer sc) { - s.getContainer() = sc and - not s instanceof BlockStmt -} - -/** - * Holds if `stmt1` and `stmt2` are duplicate statements in function or toplevel `sc1` and `sc2`, - * respectively, where `sc1` and `sc2` are not the same. - */ -predicate duplicateStatement(StmtContainer sc1, StmtContainer sc2, Stmt stmt1, Stmt stmt2) { - exists(int equivstart, int equivend, int first, int last | - stmtInContainer(stmt1, sc1) and - stmtInContainer(stmt2, sc2) and - duplicateCoversStatement(equivstart, equivend, first, last, stmt1) and - duplicateCoversStatement(equivstart, equivend, first, last, stmt2) and - stmt1 != stmt2 and - sc1 != sc2 - ) -} - -/** - * Holds if statement `stmt` is covered by a sequence of `DuplicateBlock`s, where `first` - * is the index of the token in the first block that starts at the beginning of `stmt`, - * while `last` is the index of the token in the last block that ends at the end of `stmt`, - * and `equivstart` and `equivend` are the equivalence classes of the first and the last - * block, respectively. - */ -private predicate duplicateCoversStatement( - int equivstart, int equivend, int first, int last, Stmt stmt -) { - exists(DuplicateBlock b1, DuplicateBlock b2, Location loc | - stmt.getLocation() = loc and - first = b1.tokenStartingAt(loc) and - last = b2.tokenEndingAt(loc) and - b1.getEquivalenceClass() = equivstart and - b2.getEquivalenceClass() = equivend and - duplicate_extension(b1, _, b2, _, equivstart, equivend) - ) -} - -/** - * Holds if `sc1` is a function or toplevel with `total` lines, and `sc2` is a function or - * toplevel that has `duplicate` lines in common with `sc1`. - */ -private predicate duplicateStatements(StmtContainer sc1, StmtContainer sc2, int duplicate, int total) { - duplicate = strictcount(Stmt stmt | duplicateStatement(sc1, sc2, stmt, _)) and - total = strictcount(Stmt stmt | stmtInContainer(stmt, sc1)) -} - -/** - * Holds if `sc` and `other` are functions or toplevels where `percent` is the percentage - * of lines they have in common, which is greater than 90%. - */ -predicate duplicateContainers(StmtContainer sc, StmtContainer other, float percent) { - exists(int total, int duplicate | duplicateStatements(sc, other, duplicate, total) | - percent = 100.0 * duplicate / total and - percent > 90.0 - ) -} - -/** - * Holds if `stmt1` and `stmt2` are similar statements in function or toplevel `sc1` and `sc2`, - * respectively, where `sc1` and `sc2` are not the same. - */ -private predicate similarStatement(StmtContainer sc1, StmtContainer sc2, Stmt stmt1, Stmt stmt2) { - exists(int start, int end, int first, int last | - stmtInContainer(stmt1, sc1) and - stmtInContainer(stmt2, sc2) and - similarCoversStatement(start, end, first, last, stmt1) and - similarCoversStatement(start, end, first, last, stmt2) and - stmt1 != stmt2 and - sc1 != sc2 - ) -} - -/** - * Holds if statement `stmt` is covered by a sequence of `SimilarBlock`s, where `first` - * is the index of the token in the first block that starts at the beginning of `stmt`, - * while `last` is the index of the token in the last block that ends at the end of `stmt`, - * and `equivstart` and `equivend` are the equivalence classes of the first and the last - * block, respectively. - */ -private predicate similarCoversStatement( - int equivstart, int equivend, int first, int last, Stmt stmt -) { - exists(SimilarBlock b1, SimilarBlock b2, Location loc | - stmt.getLocation() = loc and - first = b1.tokenStartingAt(loc) and - last = b2.tokenEndingAt(loc) and - b1.getEquivalenceClass() = equivstart and - b2.getEquivalenceClass() = equivend and - similar_extension(b1, _, b2, _, equivstart, equivend) - ) -} - -/** - * Holds if `sc1` is a function or toplevel with `total` lines, and `sc2` is a function or - * toplevel that has `similar` similar lines to `sc1`. - */ -private predicate similarStatements(StmtContainer sc1, StmtContainer sc2, int similar, int total) { - similar = strictcount(Stmt stmt | similarStatement(sc1, sc2, stmt, _)) and - total = strictcount(Stmt stmt | stmtInContainer(stmt, sc1)) -} - -/** - * Holds if `sc` and `other` are functions or toplevels where `percent` is the percentage - * of similar lines between the two, which is greater than 90%. - */ -predicate similarContainers(StmtContainer sc, StmtContainer other, float percent) { - exists(int total, int similar | similarStatements(sc, other, similar, total) | - percent = 100.0 * similar / total and - percent > 90.0 - ) -} - -/** - * INTERNAL: do not use. - * - * Holds if `line` in `f` is similar to a line somewhere else. - */ -predicate similarLines(File f, int line) { - exists(SimilarBlock b | b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()]) -} - -private predicate similarLinesPerEquivalenceClass(int equivClass, int lines, File f) { - lines = - strictsum(SimilarBlock b, int toSum | - (b.sourceFile() = f and b.getEquivalenceClass() = equivClass) and - toSum = b.sourceLines() - | - toSum - ) -} - -/** Holds if `coveredLines` lines of `f` are similar to lines in `otherFile`. */ -pragma[noopt] -private predicate similarLinesCovered(File f, int coveredLines, File otherFile) { - exists(int numLines | numLines = f.getNumberOfLines() | - exists(int coveredApprox | - coveredApprox = - strictsum(int num | - exists(int equivClass | - similarLinesPerEquivalenceClass(equivClass, num, f) and - similarLinesPerEquivalenceClass(equivClass, num, otherFile) and - f != otherFile - ) - ) and - exists(int n, int product | product = coveredApprox * 100 and n = product / numLines | n > 75) - ) and - exists(int notCovered | - notCovered = count(int j | j in [1 .. numLines] and not similarLines(f, j)) and - coveredLines = numLines - notCovered - ) - ) -} - -/** - * INTERNAL: do not use. - * - * Holds if `line` in `f` is duplicated by a line somewhere else. - */ -predicate duplicateLines(File f, int line) { - exists(DuplicateBlock b | - b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()] - ) -} - -private predicate duplicateLinesPerEquivalenceClass(int equivClass, int lines, File f) { - lines = - strictsum(DuplicateBlock b, int toSum | - (b.sourceFile() = f and b.getEquivalenceClass() = equivClass) and - toSum = b.sourceLines() - | - toSum - ) -} - -/** Holds if `coveredLines` lines of `f` are duplicates of lines in `otherFile`. */ -pragma[noopt] -private predicate duplicateLinesCovered(File f, int coveredLines, File otherFile) { - exists(int numLines | numLines = f.getNumberOfLines() | - exists(int coveredApprox | - coveredApprox = - strictsum(int num | - exists(int equivClass | - duplicateLinesPerEquivalenceClass(equivClass, num, f) and - duplicateLinesPerEquivalenceClass(equivClass, num, otherFile) and - f != otherFile - ) - ) and - exists(int n, int product | product = coveredApprox * 100 and n = product / numLines | n > 75) - ) and - exists(int notCovered | - notCovered = count(int j | j in [1 .. numLines] and not duplicateLines(f, j)) and - coveredLines = numLines - notCovered - ) - ) -} - -/** Holds if most of `f` (`percent`%) is similar to `other`. */ -predicate similarFiles(File f, File other, int percent) { - exists(int covered, int total | - similarLinesCovered(f, covered, other) and - total = f.getNumberOfLines() and - covered * 100 / total = percent and - percent > 80 - ) and - not duplicateFiles(f, other, _) -} - -/** Holds if most of `f` (`percent`%) is duplicated by `other`. */ -predicate duplicateFiles(File f, File other, int percent) { - exists(int covered, int total | - duplicateLinesCovered(f, covered, other) and - total = f.getNumberOfLines() and - covered * 100 / total = percent and - percent > 70 - ) -} diff --git a/javascript/ql/src/external/DuplicateFunction.ql b/javascript/ql/src/external/DuplicateFunction.ql index a59741a3670..91468f85d95 100644 --- a/javascript/ql/src/external/DuplicateFunction.ql +++ b/javascript/ql/src/external/DuplicateFunction.ql @@ -16,15 +16,10 @@ */ import javascript -import CodeDuplication import semmle.javascript.RestrictedLocations from Function f, Function g, float percent -where - duplicateContainers(f, g, percent) and - f.getNumBodyStmt() > 5 and - not duplicateContainers(f.getEnclosingStmt().getContainer(), g.getEnclosingStmt().getContainer(), - _) +where none() select f.(FirstLineOf), percent.floor() + "% of statements in " + f.describe() + " are duplicated in $@.", g.(FirstLineOf), g.describe() diff --git a/javascript/ql/src/external/DuplicateToplevel.ql b/javascript/ql/src/external/DuplicateToplevel.ql index 07d0c5a3d87..160617ea87b 100644 --- a/javascript/ql/src/external/DuplicateToplevel.ql +++ b/javascript/ql/src/external/DuplicateToplevel.ql @@ -16,12 +16,9 @@ */ import javascript -import CodeDuplication import semmle.javascript.RestrictedLocations from TopLevel one, TopLevel another, float percent -where - duplicateContainers(one, another, percent) and - one.getNumLines() > 5 +where none() select one.(FirstLineOf), percent.floor() + "% of statements in this script are duplicated in $@.", another.(FirstLineOf), "another script" diff --git a/javascript/ql/src/external/SimilarFunction.ql b/javascript/ql/src/external/SimilarFunction.ql index 13437dffc54..c946899a87d 100644 --- a/javascript/ql/src/external/SimilarFunction.ql +++ b/javascript/ql/src/external/SimilarFunction.ql @@ -16,16 +16,10 @@ */ import javascript -import CodeDuplication import semmle.javascript.RestrictedLocations from Function f, Function g, float percent -where - similarContainers(f, g, percent) and - f.getNumBodyStmt() > 5 and - not duplicateContainers(f, g, _) and - not duplicateContainers(f.getEnclosingStmt().getContainer(), g.getEnclosingStmt().getContainer(), - _) +where none() select f.(FirstLineOf), percent.floor() + "% of statements in " + f.describe() + " are similar to statements in $@.", g.(FirstLineOf), g.describe() diff --git a/javascript/ql/src/external/SimilarToplevel.ql b/javascript/ql/src/external/SimilarToplevel.ql index c9cbba38be0..aa8d5b36dbe 100644 --- a/javascript/ql/src/external/SimilarToplevel.ql +++ b/javascript/ql/src/external/SimilarToplevel.ql @@ -16,14 +16,10 @@ */ import javascript -import CodeDuplication import semmle.javascript.RestrictedLocations from TopLevel one, TopLevel another, float percent -where - similarContainers(one, another, percent) and - one.getNumChildStmt() > 5 and - not duplicateContainers(one, another, _) +where none() select one.(FirstLineOf), percent.floor() + "% of statements in this script are similar to statements in $@.", another.(FirstLineOf), "another script" diff --git a/javascript/ql/test/query-tests/external/DuplicateFunction/DuplicateFunction.expected b/javascript/ql/test/query-tests/external/DuplicateFunction/DuplicateFunction.expected index 10e41c8dde4..e69de29bb2d 100644 --- a/javascript/ql/test/query-tests/external/DuplicateFunction/DuplicateFunction.expected +++ b/javascript/ql/test/query-tests/external/DuplicateFunction/DuplicateFunction.expected @@ -1,6 +0,0 @@ -| d/tst.js:1:1:1:14 | functio ... s[1];\\n} | 100% of statements in function f are duplicated in $@. | d/tst.js:12:1:12:14 | functio ... s[1];\\n} | function g | -| d/tst.js:1:1:1:14 | functio ... s[1];\\n} | 100% of statements in function f are duplicated in $@. | d/tst.js:23:10:23:21 | functio ... s[1];\\n} | function g2 | -| d/tst.js:12:1:12:14 | functio ... s[1];\\n} | 100% of statements in function g are duplicated in $@. | d/tst.js:1:1:1:14 | functio ... s[1];\\n} | function f | -| d/tst.js:12:1:12:14 | functio ... s[1];\\n} | 100% of statements in function g are duplicated in $@. | d/tst.js:23:10:23:21 | functio ... s[1];\\n} | function g2 | -| d/tst.js:23:10:23:21 | functio ... s[1];\\n} | 100% of statements in function g2 are duplicated in $@. | d/tst.js:1:1:1:14 | functio ... s[1];\\n} | function f | -| d/tst.js:23:10:23:21 | functio ... s[1];\\n} | 100% of statements in function g2 are duplicated in $@. | d/tst.js:12:1:12:14 | functio ... s[1];\\n} | function g | diff --git a/javascript/ql/test/query-tests/external/DuplicateToplevel/DuplicateToplevel.expected b/javascript/ql/test/query-tests/external/DuplicateToplevel/DuplicateToplevel.expected index b2430574fdd..e69de29bb2d 100644 --- a/javascript/ql/test/query-tests/external/DuplicateToplevel/DuplicateToplevel.expected +++ b/javascript/ql/test/query-tests/external/DuplicateToplevel/DuplicateToplevel.expected @@ -1,6 +0,0 @@ -| a.js:1:1:1:1 | | 90% of statements in this script are duplicated in $@. | e.js:1:1:1:1 | | another script | -| a.js:1:1:1:1 | | 100% of statements in this script are duplicated in $@. | b.js:1:1:1:1 | | another script | -| b.js:1:1:1:1 | | 90% of statements in this script are duplicated in $@. | e.js:1:1:1:1 | | another script | -| b.js:1:1:1:1 | | 100% of statements in this script are duplicated in $@. | a.js:1:1:1:1 | | another script | -| e.js:1:1:1:1 | | 90% of statements in this script are duplicated in $@. | a.js:1:1:1:1 | | another script | -| e.js:1:1:1:1 | | 90% of statements in this script are duplicated in $@. | b.js:1:1:1:1 | | another script | diff --git a/javascript/ql/test/query-tests/external/SimilarFunction/SimilarFunction.expected b/javascript/ql/test/query-tests/external/SimilarFunction/SimilarFunction.expected index 264dab311e9..e69de29bb2d 100644 --- a/javascript/ql/test/query-tests/external/SimilarFunction/SimilarFunction.expected +++ b/javascript/ql/test/query-tests/external/SimilarFunction/SimilarFunction.expected @@ -1,4 +0,0 @@ -| tst.js:1:1:1:18 | functio ... = x;\\n} | 92% of statements in function f are similar to statements in $@. | tst.js:17:1:17:18 | functio ... = a;\\n} | function g | -| tst.js:1:1:1:18 | functio ... = x;\\n} | 92% of statements in function f are similar to statements in $@. | tst.js:33:9:33:24 | functio ... = a;\\n} | function h | -| tst.js:17:1:17:18 | functio ... = a;\\n} | 92% of statements in function g are similar to statements in $@. | tst.js:1:1:1:18 | functio ... = x;\\n} | function f | -| tst.js:33:9:33:24 | functio ... = a;\\n} | 92% of statements in function h are similar to statements in $@. | tst.js:1:1:1:18 | functio ... = x;\\n} | function f | diff --git a/javascript/ql/test/query-tests/external/SimilarToplevel/SimilarToplevel.expected b/javascript/ql/test/query-tests/external/SimilarToplevel/SimilarToplevel.expected index 6f2458e0950..e69de29bb2d 100644 --- a/javascript/ql/test/query-tests/external/SimilarToplevel/SimilarToplevel.expected +++ b/javascript/ql/test/query-tests/external/SimilarToplevel/SimilarToplevel.expected @@ -1 +0,0 @@ -| a.js:1:1:1:7 | | 94% of statements in this script are similar to statements in $@. | b.js:1:1:1:7 | | another script | From a456458a38d7234da6e9b2729b349962c2096ec2 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 25 Mar 2021 15:21:48 +0000 Subject: [PATCH 384/725] JS: Add change note for code duplication library removal --- .../2021-03-25-remove-legacy-code-duplication-library.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 javascript/change-notes/2021-03-25-remove-legacy-code-duplication-library.md diff --git a/javascript/change-notes/2021-03-25-remove-legacy-code-duplication-library.md b/javascript/change-notes/2021-03-25-remove-legacy-code-duplication-library.md new file mode 100644 index 00000000000..2a4ac2033ea --- /dev/null +++ b/javascript/change-notes/2021-03-25-remove-legacy-code-duplication-library.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* The legacy code duplication library has been removed. From 2f3458877019b762c3e7cc8b0db76cb9035b7f7c Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Thu, 25 Mar 2021 15:23:08 +0000 Subject: [PATCH 385/725] Constructor models: use Argument[-1] for the result, not ReturnValue --- .../code/java/frameworks/apache/Lang.qll | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll b/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll index 93d3b496ba5..d04899b7649 100644 --- a/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll +++ b/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll @@ -221,7 +221,7 @@ private class ApacheStrBuilderModel extends SummaryModelCsv { override predicate row(string row) { row = [ - "org.apache.commons.lang3.text;StrBuilder;false;StrBuilder;(java.lang.String);;Argument;ReturnValue;taint", + "org.apache.commons.lang3.text;StrBuilder;false;StrBuilder;(java.lang.String);;Argument;Argument[-1];taint", "org.apache.commons.lang3.text;StrBuilder;false;append;(char[]);;Argument;Argument[-1];taint", "org.apache.commons.lang3.text;StrBuilder;false;append;(char[],int,int);;Argument[0];Argument[-1];taint", "org.apache.commons.lang3.text;StrBuilder;false;append;(java.lang.CharSequence);;Argument;Argument[-1];taint", @@ -288,7 +288,7 @@ private class ApacheStrBuilderModel extends SummaryModelCsv { "org.apache.commons.lang3.text;StrBuilder;false;toString;;;Argument[-1];ReturnValue;taint", "org.apache.commons.lang3.text;StrBuilder;false;toStringBuffer;;;Argument[-1];ReturnValue;taint", "org.apache.commons.lang3.text;StrBuilder;false;toStringBuilder;;;Argument[-1];ReturnValue;taint", - "org.apache.commons.text;StrBuilder;false;StrBuilder;(java.lang.String);;Argument;ReturnValue;taint", + "org.apache.commons.text;StrBuilder;false;StrBuilder;(java.lang.String);;Argument;Argument[-1];taint", "org.apache.commons.text;StrBuilder;false;append;(char[]);;Argument;Argument[-1];taint", "org.apache.commons.text;StrBuilder;false;append;(char[],int,int);;Argument[0];Argument[-1];taint", "org.apache.commons.text;StrBuilder;false;append;(java.lang.CharSequence);;Argument;Argument[-1];taint", @@ -355,8 +355,8 @@ private class ApacheStrBuilderModel extends SummaryModelCsv { "org.apache.commons.text;StrBuilder;false;toString;;;Argument[-1];ReturnValue;taint", "org.apache.commons.text;StrBuilder;false;toStringBuffer;;;Argument[-1];ReturnValue;taint", "org.apache.commons.text;StrBuilder;false;toStringBuilder;;;Argument[-1];ReturnValue;taint", - "org.apache.commons.text;TextStringBuilder;false;TextStringBuilder;(java.lang.String);;Argument;ReturnValue;taint", - "org.apache.commons.text;TextStringBuilder;false;TextStringBuilder;(java.lang.CharSequence);;Argument;ReturnValue;taint", + "org.apache.commons.text;TextStringBuilder;false;TextStringBuilder;(java.lang.String);;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;TextStringBuilder;(java.lang.CharSequence);;Argument;Argument[-1];taint", "org.apache.commons.text;TextStringBuilder;false;append;(char[]);;Argument;Argument[-1];taint", "org.apache.commons.text;TextStringBuilder;false;append;(char[],int,int);;Argument[0];Argument[-1];taint", "org.apache.commons.text;TextStringBuilder;false;append;(java.lang.CharSequence);;Argument;Argument[-1];taint", @@ -471,7 +471,7 @@ private class ApacheStrTokenizerModel extends SummaryModelCsv { override predicate row(string row) { row = [ - "org.apache.commons.lang3.text;StrTokenizer;false;StrTokenizer;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3.text;StrTokenizer;false;StrTokenizer;;;Argument[0];Argument[-1];taint", "org.apache.commons.lang3.text;StrTokenizer;false;clone;;;Argument[-1];ReturnValue;taint", "org.apache.commons.lang3.text;StrTokenizer;false;toString;;;Argument[-1];ReturnValue;taint", "org.apache.commons.lang3.text;StrTokenizer;false;reset;;;Argument;ReturnValue;taint", @@ -485,7 +485,7 @@ private class ApacheStrTokenizerModel extends SummaryModelCsv { "org.apache.commons.lang3.text;StrTokenizer;false;nextToken;;;Argument[-1];ReturnValue;taint", "org.apache.commons.lang3.text;StrTokenizer;false;getTSVInstance;;;Argument;ReturnValue;taint", "org.apache.commons.lang3.text;StrTokenizer;false;getCSVInstance;;;Argument;ReturnValue;taint", - "org.apache.commons.text;StrTokenizer;false;StrTokenizer;;;Argument[0];ReturnValue;taint", + "org.apache.commons.text;StrTokenizer;false;StrTokenizer;;;Argument[0];Argument[-1];taint", "org.apache.commons.text;StrTokenizer;false;clone;;;Argument[-1];ReturnValue;taint", "org.apache.commons.text;StrTokenizer;false;toString;;;Argument[-1];ReturnValue;taint", "org.apache.commons.text;StrTokenizer;false;reset;;;Argument;ReturnValue;taint", @@ -499,7 +499,7 @@ private class ApacheStrTokenizerModel extends SummaryModelCsv { "org.apache.commons.text;StrTokenizer;false;nextToken;;;Argument[-1];ReturnValue;taint", "org.apache.commons.text;StrTokenizer;false;getTSVInstance;;;Argument;ReturnValue;taint", "org.apache.commons.text;StrTokenizer;false;getCSVInstance;;;Argument;ReturnValue;taint", - "org.apache.commons.text;StringTokenizer;false;StringTokenizer;;;Argument[0];ReturnValue;taint", + "org.apache.commons.text;StringTokenizer;false;StringTokenizer;;;Argument[0];Argument[-1];taint", "org.apache.commons.text;StringTokenizer;false;clone;;;Argument[-1];ReturnValue;taint", "org.apache.commons.text;StringTokenizer;false;toString;;;Argument[-1];ReturnValue;taint", "org.apache.commons.text;StringTokenizer;false;reset;;;Argument;ReturnValue;taint", @@ -539,7 +539,7 @@ private class ApacheStrSubstitutorModel extends SummaryModelCsv { override predicate row(string row) { row = [ - "org.apache.commons.lang3.text;StrSubstitutor;false;StrSubstitutor;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3.text;StrSubstitutor;false;StrSubstitutor;;;Argument[0];Argument[-1];taint", "org.apache.commons.lang3.text;StrSubstitutor;false;replace;;;Argument[-1];ReturnValue;taint", "org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.Object);;Argument;ReturnValue;taint", "org.apache.commons.lang3.text;StrSubstitutor;false;replace;(char[]);;Argument;ReturnValue;taint", @@ -563,7 +563,7 @@ private class ApacheStrSubstitutorModel extends SummaryModelCsv { "org.apache.commons.lang3.text;StrSubstitutor;false;replaceIn;(java.lang.StringBuilder);;Argument[-1];Argument;taint", "org.apache.commons.lang3.text;StrSubstitutor;false;replaceIn;(java.lang.StringBuilder,int,int);;Argument[-1];Argument[0];taint", "org.apache.commons.lang3.text;StrSubstitutor;false;replaceIn;(org.apache.commons.lang3.text.StrBuilder,int,int);;Argument[-1];Argument[0];taint", - "org.apache.commons.text;StringSubstitutor;false;StringSubstitutor;;;Argument[0];ReturnValue;taint", + "org.apache.commons.text;StringSubstitutor;false;StringSubstitutor;;;Argument[0];Argument[-1];taint", "org.apache.commons.text;StringSubstitutor;false;replace;;;Argument[-1];ReturnValue;taint", "org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.Object);;Argument;ReturnValue;taint", "org.apache.commons.text;StringSubstitutor;false;replace;(char[]);;Argument;ReturnValue;taint", From eaa2d4d831b00688144dccf435f323529f6ebd87 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Thu, 25 Mar 2021 15:42:35 +0000 Subject: [PATCH 386/725] Stop using wildcard Argument All instances are replaced with a specific Argument or range. --- .../code/java/frameworks/apache/Lang.qll | 364 +++++++++--------- 1 file changed, 182 insertions(+), 182 deletions(-) diff --git a/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll b/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll index d04899b7649..deab8f4a692 100644 --- a/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll +++ b/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll @@ -45,16 +45,16 @@ private class ApacheArrayUtilsModel extends SummaryModelCsv { "org.apache.commons.lang3;ArrayUtils;false;add;(int[],int);;Argument[1];ReturnValue;taint", "org.apache.commons.lang3;ArrayUtils;false;add;(long[],long);;Argument[1];ReturnValue;taint", "org.apache.commons.lang3;ArrayUtils;false;add;(short[],short);;Argument[1];ReturnValue;taint", - "org.apache.commons.lang3;ArrayUtils;false;addAll;;;Argument;ReturnValue;taint", - "org.apache.commons.lang3;ArrayUtils;false;addFirst;;;Argument;ReturnValue;taint", - "org.apache.commons.lang3;ArrayUtils;false;clone;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;ArrayUtils;false;addAll;;;Argument[0..1];ReturnValue;taint", + "org.apache.commons.lang3;ArrayUtils;false;addFirst;;;Argument[0..1];ReturnValue;taint", + "org.apache.commons.lang3;ArrayUtils;false;clone;;;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;ArrayUtils;false;get;(java.lang.Object[],int,java.lang.Object);;Argument[2];ReturnValue;taint", "org.apache.commons.lang3;ArrayUtils;false;get;;;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;ArrayUtils;false;insert;;;Argument[1];ReturnValue;taint", "org.apache.commons.lang3;ArrayUtils;false;insert;;;Argument[2];ReturnValue;taint", "org.apache.commons.lang3;ArrayUtils;false;insert;;;Argument[3];ReturnValue;taint", "org.apache.commons.lang3;ArrayUtils;false;nullToEmpty;(java.lang.Object[],java.lang.Class);;Argument[0];ReturnValue;taint", - "org.apache.commons.lang3;ArrayUtils;false;nullToEmpty;(java.lang.String[]);;Argument;ReturnValue;taint", + "org.apache.commons.lang3;ArrayUtils;false;nullToEmpty;(java.lang.String[]);;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;ArrayUtils;false;remove;;;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;ArrayUtils;false;removeAll;;;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;ArrayUtils;false;removeAllOccurences;;;Argument[0];ReturnValue;taint", @@ -62,10 +62,10 @@ private class ApacheArrayUtilsModel extends SummaryModelCsv { "org.apache.commons.lang3;ArrayUtils;false;removeElement;;;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;ArrayUtils;false;removeElements;;;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;ArrayUtils;false;subarray;;;Argument[0];ReturnValue;taint", - "org.apache.commons.lang3;ArrayUtils;false;toArray;;;Argument;ReturnValue;taint", - "org.apache.commons.lang3;ArrayUtils;false;toMap;;;Argument;ReturnValue;taint", - "org.apache.commons.lang3;ArrayUtils;false;toObject;;;Argument;ReturnValue;taint", - "org.apache.commons.lang3;ArrayUtils;false;toPrimitive;;;Argument;ReturnValue;taint" + "org.apache.commons.lang3;ArrayUtils;false;toArray;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;ArrayUtils;false;toMap;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;ArrayUtils;false;toObject;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;ArrayUtils;false;toPrimitive;;;Argument[0..1];ReturnValue;taint" ] } } @@ -83,47 +83,47 @@ private class ApacheStringUtilsModel extends SummaryModelCsv { "org.apache.commons.lang3;StringUtils;false;appendIfMissing;;;Argument[1];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;appendIfMissingIgnoreCase;;;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;appendIfMissingIgnoreCase;;;Argument[1];ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;capitalize;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;capitalize;;;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;center;(java.lang.String,int,java.lang.String);;Argument[2];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;center;;;Argument[0];ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;chomp;(java.lang.String);;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;chomp;(java.lang.String);;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;chomp;(java.lang.String,java.lang.String);;Argument[0];ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;chop;;;Argument;ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;defaultIfBlank;;;Argument;ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;defaultIfEmpty;;;Argument;ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;defaultString;;;Argument;ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;deleteWhitespace;;;Argument;ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;difference;;;Argument;ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;firstNonBlank;;;Argument;ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;firstNonEmpty;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;chop;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;defaultIfBlank;;;Argument[0..1];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;defaultIfEmpty;;;Argument[0..1];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;defaultString;;;Argument[0..1];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;deleteWhitespace;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;difference;;;Argument[0..1];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;firstNonBlank;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;firstNonEmpty;;;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;getBytes;;;Argument[0];ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;getCommonPrefix;;;Argument;ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;getDigits;;;Argument;ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;getIfBlank;;;Argument;ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;getIfEmpty;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;getCommonPrefix;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;getDigits;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;getIfBlank;;;Argument[0..1];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;getIfEmpty;;;Argument[0..1];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;join;(char[],char);;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;join;(char[],char,int,int);;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;join;(java.lang.Iterable,char);;Argument[0];ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;join;(java.lang.Iterable,java.lang.String);;Argument;ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;join;(java.lang.Object[]);;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;join;(java.lang.Iterable,java.lang.String);;Argument[0..1];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;join;(java.lang.Object[]);;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;join;(java.lang.Object[],char);;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;join;(java.lang.Object[],char,int,int);;Argument[0];ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;join;(java.lang.Object[],java.lang.String);;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;join;(java.lang.Object[],java.lang.String);;Argument[0..1];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;join;(java.lang.Object[],java.lang.String,int,int);;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;join;(java.lang.Object[],java.lang.String,int,int);;Argument[1];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;join;(java.util.Iterator,char);;Argument[0];ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;join;(java.util.Iterator,java.lang.String);;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;join;(java.util.Iterator,java.lang.String);;Argument[0..1];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;join;(java.util.List,char,int,int);;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;join;(java.util.List,java.lang.String,int,int);;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;join;(java.util.List,java.lang.String,int,int);;Argument[1];ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;joinWith;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;joinWith;;;Argument[0..1];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;left;;;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;leftPad;(java.lang.String,int,java.lang.String);;Argument[2];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;leftPad;;;Argument[0];ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;lowerCase;(java.lang.String);;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;lowerCase;(java.lang.String);;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;lowerCase;(java.lang.String,java.util.Locale);;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;mid;;;Argument[0];ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;normalizeSpace;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;normalizeSpace;;;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;overlay;;;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;overlay;;;Argument[1];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;prependIfMissing;;;Argument[0];ReturnValue;taint", @@ -161,32 +161,32 @@ private class ApacheStringUtilsModel extends SummaryModelCsv { "org.apache.commons.lang3;StringUtils;false;replaceOnceIgnoreCase;;;Argument[2];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;replacePattern;;;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;replacePattern;;;Argument[2];ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;reverse;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;reverse;;;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;reverseDelimited;;;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;right;;;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;rightPad;(java.lang.String,int,java.lang.String);;Argument[2];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;rightPad;;;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;rotate;;;Argument[0];ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;split;(java.lang.String);;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;split;(java.lang.String);;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;split;(java.lang.String,char);;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;split;(java.lang.String,java.lang.String);;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;split;(java.lang.String,java.lang.String,int);;Argument[0];ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;splitByCharacterType;;;Argument;ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;splitByCharacterTypeCamelCase;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;splitByCharacterType;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;splitByCharacterTypeCamelCase;;;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;splitByWholeSeparator;;;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;splitByWholeSeparatorPreserveAllTokens;;;Argument[0];ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;splitPreserveAllTokens;(java.lang.String);;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;splitPreserveAllTokens;(java.lang.String);;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;splitPreserveAllTokens;(java.lang.String,char);;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;splitPreserveAllTokens;(java.lang.String,java.lang.String);;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;splitPreserveAllTokens;(java.lang.String,java.lang.String,int);;Argument[0];ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;strip;(java.lang.String);;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;strip;(java.lang.String);;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;strip;(java.lang.String,java.lang.String);;Argument[0];ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;stripAccents;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;stripAccents;;;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;stripAll;;;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;stripEnd;;;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;stripStart;;;Argument[0];ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;stripToEmpty;;;Argument;ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;stripToNull;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;stripToEmpty;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;stripToNull;;;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;substring;;;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;substringAfter;;;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;substringAfterLast;;;Argument[0];ReturnValue;taint", @@ -194,25 +194,25 @@ private class ApacheStringUtilsModel extends SummaryModelCsv { "org.apache.commons.lang3;StringUtils;false;substringBeforeLast;;;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;substringBetween;;;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;substringsBetween;;;Argument[0];ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;swapCase;;;Argument;ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;toCodePoints;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;swapCase;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;toCodePoints;;;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;toEncodedString;;;Argument[0];ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;toRootLowerCase;;;Argument;ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;toRootUpperCase;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;toRootLowerCase;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;toRootUpperCase;;;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;toString;;;Argument[0];ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;trim;;;Argument;ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;trimToEmpty;;;Argument;ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;trimToNull;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;trim;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;trimToEmpty;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;trimToNull;;;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;truncate;;;Argument[0];ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;uncapitalize;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;uncapitalize;;;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;unwrap;;;Argument[0];ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;upperCase;(java.lang.String);;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;upperCase;(java.lang.String);;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;upperCase;(java.lang.String,java.util.Locale);;Argument[0];ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;valueOf;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;valueOf;;;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;wrap;(java.lang.String,char);;Argument[0];ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;wrap;(java.lang.String,java.lang.String);;Argument;ReturnValue;taint", + "org.apache.commons.lang3;StringUtils;false;wrap;(java.lang.String,java.lang.String);;Argument[0..1];ReturnValue;taint", "org.apache.commons.lang3;StringUtils;false;wrapIfMissing;(java.lang.String,char);;Argument[0];ReturnValue;taint", - "org.apache.commons.lang3;StringUtils;false;wrapIfMissing;(java.lang.String,java.lang.String);;Argument;ReturnValue;taint" + "org.apache.commons.lang3;StringUtils;false;wrapIfMissing;(java.lang.String,java.lang.String);;Argument[0..1];ReturnValue;taint" ] } } @@ -221,59 +221,59 @@ private class ApacheStrBuilderModel extends SummaryModelCsv { override predicate row(string row) { row = [ - "org.apache.commons.lang3.text;StrBuilder;false;StrBuilder;(java.lang.String);;Argument;Argument[-1];taint", - "org.apache.commons.lang3.text;StrBuilder;false;append;(char[]);;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;StrBuilder;(java.lang.String);;Argument[0];Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;append;(char[]);;Argument[0];Argument[-1];taint", "org.apache.commons.lang3.text;StrBuilder;false;append;(char[],int,int);;Argument[0];Argument[-1];taint", - "org.apache.commons.lang3.text;StrBuilder;false;append;(java.lang.CharSequence);;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;append;(java.lang.CharSequence);;Argument[0];Argument[-1];taint", "org.apache.commons.lang3.text;StrBuilder;false;append;(java.lang.CharSequence,int,int);;Argument[0];Argument[-1];taint", - "org.apache.commons.lang3.text;StrBuilder;false;append;(java.lang.Object);;Argument;Argument[-1];taint", - "org.apache.commons.lang3.text;StrBuilder;false;append;(java.lang.String);;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;append;(java.lang.Object);;Argument[0];Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;append;(java.lang.String);;Argument[0];Argument[-1];taint", "org.apache.commons.lang3.text;StrBuilder;false;append;(java.lang.String,int,int);;Argument[0];Argument[-1];taint", - "org.apache.commons.lang3.text;StrBuilder;false;append;(java.lang.String,java.lang.Object[]);;Argument;Argument[-1];taint", - "org.apache.commons.lang3.text;StrBuilder;false;append;(java.lang.StringBuffer);;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;append;(java.lang.String,java.lang.Object[]);;Argument[0..1];Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;append;(java.lang.StringBuffer);;Argument[0];Argument[-1];taint", "org.apache.commons.lang3.text;StrBuilder;false;append;(java.lang.StringBuffer,int,int);;Argument[0];Argument[-1];taint", - "org.apache.commons.lang3.text;StrBuilder;false;append;(java.lang.StringBuilder);;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;append;(java.lang.StringBuilder);;Argument[0];Argument[-1];taint", "org.apache.commons.lang3.text;StrBuilder;false;append;(java.lang.StringBuilder,int,int);;Argument[0];Argument[-1];taint", - "org.apache.commons.lang3.text;StrBuilder;false;append;(java.nio.CharBuffer);;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;append;(java.nio.CharBuffer);;Argument[0];Argument[-1];taint", "org.apache.commons.lang3.text;StrBuilder;false;append;(java.nio.CharBuffer,int,int);;Argument[0];Argument[-1];taint", - "org.apache.commons.lang3.text;StrBuilder;false;append;(org.apache.commons.lang3.text.StrBuilder);;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;append;(org.apache.commons.lang3.text.StrBuilder);;Argument[0];Argument[-1];taint", "org.apache.commons.lang3.text;StrBuilder;false;append;;;Argument[-1];ReturnValue;taint", - "org.apache.commons.lang3.text;StrBuilder;false;appendAll;;;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;appendAll;;;Argument[0];Argument[-1];taint", "org.apache.commons.lang3.text;StrBuilder;false;appendAll;;;Argument[-1];ReturnValue;taint", "org.apache.commons.lang3.text;StrBuilder;false;appendFixedWidthPadLeft;;;Argument[-1];ReturnValue;taint", "org.apache.commons.lang3.text;StrBuilder;false;appendFixedWidthPadLeft;;;Argument[0];Argument[-1];taint", "org.apache.commons.lang3.text;StrBuilder;false;appendFixedWidthPadRight;;;Argument[-1];ReturnValue;taint", "org.apache.commons.lang3.text;StrBuilder;false;appendFixedWidthPadRight;;;Argument[0];Argument[-1];taint", - "org.apache.commons.lang3.text;StrBuilder;false;appendSeparator;(java.lang.String);;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;appendSeparator;(java.lang.String);;Argument[0];Argument[-1];taint", "org.apache.commons.lang3.text;StrBuilder;false;appendSeparator;(java.lang.String,int);;Argument[0];Argument[-1];taint", - "org.apache.commons.lang3.text;StrBuilder;false;appendSeparator;(java.lang.String,java.lang.String);;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;appendSeparator;(java.lang.String,java.lang.String);;Argument[0..1];Argument[-1];taint", "org.apache.commons.lang3.text;StrBuilder;false;appendSeparator;;;Argument[-1];ReturnValue;taint", - "org.apache.commons.lang3.text;StrBuilder;false;appendTo;;;Argument[-1];Argument;taint", - "org.apache.commons.lang3.text;StrBuilder;false;appendWithSeparators;;;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;appendTo;;;Argument[-1];Argument[0];taint", + "org.apache.commons.lang3.text;StrBuilder;false;appendWithSeparators;;;Argument[0..1];Argument[-1];taint", "org.apache.commons.lang3.text;StrBuilder;false;appendWithSeparators;;;Argument[-1];ReturnValue;taint", - "org.apache.commons.lang3.text;StrBuilder;false;appendln;(char[]);;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;appendln;(char[]);;Argument[0];Argument[-1];taint", "org.apache.commons.lang3.text;StrBuilder;false;appendln;(char[],int,int);;Argument[0];Argument[-1];taint", - "org.apache.commons.lang3.text;StrBuilder;false;appendln;(java.lang.Object);;Argument;Argument[-1];taint", - "org.apache.commons.lang3.text;StrBuilder;false;appendln;(java.lang.String);;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;appendln;(java.lang.Object);;Argument[0];Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;appendln;(java.lang.String);;Argument[0];Argument[-1];taint", "org.apache.commons.lang3.text;StrBuilder;false;appendln;(java.lang.String,int,int);;Argument[0];Argument[-1];taint", - "org.apache.commons.lang3.text;StrBuilder;false;appendln;(java.lang.String,java.lang.Object[]);;Argument;Argument[-1];taint", - "org.apache.commons.lang3.text;StrBuilder;false;appendln;(java.lang.StringBuffer);;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;appendln;(java.lang.String,java.lang.Object[]);;Argument[0..1];Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;appendln;(java.lang.StringBuffer);;Argument[0];Argument[-1];taint", "org.apache.commons.lang3.text;StrBuilder;false;appendln;(java.lang.StringBuffer,int,int);;Argument[0];Argument[-1];taint", - "org.apache.commons.lang3.text;StrBuilder;false;appendln;(java.lang.StringBuilder);;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;appendln;(java.lang.StringBuilder);;Argument[0];Argument[-1];taint", "org.apache.commons.lang3.text;StrBuilder;false;appendln;(java.lang.StringBuilder,int,int);;Argument[0];Argument[-1];taint", - "org.apache.commons.lang3.text;StrBuilder;false;appendln;(org.apache.commons.lang3.text.StrBuilder);;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;appendln;(org.apache.commons.lang3.text.StrBuilder);;Argument[0];Argument[-1];taint", "org.apache.commons.lang3.text;StrBuilder;false;appendln;;;Argument[-1];ReturnValue;taint", "org.apache.commons.lang3.text;StrBuilder;false;asReader;;;Argument[-1];ReturnValue;taint", "org.apache.commons.lang3.text;StrBuilder;false;asTokenizer;;;Argument[-1];ReturnValue;taint", "org.apache.commons.lang3.text;StrBuilder;false;build;;;Argument[-1];ReturnValue;taint", - "org.apache.commons.lang3.text;StrBuilder;false;getChars;(char[]);;Argument[-1];Argument;taint", + "org.apache.commons.lang3.text;StrBuilder;false;getChars;(char[]);;Argument[-1];Argument[0];taint", "org.apache.commons.lang3.text;StrBuilder;false;getChars;(char[]);;Argument[-1];ReturnValue;taint", "org.apache.commons.lang3.text;StrBuilder;false;getChars;(int,int,char[],int);;Argument[-1];Argument[2];taint", "org.apache.commons.lang3.text;StrBuilder;false;insert;;;Argument[-1];ReturnValue;taint", "org.apache.commons.lang3.text;StrBuilder;false;insert;;;Argument[1];Argument[-1];taint", "org.apache.commons.lang3.text;StrBuilder;false;leftString;;;Argument[-1];ReturnValue;taint", "org.apache.commons.lang3.text;StrBuilder;false;midString;;;Argument[-1];ReturnValue;taint", - "org.apache.commons.lang3.text;StrBuilder;false;readFrom;;;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrBuilder;false;readFrom;;;Argument[0];Argument[-1];taint", "org.apache.commons.lang3.text;StrBuilder;false;replace;(int,int,java.lang.String);;Argument[2];Argument[-1];taint", "org.apache.commons.lang3.text;StrBuilder;false;replace;(org.apache.commons.lang3.text.StrMatcher,java.lang.String,int,int,int);;Argument[1];Argument[-1];taint", "org.apache.commons.lang3.text;StrBuilder;false;replace;;;Argument[-1];ReturnValue;taint", @@ -288,59 +288,59 @@ private class ApacheStrBuilderModel extends SummaryModelCsv { "org.apache.commons.lang3.text;StrBuilder;false;toString;;;Argument[-1];ReturnValue;taint", "org.apache.commons.lang3.text;StrBuilder;false;toStringBuffer;;;Argument[-1];ReturnValue;taint", "org.apache.commons.lang3.text;StrBuilder;false;toStringBuilder;;;Argument[-1];ReturnValue;taint", - "org.apache.commons.text;StrBuilder;false;StrBuilder;(java.lang.String);;Argument;Argument[-1];taint", - "org.apache.commons.text;StrBuilder;false;append;(char[]);;Argument;Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;StrBuilder;(java.lang.String);;Argument[0];Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;append;(char[]);;Argument[0];Argument[-1];taint", "org.apache.commons.text;StrBuilder;false;append;(char[],int,int);;Argument[0];Argument[-1];taint", - "org.apache.commons.text;StrBuilder;false;append;(java.lang.CharSequence);;Argument;Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;append;(java.lang.CharSequence);;Argument[0];Argument[-1];taint", "org.apache.commons.text;StrBuilder;false;append;(java.lang.CharSequence,int,int);;Argument[0];Argument[-1];taint", - "org.apache.commons.text;StrBuilder;false;append;(java.lang.Object);;Argument;Argument[-1];taint", - "org.apache.commons.text;StrBuilder;false;append;(java.lang.String);;Argument;Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;append;(java.lang.Object);;Argument[0];Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;append;(java.lang.String);;Argument[0];Argument[-1];taint", "org.apache.commons.text;StrBuilder;false;append;(java.lang.String,int,int);;Argument[0];Argument[-1];taint", - "org.apache.commons.text;StrBuilder;false;append;(java.lang.String,java.lang.Object[]);;Argument;Argument[-1];taint", - "org.apache.commons.text;StrBuilder;false;append;(java.lang.StringBuffer);;Argument;Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;append;(java.lang.String,java.lang.Object[]);;Argument[0..1];Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;append;(java.lang.StringBuffer);;Argument[0];Argument[-1];taint", "org.apache.commons.text;StrBuilder;false;append;(java.lang.StringBuffer,int,int);;Argument[0];Argument[-1];taint", - "org.apache.commons.text;StrBuilder;false;append;(java.lang.StringBuilder);;Argument;Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;append;(java.lang.StringBuilder);;Argument[0];Argument[-1];taint", "org.apache.commons.text;StrBuilder;false;append;(java.lang.StringBuilder,int,int);;Argument[0];Argument[-1];taint", - "org.apache.commons.text;StrBuilder;false;append;(java.nio.CharBuffer);;Argument;Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;append;(java.nio.CharBuffer);;Argument[0];Argument[-1];taint", "org.apache.commons.text;StrBuilder;false;append;(java.nio.CharBuffer,int,int);;Argument[0];Argument[-1];taint", - "org.apache.commons.text;StrBuilder;false;append;(org.apache.commons.text.StrBuilder);;Argument;Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;append;(org.apache.commons.text.StrBuilder);;Argument[0];Argument[-1];taint", "org.apache.commons.text;StrBuilder;false;append;;;Argument[-1];ReturnValue;taint", - "org.apache.commons.text;StrBuilder;false;appendAll;;;Argument;Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;appendAll;;;Argument[0];Argument[-1];taint", "org.apache.commons.text;StrBuilder;false;appendAll;;;Argument[-1];ReturnValue;taint", "org.apache.commons.text;StrBuilder;false;appendFixedWidthPadLeft;;;Argument[-1];ReturnValue;taint", "org.apache.commons.text;StrBuilder;false;appendFixedWidthPadLeft;;;Argument[0];Argument[-1];taint", "org.apache.commons.text;StrBuilder;false;appendFixedWidthPadRight;;;Argument[-1];ReturnValue;taint", "org.apache.commons.text;StrBuilder;false;appendFixedWidthPadRight;;;Argument[0];Argument[-1];taint", - "org.apache.commons.text;StrBuilder;false;appendSeparator;(java.lang.String);;Argument;Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;appendSeparator;(java.lang.String);;Argument[0];Argument[-1];taint", "org.apache.commons.text;StrBuilder;false;appendSeparator;(java.lang.String,int);;Argument[0];Argument[-1];taint", - "org.apache.commons.text;StrBuilder;false;appendSeparator;(java.lang.String,java.lang.String);;Argument;Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;appendSeparator;(java.lang.String,java.lang.String);;Argument[0..1];Argument[-1];taint", "org.apache.commons.text;StrBuilder;false;appendSeparator;;;Argument[-1];ReturnValue;taint", - "org.apache.commons.text;StrBuilder;false;appendTo;;;Argument[-1];Argument;taint", - "org.apache.commons.text;StrBuilder;false;appendWithSeparators;;;Argument;Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;appendTo;;;Argument[-1];Argument[0];taint", + "org.apache.commons.text;StrBuilder;false;appendWithSeparators;;;Argument[0..1];Argument[-1];taint", "org.apache.commons.text;StrBuilder;false;appendWithSeparators;;;Argument[-1];ReturnValue;taint", - "org.apache.commons.text;StrBuilder;false;appendln;(char[]);;Argument;Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;appendln;(char[]);;Argument[0];Argument[-1];taint", "org.apache.commons.text;StrBuilder;false;appendln;(char[],int,int);;Argument[0];Argument[-1];taint", - "org.apache.commons.text;StrBuilder;false;appendln;(java.lang.Object);;Argument;Argument[-1];taint", - "org.apache.commons.text;StrBuilder;false;appendln;(java.lang.String);;Argument;Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;appendln;(java.lang.Object);;Argument[0];Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;appendln;(java.lang.String);;Argument[0];Argument[-1];taint", "org.apache.commons.text;StrBuilder;false;appendln;(java.lang.String,int,int);;Argument[0];Argument[-1];taint", - "org.apache.commons.text;StrBuilder;false;appendln;(java.lang.String,java.lang.Object[]);;Argument;Argument[-1];taint", - "org.apache.commons.text;StrBuilder;false;appendln;(java.lang.StringBuffer);;Argument;Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;appendln;(java.lang.String,java.lang.Object[]);;Argument[0..1];Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;appendln;(java.lang.StringBuffer);;Argument[0];Argument[-1];taint", "org.apache.commons.text;StrBuilder;false;appendln;(java.lang.StringBuffer,int,int);;Argument[0];Argument[-1];taint", - "org.apache.commons.text;StrBuilder;false;appendln;(java.lang.StringBuilder);;Argument;Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;appendln;(java.lang.StringBuilder);;Argument[0];Argument[-1];taint", "org.apache.commons.text;StrBuilder;false;appendln;(java.lang.StringBuilder,int,int);;Argument[0];Argument[-1];taint", - "org.apache.commons.text;StrBuilder;false;appendln;(org.apache.commons.text.StrBuilder);;Argument;Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;appendln;(org.apache.commons.text.StrBuilder);;Argument[0];Argument[-1];taint", "org.apache.commons.text;StrBuilder;false;appendln;;;Argument[-1];ReturnValue;taint", "org.apache.commons.text;StrBuilder;false;asReader;;;Argument[-1];ReturnValue;taint", "org.apache.commons.text;StrBuilder;false;asTokenizer;;;Argument[-1];ReturnValue;taint", "org.apache.commons.text;StrBuilder;false;build;;;Argument[-1];ReturnValue;taint", - "org.apache.commons.text;StrBuilder;false;getChars;(char[]);;Argument[-1];Argument;taint", + "org.apache.commons.text;StrBuilder;false;getChars;(char[]);;Argument[-1];Argument[0];taint", "org.apache.commons.text;StrBuilder;false;getChars;(char[]);;Argument[-1];ReturnValue;taint", "org.apache.commons.text;StrBuilder;false;getChars;(int,int,char[],int);;Argument[-1];Argument[2];taint", "org.apache.commons.text;StrBuilder;false;insert;;;Argument[-1];ReturnValue;taint", "org.apache.commons.text;StrBuilder;false;insert;;;Argument[1];Argument[-1];taint", "org.apache.commons.text;StrBuilder;false;leftString;;;Argument[-1];ReturnValue;taint", "org.apache.commons.text;StrBuilder;false;midString;;;Argument[-1];ReturnValue;taint", - "org.apache.commons.text;StrBuilder;false;readFrom;;;Argument;Argument[-1];taint", + "org.apache.commons.text;StrBuilder;false;readFrom;;;Argument[0];Argument[-1];taint", "org.apache.commons.text;StrBuilder;false;replace;(int,int,java.lang.String);;Argument[2];Argument[-1];taint", "org.apache.commons.text;StrBuilder;false;replace;(org.apache.commons.text.StrMatcher,java.lang.String,int,int,int);;Argument[1];Argument[-1];taint", "org.apache.commons.text;StrBuilder;false;replace;;;Argument[-1];ReturnValue;taint", @@ -355,60 +355,60 @@ private class ApacheStrBuilderModel extends SummaryModelCsv { "org.apache.commons.text;StrBuilder;false;toString;;;Argument[-1];ReturnValue;taint", "org.apache.commons.text;StrBuilder;false;toStringBuffer;;;Argument[-1];ReturnValue;taint", "org.apache.commons.text;StrBuilder;false;toStringBuilder;;;Argument[-1];ReturnValue;taint", - "org.apache.commons.text;TextStringBuilder;false;TextStringBuilder;(java.lang.String);;Argument;Argument[-1];taint", - "org.apache.commons.text;TextStringBuilder;false;TextStringBuilder;(java.lang.CharSequence);;Argument;Argument[-1];taint", - "org.apache.commons.text;TextStringBuilder;false;append;(char[]);;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;TextStringBuilder;(java.lang.String);;Argument[0];Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;TextStringBuilder;(java.lang.CharSequence);;Argument[0];Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;append;(char[]);;Argument[0];Argument[-1];taint", "org.apache.commons.text;TextStringBuilder;false;append;(char[],int,int);;Argument[0];Argument[-1];taint", - "org.apache.commons.text;TextStringBuilder;false;append;(java.lang.CharSequence);;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;append;(java.lang.CharSequence);;Argument[0];Argument[-1];taint", "org.apache.commons.text;TextStringBuilder;false;append;(java.lang.CharSequence,int,int);;Argument[0];Argument[-1];taint", - "org.apache.commons.text;TextStringBuilder;false;append;(java.lang.Object);;Argument;Argument[-1];taint", - "org.apache.commons.text;TextStringBuilder;false;append;(java.lang.String);;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;append;(java.lang.Object);;Argument[0];Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;append;(java.lang.String);;Argument[0];Argument[-1];taint", "org.apache.commons.text;TextStringBuilder;false;append;(java.lang.String,int,int);;Argument[0];Argument[-1];taint", - "org.apache.commons.text;TextStringBuilder;false;append;(java.lang.String,java.lang.Object[]);;Argument;Argument[-1];taint", - "org.apache.commons.text;TextStringBuilder;false;append;(java.lang.StringBuffer);;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;append;(java.lang.String,java.lang.Object[]);;Argument[0..1];Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;append;(java.lang.StringBuffer);;Argument[0];Argument[-1];taint", "org.apache.commons.text;TextStringBuilder;false;append;(java.lang.StringBuffer,int,int);;Argument[0];Argument[-1];taint", - "org.apache.commons.text;TextStringBuilder;false;append;(java.lang.StringBuilder);;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;append;(java.lang.StringBuilder);;Argument[0];Argument[-1];taint", "org.apache.commons.text;TextStringBuilder;false;append;(java.lang.StringBuilder,int,int);;Argument[0];Argument[-1];taint", - "org.apache.commons.text;TextStringBuilder;false;append;(java.nio.CharBuffer);;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;append;(java.nio.CharBuffer);;Argument[0];Argument[-1];taint", "org.apache.commons.text;TextStringBuilder;false;append;(java.nio.CharBuffer,int,int);;Argument[0];Argument[-1];taint", - "org.apache.commons.text;TextStringBuilder;false;append;(org.apache.commons.text.TextStringBuilder);;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;append;(org.apache.commons.text.TextStringBuilder);;Argument[0];Argument[-1];taint", "org.apache.commons.text;TextStringBuilder;false;append;;;Argument[-1];ReturnValue;taint", - "org.apache.commons.text;TextStringBuilder;false;appendAll;;;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;appendAll;;;Argument[0];Argument[-1];taint", "org.apache.commons.text;TextStringBuilder;false;appendAll;;;Argument[-1];ReturnValue;taint", "org.apache.commons.text;TextStringBuilder;false;appendFixedWidthPadLeft;;;Argument[-1];ReturnValue;taint", "org.apache.commons.text;TextStringBuilder;false;appendFixedWidthPadLeft;;;Argument[0];Argument[-1];taint", "org.apache.commons.text;TextStringBuilder;false;appendFixedWidthPadRight;;;Argument[-1];ReturnValue;taint", "org.apache.commons.text;TextStringBuilder;false;appendFixedWidthPadRight;;;Argument[0];Argument[-1];taint", - "org.apache.commons.text;TextStringBuilder;false;appendSeparator;(java.lang.String);;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;appendSeparator;(java.lang.String);;Argument[0];Argument[-1];taint", "org.apache.commons.text;TextStringBuilder;false;appendSeparator;(java.lang.String,int);;Argument[0];Argument[-1];taint", - "org.apache.commons.text;TextStringBuilder;false;appendSeparator;(java.lang.String,java.lang.String);;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;appendSeparator;(java.lang.String,java.lang.String);;Argument[0..1];Argument[-1];taint", "org.apache.commons.text;TextStringBuilder;false;appendSeparator;;;Argument[-1];ReturnValue;taint", - "org.apache.commons.text;TextStringBuilder;false;appendTo;;;Argument[-1];Argument;taint", - "org.apache.commons.text;TextStringBuilder;false;appendWithSeparators;;;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;appendTo;;;Argument[-1];Argument[0];taint", + "org.apache.commons.text;TextStringBuilder;false;appendWithSeparators;;;Argument[0..1];Argument[-1];taint", "org.apache.commons.text;TextStringBuilder;false;appendWithSeparators;;;Argument[-1];ReturnValue;taint", - "org.apache.commons.text;TextStringBuilder;false;appendln;(char[]);;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;appendln;(char[]);;Argument[0];Argument[-1];taint", "org.apache.commons.text;TextStringBuilder;false;appendln;(char[],int,int);;Argument[0];Argument[-1];taint", - "org.apache.commons.text;TextStringBuilder;false;appendln;(java.lang.Object);;Argument;Argument[-1];taint", - "org.apache.commons.text;TextStringBuilder;false;appendln;(java.lang.String);;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;appendln;(java.lang.Object);;Argument[0];Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;appendln;(java.lang.String);;Argument[0];Argument[-1];taint", "org.apache.commons.text;TextStringBuilder;false;appendln;(java.lang.String,int,int);;Argument[0];Argument[-1];taint", - "org.apache.commons.text;TextStringBuilder;false;appendln;(java.lang.String,java.lang.Object[]);;Argument;Argument[-1];taint", - "org.apache.commons.text;TextStringBuilder;false;appendln;(java.lang.StringBuffer);;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;appendln;(java.lang.String,java.lang.Object[]);;Argument[0..1];Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;appendln;(java.lang.StringBuffer);;Argument[0];Argument[-1];taint", "org.apache.commons.text;TextStringBuilder;false;appendln;(java.lang.StringBuffer,int,int);;Argument[0];Argument[-1];taint", - "org.apache.commons.text;TextStringBuilder;false;appendln;(java.lang.StringBuilder);;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;appendln;(java.lang.StringBuilder);;Argument[0];Argument[-1];taint", "org.apache.commons.text;TextStringBuilder;false;appendln;(java.lang.StringBuilder,int,int);;Argument[0];Argument[-1];taint", - "org.apache.commons.text;TextStringBuilder;false;appendln;(org.apache.commons.text.TextStringBuilder);;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;appendln;(org.apache.commons.text.TextStringBuilder);;Argument[0];Argument[-1];taint", "org.apache.commons.text;TextStringBuilder;false;appendln;;;Argument[-1];ReturnValue;taint", "org.apache.commons.text;TextStringBuilder;false;asReader;;;Argument[-1];ReturnValue;taint", "org.apache.commons.text;TextStringBuilder;false;asTokenizer;;;Argument[-1];ReturnValue;taint", "org.apache.commons.text;TextStringBuilder;false;build;;;Argument[-1];ReturnValue;taint", - "org.apache.commons.text;TextStringBuilder;false;getChars;(char[]);;Argument[-1];Argument;taint", + "org.apache.commons.text;TextStringBuilder;false;getChars;(char[]);;Argument[-1];Argument[0];taint", "org.apache.commons.text;TextStringBuilder;false;getChars;(char[]);;Argument[-1];ReturnValue;taint", "org.apache.commons.text;TextStringBuilder;false;getChars;(int,int,char[],int);;Argument[-1];Argument[2];taint", "org.apache.commons.text;TextStringBuilder;false;insert;;;Argument[-1];ReturnValue;taint", "org.apache.commons.text;TextStringBuilder;false;insert;;;Argument[1];Argument[-1];taint", "org.apache.commons.text;TextStringBuilder;false;leftString;;;Argument[-1];ReturnValue;taint", "org.apache.commons.text;TextStringBuilder;false;midString;;;Argument[-1];ReturnValue;taint", - "org.apache.commons.text;TextStringBuilder;false;readFrom;;;Argument;Argument[-1];taint", + "org.apache.commons.text;TextStringBuilder;false;readFrom;;;Argument[0];Argument[-1];taint", "org.apache.commons.text;TextStringBuilder;false;replace;(int,int,java.lang.String);;Argument[2];Argument[-1];taint", "org.apache.commons.text;TextStringBuilder;false;replace;(org.apache.commons.text.matcher.StringMatcher,java.lang.String,int,int,int);;Argument[1];Argument[-1];taint", "org.apache.commons.text;TextStringBuilder;false;replace;;;Argument[-1];ReturnValue;taint", @@ -437,28 +437,28 @@ private class ApacheWordUtilsModel extends SummaryModelCsv { "org.apache.commons.lang3.text;WordUtils;false;wrap;;;Argument[0];ReturnValue;taint", "org.apache.commons.lang3.text;WordUtils;false;wrap;(java.lang.String,int,java.lang.String,boolean);;Argument[2];ReturnValue;taint", "org.apache.commons.lang3.text;WordUtils;false;wrap;(java.lang.String,int,java.lang.String,boolean,java.lang.String);;Argument[2];ReturnValue;taint", - "org.apache.commons.lang3.text;WordUtils;false;uncapitalize;(java.lang.String);;Argument;ReturnValue;taint", + "org.apache.commons.lang3.text;WordUtils;false;uncapitalize;(java.lang.String);;Argument[0];ReturnValue;taint", "org.apache.commons.lang3.text;WordUtils;false;uncapitalize;(java.lang.String,char[]);;Argument[0];ReturnValue;taint", - "org.apache.commons.lang3.text;WordUtils;false;swapCase;;;Argument;ReturnValue;taint", - "org.apache.commons.lang3.text;WordUtils;false;capitalize;(java.lang.String);;Argument;ReturnValue;taint", + "org.apache.commons.lang3.text;WordUtils;false;swapCase;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3.text;WordUtils;false;capitalize;(java.lang.String);;Argument[0];ReturnValue;taint", "org.apache.commons.lang3.text;WordUtils;false;capitalize;(java.lang.String,char[]);;Argument[0];ReturnValue;taint", - "org.apache.commons.lang3.text;WordUtils;false;initials;(java.lang.String);;Argument;ReturnValue;taint", + "org.apache.commons.lang3.text;WordUtils;false;initials;(java.lang.String);;Argument[0];ReturnValue;taint", "org.apache.commons.lang3.text;WordUtils;false;initials;(java.lang.String,char[]);;Argument[0];ReturnValue;taint", - "org.apache.commons.lang3.text;WordUtils;false;capitalizeFully;(java.lang.String);;Argument;ReturnValue;taint", + "org.apache.commons.lang3.text;WordUtils;false;capitalizeFully;(java.lang.String);;Argument[0];ReturnValue;taint", "org.apache.commons.lang3.text;WordUtils;false;capitalizeFully;(java.lang.String,char[]);;Argument[0];ReturnValue;taint", "org.apache.commons.text;WordUtils;false;wrap;;;Argument[0];ReturnValue;taint", "org.apache.commons.text;WordUtils;false;wrap;(java.lang.String,int,java.lang.String,boolean);;Argument[2];ReturnValue;taint", "org.apache.commons.text;WordUtils;false;wrap;(java.lang.String,int,java.lang.String,boolean,java.lang.String);;Argument[2];ReturnValue;taint", - "org.apache.commons.text;WordUtils;false;uncapitalize;(java.lang.String);;Argument;ReturnValue;taint", + "org.apache.commons.text;WordUtils;false;uncapitalize;(java.lang.String);;Argument[0];ReturnValue;taint", "org.apache.commons.text;WordUtils;false;uncapitalize;(java.lang.String,char[]);;Argument[0];ReturnValue;taint", - "org.apache.commons.text;WordUtils;false;swapCase;;;Argument;ReturnValue;taint", - "org.apache.commons.text;WordUtils;false;capitalize;(java.lang.String);;Argument;ReturnValue;taint", + "org.apache.commons.text;WordUtils;false;swapCase;;;Argument[0];ReturnValue;taint", + "org.apache.commons.text;WordUtils;false;capitalize;(java.lang.String);;Argument[0];ReturnValue;taint", "org.apache.commons.text;WordUtils;false;capitalize;(java.lang.String,char[]);;Argument[0];ReturnValue;taint", "org.apache.commons.text;WordUtils;false;abbreviate;;;Argument[0];ReturnValue;taint", "org.apache.commons.text;WordUtils;false;abbreviate;;;Argument[3];ReturnValue;taint", - "org.apache.commons.text;WordUtils;false;initials;(java.lang.String);;Argument;ReturnValue;taint", + "org.apache.commons.text;WordUtils;false;initials;(java.lang.String);;Argument[0];ReturnValue;taint", "org.apache.commons.text;WordUtils;false;initials;(java.lang.String,char[]);;Argument[0];ReturnValue;taint", - "org.apache.commons.text;WordUtils;false;capitalizeFully;(java.lang.String);;Argument;ReturnValue;taint", + "org.apache.commons.text;WordUtils;false;capitalizeFully;(java.lang.String);;Argument[0];ReturnValue;taint", "org.apache.commons.text;WordUtils;false;capitalizeFully;(java.lang.String,char[]);;Argument[0];ReturnValue;taint" ] } @@ -474,8 +474,8 @@ private class ApacheStrTokenizerModel extends SummaryModelCsv { "org.apache.commons.lang3.text;StrTokenizer;false;StrTokenizer;;;Argument[0];Argument[-1];taint", "org.apache.commons.lang3.text;StrTokenizer;false;clone;;;Argument[-1];ReturnValue;taint", "org.apache.commons.lang3.text;StrTokenizer;false;toString;;;Argument[-1];ReturnValue;taint", - "org.apache.commons.lang3.text;StrTokenizer;false;reset;;;Argument;ReturnValue;taint", - "org.apache.commons.lang3.text;StrTokenizer;false;reset;;;Argument;Argument[-1];taint", + "org.apache.commons.lang3.text;StrTokenizer;false;reset;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3.text;StrTokenizer;false;reset;;;Argument[0];Argument[-1];taint", "org.apache.commons.lang3.text;StrTokenizer;false;next;;;Argument[-1];ReturnValue;taint", "org.apache.commons.lang3.text;StrTokenizer;false;getContent;;;Argument[-1];ReturnValue;taint", "org.apache.commons.lang3.text;StrTokenizer;false;previous;;;Argument[-1];ReturnValue;taint", @@ -483,13 +483,13 @@ private class ApacheStrTokenizerModel extends SummaryModelCsv { "org.apache.commons.lang3.text;StrTokenizer;false;getTokenArray;;;Argument[-1];ReturnValue;taint", "org.apache.commons.lang3.text;StrTokenizer;false;previousToken;;;Argument[-1];ReturnValue;taint", "org.apache.commons.lang3.text;StrTokenizer;false;nextToken;;;Argument[-1];ReturnValue;taint", - "org.apache.commons.lang3.text;StrTokenizer;false;getTSVInstance;;;Argument;ReturnValue;taint", - "org.apache.commons.lang3.text;StrTokenizer;false;getCSVInstance;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3.text;StrTokenizer;false;getTSVInstance;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3.text;StrTokenizer;false;getCSVInstance;;;Argument[0];ReturnValue;taint", "org.apache.commons.text;StrTokenizer;false;StrTokenizer;;;Argument[0];Argument[-1];taint", "org.apache.commons.text;StrTokenizer;false;clone;;;Argument[-1];ReturnValue;taint", "org.apache.commons.text;StrTokenizer;false;toString;;;Argument[-1];ReturnValue;taint", - "org.apache.commons.text;StrTokenizer;false;reset;;;Argument;ReturnValue;taint", - "org.apache.commons.text;StrTokenizer;false;reset;;;Argument;Argument[-1];taint", + "org.apache.commons.text;StrTokenizer;false;reset;;;Argument[0];ReturnValue;taint", + "org.apache.commons.text;StrTokenizer;false;reset;;;Argument[0];Argument[-1];taint", "org.apache.commons.text;StrTokenizer;false;next;;;Argument[-1];ReturnValue;taint", "org.apache.commons.text;StrTokenizer;false;getContent;;;Argument[-1];ReturnValue;taint", "org.apache.commons.text;StrTokenizer;false;previous;;;Argument[-1];ReturnValue;taint", @@ -497,13 +497,13 @@ private class ApacheStrTokenizerModel extends SummaryModelCsv { "org.apache.commons.text;StrTokenizer;false;getTokenArray;;;Argument[-1];ReturnValue;taint", "org.apache.commons.text;StrTokenizer;false;previousToken;;;Argument[-1];ReturnValue;taint", "org.apache.commons.text;StrTokenizer;false;nextToken;;;Argument[-1];ReturnValue;taint", - "org.apache.commons.text;StrTokenizer;false;getTSVInstance;;;Argument;ReturnValue;taint", - "org.apache.commons.text;StrTokenizer;false;getCSVInstance;;;Argument;ReturnValue;taint", + "org.apache.commons.text;StrTokenizer;false;getTSVInstance;;;Argument[0];ReturnValue;taint", + "org.apache.commons.text;StrTokenizer;false;getCSVInstance;;;Argument[0];ReturnValue;taint", "org.apache.commons.text;StringTokenizer;false;StringTokenizer;;;Argument[0];Argument[-1];taint", "org.apache.commons.text;StringTokenizer;false;clone;;;Argument[-1];ReturnValue;taint", "org.apache.commons.text;StringTokenizer;false;toString;;;Argument[-1];ReturnValue;taint", - "org.apache.commons.text;StringTokenizer;false;reset;;;Argument;ReturnValue;taint", - "org.apache.commons.text;StringTokenizer;false;reset;;;Argument;Argument[-1];taint", + "org.apache.commons.text;StringTokenizer;false;reset;;;Argument[0];ReturnValue;taint", + "org.apache.commons.text;StringTokenizer;false;reset;;;Argument[0];Argument[-1];taint", "org.apache.commons.text;StringTokenizer;false;next;;;Argument[-1];ReturnValue;taint", "org.apache.commons.text;StringTokenizer;false;getContent;;;Argument[-1];ReturnValue;taint", "org.apache.commons.text;StringTokenizer;false;previous;;;Argument[-1];ReturnValue;taint", @@ -511,8 +511,8 @@ private class ApacheStrTokenizerModel extends SummaryModelCsv { "org.apache.commons.text;StringTokenizer;false;getTokenArray;;;Argument[-1];ReturnValue;taint", "org.apache.commons.text;StringTokenizer;false;previousToken;;;Argument[-1];ReturnValue;taint", "org.apache.commons.text;StringTokenizer;false;nextToken;;;Argument[-1];ReturnValue;taint", - "org.apache.commons.text;StringTokenizer;false;getTSVInstance;;;Argument;ReturnValue;taint", - "org.apache.commons.text;StringTokenizer;false;getCSVInstance;;;Argument;ReturnValue;taint" + "org.apache.commons.text;StringTokenizer;false;getTSVInstance;;;Argument[0];ReturnValue;taint", + "org.apache.commons.text;StringTokenizer;false;getCSVInstance;;;Argument[0];ReturnValue;taint" ] } } @@ -525,9 +525,9 @@ private class ApacheStrLookupModel extends SummaryModelCsv { row = [ "org.apache.commons.lang3.text;StrLookup;false;lookup;;;Argument[-1];ReturnValue;taint", - "org.apache.commons.lang3.text;StrLookup;false;mapLookup;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3.text;StrLookup;false;mapLookup;;;Argument[0];ReturnValue;taint", "org.apache.commons.text.lookup;StringLookup;true;lookup;;;Argument[-1];ReturnValue;taint", - "org.apache.commons.text.lookup;StringLookupFactory;false;mapStringLookup;;;Argument;ReturnValue;taint" + "org.apache.commons.text.lookup;StringLookupFactory;false;mapStringLookup;;;Argument[0];ReturnValue;taint" ] } } @@ -541,51 +541,51 @@ private class ApacheStrSubstitutorModel extends SummaryModelCsv { [ "org.apache.commons.lang3.text;StrSubstitutor;false;StrSubstitutor;;;Argument[0];Argument[-1];taint", "org.apache.commons.lang3.text;StrSubstitutor;false;replace;;;Argument[-1];ReturnValue;taint", - "org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.Object);;Argument;ReturnValue;taint", - "org.apache.commons.lang3.text;StrSubstitutor;false;replace;(char[]);;Argument;ReturnValue;taint", + "org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.Object);;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3.text;StrSubstitutor;false;replace;(char[]);;Argument[0];ReturnValue;taint", "org.apache.commons.lang3.text;StrSubstitutor;false;replace;(char[],int,int);;Argument[0];ReturnValue;taint", - "org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.CharSequence);;Argument;ReturnValue;taint", + "org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.CharSequence);;Argument[0];ReturnValue;taint", "org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.CharSequence,int,int);;Argument[0];ReturnValue;taint", - "org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.String);;Argument;ReturnValue;taint", - "org.apache.commons.lang3.text;StrSubstitutor;false;replace;(org.apache.commons.lang3.text.StrBuilder);;Argument;ReturnValue;taint", - "org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.StringBuffer);;Argument;ReturnValue;taint", + "org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.String);;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3.text;StrSubstitutor;false;replace;(org.apache.commons.lang3.text.StrBuilder);;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.StringBuffer);;Argument[0];ReturnValue;taint", "org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.StringBuffer,int,int);;Argument[0];ReturnValue;taint", "org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.String,int,int);;Argument[0];ReturnValue;taint", "org.apache.commons.lang3.text;StrSubstitutor;false;replace;(org.apache.commons.lang3.text.StrBuilder,int,int);;Argument[0];ReturnValue;taint", - "org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.Object,java.util.Map);;Argument;ReturnValue;taint", + "org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.Object,java.util.Map);;Argument[0..1];ReturnValue;taint", "org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.Object,java.util.Map,java.lang.String,java.lang.String);;Argument[0];ReturnValue;taint", "org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.Object,java.util.Map,java.lang.String,java.lang.String);;Argument[1];ReturnValue;taint", - "org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.Object,java.util.Properties);;Argument;ReturnValue;taint", - "org.apache.commons.lang3.text;StrSubstitutor;false;setVariableResolver;;;Argument;Argument[-1];taint", - "org.apache.commons.lang3.text;StrSubstitutor;false;replaceIn;(org.apache.commons.lang3.text.StrBuilder);;Argument[-1];Argument;taint", - "org.apache.commons.lang3.text;StrSubstitutor;false;replaceIn;(java.lang.StringBuffer);;Argument[-1];Argument;taint", + "org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.Object,java.util.Properties);;Argument[0..1];ReturnValue;taint", + "org.apache.commons.lang3.text;StrSubstitutor;false;setVariableResolver;;;Argument[0];Argument[-1];taint", + "org.apache.commons.lang3.text;StrSubstitutor;false;replaceIn;(org.apache.commons.lang3.text.StrBuilder);;Argument[-1];Argument[0];taint", + "org.apache.commons.lang3.text;StrSubstitutor;false;replaceIn;(java.lang.StringBuffer);;Argument[-1];Argument[0];taint", "org.apache.commons.lang3.text;StrSubstitutor;false;replaceIn;(java.lang.StringBuffer,int,int);;Argument[-1];Argument[0];taint", - "org.apache.commons.lang3.text;StrSubstitutor;false;replaceIn;(java.lang.StringBuilder);;Argument[-1];Argument;taint", + "org.apache.commons.lang3.text;StrSubstitutor;false;replaceIn;(java.lang.StringBuilder);;Argument[-1];Argument[0];taint", "org.apache.commons.lang3.text;StrSubstitutor;false;replaceIn;(java.lang.StringBuilder,int,int);;Argument[-1];Argument[0];taint", "org.apache.commons.lang3.text;StrSubstitutor;false;replaceIn;(org.apache.commons.lang3.text.StrBuilder,int,int);;Argument[-1];Argument[0];taint", "org.apache.commons.text;StringSubstitutor;false;StringSubstitutor;;;Argument[0];Argument[-1];taint", "org.apache.commons.text;StringSubstitutor;false;replace;;;Argument[-1];ReturnValue;taint", - "org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.Object);;Argument;ReturnValue;taint", - "org.apache.commons.text;StringSubstitutor;false;replace;(char[]);;Argument;ReturnValue;taint", + "org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.Object);;Argument[0];ReturnValue;taint", + "org.apache.commons.text;StringSubstitutor;false;replace;(char[]);;Argument[0];ReturnValue;taint", "org.apache.commons.text;StringSubstitutor;false;replace;(char[],int,int);;Argument[0];ReturnValue;taint", - "org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.CharSequence);;Argument;ReturnValue;taint", + "org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.CharSequence);;Argument[0];ReturnValue;taint", "org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.CharSequence,int,int);;Argument[0];ReturnValue;taint", - "org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.String);;Argument;ReturnValue;taint", - "org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.StringBuffer);;Argument;ReturnValue;taint", + "org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.String);;Argument[0];ReturnValue;taint", + "org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.StringBuffer);;Argument[0];ReturnValue;taint", "org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.StringBuffer,int,int);;Argument[0];ReturnValue;taint", "org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.String,int,int);;Argument[0];ReturnValue;taint", - "org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.Object,java.util.Map);;Argument;ReturnValue;taint", + "org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.Object,java.util.Map);;Argument[0..1];ReturnValue;taint", "org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.Object,java.util.Map,java.lang.String,java.lang.String);;Argument[0];ReturnValue;taint", "org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.Object,java.util.Map,java.lang.String,java.lang.String);;Argument[1];ReturnValue;taint", - "org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.Object,java.util.Properties);;Argument;ReturnValue;taint", - "org.apache.commons.text;StringSubstitutor;false;replace;(org.apache.commons.text.TextStringBuilder);;Argument;ReturnValue;taint", + "org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.Object,java.util.Properties);;Argument[0..1];ReturnValue;taint", + "org.apache.commons.text;StringSubstitutor;false;replace;(org.apache.commons.text.TextStringBuilder);;Argument[0];ReturnValue;taint", "org.apache.commons.text;StringSubstitutor;false;replace;(org.apache.commons.text.TextStringBuilder,int,int);;Argument[0];ReturnValue;taint", - "org.apache.commons.text;StringSubstitutor;false;setVariableResolver;;;Argument;Argument[-1];taint", - "org.apache.commons.text;StringSubstitutor;false;replaceIn;(java.lang.StringBuffer);;Argument[-1];Argument;taint", + "org.apache.commons.text;StringSubstitutor;false;setVariableResolver;;;Argument[0];Argument[-1];taint", + "org.apache.commons.text;StringSubstitutor;false;replaceIn;(java.lang.StringBuffer);;Argument[-1];Argument[0];taint", "org.apache.commons.text;StringSubstitutor;false;replaceIn;(java.lang.StringBuffer,int,int);;Argument[-1];Argument[0];taint", - "org.apache.commons.text;StringSubstitutor;false;replaceIn;(java.lang.StringBuilder);;Argument[-1];Argument;taint", + "org.apache.commons.text;StringSubstitutor;false;replaceIn;(java.lang.StringBuilder);;Argument[-1];Argument[0];taint", "org.apache.commons.text;StringSubstitutor;false;replaceIn;(java.lang.StringBuilder,int,int);;Argument[-1];Argument[0];taint", - "org.apache.commons.text;StringSubstitutor;false;replaceIn;(org.apache.commons.text.TextStringBuilder);;Argument[-1];Argument;taint", + "org.apache.commons.text;StringSubstitutor;false;replaceIn;(org.apache.commons.text.TextStringBuilder);;Argument[-1];Argument[0];taint", "org.apache.commons.text;StringSubstitutor;false;replaceIn;(org.apache.commons.text.TextStringBuilder,int,int);;Argument[-1];Argument[0];taint" ] } @@ -620,18 +620,18 @@ private class ApacheObjectUtilsModel extends SummaryModelCsv { [ // Note all the functions annotated with `taint` flow really should have `value` flow, // but we don't support value-preserving varargs functions at the moment. - "org.apache.commons.lang3;ObjectUtils;false;clone;;;Argument;ReturnValue;value", - "org.apache.commons.lang3;ObjectUtils;false;cloneIfPossible;;;Argument;ReturnValue;value", - "org.apache.commons.lang3;ObjectUtils;false;CONST;;;Argument;ReturnValue;value", - "org.apache.commons.lang3;ObjectUtils;false;CONST_BYTE;;;Argument;ReturnValue;value", - "org.apache.commons.lang3;ObjectUtils;false;CONST_SHORT;;;Argument;ReturnValue;value", - "org.apache.commons.lang3;ObjectUtils;false;defaultIfNull;;;Argument;ReturnValue;value", - "org.apache.commons.lang3;ObjectUtils;false;firstNonNull;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;ObjectUtils;false;clone;;;Argument[0];ReturnValue;value", + "org.apache.commons.lang3;ObjectUtils;false;cloneIfPossible;;;Argument[0];ReturnValue;value", + "org.apache.commons.lang3;ObjectUtils;false;CONST;;;Argument[0];ReturnValue;value", + "org.apache.commons.lang3;ObjectUtils;false;CONST_BYTE;;;Argument[0];ReturnValue;value", + "org.apache.commons.lang3;ObjectUtils;false;CONST_SHORT;;;Argument[0];ReturnValue;value", + "org.apache.commons.lang3;ObjectUtils;false;defaultIfNull;;;Argument[0..1];ReturnValue;value", + "org.apache.commons.lang3;ObjectUtils;false;firstNonNull;;;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;ObjectUtils;false;getIfNull;;;Argument[0];ReturnValue;value", - "org.apache.commons.lang3;ObjectUtils;false;max;;;Argument;ReturnValue;taint", - "org.apache.commons.lang3;ObjectUtils;false;median;;;Argument;ReturnValue;taint", - "org.apache.commons.lang3;ObjectUtils;false;min;;;Argument;ReturnValue;taint", - "org.apache.commons.lang3;ObjectUtils;false;mode;;;Argument;ReturnValue;taint", + "org.apache.commons.lang3;ObjectUtils;false;max;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;ObjectUtils;false;median;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;ObjectUtils;false;min;;;Argument[0];ReturnValue;taint", + "org.apache.commons.lang3;ObjectUtils;false;mode;;;Argument[0];ReturnValue;taint", "org.apache.commons.lang3;ObjectUtils;false;requireNonEmpty;;;Argument[0];ReturnValue;value", "org.apache.commons.lang3;ObjectUtils;false;toString;(Object,String);;Argument[1];ReturnValue;value" ] From dbef36cbbbf5a025279d0c46a02c64e0ab08c416 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Thu, 25 Mar 2021 17:28:37 +0100 Subject: [PATCH 387/725] Python: Prevent bad TC and add a bit of caching Using `simpleLocalFlowStep+` with the first argument specialised to `CfgNode` was causing the compiler to turn this into a very slowly converging manual TC computation. Instead, we use `simpleLocalFlowStep*` (which is fast) and then join that with a single step from any `CfgNode`. This should amount to the same thing. I also noticed that the charpred for `LocalSourceNode` was getting recomputed a lot, so this is now cached. (The recomputation was especially bad since it relied on `simpleLocalFlowStep+`, but anyway it's a good idea not to recompute this.) --- .../python/dataflow/new/internal/DataFlowPublic.qll | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll index 7b75fd70f2a..f53162e0517 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll @@ -467,14 +467,22 @@ class BarrierGuard extends GuardNode { } } +private predicate comes_from_cfgnode(Node node) { + exists(Node second | + simpleLocalFlowStep(any(CfgNode c), second) and + simpleLocalFlowStep*(second, node) + ) +} + /** * A data flow node that is a source of local flow. This includes things like * - Expressions * - Function parameters */ class LocalSourceNode extends Node { + cached LocalSourceNode() { - not simpleLocalFlowStep+(any(CfgNode n), this) and + not comes_from_cfgnode(this) and not this instanceof ModuleVariableNode or this = any(ModuleVariableNode mvn).getARead() From ed78acb1d44affb8f4c2b7e1181b5bb511505532 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 19 Mar 2021 16:47:09 +0100 Subject: [PATCH 388/725] C#: Update more nuget packages --- .../Semmle.Autobuild.CSharp.Tests.csproj | 4 ++-- .../Semmle.Autobuild.CSharp/Semmle.Autobuild.CSharp.csproj | 2 +- .../Semmle.Extraction.Tests/Semmle.Extraction.Tests.csproj | 4 ++-- csharp/extractor/Semmle.Extraction/Semmle.Extraction.csproj | 2 +- csharp/extractor/Semmle.Util.Tests/Semmle.Util.Tests.csproj | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/Semmle.Autobuild.CSharp.Tests.csproj b/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/Semmle.Autobuild.CSharp.Tests.csproj index 64e25a8eb64..cc79699848a 100644 --- a/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/Semmle.Autobuild.CSharp.Tests.csproj +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/Semmle.Autobuild.CSharp.Tests.csproj @@ -1,7 +1,6 @@ - Exe net5.0 false win-x64;linux-x64;osx-x64 @@ -12,10 +11,11 @@ - + all runtime; build; native; contentfiles; analyzers + diff --git a/csharp/autobuilder/Semmle.Autobuild.CSharp/Semmle.Autobuild.CSharp.csproj b/csharp/autobuilder/Semmle.Autobuild.CSharp/Semmle.Autobuild.CSharp.csproj index 60291bfc308..b24f243de01 100644 --- a/csharp/autobuilder/Semmle.Autobuild.CSharp/Semmle.Autobuild.CSharp.csproj +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp/Semmle.Autobuild.CSharp.csproj @@ -18,7 +18,7 @@ - + diff --git a/csharp/extractor/Semmle.Extraction.Tests/Semmle.Extraction.Tests.csproj b/csharp/extractor/Semmle.Extraction.Tests/Semmle.Extraction.Tests.csproj index 5b242d984ee..4a3e079e754 100644 --- a/csharp/extractor/Semmle.Extraction.Tests/Semmle.Extraction.Tests.csproj +++ b/csharp/extractor/Semmle.Extraction.Tests/Semmle.Extraction.Tests.csproj @@ -1,7 +1,6 @@ - Exe net5.0 false win-x64;linux-x64;osx-x64 @@ -12,10 +11,11 @@ - + all runtime; build; native; contentfiles; analyzers + diff --git a/csharp/extractor/Semmle.Extraction/Semmle.Extraction.csproj b/csharp/extractor/Semmle.Extraction/Semmle.Extraction.csproj index 87259c99668..03189150a47 100644 --- a/csharp/extractor/Semmle.Extraction/Semmle.Extraction.csproj +++ b/csharp/extractor/Semmle.Extraction/Semmle.Extraction.csproj @@ -16,7 +16,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/csharp/extractor/Semmle.Util.Tests/Semmle.Util.Tests.csproj b/csharp/extractor/Semmle.Util.Tests/Semmle.Util.Tests.csproj index ca9599cf770..e5c2019bb42 100644 --- a/csharp/extractor/Semmle.Util.Tests/Semmle.Util.Tests.csproj +++ b/csharp/extractor/Semmle.Util.Tests/Semmle.Util.Tests.csproj @@ -1,7 +1,6 @@ - Exe net5.0 false win-x64;linux-x64;osx-x64 @@ -10,10 +9,11 @@ - + all runtime; build; native; contentfiles; analyzers + From f100c8a9c025a323f3fd7cbbbfa3e13feb54b72a Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 25 Mar 2021 17:43:48 +0100 Subject: [PATCH 389/725] C++: Make Windows autobuilder tests pass again --- .../BuildScripts.cs | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests/BuildScripts.cs b/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests/BuildScripts.cs index 87390b7bf8f..d37f3e30e66 100644 --- a/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests/BuildScripts.cs +++ b/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests/BuildScripts.cs @@ -5,6 +5,7 @@ using System; using System.Linq; using Microsoft.Build.Construction; using System.Xml; +using System.IO; namespace Semmle.Autobuild.Cpp.Tests { @@ -43,6 +44,8 @@ namespace Semmle.Autobuild.Cpp.Tests public IDictionary RunProcess = new Dictionary(); public IDictionary RunProcessOut = new Dictionary(); public IDictionary RunProcessWorkingDirectory = new Dictionary(); + public HashSet CreateDirectories { get; } = new HashSet(); + public HashSet<(string, string)> DownloadFiles { get; } = new HashSet<(string, string)>(); int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary? env, out IList stdOut) { @@ -135,6 +138,14 @@ namespace Semmle.Autobuild.Cpp.Tests string IBuildActions.GetFullPath(string path) => path; + string? IBuildActions.GetFileName(string? path) => Path.GetFileName(path?.Replace('\\', '/')); + + public string? GetDirectoryName(string? path) + { + var dir = Path.GetDirectoryName(path?.Replace('\\', '/')); + return dir is null ? path : path?.Substring(0, dir.Length); + } + void IBuildActions.WriteAllText(string filename, string contents) { } @@ -153,6 +164,18 @@ namespace Semmle.Autobuild.Cpp.Tests s = s.Replace($"%{kvp.Key}%", kvp.Value); return s; } + + public void CreateDirectory(string path) + { + if (!CreateDirectories.Contains(path)) + throw new ArgumentException($"Missing CreateDirectory, {path}"); + } + + public void DownloadFile(string address, string fileName) + { + if (!DownloadFiles.Contains((address, fileName))) + throw new ArgumentException($"Missing DownloadFile, {address}, {fileName}"); + } } /// @@ -213,6 +236,7 @@ namespace Semmle.Autobuild.Cpp.Tests Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_SOURCE_ARCHIVE_DIR"] = ""; Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_ROOT"] = $@"C:\codeql\{codeqlUpperLanguage.ToLowerInvariant()}"; Actions.GetEnvironmentVariable["CODEQL_JAVA_HOME"] = @"C:\codeql\tools\java"; + Actions.GetEnvironmentVariable["CODEQL_PLATFORM"] = "win64"; Actions.GetEnvironmentVariable["SEMMLE_DIST"] = @"C:\odasa"; Actions.GetEnvironmentVariable["SEMMLE_JAVA_HOME"] = @"C:\odasa\tools\java"; Actions.GetEnvironmentVariable["SEMMLE_PLATFORM_TOOLS"] = @"C:\odasa\tools"; @@ -273,7 +297,8 @@ namespace Semmle.Autobuild.Cpp.Tests [Fact] public void TestCppAutobuilderSuccess() { - Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\csharp\nuget\nuget.exe restore C:\Project\test.sln"] = 1; + Actions.RunProcess[@"cmd.exe /C nuget restore C:\Project\test.sln -DisableParallelProcessing"] = 1; + Actions.RunProcess[@"cmd.exe /C C:\Project\.nuget\nuget.exe restore C:\Project\test.sln -DisableParallelProcessing"] = 0; Actions.RunProcess[@"cmd.exe /C CALL ^""C:\Program Files ^(x86^)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat^"" && set Platform=&& type NUL && C:\odasa\tools\odasa index --auto msbuild C:\Project\test.sln /p:UseSharedCompilation=false /t:rebuild /p:Platform=""x86"" /p:Configuration=""Release"" /p:MvcBuildViews=true"] = 0; Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = ""; Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = 1; @@ -286,11 +311,13 @@ namespace Semmle.Autobuild.Cpp.Tests Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = true; Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.slx"; Actions.EnumerateDirectories[@"C:\Project"] = ""; + Actions.CreateDirectories.Add(@"C:\Project\.nuget"); + Actions.DownloadFiles.Add(("https://dist.nuget.org/win-x86-commandline/latest/nuget.exe", @"C:\Project\.nuget\nuget.exe")); var autobuilder = CreateAutoBuilder(true); var solution = new TestSolution(@"C:\Project\test.sln"); autobuilder.ProjectsOrSolutionsToBuild.Add(solution); - TestAutobuilderScript(autobuilder, 0, 2); + TestAutobuilderScript(autobuilder, 0, 3); } } } From 229250dc5421b6a8e9af251f11c1877a0c7c29e9 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Thu, 25 Mar 2021 18:28:49 +0100 Subject: [PATCH 390/725] Python: Limit size of `TupleElementContent` A more principled approach is possible here, but in the short term this will prevent an explosion. For reference, openstack/cinder has roughly 19000 `ForTarget`s and tuples of size up to 5300, and we were calculating the cartesian product of these. --- .../src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index 86ef69a87b9..cc99e092496 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -1517,7 +1517,7 @@ predicate forReadStep(CfgNode nodeFrom, Content c, Node nodeTo) { or c instanceof SetElementContent or - c instanceof TupleElementContent + c.(TupleElementContent).getIndex() <= 7 ) } From 8734df334be9337a8f66b8d5e2f6ce9fdcbdcac9 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Thu, 25 Mar 2021 18:35:16 +0100 Subject: [PATCH 391/725] Python: Slight cleanup --- .../semmle/python/dataflow/new/internal/DataFlowPublic.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll index f53162e0517..0836de26faf 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll @@ -468,8 +468,8 @@ class BarrierGuard extends GuardNode { } private predicate comes_from_cfgnode(Node node) { - exists(Node second | - simpleLocalFlowStep(any(CfgNode c), second) and + exists(CfgNode first, Node second | + simpleLocalFlowStep(first, second) and simpleLocalFlowStep*(second, node) ) } From 5e59f6d558e84f4bae5fdb30bc5e0ad298454cad Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 25 Mar 2021 19:03:37 +0100 Subject: [PATCH 392/725] Update javascript/ql/src/semmle/javascript/security/dataflow/ShellCommandInjectionFromEnvironmentCustomizations.qll Co-authored-by: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com> --- .../ShellCommandInjectionFromEnvironmentCustomizations.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ShellCommandInjectionFromEnvironmentCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ShellCommandInjectionFromEnvironmentCustomizations.qll index 29e0afa39b2..178c396ad8c 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/ShellCommandInjectionFromEnvironmentCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/ShellCommandInjectionFromEnvironmentCustomizations.qll @@ -57,7 +57,7 @@ module ShellCommandInjectionFromEnvironment { } /** - * A string-concatenation leaf that is sorounded by quotes, seen as a sanitizer for command-injection. + * A string-concatenation leaf that is surrounded by quotes, seen as a sanitizer for command-injection. */ class QuotingConcatSanitizer extends Sanitizer, StringOps::ConcatenationLeaf { QuotingConcatSanitizer() { From c2f112cb9204eb0e62af58e7980dfbb2cf285a40 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Thu, 25 Mar 2021 19:06:05 +0100 Subject: [PATCH 393/725] Python: Filter _before_ the cartesian product It's always a sad thing to see a good plan go wrong: 86860032 ~0% {4} r26 = JOIN r19 WITH DataFlowPublic::TupleElementContent#class#ff CARTESIAN PRODUCT OUTPUT Lhs.0 'nodeFrom', Lhs.1 'nodeTo', Rhs.0, Rhs.1 129256 ~3% {4} r27 = SELECT r26 ON In.3 <= 7 129256 ~0% {3} r28 = SCAN r27 OUTPUT In.0 'nodeFrom', In.2 'c', In.1 'nodeTo' Happily, now it looks like this: 129256 ~0% {3} r20 = JOIN r19 WITH DataFlowPrivate::small_tuple#f CARTESIAN PRODUCT OUTPUT Lhs.0 'nodeFrom', Rhs.0, Lhs.1 'nodeTo' --- .../semmle/python/dataflow/new/internal/DataFlowPrivate.qll | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index cc99e092496..9b0a8267270 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -1517,10 +1517,13 @@ predicate forReadStep(CfgNode nodeFrom, Content c, Node nodeTo) { or c instanceof SetElementContent or - c.(TupleElementContent).getIndex() <= 7 + c = small_tuple() ) } +pragma[noinline] +TupleElementContent small_tuple() { result.getIndex() <= 7 } + /** * Holds if `nodeTo` is a read of an attribute (corresponding to `c`) of the object in `nodeFrom`. * From 2ca95166d916cc89bf2d7086aa664ef3757c95e4 Mon Sep 17 00:00:00 2001 From: Porcuiney Hairs Date: Wed, 13 Jan 2021 01:32:54 +0530 Subject: [PATCH 394/725] Java : add query to detect insecure loading of Dex File --- .../CWE/CWE-094/InsecureDexLoading.qhelp | 44 ++++++++ .../CWE/CWE-094/InsecureDexLoading.ql | 20 ++++ .../CWE/CWE-094/InsecureDexLoading.qll | 100 ++++++++++++++++++ .../CWE/CWE-094/InsecureDexLoadingBad.java | 32 ++++++ .../CWE/CWE-094/InsecureDexLoadingGood.java | 23 ++++ 5 files changed, 219 insertions(+) create mode 100644 java/ql/src/experimental/Security/CWE/CWE-094/InsecureDexLoading.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-094/InsecureDexLoading.ql create mode 100644 java/ql/src/experimental/Security/CWE/CWE-094/InsecureDexLoading.qll create mode 100644 java/ql/src/experimental/Security/CWE/CWE-094/InsecureDexLoadingBad.java create mode 100644 java/ql/src/experimental/Security/CWE/CWE-094/InsecureDexLoadingGood.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/InsecureDexLoading.qhelp b/java/ql/src/experimental/Security/CWE/CWE-094/InsecureDexLoading.qhelp new file mode 100644 index 00000000000..feda3af3fc2 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/InsecureDexLoading.qhelp @@ -0,0 +1,44 @@ + + + +

    +Shared world writable storage spaces are not secure to load Dex libraries from. A malicious actor can replace a dex file with a maliciously crafted file +which when loaded by the app can lead to code execution. +

    +
    + + +

    + Loading a file from private storage instead of a world writable one can prevent this issue. + As the attacker cannot access files stored by the app in its private storage. +

    +
    + + +

    + The following example loads a Dex file from a shared world writable location. in this case, + since the `/sdcard` directory is on external storage, any one can read/write to the location. + bypassing all Android security policies. Hence, this is insecure. +

    + + +

    + The next example loads a Dex file stored inside the app's private storage. + This is not exploitable as nobody else except the app can access the data stored here. +

    + +
    + + +
  • + Android Documentation: + Data and file storage overview + . +
  • +
  • + Android Documentation: + DexClassLoader + . +
  • +
    +
    diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/InsecureDexLoading.ql b/java/ql/src/experimental/Security/CWE/CWE-094/InsecureDexLoading.ql new file mode 100644 index 00000000000..58d9844d38a --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/InsecureDexLoading.ql @@ -0,0 +1,20 @@ +/** + * @name Insecure loading of an Android Dex File + * @description Loading a DEX library located in a world-readable/ writable location such as + * a SD card can cause arbitary code execution vulnerabilities. + * @kind path-problem + * @problem.severity error + * @precision high + * @id java/android-insecure-dex-loading + * @tags security + * external/cwe/cwe-094 + */ + +import java +import InsecureDexLoading +import DataFlow::PathGraph + +from DataFlow::PathNode source, DataFlow::PathNode sink, InsecureDexConfiguration conf +where conf.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "Potential arbitary code execution due to $@.", + source.getNode(), "a value loaded from a world readable/writable source." diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/InsecureDexLoading.qll b/java/ql/src/experimental/Security/CWE/CWE-094/InsecureDexLoading.qll new file mode 100644 index 00000000000..2a4b387be7e --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/InsecureDexLoading.qll @@ -0,0 +1,100 @@ +import java +import semmle.code.java.dataflow.FlowSources + +/** + * A taint-tracking configuration fordetecting unsafe use of a + * `DexClassLoader` by an Android app. + */ +class InsecureDexConfiguration extends TaintTracking::Configuration { + InsecureDexConfiguration() { this = "Insecure Dex File Load" } + + override predicate isSource(DataFlow::Node source) { source instanceof InsecureDexSource } + + override predicate isSink(DataFlow::Node sink) { sink instanceof InsecureDexSink } + + override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { + flowStep(pred, succ) + } +} + +/** A data flow source for insecure Dex class loading vulnerabilities. */ +abstract class InsecureDexSource extends DataFlow::Node { } + +/** A data flow sink for insecure Dex class loading vulnerabilities. */ +abstract class InsecureDexSink extends DataFlow::Node { } + +private predicate flowStep(DataFlow::Node pred, DataFlow::Node succ) { + // propagate from a `java.io.File` via the `File.getAbsolutePath` call. + exists(MethodAccess m | + m.getMethod().getDeclaringType() instanceof TypeFile and + m.getMethod().hasName("getAbsolutePath") and + m.getQualifier() = pred.asExpr() and + m = succ.asExpr() + ) + or + // propagate from a `java.io.File` via the `File.toString` call. + exists(MethodAccess m | + m.getMethod().getDeclaringType() instanceof TypeFile and + m.getMethod().hasName("toString") and + m.getQualifier() = pred.asExpr() and + m = succ.asExpr() + ) + or + // propagate to newly created `File` if the parent directory of the new `File` is tainted + exists(ConstructorCall cc | + cc.getConstructedType() instanceof TypeFile and + cc.getArgument(0) = pred.asExpr() and + cc = succ.asExpr() + ) +} + +/** + * An argument to a `DexClassLoader` call taken as a sink for + * insecure Dex class loading vulnerabilities. + */ +private class DexClassLoader extends InsecureDexSink { + DexClassLoader() { + exists(ConstructorCall cc | + cc.getConstructedType().hasQualifiedName("dalvik.system", "DexClassLoader") + | + this.asExpr() = cc.getArgument(0) + ) + } +} + +/** + * An `File` instance which reads from an SD card + * taken as a source for insecure Dex class loading vulnerabilities. + */ +private class ExternalFile extends InsecureDexSource { + ExternalFile() { + exists(ConstructorCall cc, Argument a | + cc.getConstructedType() instanceof TypeFile and + a = cc.getArgument(0) and + a.(CompileTimeConstantExpr).getStringValue().matches("%sdcard%") + | + this.asExpr() = a + ) + } +} + +/** + * A directory or file which may be stored in an world writable directory + * taken as a source for insecure Dex class loading vulnerabilities. + */ +private class ExternalStorageDirSource extends InsecureDexSource { + ExternalStorageDirSource() { + exists(Method m | + m.getDeclaringType().hasQualifiedName("android.os", "Environment") and + m.hasName("getExternalStorageDirectory") + or + m.getDeclaringType().hasQualifiedName("android.content", "Context") and + m.hasName([ + "getExternalFilesDir", "getExternalFilesDirs", "getExternalMediaDirs", + "getExternalCacheDir", "getExternalCacheDirs" + ]) + | + this.asExpr() = m.getAReference() + ) + } +} diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/InsecureDexLoadingBad.java b/java/ql/src/experimental/Security/CWE/CWE-094/InsecureDexLoadingBad.java new file mode 100644 index 00000000000..d8fdd828f4f --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/InsecureDexLoadingBad.java @@ -0,0 +1,32 @@ + +import android.app.Application; +import android.content.Context; +import android.content.pm.PackageInfo; +import android.os.Bundle; + +import dalvik.system.DexClassLoader; +import dalvik.system.DexFile; + +public class InsecureDexLoading extends Application { + @Override + public void onCreate() { + super.onCreate(); + updateChecker(); + } + + private void updateChecker() { + try { + File file = new File("/sdcard/updater.apk"); + if (file.exists() && file.isFile() && file.length() <= 1000) { + DexClassLoader cl = new DexClassLoader(file.getAbsolutePath(), getCacheDir().getAbsolutePath(), null, + getClassLoader()); + int version = (int) cl.loadClass("my.package.class").getDeclaredMethod("myMethod").invoke(null); + if (Build.VERSION.SDK_INT < version) { + Toast.makeText(this, "Securely loaded Dex!", Toast.LENGTH_LONG).show(); + } + } + } catch (Exception e) { + // ignore + } + } +} \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/InsecureDexLoadingGood.java b/java/ql/src/experimental/Security/CWE/CWE-094/InsecureDexLoadingGood.java new file mode 100644 index 00000000000..e45e3938f7b --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/InsecureDexLoadingGood.java @@ -0,0 +1,23 @@ +public class SecureDexLoading extends Application { + @Override + public void onCreate() { + super.onCreate(); + updateChecker(); + } + + private void updateChecker() { + try { + File file = new File(getCacheDir() + "/updater.apk"); + if (file.exists() && file.isFile() && file.length() <= 1000) { + DexClassLoader cl = new DexClassLoader(file.getAbsolutePath(), getCacheDir().getAbsolutePath(), null, + getClassLoader()); + int version = (int) cl.loadClass("my.package.class").getDeclaredMethod("myMethod").invoke(null); + if (Build.VERSION.SDK_INT < version) { + Toast.makeText(this, "Securely loaded Dex!", Toast.LENGTH_LONG).show(); + } + } + } catch (Exception e) { + // ignore + } + } +} \ No newline at end of file From d33b04cd965de99180434c998f96a15f98c1f5fa Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Fri, 26 Mar 2021 02:33:40 +0000 Subject: [PATCH 395/725] Query to detect plaintext credentials in Java properties files --- .../CWE-555/CredentialsInPropertiesFile.qhelp | 45 ++++++++++ .../CWE-555/CredentialsInPropertiesFile.ql | 87 +++++++++++++++++++ .../CWE/CWE-555/configuration.properties | 26 ++++++ .../CredentialsInPropertiesFile.expected | 5 ++ .../CWE-555/CredentialsInPropertiesFile.qlref | 1 + .../security/CWE-555/configuration.properties | 37 ++++++++ .../security/CWE-555/messages.properties | 8 ++ 7 files changed, 209 insertions(+) create mode 100644 java/ql/src/experimental/Security/CWE/CWE-555/CredentialsInPropertiesFile.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-555/CredentialsInPropertiesFile.ql create mode 100644 java/ql/src/experimental/Security/CWE/CWE-555/configuration.properties create mode 100644 java/ql/test/experimental/query-tests/security/CWE-555/CredentialsInPropertiesFile.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-555/CredentialsInPropertiesFile.qlref create mode 100644 java/ql/test/experimental/query-tests/security/CWE-555/configuration.properties create mode 100644 java/ql/test/experimental/query-tests/security/CWE-555/messages.properties diff --git a/java/ql/src/experimental/Security/CWE/CWE-555/CredentialsInPropertiesFile.qhelp b/java/ql/src/experimental/Security/CWE/CWE-555/CredentialsInPropertiesFile.qhelp new file mode 100644 index 00000000000..afbd40685ba --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-555/CredentialsInPropertiesFile.qhelp @@ -0,0 +1,45 @@ + + + +

    + Credentials management issues occur when credentials are stored in plaintext in + an application’s properties file. Common credentials include but are not limited + to LDAP, mail, database, proxy account, and so on. Storing plaintext credentials + in a properties file allows anyone who can read the file access to the protected + resource. Good credentials management guidelines require that credentials never + be stored in plaintext. +

    +
    + + +

    + Credentials stored in properties files should be encrypted and recycled regularly. + In a Java EE deployment scenario, utilities provided by application servers like + keystore and password vault can be used to encrypt and manage credentials. +

    +
    + + +

    + In the first example, the credentials of a LDAP and datasource properties are stored + in cleartext in the properties file. +

    + +

    + In the second example, the credentials of a LDAP and datasource properties are stored + in the encrypted format. +

    + +
    + + +
  • + OWASP: + Password Plaintext Storage +
  • +
  • + Medium (Rajeev Shukla): + Encrypting database password in the application.properties file +
  • +
    +
    diff --git a/java/ql/src/experimental/Security/CWE/CWE-555/CredentialsInPropertiesFile.ql b/java/ql/src/experimental/Security/CWE/CWE-555/CredentialsInPropertiesFile.ql new file mode 100644 index 00000000000..2ab074e56d8 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-555/CredentialsInPropertiesFile.ql @@ -0,0 +1,87 @@ +/** + * @name Cleartext Credentials in Properties File + * @description Finds cleartext credentials in Java properties files. + * @kind problem + * @id java/credentials-in-properties + * @tags security + * external/cwe/cwe-555 + * external/cwe/cwe-256 + * external/cwe/cwe-260 + */ + +import java +import semmle.code.configfiles.ConfigFiles + +private string suspicious() { + result = "%password%" or + result = "%passwd%" or + result = "%account%" or + result = "%accnt%" or + result = "%credential%" or + result = "%token%" or + result = "%secret%" or + result = "%access%key%" +} + +private string nonSuspicious() { + result = "%hashed%" or + result = "%encrypted%" or + result = "%crypt%" +} + +/** Holds if the value is not cleartext credentials. */ +bindingset[value] +predicate isNotCleartextCredentials(string value) { + value = "" // Empty string + or + value.length() < 7 // Typical credentials are no less than 6 characters + or + value.matches("% %") // Sentences containing spaces + or + value.regexpMatch(".*[^a-zA-Z\\d]{3,}.*") // Contain repeated non-alphanumeric characters such as a fake password pass**** or ???? + or + value.matches("@%") // Starts with the "@" sign + or + value.regexpMatch("\\$\\{.*\\}") // Variable placeholder ${credentials} + or + value.matches("%=") // A basic check of encrypted credentials ending with padding characters + or + value.matches("ENC(%)") // Encrypted value + or + value.toLowerCase().matches(suspicious()) // Could be message properties or fake passwords +} + +/** + * Holds if the credentials are in a non-production properties file indicated by: + * a) in a non-production directory + * b) with a non-production file name + */ +predicate isNonProdCredentials(CredentialsConfig cc) { + cc.getFile().getAbsolutePath().matches(["%dev%", "%test%", "%sample%"]) and + not cc.getFile().getAbsolutePath().matches("%codeql%") // CodeQL test cases +} + +/** The properties file with configuration key/value pairs. */ +class ConfigProperties extends ConfigPair { + ConfigProperties() { this.getFile().getBaseName().toLowerCase().matches("%.properties") } +} + +/** The credentials configuration property. */ +class CredentialsConfig extends ConfigProperties { + CredentialsConfig() { + this.getNameElement().getName().trim().toLowerCase().matches(suspicious()) and + not this.getNameElement().getName().trim().toLowerCase().matches(nonSuspicious()) + } + + string getName() { result = this.getNameElement().getName().trim() } + + string getValue() { result = this.getValueElement().getValue().trim() } +} + +from CredentialsConfig cc +where + not isNotCleartextCredentials(cc.getValue()) and + not isNonProdCredentials(cc) +select cc, + "Plaintext credentials " + cc.getName() + " have cleartext value " + cc.getValue() + + " in properties file." diff --git a/java/ql/src/experimental/Security/CWE/CWE-555/configuration.properties b/java/ql/src/experimental/Security/CWE/CWE-555/configuration.properties new file mode 100644 index 00000000000..55e8b0d86da --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-555/configuration.properties @@ -0,0 +1,26 @@ +#***************************** LDAP Credentials *****************************************# + +ldap.ldapHost = ldap.example.com +ldap.ldapPort = 636 +ldap.loginDN = cn=Directory Manager + +#### BAD: LDAP credentials are stored in cleartext #### +ldap.password = mysecpass + +#### GOOD: LDAP credentials are stored in the encrypted format #### +ldap.password = eFRZ3Cqo5zDJWMYLiaEupw== + +ldap.domain1 = example +ldap.domain2 = com +ldap.url= ldaps://ldap.example.com:636/dc=example,dc=com + +#*************************** MS SQL Database Connection **********************************# +datasource1.driverClassName = com.microsoft.sqlserver.jdbc.SQLServerDriver +datasource1.url = jdbc:sqlserver://ms.example.com\\exampledb:1433; +datasource1.username = sa + +#### BAD: Datasource credentials are stored in cleartext #### +datasource1.password = Passw0rd@123 + +#### GOOD: Datasource credentials are stored in the encrypted format #### +datasource1.password = VvOgflYS1EUzJdVNDoBcnA== diff --git a/java/ql/test/experimental/query-tests/security/CWE-555/CredentialsInPropertiesFile.expected b/java/ql/test/experimental/query-tests/security/CWE-555/CredentialsInPropertiesFile.expected new file mode 100644 index 00000000000..0ce33913932 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-555/CredentialsInPropertiesFile.expected @@ -0,0 +1,5 @@ +| configuration.properties:6:1:6:25 | ldap.password=mysecpass | Plaintext credentials ldap.password have cleartext value mysecpass in properties file. | +| configuration.properties:18:1:18:35 | datasource1.password=Passw0rd@123 | Plaintext credentials datasource1.password have cleartext value Passw0rd@123 in properties file. | +| configuration.properties:25:1:25:31 | mail.password=MysecPWxWa@1993 | Plaintext credentials mail.password have cleartext value MysecPWxWa@1993 in properties file. | +| configuration.properties:33:1:33:50 | com.example.aws.s3.access_key=AKMAMQPBYMCD6YSAYCBA | Plaintext credentials com.example.aws.s3.access_key have cleartext value AKMAMQPBYMCD6YSAYCBA in properties file. | +| configuration.properties:34:1:34:70 | com.example.aws.s3.secret_key=8lMPSfWzZq+wcWtck5+QPLOJDZzE783pS09/IO3k | Plaintext credentials com.example.aws.s3.secret_key have cleartext value 8lMPSfWzZq+wcWtck5+QPLOJDZzE783pS09/IO3k in properties file. | diff --git a/java/ql/test/experimental/query-tests/security/CWE-555/CredentialsInPropertiesFile.qlref b/java/ql/test/experimental/query-tests/security/CWE-555/CredentialsInPropertiesFile.qlref new file mode 100644 index 00000000000..e2536bfe883 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-555/CredentialsInPropertiesFile.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-555/CredentialsInPropertiesFile.ql \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-555/configuration.properties b/java/ql/test/experimental/query-tests/security/CWE-555/configuration.properties new file mode 100644 index 00000000000..a044161f097 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-555/configuration.properties @@ -0,0 +1,37 @@ +#***************************** LDAP Credentials *****************************************# +ldap.ldapHost = ldap.example.com +ldap.ldapPort = 636 +ldap.loginDN = cn=Directory Manager +#### BAD: LDAP credentials are stored in cleartext #### +ldap.password = mysecpass +#### GOOD: LDAP credentials are stored in the encrypted format #### +ldap.password = eFRZ3Cqo5zDJWMYLiaEupw== +ldap.domain1 = example +ldap.domain2 = com +ldap.url= ldaps://ldap.example.com:636/dc=example,dc=com + +#*************************** MS SQL Database Connection **********************************# +datasource1.driverClassName = com.microsoft.sqlserver.jdbc.SQLServerDriver +datasource1.url = jdbc:sqlserver://ms.example.com\\exampledb:1433; +datasource1.username = sa +#### BAD: Datasource credentials are stored in cleartext #### +datasource1.password = Passw0rd@123 +#### GOOD: Datasource credentials are stored in the encrypted format #### +datasource1.password = VvOgflYS1EUzJdVNDoBcnA== + +#*************************** Mail Connection **********************************# +mail.username = test@example.com +#### BAD: Mail credentials are stored in cleartext #### +mail.password = MysecPWxWa@1993 +#### GOOD: Mail credentials are stored in the encrypted format #### +mail.password = M*********@1993 + +#*************************** AWS S3 Connection **********************************# +com.example.aws.s3.bucket_name=com-bucket-1 +com.example.aws.s3.directory_name=com-directory-1 +#### BAD: Access keys are stored in properties file in cleartext #### +com.example.aws.s3.access_key=AKMAMQPBYMCD6YSAYCBA +com.example.aws.s3.secret_key=8lMPSfWzZq+wcWtck5+QPLOJDZzE783pS09/IO3k +#### GOOD: Access keys are not stored in properties file #### +com.example.aws.s3.access_key=${ENV:AWS_ACCESS_KEY_ID} +com.example.aws.s3.secret_key=${ENV:AWS_SECRET_ACCESS_KEY} diff --git a/java/ql/test/experimental/query-tests/security/CWE-555/messages.properties b/java/ql/test/experimental/query-tests/security/CWE-555/messages.properties new file mode 100644 index 00000000000..fac63ec23e8 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-555/messages.properties @@ -0,0 +1,8 @@ +prompt.username=Username +prompt.password=Password + +forgot_password.error=Please enter a valid email address. +reset_password.error=Passwords must match and not be empty. + +login.password_expired=Your current password has expired. Please reset your password. +login.login_failure=Unable to verify username or password. Please try again. From 57fd2e3578b809373af83286077218e70c63b888 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 26 Mar 2021 08:49:06 +0100 Subject: [PATCH 396/725] C#: Rename parameter in `fieldOf()` --- csharp/ql/src/semmle/code/csharp/dataflow/FlowSummary.qll | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/FlowSummary.qll b/csharp/ql/src/semmle/code/csharp/dataflow/FlowSummary.qll index 65b1cc2928f..374c42ed7e9 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/FlowSummary.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/FlowSummary.qll @@ -80,9 +80,9 @@ module SummaryComponentStack { result = push(SummaryComponent::property(p), object) } - /** Gets a stack representing a field `f` of `of`. */ - SummaryComponentStack fieldOf(Field f, SummaryComponentStack of) { - result = push(SummaryComponent::field(f), of) + /** Gets a stack representing a field `f` of `object`. */ + SummaryComponentStack fieldOf(Field f, SummaryComponentStack object) { + result = push(SummaryComponent::field(f), object) } /** Gets a singleton stack representing the return value of a call. */ From c7c65736a9c32945f9b7e7aa578b50ca77cbcae5 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 26 Mar 2021 10:57:58 +0100 Subject: [PATCH 397/725] C++: Accept test changes. These happened because of the incorrect usage of multiple configurations in 6c1ec6d96b1bfd7ab98b2d47c6fb059339956c16. --- .../UncontrolledFormatString.expected | 115 ---------------- ...olledFormatStringThroughGlobalVar.expected | 125 ------------------ 2 files changed, 240 deletions(-) diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatString.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatString.expected index 01ef5030e5f..58e3dda0964 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatString.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatString.expected @@ -1,118 +1,3 @@ edges -| globalVars.c:8:7:8:10 | copy | globalVars.c:27:9:27:12 | copy | -| globalVars.c:8:7:8:10 | copy | globalVars.c:27:9:27:12 | copy | -| globalVars.c:8:7:8:10 | copy | globalVars.c:30:15:30:18 | copy | -| globalVars.c:8:7:8:10 | copy | globalVars.c:30:15:30:18 | copy | -| globalVars.c:8:7:8:10 | copy | globalVars.c:33:15:33:18 | copy | -| globalVars.c:8:7:8:10 | copy | globalVars.c:33:15:33:18 | copy | -| globalVars.c:8:7:8:10 | copy | globalVars.c:35:11:35:14 | copy | -| globalVars.c:8:7:8:10 | copy | globalVars.c:35:11:35:14 | copy | -| globalVars.c:9:7:9:11 | copy2 | globalVars.c:38:9:38:13 | copy2 | -| globalVars.c:9:7:9:11 | copy2 | globalVars.c:38:9:38:13 | copy2 | -| globalVars.c:9:7:9:11 | copy2 | globalVars.c:41:15:41:19 | copy2 | -| globalVars.c:9:7:9:11 | copy2 | globalVars.c:41:15:41:19 | copy2 | -| globalVars.c:9:7:9:11 | copy2 | globalVars.c:44:15:44:19 | copy2 | -| globalVars.c:9:7:9:11 | copy2 | globalVars.c:44:15:44:19 | copy2 | -| globalVars.c:9:7:9:11 | copy2 | globalVars.c:50:9:50:13 | copy2 | -| globalVars.c:9:7:9:11 | copy2 | globalVars.c:50:9:50:13 | copy2 | -| globalVars.c:15:21:15:23 | val | globalVars.c:16:10:16:12 | val | -| globalVars.c:19:25:19:27 | *str | globalVars.c:20:9:20:11 | (const char *)... | -| globalVars.c:19:25:19:27 | *str | globalVars.c:20:9:20:11 | str indirection | -| globalVars.c:19:25:19:27 | str | globalVars.c:20:9:20:11 | (const char *)... | -| globalVars.c:19:25:19:27 | str | globalVars.c:20:9:20:11 | str | -| globalVars.c:19:25:19:27 | str | globalVars.c:20:9:20:11 | str | -| globalVars.c:19:25:19:27 | str | globalVars.c:20:9:20:11 | str indirection | -| globalVars.c:20:9:20:11 | str | globalVars.c:20:9:20:11 | (const char *)... | -| globalVars.c:20:9:20:11 | str | globalVars.c:20:9:20:11 | str indirection | -| globalVars.c:27:9:27:12 | copy | globalVars.c:27:9:27:12 | (const char *)... | -| globalVars.c:27:9:27:12 | copy | globalVars.c:27:9:27:12 | copy indirection | -| globalVars.c:30:2:30:13 | copy | globalVars.c:19:25:19:27 | str | -| globalVars.c:30:2:30:13 | copy | globalVars.c:19:25:19:27 | str | -| globalVars.c:30:15:30:18 | copy | globalVars.c:30:2:30:13 | copy | -| globalVars.c:30:15:30:18 | copy | globalVars.c:30:15:30:18 | copy | -| globalVars.c:30:15:30:18 | copy | globalVars.c:30:15:30:18 | copy | -| globalVars.c:30:15:30:18 | copy | globalVars.c:30:15:30:18 | copy indirection | -| globalVars.c:30:15:30:18 | copy | globalVars.c:30:15:30:18 | copy indirection | -| globalVars.c:30:15:30:18 | copy indirection | globalVars.c:19:25:19:27 | *str | -| globalVars.c:33:15:33:18 | copy | globalVars.c:33:15:33:18 | copy | -| globalVars.c:33:15:33:18 | copy | globalVars.c:33:15:33:18 | copy | -| globalVars.c:33:15:33:18 | copy | globalVars.c:33:15:33:18 | copy indirection | -| globalVars.c:35:2:35:9 | copy | globalVars.c:15:21:15:23 | val | -| globalVars.c:35:2:35:9 | copy | globalVars.c:15:21:15:23 | val | -| globalVars.c:35:11:35:14 | copy | globalVars.c:35:2:35:9 | copy | -| globalVars.c:35:11:35:14 | copy | globalVars.c:35:11:35:14 | copy | -| globalVars.c:35:11:35:14 | copy | globalVars.c:35:11:35:14 | copy | -| globalVars.c:35:11:35:14 | copy | globalVars.c:35:11:35:14 | copy indirection | -| globalVars.c:38:9:38:13 | copy2 | globalVars.c:38:9:38:13 | (const char *)... | -| globalVars.c:38:9:38:13 | copy2 | globalVars.c:38:9:38:13 | copy2 indirection | -| globalVars.c:41:2:41:13 | copy2 | globalVars.c:19:25:19:27 | str | -| globalVars.c:41:2:41:13 | copy2 | globalVars.c:19:25:19:27 | str | -| globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:2:41:13 | copy2 | -| globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:15:41:19 | copy2 | -| globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:15:41:19 | copy2 | -| globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:15:41:19 | copy2 indirection | -| globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:15:41:19 | copy2 indirection | -| globalVars.c:41:15:41:19 | copy2 indirection | globalVars.c:19:25:19:27 | *str | -| globalVars.c:44:15:44:19 | copy2 | globalVars.c:44:15:44:19 | copy2 | -| globalVars.c:44:15:44:19 | copy2 | globalVars.c:44:15:44:19 | copy2 | -| globalVars.c:44:15:44:19 | copy2 | globalVars.c:44:15:44:19 | copy2 indirection | -| globalVars.c:50:9:50:13 | copy2 | globalVars.c:50:9:50:13 | (const char *)... | -| globalVars.c:50:9:50:13 | copy2 | globalVars.c:50:9:50:13 | copy2 indirection | nodes -| globalVars.c:8:7:8:10 | copy | semmle.label | copy | -| globalVars.c:9:7:9:11 | copy2 | semmle.label | copy2 | -| globalVars.c:15:21:15:23 | val | semmle.label | val | -| globalVars.c:15:21:15:23 | val | semmle.label | val | -| globalVars.c:16:10:16:12 | val | semmle.label | val | -| globalVars.c:16:10:16:12 | val | semmle.label | val | -| globalVars.c:19:25:19:27 | *str | semmle.label | *str | -| globalVars.c:19:25:19:27 | str | semmle.label | str | -| globalVars.c:19:25:19:27 | str | semmle.label | str | -| globalVars.c:20:9:20:11 | (const char *)... | semmle.label | (const char *)... | -| globalVars.c:20:9:20:11 | (const char *)... | semmle.label | (const char *)... | -| globalVars.c:20:9:20:11 | str | semmle.label | str | -| globalVars.c:20:9:20:11 | str | semmle.label | str | -| globalVars.c:20:9:20:11 | str indirection | semmle.label | str indirection | -| globalVars.c:20:9:20:11 | str indirection | semmle.label | str indirection | -| globalVars.c:27:9:27:12 | (const char *)... | semmle.label | (const char *)... | -| globalVars.c:27:9:27:12 | (const char *)... | semmle.label | (const char *)... | -| globalVars.c:27:9:27:12 | copy | semmle.label | copy | -| globalVars.c:27:9:27:12 | copy | semmle.label | copy | -| globalVars.c:27:9:27:12 | copy indirection | semmle.label | copy indirection | -| globalVars.c:27:9:27:12 | copy indirection | semmle.label | copy indirection | -| globalVars.c:30:2:30:13 | copy | semmle.label | copy | -| globalVars.c:30:15:30:18 | copy | semmle.label | copy | -| globalVars.c:30:15:30:18 | copy | semmle.label | copy | -| globalVars.c:30:15:30:18 | copy indirection | semmle.label | copy indirection | -| globalVars.c:30:15:30:18 | copy indirection | semmle.label | copy indirection | -| globalVars.c:33:15:33:18 | copy | semmle.label | copy | -| globalVars.c:33:15:33:18 | copy | semmle.label | copy | -| globalVars.c:33:15:33:18 | copy indirection | semmle.label | copy indirection | -| globalVars.c:33:15:33:18 | copy indirection | semmle.label | copy indirection | -| globalVars.c:35:2:35:9 | copy | semmle.label | copy | -| globalVars.c:35:11:35:14 | copy | semmle.label | copy | -| globalVars.c:35:11:35:14 | copy | semmle.label | copy | -| globalVars.c:35:11:35:14 | copy indirection | semmle.label | copy indirection | -| globalVars.c:35:11:35:14 | copy indirection | semmle.label | copy indirection | -| globalVars.c:38:9:38:13 | (const char *)... | semmle.label | (const char *)... | -| globalVars.c:38:9:38:13 | (const char *)... | semmle.label | (const char *)... | -| globalVars.c:38:9:38:13 | copy2 | semmle.label | copy2 | -| globalVars.c:38:9:38:13 | copy2 | semmle.label | copy2 | -| globalVars.c:38:9:38:13 | copy2 indirection | semmle.label | copy2 indirection | -| globalVars.c:38:9:38:13 | copy2 indirection | semmle.label | copy2 indirection | -| globalVars.c:41:2:41:13 | copy2 | semmle.label | copy2 | -| globalVars.c:41:15:41:19 | copy2 | semmle.label | copy2 | -| globalVars.c:41:15:41:19 | copy2 | semmle.label | copy2 | -| globalVars.c:41:15:41:19 | copy2 indirection | semmle.label | copy2 indirection | -| globalVars.c:41:15:41:19 | copy2 indirection | semmle.label | copy2 indirection | -| globalVars.c:44:15:44:19 | copy2 | semmle.label | copy2 | -| globalVars.c:44:15:44:19 | copy2 | semmle.label | copy2 | -| globalVars.c:44:15:44:19 | copy2 indirection | semmle.label | copy2 indirection | -| globalVars.c:44:15:44:19 | copy2 indirection | semmle.label | copy2 indirection | -| globalVars.c:50:9:50:13 | (const char *)... | semmle.label | (const char *)... | -| globalVars.c:50:9:50:13 | (const char *)... | semmle.label | (const char *)... | -| globalVars.c:50:9:50:13 | copy2 | semmle.label | copy2 | -| globalVars.c:50:9:50:13 | copy2 | semmle.label | copy2 | -| globalVars.c:50:9:50:13 | copy2 indirection | semmle.label | copy2 indirection | -| globalVars.c:50:9:50:13 | copy2 indirection | semmle.label | copy2 indirection | #select diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatStringThroughGlobalVar.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatStringThroughGlobalVar.expected index 5ac81e70545..f095153f39c 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatStringThroughGlobalVar.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatStringThroughGlobalVar.expected @@ -2,37 +2,16 @@ edges | globalVars.c:8:7:8:10 | copy | globalVars.c:27:9:27:12 | copy | | globalVars.c:8:7:8:10 | copy | globalVars.c:27:9:27:12 | copy | | globalVars.c:8:7:8:10 | copy | globalVars.c:27:9:27:12 | copy | -| globalVars.c:8:7:8:10 | copy | globalVars.c:27:9:27:12 | copy | -| globalVars.c:8:7:8:10 | copy | globalVars.c:27:9:27:12 | copy | -| globalVars.c:8:7:8:10 | copy | globalVars.c:27:9:27:12 | copy | | globalVars.c:8:7:8:10 | copy | globalVars.c:30:15:30:18 | copy | | globalVars.c:8:7:8:10 | copy | globalVars.c:30:15:30:18 | copy | | globalVars.c:8:7:8:10 | copy | globalVars.c:30:15:30:18 | copy | -| globalVars.c:8:7:8:10 | copy | globalVars.c:30:15:30:18 | copy | -| globalVars.c:8:7:8:10 | copy | globalVars.c:30:15:30:18 | copy | -| globalVars.c:8:7:8:10 | copy | globalVars.c:30:15:30:18 | copy | -| globalVars.c:8:7:8:10 | copy | globalVars.c:33:15:33:18 | copy | -| globalVars.c:8:7:8:10 | copy | globalVars.c:33:15:33:18 | copy | -| globalVars.c:8:7:8:10 | copy | globalVars.c:35:11:35:14 | copy | -| globalVars.c:8:7:8:10 | copy | globalVars.c:35:11:35:14 | copy | | globalVars.c:8:7:8:10 | copy | globalVars.c:35:11:35:14 | copy | | globalVars.c:9:7:9:11 | copy2 | globalVars.c:38:9:38:13 | copy2 | | globalVars.c:9:7:9:11 | copy2 | globalVars.c:38:9:38:13 | copy2 | | globalVars.c:9:7:9:11 | copy2 | globalVars.c:38:9:38:13 | copy2 | -| globalVars.c:9:7:9:11 | copy2 | globalVars.c:38:9:38:13 | copy2 | -| globalVars.c:9:7:9:11 | copy2 | globalVars.c:38:9:38:13 | copy2 | -| globalVars.c:9:7:9:11 | copy2 | globalVars.c:38:9:38:13 | copy2 | | globalVars.c:9:7:9:11 | copy2 | globalVars.c:41:15:41:19 | copy2 | | globalVars.c:9:7:9:11 | copy2 | globalVars.c:41:15:41:19 | copy2 | | globalVars.c:9:7:9:11 | copy2 | globalVars.c:41:15:41:19 | copy2 | -| globalVars.c:9:7:9:11 | copy2 | globalVars.c:41:15:41:19 | copy2 | -| globalVars.c:9:7:9:11 | copy2 | globalVars.c:41:15:41:19 | copy2 | -| globalVars.c:9:7:9:11 | copy2 | globalVars.c:41:15:41:19 | copy2 | -| globalVars.c:9:7:9:11 | copy2 | globalVars.c:44:15:44:19 | copy2 | -| globalVars.c:9:7:9:11 | copy2 | globalVars.c:44:15:44:19 | copy2 | -| globalVars.c:9:7:9:11 | copy2 | globalVars.c:50:9:50:13 | copy2 | -| globalVars.c:9:7:9:11 | copy2 | globalVars.c:50:9:50:13 | copy2 | -| globalVars.c:9:7:9:11 | copy2 | globalVars.c:50:9:50:13 | copy2 | | globalVars.c:9:7:9:11 | copy2 | globalVars.c:50:9:50:13 | copy2 | | globalVars.c:9:7:9:11 | copy2 | globalVars.c:50:9:50:13 | copy2 | | globalVars.c:9:7:9:11 | copy2 | globalVars.c:50:9:50:13 | copy2 | @@ -41,16 +20,7 @@ edges | globalVars.c:11:22:11:25 | argv | globalVars.c:12:2:12:15 | Store | | globalVars.c:12:2:12:15 | Store | globalVars.c:8:7:8:10 | copy | | globalVars.c:15:21:15:23 | val | globalVars.c:16:2:16:12 | Store | -| globalVars.c:15:21:15:23 | val | globalVars.c:16:10:16:12 | val | | globalVars.c:16:2:16:12 | Store | globalVars.c:9:7:9:11 | copy2 | -| globalVars.c:19:25:19:27 | *str | globalVars.c:20:9:20:11 | (const char *)... | -| globalVars.c:19:25:19:27 | *str | globalVars.c:20:9:20:11 | str indirection | -| globalVars.c:19:25:19:27 | str | globalVars.c:20:9:20:11 | (const char *)... | -| globalVars.c:19:25:19:27 | str | globalVars.c:20:9:20:11 | str | -| globalVars.c:19:25:19:27 | str | globalVars.c:20:9:20:11 | str | -| globalVars.c:19:25:19:27 | str | globalVars.c:20:9:20:11 | str indirection | -| globalVars.c:20:9:20:11 | str | globalVars.c:20:9:20:11 | (const char *)... | -| globalVars.c:20:9:20:11 | str | globalVars.c:20:9:20:11 | str indirection | | globalVars.c:24:2:24:9 | argv | globalVars.c:11:22:11:25 | argv | | globalVars.c:24:11:24:14 | argv | globalVars.c:24:2:24:9 | argv | | globalVars.c:24:11:24:14 | argv | globalVars.c:24:2:24:9 | argv | @@ -58,162 +28,67 @@ edges | globalVars.c:24:11:24:14 | argv | globalVars.c:24:11:24:14 | argv indirection | | globalVars.c:24:11:24:14 | argv indirection | globalVars.c:11:22:11:25 | *argv | | globalVars.c:27:9:27:12 | copy | globalVars.c:27:9:27:12 | (const char *)... | -| globalVars.c:27:9:27:12 | copy | globalVars.c:27:9:27:12 | (const char *)... | -| globalVars.c:27:9:27:12 | copy | globalVars.c:27:9:27:12 | copy | | globalVars.c:27:9:27:12 | copy | globalVars.c:27:9:27:12 | copy | | globalVars.c:27:9:27:12 | copy | globalVars.c:27:9:27:12 | copy indirection | -| globalVars.c:27:9:27:12 | copy | globalVars.c:27:9:27:12 | copy indirection | -| globalVars.c:30:2:30:13 | copy | globalVars.c:19:25:19:27 | str | -| globalVars.c:30:2:30:13 | copy | globalVars.c:19:25:19:27 | str | -| globalVars.c:30:15:30:18 | copy | globalVars.c:30:2:30:13 | copy | -| globalVars.c:30:15:30:18 | copy | globalVars.c:30:15:30:18 | copy | -| globalVars.c:30:15:30:18 | copy | globalVars.c:30:15:30:18 | copy | -| globalVars.c:30:15:30:18 | copy | globalVars.c:30:15:30:18 | copy | | globalVars.c:30:15:30:18 | copy | globalVars.c:30:15:30:18 | copy | | globalVars.c:30:15:30:18 | copy | globalVars.c:30:15:30:18 | copy | | globalVars.c:30:15:30:18 | copy | globalVars.c:30:15:30:18 | copy | | globalVars.c:30:15:30:18 | copy | globalVars.c:30:15:30:18 | copy indirection | -| globalVars.c:30:15:30:18 | copy | globalVars.c:30:15:30:18 | copy indirection | -| globalVars.c:30:15:30:18 | copy | globalVars.c:30:15:30:18 | copy indirection | -| globalVars.c:30:15:30:18 | copy indirection | globalVars.c:19:25:19:27 | *str | -| globalVars.c:33:15:33:18 | copy | globalVars.c:33:15:33:18 | copy | -| globalVars.c:33:15:33:18 | copy | globalVars.c:33:15:33:18 | copy | -| globalVars.c:33:15:33:18 | copy | globalVars.c:33:15:33:18 | copy indirection | -| globalVars.c:35:2:35:9 | copy | globalVars.c:15:21:15:23 | val | -| globalVars.c:35:2:35:9 | copy | globalVars.c:15:21:15:23 | val | | globalVars.c:35:2:35:9 | copy | globalVars.c:15:21:15:23 | val | | globalVars.c:35:11:35:14 | copy | globalVars.c:35:2:35:9 | copy | -| globalVars.c:35:11:35:14 | copy | globalVars.c:35:2:35:9 | copy | -| globalVars.c:35:11:35:14 | copy | globalVars.c:35:11:35:14 | copy | -| globalVars.c:35:11:35:14 | copy | globalVars.c:35:11:35:14 | copy | -| globalVars.c:35:11:35:14 | copy | globalVars.c:35:11:35:14 | copy indirection | -| globalVars.c:38:9:38:13 | copy2 | globalVars.c:38:9:38:13 | (const char *)... | | globalVars.c:38:9:38:13 | copy2 | globalVars.c:38:9:38:13 | (const char *)... | | globalVars.c:38:9:38:13 | copy2 | globalVars.c:38:9:38:13 | copy2 | -| globalVars.c:38:9:38:13 | copy2 | globalVars.c:38:9:38:13 | copy2 | | globalVars.c:38:9:38:13 | copy2 | globalVars.c:38:9:38:13 | copy2 indirection | -| globalVars.c:38:9:38:13 | copy2 | globalVars.c:38:9:38:13 | copy2 indirection | -| globalVars.c:41:2:41:13 | copy2 | globalVars.c:19:25:19:27 | str | -| globalVars.c:41:2:41:13 | copy2 | globalVars.c:19:25:19:27 | str | -| globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:2:41:13 | copy2 | -| globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:15:41:19 | copy2 | -| globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:15:41:19 | copy2 | -| globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:15:41:19 | copy2 | | globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:15:41:19 | copy2 | | globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:15:41:19 | copy2 | | globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:15:41:19 | copy2 | | globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:15:41:19 | copy2 indirection | -| globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:15:41:19 | copy2 indirection | -| globalVars.c:41:15:41:19 | copy2 | globalVars.c:41:15:41:19 | copy2 indirection | -| globalVars.c:41:15:41:19 | copy2 indirection | globalVars.c:19:25:19:27 | *str | -| globalVars.c:44:15:44:19 | copy2 | globalVars.c:44:15:44:19 | copy2 | -| globalVars.c:44:15:44:19 | copy2 | globalVars.c:44:15:44:19 | copy2 | -| globalVars.c:44:15:44:19 | copy2 | globalVars.c:44:15:44:19 | copy2 indirection | -| globalVars.c:50:9:50:13 | copy2 | globalVars.c:50:9:50:13 | (const char *)... | | globalVars.c:50:9:50:13 | copy2 | globalVars.c:50:9:50:13 | (const char *)... | | globalVars.c:50:9:50:13 | copy2 | globalVars.c:50:9:50:13 | copy2 | -| globalVars.c:50:9:50:13 | copy2 | globalVars.c:50:9:50:13 | copy2 | -| globalVars.c:50:9:50:13 | copy2 | globalVars.c:50:9:50:13 | copy2 indirection | | globalVars.c:50:9:50:13 | copy2 | globalVars.c:50:9:50:13 | copy2 indirection | nodes | globalVars.c:8:7:8:10 | copy | semmle.label | copy | -| globalVars.c:8:7:8:10 | copy | semmle.label | copy | -| globalVars.c:9:7:9:11 | copy2 | semmle.label | copy2 | | globalVars.c:9:7:9:11 | copy2 | semmle.label | copy2 | | globalVars.c:11:22:11:25 | *argv | semmle.label | *argv | | globalVars.c:11:22:11:25 | argv | semmle.label | argv | | globalVars.c:12:2:12:15 | Store | semmle.label | Store | | globalVars.c:15:21:15:23 | val | semmle.label | val | -| globalVars.c:15:21:15:23 | val | semmle.label | val | -| globalVars.c:15:21:15:23 | val | semmle.label | val | | globalVars.c:16:2:16:12 | Store | semmle.label | Store | -| globalVars.c:16:10:16:12 | val | semmle.label | val | -| globalVars.c:16:10:16:12 | val | semmle.label | val | -| globalVars.c:19:25:19:27 | *str | semmle.label | *str | -| globalVars.c:19:25:19:27 | str | semmle.label | str | -| globalVars.c:19:25:19:27 | str | semmle.label | str | -| globalVars.c:20:9:20:11 | (const char *)... | semmle.label | (const char *)... | -| globalVars.c:20:9:20:11 | (const char *)... | semmle.label | (const char *)... | -| globalVars.c:20:9:20:11 | str | semmle.label | str | -| globalVars.c:20:9:20:11 | str | semmle.label | str | -| globalVars.c:20:9:20:11 | str indirection | semmle.label | str indirection | -| globalVars.c:20:9:20:11 | str indirection | semmle.label | str indirection | | globalVars.c:24:2:24:9 | argv | semmle.label | argv | | globalVars.c:24:11:24:14 | argv | semmle.label | argv | | globalVars.c:24:11:24:14 | argv | semmle.label | argv | | globalVars.c:24:11:24:14 | argv indirection | semmle.label | argv indirection | | globalVars.c:27:9:27:12 | (const char *)... | semmle.label | (const char *)... | | globalVars.c:27:9:27:12 | (const char *)... | semmle.label | (const char *)... | -| globalVars.c:27:9:27:12 | (const char *)... | semmle.label | (const char *)... | -| globalVars.c:27:9:27:12 | (const char *)... | semmle.label | (const char *)... | -| globalVars.c:27:9:27:12 | copy | semmle.label | copy | -| globalVars.c:27:9:27:12 | copy | semmle.label | copy | | globalVars.c:27:9:27:12 | copy | semmle.label | copy | | globalVars.c:27:9:27:12 | copy | semmle.label | copy | | globalVars.c:27:9:27:12 | copy | semmle.label | copy | | globalVars.c:27:9:27:12 | copy indirection | semmle.label | copy indirection | | globalVars.c:27:9:27:12 | copy indirection | semmle.label | copy indirection | -| globalVars.c:27:9:27:12 | copy indirection | semmle.label | copy indirection | -| globalVars.c:27:9:27:12 | copy indirection | semmle.label | copy indirection | -| globalVars.c:30:2:30:13 | copy | semmle.label | copy | -| globalVars.c:30:15:30:18 | copy | semmle.label | copy | -| globalVars.c:30:15:30:18 | copy | semmle.label | copy | | globalVars.c:30:15:30:18 | copy | semmle.label | copy | | globalVars.c:30:15:30:18 | copy | semmle.label | copy | | globalVars.c:30:15:30:18 | copy | semmle.label | copy | | globalVars.c:30:15:30:18 | copy indirection | semmle.label | copy indirection | | globalVars.c:30:15:30:18 | copy indirection | semmle.label | copy indirection | -| globalVars.c:30:15:30:18 | copy indirection | semmle.label | copy indirection | -| globalVars.c:30:15:30:18 | copy indirection | semmle.label | copy indirection | -| globalVars.c:33:15:33:18 | copy | semmle.label | copy | -| globalVars.c:33:15:33:18 | copy | semmle.label | copy | -| globalVars.c:33:15:33:18 | copy indirection | semmle.label | copy indirection | -| globalVars.c:33:15:33:18 | copy indirection | semmle.label | copy indirection | -| globalVars.c:35:2:35:9 | copy | semmle.label | copy | | globalVars.c:35:2:35:9 | copy | semmle.label | copy | | globalVars.c:35:11:35:14 | copy | semmle.label | copy | -| globalVars.c:35:11:35:14 | copy | semmle.label | copy | -| globalVars.c:35:11:35:14 | copy | semmle.label | copy | -| globalVars.c:35:11:35:14 | copy indirection | semmle.label | copy indirection | -| globalVars.c:35:11:35:14 | copy indirection | semmle.label | copy indirection | -| globalVars.c:38:9:38:13 | (const char *)... | semmle.label | (const char *)... | -| globalVars.c:38:9:38:13 | (const char *)... | semmle.label | (const char *)... | | globalVars.c:38:9:38:13 | (const char *)... | semmle.label | (const char *)... | | globalVars.c:38:9:38:13 | (const char *)... | semmle.label | (const char *)... | | globalVars.c:38:9:38:13 | copy2 | semmle.label | copy2 | | globalVars.c:38:9:38:13 | copy2 | semmle.label | copy2 | | globalVars.c:38:9:38:13 | copy2 | semmle.label | copy2 | -| globalVars.c:38:9:38:13 | copy2 | semmle.label | copy2 | -| globalVars.c:38:9:38:13 | copy2 | semmle.label | copy2 | | globalVars.c:38:9:38:13 | copy2 indirection | semmle.label | copy2 indirection | | globalVars.c:38:9:38:13 | copy2 indirection | semmle.label | copy2 indirection | -| globalVars.c:38:9:38:13 | copy2 indirection | semmle.label | copy2 indirection | -| globalVars.c:38:9:38:13 | copy2 indirection | semmle.label | copy2 indirection | -| globalVars.c:41:2:41:13 | copy2 | semmle.label | copy2 | -| globalVars.c:41:15:41:19 | copy2 | semmle.label | copy2 | -| globalVars.c:41:15:41:19 | copy2 | semmle.label | copy2 | | globalVars.c:41:15:41:19 | copy2 | semmle.label | copy2 | | globalVars.c:41:15:41:19 | copy2 | semmle.label | copy2 | | globalVars.c:41:15:41:19 | copy2 | semmle.label | copy2 | | globalVars.c:41:15:41:19 | copy2 indirection | semmle.label | copy2 indirection | | globalVars.c:41:15:41:19 | copy2 indirection | semmle.label | copy2 indirection | -| globalVars.c:41:15:41:19 | copy2 indirection | semmle.label | copy2 indirection | -| globalVars.c:41:15:41:19 | copy2 indirection | semmle.label | copy2 indirection | -| globalVars.c:44:15:44:19 | copy2 | semmle.label | copy2 | -| globalVars.c:44:15:44:19 | copy2 | semmle.label | copy2 | -| globalVars.c:44:15:44:19 | copy2 indirection | semmle.label | copy2 indirection | -| globalVars.c:44:15:44:19 | copy2 indirection | semmle.label | copy2 indirection | -| globalVars.c:50:9:50:13 | (const char *)... | semmle.label | (const char *)... | -| globalVars.c:50:9:50:13 | (const char *)... | semmle.label | (const char *)... | | globalVars.c:50:9:50:13 | (const char *)... | semmle.label | (const char *)... | | globalVars.c:50:9:50:13 | (const char *)... | semmle.label | (const char *)... | | globalVars.c:50:9:50:13 | copy2 | semmle.label | copy2 | | globalVars.c:50:9:50:13 | copy2 | semmle.label | copy2 | | globalVars.c:50:9:50:13 | copy2 | semmle.label | copy2 | -| globalVars.c:50:9:50:13 | copy2 | semmle.label | copy2 | -| globalVars.c:50:9:50:13 | copy2 | semmle.label | copy2 | -| globalVars.c:50:9:50:13 | copy2 indirection | semmle.label | copy2 indirection | -| globalVars.c:50:9:50:13 | copy2 indirection | semmle.label | copy2 indirection | | globalVars.c:50:9:50:13 | copy2 indirection | semmle.label | copy2 indirection | | globalVars.c:50:9:50:13 | copy2 indirection | semmle.label | copy2 indirection | #select From 9d1ef21d855e4120bfb0e797dab9723ffd9a9f09 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 26 Mar 2021 11:17:27 +0100 Subject: [PATCH 398/725] C#: Remove deleted queries from suites --- csharp/config/suites/lgtm/csharp-metrics-lgtm | 2 -- csharp/ql/src/codeql-suites/exclude-dependency-queries.yml | 4 ---- 2 files changed, 6 deletions(-) delete mode 100644 csharp/ql/src/codeql-suites/exclude-dependency-queries.yml diff --git a/csharp/config/suites/lgtm/csharp-metrics-lgtm b/csharp/config/suites/lgtm/csharp-metrics-lgtm index 00c35820362..7a9cd6efb31 100644 --- a/csharp/config/suites/lgtm/csharp-metrics-lgtm +++ b/csharp/config/suites/lgtm/csharp-metrics-lgtm @@ -4,8 +4,6 @@ @_namespace com.lgtm/csharp-queries + odasa-csharp-metrics/Files/FLinesOfCommentedCode.ql: /Metrics/Documentation @_namespace com.lgtm/csharp-queries -+ odasa-csharp-metrics/Files/FLinesOfDuplicatedCode.ql: /Metrics/Coupling - @_namespace com.lgtm/csharp-queries + odasa-csharp-metrics/Files/FNumberOfTests.ql: /Metrics/Size @_namespace com.lgtm/csharp-queries diff --git a/csharp/ql/src/codeql-suites/exclude-dependency-queries.yml b/csharp/ql/src/codeql-suites/exclude-dependency-queries.yml deleted file mode 100644 index 53ad48be212..00000000000 --- a/csharp/ql/src/codeql-suites/exclude-dependency-queries.yml +++ /dev/null @@ -1,4 +0,0 @@ -- description: C# queries which overlap with dependency analysis -- exclude: - query path: - - Security Features/CWE-937/VulnerablePackage.ql From cc2a531684385fb0c39cc844d39715eb78a8e970 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 26 Mar 2021 10:48:25 +0000 Subject: [PATCH 399/725] JS: Cache PropRef.getBase --- javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll | 6 +++++- .../ql/src/semmle/javascript/internal/CachedStages.qll | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll index 75c8cd7b236..8835b14af05 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll @@ -492,6 +492,7 @@ module DataFlow { * Gets the data flow node corresponding to the base object * whose property is read from or written to. */ + cached abstract Node getBase(); /** @@ -595,7 +596,10 @@ module DataFlow { PropLValueAsPropWrite() { astNode instanceof LValue } - override Node getBase() { result = valueNode(astNode.getBase()) } + override Node getBase() { + result = valueNode(astNode.getBase()) and + Stages::DataFlowStage::ref() + } override Expr getPropertyNameExpr() { result = astNode.getPropertyNameExpr() } diff --git a/javascript/ql/src/semmle/javascript/internal/CachedStages.qll b/javascript/ql/src/semmle/javascript/internal/CachedStages.qll index b56a1324e77..6980a6eef7f 100644 --- a/javascript/ql/src/semmle/javascript/internal/CachedStages.qll +++ b/javascript/ql/src/semmle/javascript/internal/CachedStages.qll @@ -133,6 +133,8 @@ module Stages { exists(any(DataFlow::Node node).toString()) or exists(any(AccessPath a).getAnInstanceIn(_)) + or + exists(any(DataFlow::PropRef ref).getBase()) } } From d20a0c9e82954889aeda29e5cd99a631ddf82af5 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 26 Mar 2021 11:38:03 +0100 Subject: [PATCH 400/725] C++: Add a class that models wrapped pointer types. --- cpp/ql/src/semmle/code/cpp/exprs/Call.qll | 47 +++++++++++++++++++ cpp/ql/src/semmle/code/cpp/models/Models.qll | 1 + .../models/implementations/PointerWrapper.qll | 26 ++++++++++ 3 files changed, 74 insertions(+) create mode 100644 cpp/ql/src/semmle/code/cpp/models/implementations/PointerWrapper.qll diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Call.qll b/cpp/ql/src/semmle/code/cpp/exprs/Call.qll index c57c608b69b..3ec1a5aec95 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Call.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Call.qll @@ -350,6 +350,53 @@ class OverloadedPointerDereferenceExpr extends FunctionCall { } } +/** + * An instance of a call to a _user-defined_ `operator->`. + * ``` + * struct T2 { T1 b; }; + * struct T3 { T2* operator->(); }; + * T3 a; + * T1 x = a->b; + * ``` + */ +class OverloadedArrowExpr extends FunctionCall { + OverloadedArrowExpr() { getTarget().hasName("operator->") } + + override string getAPrimaryQlClass() { result = "OverloadedArrowExpr" } + + /** Gets the expression this `operator->` applies to. */ + Expr getExpr() { result = this.getQualifier() } + + /** Gets the field accessed by this call to `operator->`, if any. */ + FieldAccess getFieldAccess() { result.getQualifier() = this } + + override predicate mayBeImpure() { + FunctionCall.super.mayBeImpure() and + ( + this.getExpr().mayBeImpure() + or + not exists(Class declaring | + this.getTarget().getDeclaringType().isConstructedFrom*(declaring) + | + declaring.getNamespace() instanceof StdNamespace + ) + ) + } + + override predicate mayBeGloballyImpure() { + FunctionCall.super.mayBeGloballyImpure() and + ( + this.getExpr().mayBeGloballyImpure() + or + not exists(Class declaring | + this.getTarget().getDeclaringType().isConstructedFrom*(declaring) + | + declaring.getNamespace() instanceof StdNamespace + ) + ) + } +} + /** * An instance of a _user-defined_ binary `operator[]` applied to its arguments. * ``` diff --git a/cpp/ql/src/semmle/code/cpp/models/Models.qll b/cpp/ql/src/semmle/code/cpp/models/Models.qll index d5c7f50dde1..b5f552e75aa 100644 --- a/cpp/ql/src/semmle/code/cpp/models/Models.qll +++ b/cpp/ql/src/semmle/code/cpp/models/Models.qll @@ -33,3 +33,4 @@ private import implementations.Recv private import implementations.Accept private import implementations.Poll private import implementations.Select +private import implementations.PointerWrapper diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/PointerWrapper.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/PointerWrapper.qll new file mode 100644 index 00000000000..584f6353c64 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/PointerWrapper.qll @@ -0,0 +1,26 @@ +/** Provides classes for modeling pointer wrapper types and expressions. */ + +private import cpp + +/** A class that wraps a pointer type. For example, `std::unique_ptr` and `std::shared_ptr`. */ +class PointerWrapper extends Class { + PointerWrapper() { this.hasQualifiedName(["std", "bsl", "boost"], ["shared_ptr", "unique_ptr"]) } +} + +/** An expression of a `PointerWrapper` type. */ +class PointerWrapperExpr extends Expr { + PointerWrapperExpr() { this.getUnspecifiedType() instanceof PointerWrapper } + + /** Gets a dereference of the wrapped pointer. */ + Expr getADereference() { result.(OverloadedPointerDereferenceExpr).getExpr() = this } + + /** Gets an access to the wrapped pointer. */ + Expr getAPointerAccess() { + result.(OverloadedArrowExpr).getExpr() = this + or + exists(FunctionCall call | call = result | + call.getQualifier() = this and + call.getTarget().hasName("get") + ) + } +} From 8dc7b6403a92c5d7a061d5e8d3bc4ee92d98c444 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 26 Mar 2021 11:13:50 +0100 Subject: [PATCH 401/725] C++: Add shared_ptr and unique_ptr implementations. Also add some very basic tests. --- .../dataflow/smart-pointers-taint/memory.h | 127 ++++++++++++++++++ .../smart-pointers-taint/taint.expected | 0 .../dataflow/smart-pointers-taint/taint.ql | 39 ++++++ .../dataflow/smart-pointers-taint/test.cpp | 28 ++++ 4 files changed, 194 insertions(+) create mode 100644 cpp/ql/test/library-tests/dataflow/smart-pointers-taint/memory.h create mode 100644 cpp/ql/test/library-tests/dataflow/smart-pointers-taint/taint.expected create mode 100644 cpp/ql/test/library-tests/dataflow/smart-pointers-taint/taint.ql create mode 100644 cpp/ql/test/library-tests/dataflow/smart-pointers-taint/test.cpp diff --git a/cpp/ql/test/library-tests/dataflow/smart-pointers-taint/memory.h b/cpp/ql/test/library-tests/dataflow/smart-pointers-taint/memory.h new file mode 100644 index 00000000000..79f39b831c6 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/smart-pointers-taint/memory.h @@ -0,0 +1,127 @@ + +namespace std { + namespace detail { + template + class compressed_pair_element { + T element; + + public: + compressed_pair_element() = default; + compressed_pair_element(const T& t) : element(t) {} + + T& get() { return element; } + + const T& get() const { return element; } + }; + + template + struct compressed_pair : private compressed_pair_element, private compressed_pair_element { + compressed_pair() = default; + compressed_pair(T& t) : compressed_pair_element(t), compressed_pair_element() {} + compressed_pair(const compressed_pair&) = delete; + compressed_pair(compressed_pair&&) noexcept = default; + + T& first() { return static_cast&>(*this).get(); } + U& second() { return static_cast&>(*this).get(); } + + const T& first() const { return static_cast&>(*this).get(); } + const U& second() const { return static_cast&>(*this).get(); } + }; + } + + template + struct default_delete { + void operator()(T* ptr) const { delete ptr; } + }; + + template + struct default_delete { + template + void operator()(U* ptr) const { delete[] ptr; } + }; + + template > + class unique_ptr { + private: + detail::compressed_pair data; + public: + constexpr unique_ptr() noexcept {} + explicit unique_ptr(T* ptr) noexcept : data(ptr) {} + unique_ptr(const unique_ptr& ptr) = delete; + unique_ptr(unique_ptr&& ptr) noexcept = default; + + unique_ptr& operator=(unique_ptr&& ptr) noexcept = default; + + T& operator*() const { return *get(); } + T* operator->() const noexcept { return get(); } + + T* get() const noexcept { return data.first(); } + + ~unique_ptr() { + Deleter& d = data.second(); + d(data.first()); + } + }; + + template unique_ptr make_unique(Args&&... args) { + return unique_ptr(new T(args...)); // std::forward calls elided for simplicity. + } + + class ctrl_block { + unsigned uses; + + public: + ctrl_block() : uses(1) {} + + void inc() { ++uses; } + bool dec() { return --uses == 0; } + + virtual void destroy() = 0; + virtual ~ctrl_block() {} + }; + + template > + struct ctrl_block_impl: public ctrl_block { + T* ptr; + Deleter d; + + ctrl_block_impl(T* ptr, Deleter d) : ptr(ptr), d(d) {} + virtual void destroy() override { d(ptr); } + }; + + template + class shared_ptr { + private: + ctrl_block* ctrl; + T* ptr; + + void dec() { + if(ctrl->dec()) { + ctrl->destroy(); + delete ctrl; + } + } + + void inc() { + ctrl->inc(); + } + + public: + constexpr shared_ptr() noexcept = default; + shared_ptr(T* ptr) : ctrl(new ctrl_block_impl(ptr, default_delete())) {} + shared_ptr(const shared_ptr& s) noexcept : ptr(s.ptr), ctrl(s.ctrl) { + inc(); + } + shared_ptr(shared_ptr&& s) noexcept = default; + + T* operator->() const { return ptr; } + + T& operator*() const { return *ptr; } + + ~shared_ptr() { dec(); } + }; + + template shared_ptr make_shared(Args&&... args) { + return shared_ptr(new T(args...)); // std::forward calls elided for simplicity. + } +} \ No newline at end of file diff --git a/cpp/ql/test/library-tests/dataflow/smart-pointers-taint/taint.expected b/cpp/ql/test/library-tests/dataflow/smart-pointers-taint/taint.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cpp/ql/test/library-tests/dataflow/smart-pointers-taint/taint.ql b/cpp/ql/test/library-tests/dataflow/smart-pointers-taint/taint.ql new file mode 100644 index 00000000000..4f18139b2af --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/smart-pointers-taint/taint.ql @@ -0,0 +1,39 @@ +import TestUtilities.dataflow.FlowTestCommon + +module ASTTest { + private import semmle.code.cpp.dataflow.TaintTracking + + class ASTSmartPointerTaintConfig extends TaintTracking::Configuration { + ASTSmartPointerTaintConfig() { this = "ASTSmartPointerTaintConfig" } + + override predicate isSource(DataFlow::Node source) { + source.asExpr().(FunctionCall).getTarget().getName() = "source" + } + + override predicate isSink(DataFlow::Node sink) { + exists(FunctionCall call | + call.getTarget().getName() = "sink" and + sink.asExpr() = call.getAnArgument() + ) + } + } +} + +module IRTest { + private import semmle.code.cpp.ir.dataflow.TaintTracking + + class IRSmartPointerTaintConfig extends TaintTracking::Configuration { + IRSmartPointerTaintConfig() { this = "IRSmartPointerTaintConfig" } + + override predicate isSource(DataFlow::Node source) { + source.asExpr().(FunctionCall).getTarget().getName() = "source" + } + + override predicate isSink(DataFlow::Node sink) { + exists(FunctionCall call | + call.getTarget().getName() = "sink" and + sink.asExpr() = call.getAnArgument() + ) + } + } +} diff --git a/cpp/ql/test/library-tests/dataflow/smart-pointers-taint/test.cpp b/cpp/ql/test/library-tests/dataflow/smart-pointers-taint/test.cpp new file mode 100644 index 00000000000..c836a20414a --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/smart-pointers-taint/test.cpp @@ -0,0 +1,28 @@ +#include "memory.h" + +int source(); +void sink(int); + +void test_unique_ptr_int() { + std::unique_ptr p1(new int(source())); + std::unique_ptr p2 = std::make_unique(source()); + + sink(*p1); // $ MISSING: ast,ir + sink(*p2); // $ ast ir=8:50 +} + +struct A { + int x, y; + + A(int x, int y) : x(x), y(y) {} +}; + +void test_unique_ptr_struct() { + std::unique_ptr p1(new A{source(), 0}); + std::unique_ptr p2 = std::make_unique(source(), 0); + + sink(p1->x); // $ MISSING: ast,ir + sink(p1->y); + sink(p2->x); // $ ir=22:46 + sink(p2->y); // $ SPURIOUS: ir=22:46 +} \ No newline at end of file From e345064a53f125fd0e4bcc1c020b7fefaf304ef9 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 26 Mar 2021 09:48:05 +0100 Subject: [PATCH 402/725] C#: Performance tweaks in `SsaImplCommon.qll` --- .../code/cil/internal/SsaImplCommon.qll | 39 ++++++++++--------- .../internal/pressa/SsaImplCommon.qll | 39 ++++++++++--------- .../dataflow/internal/SsaImplCommon.qll | 39 ++++++++++--------- .../internal/basessa/SsaImplCommon.qll | 39 ++++++++++--------- 4 files changed, 80 insertions(+), 76 deletions(-) diff --git a/csharp/ql/src/semmle/code/cil/internal/SsaImplCommon.qll b/csharp/ql/src/semmle/code/cil/internal/SsaImplCommon.qll index 7a1879059c3..f828419a440 100644 --- a/csharp/ql/src/semmle/code/cil/internal/SsaImplCommon.qll +++ b/csharp/ql/src/semmle/code/cil/internal/SsaImplCommon.qll @@ -321,10 +321,9 @@ private module SsaDefReaches { } pragma[noinline] - private BasicBlock getAMaybeLiveSuccessor(Definition def, BasicBlock bb) { - result = getABasicBlockSuccessor(bb) and - not defOccursInBlock(_, bb, def.getSourceVariable()) and - ssaDefReachesEndOfBlock(bb, def, _) + private predicate ssaDefReachesThroughBlock(Definition def, BasicBlock bb) { + ssaDefReachesEndOfBlock(bb, def, _) and + not defOccursInBlock(_, bb, def.getSourceVariable()) } /** @@ -337,7 +336,11 @@ private module SsaDefReaches { defOccursInBlock(def, bb1, _) and bb2 = getABasicBlockSuccessor(bb1) or - exists(BasicBlock mid | varBlockReaches(def, bb1, mid) | bb2 = getAMaybeLiveSuccessor(def, mid)) + exists(BasicBlock mid | + varBlockReaches(def, bb1, mid) and + ssaDefReachesThroughBlock(def, mid) and + bb2 = getABasicBlockSuccessor(mid) + ) } /** @@ -355,17 +358,10 @@ private module SsaDefReaches { private import SsaDefReaches -pragma[noinline] -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 - // control flow node if it is the _closest_ SSA definition that dominates - // the node. If two definitions dominate a node then one must dominate the - // other, so therefore the definition of _closest_ is given by the dominator - // tree. Thus, reaching definitions can be calculated in terms of dominance. - idom = getImmediateBasicBlockDominator(bb) - ) +pragma[nomagic] +predicate liveThrough(BasicBlock bb, SourceVariable v) { + liveAtExit(bb, v) and + not ssaRef(bb, _, v, SsaDef()) } /** @@ -382,9 +378,14 @@ predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SourceVariable liveAtExit(bb, v) ) or - ssaDefReachesEndOfBlockRec(bb, def, v) and - liveAtExit(bb, v) and - not ssaRef(bb, _, v, SsaDef()) + // The construction of SSA form ensures that each read of a variable is + // dominated by its definition. An SSA definition therefore reaches a + // control flow node if it is the _closest_ SSA definition that dominates + // the node. If two definitions dominate a node then one must dominate the + // other, so therefore the definition of _closest_ is given by the dominator + // tree. Thus, reaching definitions can be calculated in terms of dominance. + ssaDefReachesEndOfBlock(getImmediateBasicBlockDominator(bb), def, pragma[only_bind_into](v)) and + liveThrough(bb, pragma[only_bind_into](v)) } /** diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/internal/pressa/SsaImplCommon.qll b/csharp/ql/src/semmle/code/csharp/controlflow/internal/pressa/SsaImplCommon.qll index 7a1879059c3..f828419a440 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/internal/pressa/SsaImplCommon.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/internal/pressa/SsaImplCommon.qll @@ -321,10 +321,9 @@ private module SsaDefReaches { } pragma[noinline] - private BasicBlock getAMaybeLiveSuccessor(Definition def, BasicBlock bb) { - result = getABasicBlockSuccessor(bb) and - not defOccursInBlock(_, bb, def.getSourceVariable()) and - ssaDefReachesEndOfBlock(bb, def, _) + private predicate ssaDefReachesThroughBlock(Definition def, BasicBlock bb) { + ssaDefReachesEndOfBlock(bb, def, _) and + not defOccursInBlock(_, bb, def.getSourceVariable()) } /** @@ -337,7 +336,11 @@ private module SsaDefReaches { defOccursInBlock(def, bb1, _) and bb2 = getABasicBlockSuccessor(bb1) or - exists(BasicBlock mid | varBlockReaches(def, bb1, mid) | bb2 = getAMaybeLiveSuccessor(def, mid)) + exists(BasicBlock mid | + varBlockReaches(def, bb1, mid) and + ssaDefReachesThroughBlock(def, mid) and + bb2 = getABasicBlockSuccessor(mid) + ) } /** @@ -355,17 +358,10 @@ private module SsaDefReaches { private import SsaDefReaches -pragma[noinline] -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 - // control flow node if it is the _closest_ SSA definition that dominates - // the node. If two definitions dominate a node then one must dominate the - // other, so therefore the definition of _closest_ is given by the dominator - // tree. Thus, reaching definitions can be calculated in terms of dominance. - idom = getImmediateBasicBlockDominator(bb) - ) +pragma[nomagic] +predicate liveThrough(BasicBlock bb, SourceVariable v) { + liveAtExit(bb, v) and + not ssaRef(bb, _, v, SsaDef()) } /** @@ -382,9 +378,14 @@ predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SourceVariable liveAtExit(bb, v) ) or - ssaDefReachesEndOfBlockRec(bb, def, v) and - liveAtExit(bb, v) and - not ssaRef(bb, _, v, SsaDef()) + // The construction of SSA form ensures that each read of a variable is + // dominated by its definition. An SSA definition therefore reaches a + // control flow node if it is the _closest_ SSA definition that dominates + // the node. If two definitions dominate a node then one must dominate the + // other, so therefore the definition of _closest_ is given by the dominator + // tree. Thus, reaching definitions can be calculated in terms of dominance. + ssaDefReachesEndOfBlock(getImmediateBasicBlockDominator(bb), def, pragma[only_bind_into](v)) and + liveThrough(bb, pragma[only_bind_into](v)) } /** diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll index 7a1879059c3..f828419a440 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll @@ -321,10 +321,9 @@ private module SsaDefReaches { } pragma[noinline] - private BasicBlock getAMaybeLiveSuccessor(Definition def, BasicBlock bb) { - result = getABasicBlockSuccessor(bb) and - not defOccursInBlock(_, bb, def.getSourceVariable()) and - ssaDefReachesEndOfBlock(bb, def, _) + private predicate ssaDefReachesThroughBlock(Definition def, BasicBlock bb) { + ssaDefReachesEndOfBlock(bb, def, _) and + not defOccursInBlock(_, bb, def.getSourceVariable()) } /** @@ -337,7 +336,11 @@ private module SsaDefReaches { defOccursInBlock(def, bb1, _) and bb2 = getABasicBlockSuccessor(bb1) or - exists(BasicBlock mid | varBlockReaches(def, bb1, mid) | bb2 = getAMaybeLiveSuccessor(def, mid)) + exists(BasicBlock mid | + varBlockReaches(def, bb1, mid) and + ssaDefReachesThroughBlock(def, mid) and + bb2 = getABasicBlockSuccessor(mid) + ) } /** @@ -355,17 +358,10 @@ private module SsaDefReaches { private import SsaDefReaches -pragma[noinline] -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 - // control flow node if it is the _closest_ SSA definition that dominates - // the node. If two definitions dominate a node then one must dominate the - // other, so therefore the definition of _closest_ is given by the dominator - // tree. Thus, reaching definitions can be calculated in terms of dominance. - idom = getImmediateBasicBlockDominator(bb) - ) +pragma[nomagic] +predicate liveThrough(BasicBlock bb, SourceVariable v) { + liveAtExit(bb, v) and + not ssaRef(bb, _, v, SsaDef()) } /** @@ -382,9 +378,14 @@ predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SourceVariable liveAtExit(bb, v) ) or - ssaDefReachesEndOfBlockRec(bb, def, v) and - liveAtExit(bb, v) and - not ssaRef(bb, _, v, SsaDef()) + // The construction of SSA form ensures that each read of a variable is + // dominated by its definition. An SSA definition therefore reaches a + // control flow node if it is the _closest_ SSA definition that dominates + // the node. If two definitions dominate a node then one must dominate the + // other, so therefore the definition of _closest_ is given by the dominator + // tree. Thus, reaching definitions can be calculated in terms of dominance. + ssaDefReachesEndOfBlock(getImmediateBasicBlockDominator(bb), def, pragma[only_bind_into](v)) and + liveThrough(bb, pragma[only_bind_into](v)) } /** diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll index 7a1879059c3..f828419a440 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll @@ -321,10 +321,9 @@ private module SsaDefReaches { } pragma[noinline] - private BasicBlock getAMaybeLiveSuccessor(Definition def, BasicBlock bb) { - result = getABasicBlockSuccessor(bb) and - not defOccursInBlock(_, bb, def.getSourceVariable()) and - ssaDefReachesEndOfBlock(bb, def, _) + private predicate ssaDefReachesThroughBlock(Definition def, BasicBlock bb) { + ssaDefReachesEndOfBlock(bb, def, _) and + not defOccursInBlock(_, bb, def.getSourceVariable()) } /** @@ -337,7 +336,11 @@ private module SsaDefReaches { defOccursInBlock(def, bb1, _) and bb2 = getABasicBlockSuccessor(bb1) or - exists(BasicBlock mid | varBlockReaches(def, bb1, mid) | bb2 = getAMaybeLiveSuccessor(def, mid)) + exists(BasicBlock mid | + varBlockReaches(def, bb1, mid) and + ssaDefReachesThroughBlock(def, mid) and + bb2 = getABasicBlockSuccessor(mid) + ) } /** @@ -355,17 +358,10 @@ private module SsaDefReaches { private import SsaDefReaches -pragma[noinline] -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 - // control flow node if it is the _closest_ SSA definition that dominates - // the node. If two definitions dominate a node then one must dominate the - // other, so therefore the definition of _closest_ is given by the dominator - // tree. Thus, reaching definitions can be calculated in terms of dominance. - idom = getImmediateBasicBlockDominator(bb) - ) +pragma[nomagic] +predicate liveThrough(BasicBlock bb, SourceVariable v) { + liveAtExit(bb, v) and + not ssaRef(bb, _, v, SsaDef()) } /** @@ -382,9 +378,14 @@ predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SourceVariable liveAtExit(bb, v) ) or - ssaDefReachesEndOfBlockRec(bb, def, v) and - liveAtExit(bb, v) and - not ssaRef(bb, _, v, SsaDef()) + // The construction of SSA form ensures that each read of a variable is + // dominated by its definition. An SSA definition therefore reaches a + // control flow node if it is the _closest_ SSA definition that dominates + // the node. If two definitions dominate a node then one must dominate the + // other, so therefore the definition of _closest_ is given by the dominator + // tree. Thus, reaching definitions can be calculated in terms of dominance. + ssaDefReachesEndOfBlock(getImmediateBasicBlockDominator(bb), def, pragma[only_bind_into](v)) and + liveThrough(bb, pragma[only_bind_into](v)) } /** From 0ce08617ba9f5afc67685085df398624309d6026 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 26 Mar 2021 13:42:18 +0100 Subject: [PATCH 403/725] C++: Respond to review comments. --- cpp/ql/src/semmle/code/cpp/exprs/Call.qll | 58 +++---------------- cpp/ql/src/semmle/code/cpp/models/Models.qll | 1 - .../models/implementations/PointerWrapper.qll | 26 --------- .../models/implementations/SmartPointer.qll | 12 +++- .../cpp/models/interfaces/PointerWrapper.qll | 12 ++++ 5 files changed, 32 insertions(+), 77 deletions(-) delete mode 100644 cpp/ql/src/semmle/code/cpp/models/implementations/PointerWrapper.qll create mode 100644 cpp/ql/src/semmle/code/cpp/models/interfaces/PointerWrapper.qll diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Call.qll b/cpp/ql/src/semmle/code/cpp/exprs/Call.qll index 3ec1a5aec95..349efdcee10 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Call.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Call.qll @@ -300,6 +300,14 @@ class FunctionCall extends Call, @funbindexpr { } } +/** A _user-defined_ unary `operator*` function. */ +class OverloadedPointerDereferenceFunction extends Function { + OverloadedPointerDereferenceFunction() { + this.hasName("operator*") and + this.getEffectiveNumberOfParameters() = 1 + } +} + /** * An instance of a _user-defined_ unary `operator*` applied to its argument. * ``` @@ -309,8 +317,7 @@ class FunctionCall extends Call, @funbindexpr { */ class OverloadedPointerDereferenceExpr extends FunctionCall { OverloadedPointerDereferenceExpr() { - getTarget().hasName("operator*") and - getTarget().getEffectiveNumberOfParameters() = 1 + this.getTarget() instanceof OverloadedPointerDereferenceFunction } override string getAPrimaryQlClass() { result = "OverloadedPointerDereferenceExpr" } @@ -350,53 +357,6 @@ class OverloadedPointerDereferenceExpr extends FunctionCall { } } -/** - * An instance of a call to a _user-defined_ `operator->`. - * ``` - * struct T2 { T1 b; }; - * struct T3 { T2* operator->(); }; - * T3 a; - * T1 x = a->b; - * ``` - */ -class OverloadedArrowExpr extends FunctionCall { - OverloadedArrowExpr() { getTarget().hasName("operator->") } - - override string getAPrimaryQlClass() { result = "OverloadedArrowExpr" } - - /** Gets the expression this `operator->` applies to. */ - Expr getExpr() { result = this.getQualifier() } - - /** Gets the field accessed by this call to `operator->`, if any. */ - FieldAccess getFieldAccess() { result.getQualifier() = this } - - override predicate mayBeImpure() { - FunctionCall.super.mayBeImpure() and - ( - this.getExpr().mayBeImpure() - or - not exists(Class declaring | - this.getTarget().getDeclaringType().isConstructedFrom*(declaring) - | - declaring.getNamespace() instanceof StdNamespace - ) - ) - } - - override predicate mayBeGloballyImpure() { - FunctionCall.super.mayBeGloballyImpure() and - ( - this.getExpr().mayBeGloballyImpure() - or - not exists(Class declaring | - this.getTarget().getDeclaringType().isConstructedFrom*(declaring) - | - declaring.getNamespace() instanceof StdNamespace - ) - ) - } -} - /** * An instance of a _user-defined_ binary `operator[]` applied to its arguments. * ``` diff --git a/cpp/ql/src/semmle/code/cpp/models/Models.qll b/cpp/ql/src/semmle/code/cpp/models/Models.qll index b5f552e75aa..d5c7f50dde1 100644 --- a/cpp/ql/src/semmle/code/cpp/models/Models.qll +++ b/cpp/ql/src/semmle/code/cpp/models/Models.qll @@ -33,4 +33,3 @@ private import implementations.Recv private import implementations.Accept private import implementations.Poll private import implementations.Select -private import implementations.PointerWrapper diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/PointerWrapper.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/PointerWrapper.qll deleted file mode 100644 index 584f6353c64..00000000000 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/PointerWrapper.qll +++ /dev/null @@ -1,26 +0,0 @@ -/** Provides classes for modeling pointer wrapper types and expressions. */ - -private import cpp - -/** A class that wraps a pointer type. For example, `std::unique_ptr` and `std::shared_ptr`. */ -class PointerWrapper extends Class { - PointerWrapper() { this.hasQualifiedName(["std", "bsl", "boost"], ["shared_ptr", "unique_ptr"]) } -} - -/** An expression of a `PointerWrapper` type. */ -class PointerWrapperExpr extends Expr { - PointerWrapperExpr() { this.getUnspecifiedType() instanceof PointerWrapper } - - /** Gets a dereference of the wrapped pointer. */ - Expr getADereference() { result.(OverloadedPointerDereferenceExpr).getExpr() = this } - - /** Gets an access to the wrapped pointer. */ - Expr getAPointerAccess() { - result.(OverloadedArrowExpr).getExpr() = this - or - exists(FunctionCall call | call = result | - call.getQualifier() = this and - call.getTarget().hasName("get") - ) - } -} diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/SmartPointer.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/SmartPointer.qll index c6152624792..537421c2e6f 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/SmartPointer.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/SmartPointer.qll @@ -1,10 +1,20 @@ import semmle.code.cpp.models.interfaces.Taint +import semmle.code.cpp.models.interfaces.PointerWrapper /** * The `std::shared_ptr` and `std::unique_ptr` template classes. */ -private class UniqueOrSharedPtr extends Class { +private class UniqueOrSharedPtr extends Class, PointerWrapper { UniqueOrSharedPtr() { this.hasQualifiedName(["std", "bsl"], ["shared_ptr", "unique_ptr"]) } + + override MemberFunction getADereferenceFunction() { + result.(OverloadedPointerDereferenceFunction).getDeclaringType() = this + } + + override MemberFunction getAnUnwrapperFunction() { + result.getDeclaringType() = this and + result.hasName(["operator->", "get"]) + } } /** diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/PointerWrapper.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/PointerWrapper.qll new file mode 100644 index 00000000000..02fb1e291f4 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/PointerWrapper.qll @@ -0,0 +1,12 @@ +/** Provides classes for modeling pointer wrapper types and expressions. */ + +private import cpp + +/** A class that wraps a pointer type. For example, `std::unique_ptr` and `std::shared_ptr`. */ +abstract class PointerWrapper extends Class { + /** Gets a member fucntion of this class that dereferences wrapped pointer, if any. */ + abstract MemberFunction getADereferenceFunction(); + + /** Gets a member fucntion of this class that returns the wrapped pointer, if any. */ + abstract MemberFunction getAnUnwrapperFunction(); +} From b466f0515d182cde679a9beacd5a88ed6b5c1376 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 26 Mar 2021 16:16:23 +0100 Subject: [PATCH 404/725] C++: Respond to more review comments. (1) Use getClassAndName to ensure a good join order, and (2) unify the two abstract predicates on PointerWrapper. --- .../code/cpp/models/implementations/SmartPointer.qll | 9 +++------ .../code/cpp/models/interfaces/PointerWrapper.qll | 10 ++++++---- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/SmartPointer.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/SmartPointer.qll index 537421c2e6f..7a1ad0403f7 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/SmartPointer.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/SmartPointer.qll @@ -7,13 +7,10 @@ import semmle.code.cpp.models.interfaces.PointerWrapper private class UniqueOrSharedPtr extends Class, PointerWrapper { UniqueOrSharedPtr() { this.hasQualifiedName(["std", "bsl"], ["shared_ptr", "unique_ptr"]) } - override MemberFunction getADereferenceFunction() { - result.(OverloadedPointerDereferenceFunction).getDeclaringType() = this - } - override MemberFunction getAnUnwrapperFunction() { - result.getDeclaringType() = this and - result.hasName(["operator->", "get"]) + result.(OverloadedPointerDereferenceFunction).getDeclaringType() = this + or + result.getClassAndName(["operator->", "get"]) = this } } diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/PointerWrapper.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/PointerWrapper.qll index 02fb1e291f4..447e7f7cede 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/PointerWrapper.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/PointerWrapper.qll @@ -4,9 +4,11 @@ private import cpp /** A class that wraps a pointer type. For example, `std::unique_ptr` and `std::shared_ptr`. */ abstract class PointerWrapper extends Class { - /** Gets a member fucntion of this class that dereferences wrapped pointer, if any. */ - abstract MemberFunction getADereferenceFunction(); - - /** Gets a member fucntion of this class that returns the wrapped pointer, if any. */ + /** + * Gets a member function of this class that returns the wrapped pointer, if any. + * + * This includes both functions that return the wrapped pointer by value, and functions + * that return a reference to the pointed-to object. + */ abstract MemberFunction getAnUnwrapperFunction(); } From c83daa66e78fa16c4f89ef9f174099b767907b17 Mon Sep 17 00:00:00 2001 From: Henry Mercer Date: Fri, 26 Mar 2021 15:30:23 +0000 Subject: [PATCH 405/725] CodeQL CLI Docs: Mention that QL packs use SemVer versioning --- docs/codeql/codeql-cli/about-ql-packs.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/codeql/codeql-cli/about-ql-packs.rst b/docs/codeql/codeql-cli/about-ql-packs.rst index 200dadc173b..7391b3ac73c 100644 --- a/docs/codeql/codeql-cli/about-ql-packs.rst +++ b/docs/codeql/codeql-cli/about-ql-packs.rst @@ -79,7 +79,7 @@ The following properties are supported in ``qlpack.yml`` files. * - ``version`` - ``0.0.0`` - All packs - - A version number for this QL pack. This field is not currently used by any commands, but may be required by future releases of CodeQL. + - A version number for this QL pack. This must be a valid semantic version that meets the `SemVer v2.0.0 specification `__. * - ``libraryPathDependencies`` - ``codeql-javascript`` - Optional From f17bbd998208432f8235e09fa3e329f491ecef6f Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Fri, 26 Mar 2021 16:38:13 +0100 Subject: [PATCH 406/725] Python: Fix another bad TC. This one is a bit awkward, since the previous version was supposed to improve indexing. Unfortunately this is vastly outweighed by the slow convergence of the TC. Right now we pay the cost of inverting the `hasFlowSource` relation, but this is still cheaper. --- .../python/dataflow/new/internal/DataFlowPublic.qll | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll index 0836de26faf..360e5e170de 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll @@ -530,15 +530,12 @@ private module Cached { * The slightly backwards parametering ordering is to force correct indexing. */ cached - predicate hasLocalSource(Node sink, Node source) { - // Declaring `source` to be a `SourceNode` currently causes a redundant check in the - // recursive case, so instead we check it explicitly here. - source = sink and - source instanceof LocalSourceNode + predicate hasLocalSource(Node sink, LocalSourceNode source) { + source = sink or - exists(Node mid | - hasLocalSource(mid, source) and - simpleLocalFlowStep(mid, sink) + exists(Node second | + simpleLocalFlowStep(source, second) and + simpleLocalFlowStep*(second, sink) ) } From a72b1340eb6bb3bdbea9cabd6bdd942a9365b848 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Fri, 26 Mar 2021 16:51:43 +0000 Subject: [PATCH 407/725] Add a comment on how to run the query --- .../Security/CWE/CWE-016/InsecureSpringActuatorConfig.ql | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/java/ql/src/experimental/Security/CWE/CWE-016/InsecureSpringActuatorConfig.ql b/java/ql/src/experimental/Security/CWE/CWE-016/InsecureSpringActuatorConfig.ql index 3acd22e767a..772ac6cd209 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-016/InsecureSpringActuatorConfig.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-016/InsecureSpringActuatorConfig.ql @@ -8,6 +8,14 @@ * external/cwe-016 */ +/* + * Note this query requires properties files to be indexed before it can produce results. + * If creating your own database with the CodeQL CLI, you should run + * `codeql database index-files --language=properties ...` + * If using lgtm.com, you should add `properties_files: true` to the index block of your + * lgtm.yml file (see https://lgtm.com/help/lgtm/java-extraction) + */ + import java import semmle.code.configfiles.ConfigFiles import semmle.code.xml.MavenPom From 725122decc6271e53188237b77103acd47928c45 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 26 Mar 2021 17:25:55 +0000 Subject: [PATCH 408/725] C++: Replace toString logic. --- .../WrongInDetectingAndHandlingMemoryAllocationErrors.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql b/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql index dd9c16fac11..ea946c47c76 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql @@ -74,7 +74,7 @@ class WrongCheckErrorOperatorNew extends FunctionCall { /** * Holds if `(std::nothrow)` exists in call `operator new`. */ - predicate isExistsNothrow() { this.getAChild().toString() = "nothrow" } + predicate isExistsNothrow() { getTarget().isNoExcept() or getTarget().isNoThrow() } } from WrongCheckErrorOperatorNew op From 4100d68a71c8600b74360d4489cc41815ab3c4ae Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 26 Mar 2021 18:14:31 +0000 Subject: [PATCH 409/725] C++: Test failures. --- ...ongInDetectingAndHandlingMemoryAllocationErrors.expected | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-570/semmle/tests/WrongInDetectingAndHandlingMemoryAllocationErrors.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-570/semmle/tests/WrongInDetectingAndHandlingMemoryAllocationErrors.expected index 80e82cff212..d94564d7729 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-570/semmle/tests/WrongInDetectingAndHandlingMemoryAllocationErrors.expected +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-570/semmle/tests/WrongInDetectingAndHandlingMemoryAllocationErrors.expected @@ -1,5 +1,5 @@ | test.cpp:30:15:30:26 | call to operator new[] | memory allocation error check is incorrect or missing | | test.cpp:38:9:38:20 | call to operator new[] | memory allocation error check is incorrect or missing | -| test.cpp:50:13:50:38 | call to operator new[] | memory allocation error check is incorrect or missing | -| test.cpp:51:22:51:47 | call to operator new[] | memory allocation error check is incorrect or missing | -| test.cpp:53:18:53:43 | call to operator new[] | memory allocation error check is incorrect or missing | +| test.cpp:81:18:81:43 | call to operator new[] | memory allocation error check is incorrect or missing | +| test.cpp:87:14:87:39 | call to operator new[] | memory allocation error check is incorrect or missing | +| test.cpp:92:13:92:38 | call to operator new[] | memory allocation error check is incorrect or missing | From c6e7b8d4fd04f2c96592c4f112f93a6e55a2ed46 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 26 Mar 2021 19:12:09 +0000 Subject: [PATCH 410/725] C++: Repair test. --- ...ongInDetectingAndHandlingMemoryAllocationErrors.expected | 6 +++--- .../query-tests/Security/CWE/CWE-570/semmle/tests/test.cpp | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-570/semmle/tests/WrongInDetectingAndHandlingMemoryAllocationErrors.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-570/semmle/tests/WrongInDetectingAndHandlingMemoryAllocationErrors.expected index d94564d7729..80e82cff212 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-570/semmle/tests/WrongInDetectingAndHandlingMemoryAllocationErrors.expected +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-570/semmle/tests/WrongInDetectingAndHandlingMemoryAllocationErrors.expected @@ -1,5 +1,5 @@ | test.cpp:30:15:30:26 | call to operator new[] | memory allocation error check is incorrect or missing | | test.cpp:38:9:38:20 | call to operator new[] | memory allocation error check is incorrect or missing | -| test.cpp:81:18:81:43 | call to operator new[] | memory allocation error check is incorrect or missing | -| test.cpp:87:14:87:39 | call to operator new[] | memory allocation error check is incorrect or missing | -| test.cpp:92:13:92:38 | call to operator new[] | memory allocation error check is incorrect or missing | +| test.cpp:50:13:50:38 | call to operator new[] | memory allocation error check is incorrect or missing | +| test.cpp:51:22:51:47 | call to operator new[] | memory allocation error check is incorrect or missing | +| test.cpp:53:18:53:43 | call to operator new[] | memory allocation error check is incorrect or missing | diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-570/semmle/tests/test.cpp b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-570/semmle/tests/test.cpp index e4aa8cf2976..4fc12d9ccbf 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-570/semmle/tests/test.cpp +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-570/semmle/tests/test.cpp @@ -14,8 +14,8 @@ using namespace std; void* operator new(std::size_t _Size); void* operator new[](std::size_t _Size); -void* operator new( std::size_t count, const std::nothrow_t& tag ); -void* operator new[]( std::size_t count, const std::nothrow_t& tag ); +void* operator new( std::size_t count, const std::nothrow_t& tag ) noexcept; +void* operator new[]( std::size_t count, const std::nothrow_t& tag ) noexcept; void badNew_0_0() { From a53cbc1631c2cfc994f74d4c5ce9e39f6c38abbc Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Sat, 27 Mar 2021 00:11:01 +0000 Subject: [PATCH 411/725] Update qldoc and make the query more readable --- .../CWE-555/CredentialsInPropertiesFile.qhelp | 4 +- .../CWE-555/CredentialsInPropertiesFile.ql | 22 +++-- .../CWE-555/CredentialsInPropertiesFile.ql | 84 +++++++++++++++++++ .../CWE-555/CredentialsInPropertiesFile.qlref | 1 - 4 files changed, 101 insertions(+), 10 deletions(-) create mode 100644 java/ql/test/experimental/query-tests/security/CWE-555/CredentialsInPropertiesFile.ql delete mode 100644 java/ql/test/experimental/query-tests/security/CWE-555/CredentialsInPropertiesFile.qlref diff --git a/java/ql/src/experimental/Security/CWE/CWE-555/CredentialsInPropertiesFile.qhelp b/java/ql/src/experimental/Security/CWE/CWE-555/CredentialsInPropertiesFile.qhelp index afbd40685ba..0869b886260 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-555/CredentialsInPropertiesFile.qhelp +++ b/java/ql/src/experimental/Security/CWE/CWE-555/CredentialsInPropertiesFile.qhelp @@ -15,7 +15,7 @@

    Credentials stored in properties files should be encrypted and recycled regularly. In a Java EE deployment scenario, utilities provided by application servers like - keystore and password vault can be used to encrypt and manage credentials. + keystores and password vaults can be used to encrypt and manage credentials.

    @@ -27,7 +27,7 @@

    In the second example, the credentials of a LDAP and datasource properties are stored - in the encrypted format. + in an encrypted format.

    diff --git a/java/ql/src/experimental/Security/CWE/CWE-555/CredentialsInPropertiesFile.ql b/java/ql/src/experimental/Security/CWE/CWE-555/CredentialsInPropertiesFile.ql index 2ab074e56d8..1e9b9906096 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-555/CredentialsInPropertiesFile.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-555/CredentialsInPropertiesFile.ql @@ -9,10 +9,18 @@ * external/cwe/cwe-260 */ +/* + * Note this query requires properties files to be indexed before it can produce results. + * If creating your own database with the CodeQL CLI, you should run + * `codeql database index-files --language=properties ...` + * If using lgtm.com, you should add `properties_files: true` to the index block of your + * lgtm.yml file (see https://lgtm.com/help/lgtm/java-extraction) + */ + import java import semmle.code.configfiles.ConfigFiles -private string suspicious() { +private string possibleSecretName() { result = "%password%" or result = "%passwd%" or result = "%account%" or @@ -23,7 +31,7 @@ private string suspicious() { result = "%access%key%" } -private string nonSuspicious() { +private string possibleEncryptedSecretName() { result = "%hashed%" or result = "%encrypted%" or result = "%crypt%" @@ -48,7 +56,8 @@ predicate isNotCleartextCredentials(string value) { or value.matches("ENC(%)") // Encrypted value or - value.toLowerCase().matches(suspicious()) // Could be message properties or fake passwords + // Could be a message property for UI display or fake passwords, e.g. login.password_expired=Your current password has expired. + value.toLowerCase().matches(possibleSecretName()) } /** @@ -57,8 +66,7 @@ predicate isNotCleartextCredentials(string value) { * b) with a non-production file name */ predicate isNonProdCredentials(CredentialsConfig cc) { - cc.getFile().getAbsolutePath().matches(["%dev%", "%test%", "%sample%"]) and - not cc.getFile().getAbsolutePath().matches("%codeql%") // CodeQL test cases + cc.getFile().getAbsolutePath().matches(["%dev%", "%test%", "%sample%"]) } /** The properties file with configuration key/value pairs. */ @@ -69,8 +77,8 @@ class ConfigProperties extends ConfigPair { /** The credentials configuration property. */ class CredentialsConfig extends ConfigProperties { CredentialsConfig() { - this.getNameElement().getName().trim().toLowerCase().matches(suspicious()) and - not this.getNameElement().getName().trim().toLowerCase().matches(nonSuspicious()) + this.getNameElement().getName().trim().toLowerCase().matches(possibleSecretName()) and + not this.getNameElement().getName().trim().toLowerCase().matches(possibleEncryptedSecretName()) } string getName() { result = this.getNameElement().getName().trim() } diff --git a/java/ql/test/experimental/query-tests/security/CWE-555/CredentialsInPropertiesFile.ql b/java/ql/test/experimental/query-tests/security/CWE-555/CredentialsInPropertiesFile.ql new file mode 100644 index 00000000000..bb7495dc4d9 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-555/CredentialsInPropertiesFile.ql @@ -0,0 +1,84 @@ +/** + * @name Cleartext Credentials in Properties File + * @description Finds cleartext credentials in Java properties files. + * @kind problem + * @id java/credentials-in-properties + * @tags security + * external/cwe/cwe-555 + * external/cwe/cwe-256 + * external/cwe/cwe-260 + */ + +/* + * Note this query requires properties files to be indexed before it can produce results. + * If creating your own database with the CodeQL CLI, you should run + * `codeql database index-files --language=properties ...` + * If using lgtm.com, you should add `properties_files: true` to the index block of your + * lgtm.yml file (see https://lgtm.com/help/lgtm/java-extraction) + */ + +import java +import semmle.code.configfiles.ConfigFiles + +private string possibleSecretName() { + result = "%password%" or + result = "%passwd%" or + result = "%account%" or + result = "%accnt%" or + result = "%credential%" or + result = "%token%" or + result = "%secret%" or + result = "%access%key%" +} + +private string possibleEncryptedSecretName() { + result = "%hashed%" or + result = "%encrypted%" or + result = "%crypt%" +} + +/** Holds if the value is not cleartext credentials. */ +bindingset[value] +predicate isNotCleartextCredentials(string value) { + value = "" // Empty string + or + value.length() < 7 // Typical credentials are no less than 6 characters + or + value.matches("% %") // Sentences containing spaces + or + value.regexpMatch(".*[^a-zA-Z\\d]{3,}.*") // Contain repeated non-alphanumeric characters such as a fake password pass**** or ???? + or + value.matches("@%") // Starts with the "@" sign + or + value.regexpMatch("\\$\\{.*\\}") // Variable placeholder ${credentials} + or + value.matches("%=") // A basic check of encrypted credentials ending with padding characters + or + value.matches("ENC(%)") // Encrypted value + or + // Could be a message property for UI display or fake passwords, e.g. login.password_expired=Your current password has expired. + value.toLowerCase().matches(possibleSecretName()) +} + +/** The properties file with configuration key/value pairs. */ +class ConfigProperties extends ConfigPair { + ConfigProperties() { this.getFile().getBaseName().toLowerCase().matches("%.properties") } +} + +/** The credentials configuration property. */ +class CredentialsConfig extends ConfigProperties { + CredentialsConfig() { + this.getNameElement().getName().trim().toLowerCase().matches(possibleSecretName()) and + not this.getNameElement().getName().trim().toLowerCase().matches(possibleEncryptedSecretName()) + } + + string getName() { result = this.getNameElement().getName().trim() } + + string getValue() { result = this.getValueElement().getValue().trim() } +} + +from CredentialsConfig cc +where not isNotCleartextCredentials(cc.getValue()) +select cc, + "Plaintext credentials " + cc.getName() + " have cleartext value " + cc.getValue() + + " in properties file." diff --git a/java/ql/test/experimental/query-tests/security/CWE-555/CredentialsInPropertiesFile.qlref b/java/ql/test/experimental/query-tests/security/CWE-555/CredentialsInPropertiesFile.qlref deleted file mode 100644 index e2536bfe883..00000000000 --- a/java/ql/test/experimental/query-tests/security/CWE-555/CredentialsInPropertiesFile.qlref +++ /dev/null @@ -1 +0,0 @@ -experimental/Security/CWE/CWE-555/CredentialsInPropertiesFile.ql \ No newline at end of file From 92e0e195a4d1e009e2902ea34386b45f1e848d34 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Sat, 27 Mar 2021 18:08:20 +0100 Subject: [PATCH 412/725] Revert "Merge pull request #5506 from tausbn/python-allow-absolute-imports-from-source-directory" This reverts commit 8d15680af4a6d1361d19b8c328c389263c06c902, reversing changes made to 63831cc62b65559f7028d1a35559a796e97efb62. This PR caused performance problems, so reverting now to clear up immediate problems. --- python/ql/src/semmle/python/Files.qll | 30 ------------------- python/ql/src/semmle/python/Module.qll | 7 +---- .../modules/entry_point/hash_bang/main.py | 7 ----- .../modules/entry_point/hash_bang/module.py | 2 -- .../namespace_package_main.py | 2 -- .../namespace_package_module.py | 1 - .../entry_point/hash_bang/package/__init__.py | 2 -- .../hash_bang/package/package_main.py | 2 -- .../hash_bang/package/package_module.py | 1 - .../modules/entry_point/modules.expected | 16 ---------- .../modules/entry_point/modules.ql | 4 --- .../modules/entry_point/name_main/main.py | 8 ----- .../modules/entry_point/name_main/module.py | 2 -- .../namespace_package_main.py | 2 -- .../namespace_package_module.py | 1 - .../entry_point/name_main/package/__init__.py | 2 -- .../name_main/package/package_main.py | 2 -- .../name_main/package/package_module.py | 1 - .../entry_point/no_py_extension/main.secretpy | 6 ---- .../entry_point/no_py_extension/module.py | 2 -- .../namespace_package_main.py | 2 -- .../namespace_package_module.py | 1 - .../no_py_extension/package/__init__.py | 2 -- .../no_py_extension/package/package_main.py | 2 -- .../no_py_extension/package/package_module.py | 1 - .../library-tests/modules/entry_point/options | 1 - 26 files changed, 1 insertion(+), 108 deletions(-) delete mode 100755 python/ql/test/3/library-tests/modules/entry_point/hash_bang/main.py delete mode 100644 python/ql/test/3/library-tests/modules/entry_point/hash_bang/module.py delete mode 100644 python/ql/test/3/library-tests/modules/entry_point/hash_bang/namespace_package/namespace_package_main.py delete mode 100644 python/ql/test/3/library-tests/modules/entry_point/hash_bang/namespace_package/namespace_package_module.py delete mode 100644 python/ql/test/3/library-tests/modules/entry_point/hash_bang/package/__init__.py delete mode 100644 python/ql/test/3/library-tests/modules/entry_point/hash_bang/package/package_main.py delete mode 100644 python/ql/test/3/library-tests/modules/entry_point/hash_bang/package/package_module.py delete mode 100644 python/ql/test/3/library-tests/modules/entry_point/modules.expected delete mode 100644 python/ql/test/3/library-tests/modules/entry_point/modules.ql delete mode 100755 python/ql/test/3/library-tests/modules/entry_point/name_main/main.py delete mode 100644 python/ql/test/3/library-tests/modules/entry_point/name_main/module.py delete mode 100644 python/ql/test/3/library-tests/modules/entry_point/name_main/namespace_package/namespace_package_main.py delete mode 100644 python/ql/test/3/library-tests/modules/entry_point/name_main/namespace_package/namespace_package_module.py delete mode 100644 python/ql/test/3/library-tests/modules/entry_point/name_main/package/__init__.py delete mode 100644 python/ql/test/3/library-tests/modules/entry_point/name_main/package/package_main.py delete mode 100644 python/ql/test/3/library-tests/modules/entry_point/name_main/package/package_module.py delete mode 100755 python/ql/test/3/library-tests/modules/entry_point/no_py_extension/main.secretpy delete mode 100644 python/ql/test/3/library-tests/modules/entry_point/no_py_extension/module.py delete mode 100644 python/ql/test/3/library-tests/modules/entry_point/no_py_extension/namespace_package/namespace_package_main.py delete mode 100644 python/ql/test/3/library-tests/modules/entry_point/no_py_extension/namespace_package/namespace_package_module.py delete mode 100644 python/ql/test/3/library-tests/modules/entry_point/no_py_extension/package/__init__.py delete mode 100644 python/ql/test/3/library-tests/modules/entry_point/no_py_extension/package/package_main.py delete mode 100644 python/ql/test/3/library-tests/modules/entry_point/no_py_extension/package/package_module.py delete mode 100644 python/ql/test/3/library-tests/modules/entry_point/options diff --git a/python/ql/src/semmle/python/Files.qll b/python/ql/src/semmle/python/Files.qll index 83ba92f0abc..ef6484fbdc6 100644 --- a/python/ql/src/semmle/python/Files.qll +++ b/python/ql/src/semmle/python/Files.qll @@ -72,33 +72,6 @@ class File extends Container { * are specified to be extracted. */ string getContents() { file_contents(this, result) } - - /** Holds if this file is likely to get executed directly, and thus act as an entry point for execution. */ - predicate maybeExecutedDirectly() { - // Only consider files in the source code, and not things like the standard library - exists(this.getRelativePath()) and - ( - // The file doesn't have the extension `.py` but still contains Python statements - not this.getExtension().matches("py%") and - exists(Stmt s | s.getLocation().getFile() = this) - or - // The file contains the usual `if __name__ == '__main__':` construction - exists(If i, Name name, StrConst main, Cmpop op | - i.getScope().(Module).getFile() = this and - op instanceof Eq and - i.getTest().(Compare).compares(name, op, main) and - name.getId() = "__name__" and - main.getText() = "__main__" - ) - or - // The file contains a `#!` line referencing the python interpreter - exists(Comment c | - c.getLocation().getFile() = this and - c.getLocation().getStartLine() = 1 and - c.getText().regexpMatch("^#! */.*python(2|3)?[ \\\\t]*$") - ) - ) - } } private predicate occupied_line(File f, int n) { @@ -148,9 +121,6 @@ class Folder extends Container { this.getBaseName().regexpMatch("[^\\d\\W]\\w*") and result = this.getParent().getImportRoot(n) } - - /** Holds if execution may start in a file in this directory. */ - predicate mayContainEntryPoint() { any(File f | f.getParent() = this).maybeExecutedDirectly() } } /** diff --git a/python/ql/src/semmle/python/Module.qll b/python/ql/src/semmle/python/Module.qll index 8a420a800ea..fcf1c0b2925 100644 --- a/python/ql/src/semmle/python/Module.qll +++ b/python/ql/src/semmle/python/Module.qll @@ -204,13 +204,8 @@ private string moduleNameFromBase(Container file) { string moduleNameFromFile(Container file) { exists(string basename | basename = moduleNameFromBase(file) and - legalShortName(basename) - | + legalShortName(basename) and result = moduleNameFromFile(file.getParent()) + "." + basename - or - // If execution can start in the folder containing this module, then we will assume `file` can - // be imported as an absolute import, and hence return `basename` as a possible name. - file.getParent().(Folder).mayContainEntryPoint() and result = basename ) or isPotentialSourcePackage(file) and diff --git a/python/ql/test/3/library-tests/modules/entry_point/hash_bang/main.py b/python/ql/test/3/library-tests/modules/entry_point/hash_bang/main.py deleted file mode 100755 index ad619e5cbd8..00000000000 --- a/python/ql/test/3/library-tests/modules/entry_point/hash_bang/main.py +++ /dev/null @@ -1,7 +0,0 @@ -#! /usr/bin/python3 -print(__file__) -import module -import package -import namespace_package -import namespace_package.namespace_package_main -print(module.message) diff --git a/python/ql/test/3/library-tests/modules/entry_point/hash_bang/module.py b/python/ql/test/3/library-tests/modules/entry_point/hash_bang/module.py deleted file mode 100644 index 36206ca60b7..00000000000 --- a/python/ql/test/3/library-tests/modules/entry_point/hash_bang/module.py +++ /dev/null @@ -1,2 +0,0 @@ -print(__file__.split("entry_point")[1]) -message = "Hello world!" diff --git a/python/ql/test/3/library-tests/modules/entry_point/hash_bang/namespace_package/namespace_package_main.py b/python/ql/test/3/library-tests/modules/entry_point/hash_bang/namespace_package/namespace_package_main.py deleted file mode 100644 index 5db80f18a27..00000000000 --- a/python/ql/test/3/library-tests/modules/entry_point/hash_bang/namespace_package/namespace_package_main.py +++ /dev/null @@ -1,2 +0,0 @@ -print(__file__.split("entry_point")[1]) -import namespace_package.namespace_package_module diff --git a/python/ql/test/3/library-tests/modules/entry_point/hash_bang/namespace_package/namespace_package_module.py b/python/ql/test/3/library-tests/modules/entry_point/hash_bang/namespace_package/namespace_package_module.py deleted file mode 100644 index 567a23d59ce..00000000000 --- a/python/ql/test/3/library-tests/modules/entry_point/hash_bang/namespace_package/namespace_package_module.py +++ /dev/null @@ -1 +0,0 @@ -print(__file__.split("entry_point")[1]) diff --git a/python/ql/test/3/library-tests/modules/entry_point/hash_bang/package/__init__.py b/python/ql/test/3/library-tests/modules/entry_point/hash_bang/package/__init__.py deleted file mode 100644 index ca14a9f5804..00000000000 --- a/python/ql/test/3/library-tests/modules/entry_point/hash_bang/package/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -print(__file__.split("entry_point")[1]) -from . import package_main diff --git a/python/ql/test/3/library-tests/modules/entry_point/hash_bang/package/package_main.py b/python/ql/test/3/library-tests/modules/entry_point/hash_bang/package/package_main.py deleted file mode 100644 index 158b12678e3..00000000000 --- a/python/ql/test/3/library-tests/modules/entry_point/hash_bang/package/package_main.py +++ /dev/null @@ -1,2 +0,0 @@ -print(__file__.split("entry_point")[1]) -from . import package_module diff --git a/python/ql/test/3/library-tests/modules/entry_point/hash_bang/package/package_module.py b/python/ql/test/3/library-tests/modules/entry_point/hash_bang/package/package_module.py deleted file mode 100644 index 567a23d59ce..00000000000 --- a/python/ql/test/3/library-tests/modules/entry_point/hash_bang/package/package_module.py +++ /dev/null @@ -1 +0,0 @@ -print(__file__.split("entry_point")[1]) diff --git a/python/ql/test/3/library-tests/modules/entry_point/modules.expected b/python/ql/test/3/library-tests/modules/entry_point/modules.expected deleted file mode 100644 index e5f6b300074..00000000000 --- a/python/ql/test/3/library-tests/modules/entry_point/modules.expected +++ /dev/null @@ -1,16 +0,0 @@ -| main | hash_bang/main.py:0:0:0:0 | Script main | -| main | name_main/main.py:0:0:0:0 | Module main | -| module | hash_bang/module.py:0:0:0:0 | Module module | -| module | name_main/module.py:0:0:0:0 | Module module | -| package | hash_bang/package:0:0:0:0 | Package package | -| package | name_main/package:0:0:0:0 | Package package | -| package | no_py_extension/package:0:0:0:0 | Package package | -| package.__init__ | hash_bang/package/__init__.py:0:0:0:0 | Module package.__init__ | -| package.__init__ | name_main/package/__init__.py:0:0:0:0 | Module package.__init__ | -| package.__init__ | no_py_extension/package/__init__.py:0:0:0:0 | Module package.__init__ | -| package.package_main | hash_bang/package/package_main.py:0:0:0:0 | Module package.package_main | -| package.package_main | name_main/package/package_main.py:0:0:0:0 | Module package.package_main | -| package.package_main | no_py_extension/package/package_main.py:0:0:0:0 | Module package.package_main | -| package.package_module | hash_bang/package/package_module.py:0:0:0:0 | Module package.package_module | -| package.package_module | name_main/package/package_module.py:0:0:0:0 | Module package.package_module | -| package.package_module | no_py_extension/package/package_module.py:0:0:0:0 | Module package.package_module | diff --git a/python/ql/test/3/library-tests/modules/entry_point/modules.ql b/python/ql/test/3/library-tests/modules/entry_point/modules.ql deleted file mode 100644 index 10c390e8616..00000000000 --- a/python/ql/test/3/library-tests/modules/entry_point/modules.ql +++ /dev/null @@ -1,4 +0,0 @@ -import python - -from Module m -select m.getName(), m diff --git a/python/ql/test/3/library-tests/modules/entry_point/name_main/main.py b/python/ql/test/3/library-tests/modules/entry_point/name_main/main.py deleted file mode 100755 index 08ec212383b..00000000000 --- a/python/ql/test/3/library-tests/modules/entry_point/name_main/main.py +++ /dev/null @@ -1,8 +0,0 @@ -print(__file__) -import module -import package -import namespace_package -import namespace_package.namespace_package_main - -if __name__ == '__main__': - print(module.message) diff --git a/python/ql/test/3/library-tests/modules/entry_point/name_main/module.py b/python/ql/test/3/library-tests/modules/entry_point/name_main/module.py deleted file mode 100644 index 36206ca60b7..00000000000 --- a/python/ql/test/3/library-tests/modules/entry_point/name_main/module.py +++ /dev/null @@ -1,2 +0,0 @@ -print(__file__.split("entry_point")[1]) -message = "Hello world!" diff --git a/python/ql/test/3/library-tests/modules/entry_point/name_main/namespace_package/namespace_package_main.py b/python/ql/test/3/library-tests/modules/entry_point/name_main/namespace_package/namespace_package_main.py deleted file mode 100644 index 5db80f18a27..00000000000 --- a/python/ql/test/3/library-tests/modules/entry_point/name_main/namespace_package/namespace_package_main.py +++ /dev/null @@ -1,2 +0,0 @@ -print(__file__.split("entry_point")[1]) -import namespace_package.namespace_package_module diff --git a/python/ql/test/3/library-tests/modules/entry_point/name_main/namespace_package/namespace_package_module.py b/python/ql/test/3/library-tests/modules/entry_point/name_main/namespace_package/namespace_package_module.py deleted file mode 100644 index 567a23d59ce..00000000000 --- a/python/ql/test/3/library-tests/modules/entry_point/name_main/namespace_package/namespace_package_module.py +++ /dev/null @@ -1 +0,0 @@ -print(__file__.split("entry_point")[1]) diff --git a/python/ql/test/3/library-tests/modules/entry_point/name_main/package/__init__.py b/python/ql/test/3/library-tests/modules/entry_point/name_main/package/__init__.py deleted file mode 100644 index ca14a9f5804..00000000000 --- a/python/ql/test/3/library-tests/modules/entry_point/name_main/package/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -print(__file__.split("entry_point")[1]) -from . import package_main diff --git a/python/ql/test/3/library-tests/modules/entry_point/name_main/package/package_main.py b/python/ql/test/3/library-tests/modules/entry_point/name_main/package/package_main.py deleted file mode 100644 index 158b12678e3..00000000000 --- a/python/ql/test/3/library-tests/modules/entry_point/name_main/package/package_main.py +++ /dev/null @@ -1,2 +0,0 @@ -print(__file__.split("entry_point")[1]) -from . import package_module diff --git a/python/ql/test/3/library-tests/modules/entry_point/name_main/package/package_module.py b/python/ql/test/3/library-tests/modules/entry_point/name_main/package/package_module.py deleted file mode 100644 index 567a23d59ce..00000000000 --- a/python/ql/test/3/library-tests/modules/entry_point/name_main/package/package_module.py +++ /dev/null @@ -1 +0,0 @@ -print(__file__.split("entry_point")[1]) diff --git a/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/main.secretpy b/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/main.secretpy deleted file mode 100755 index e2673d4da78..00000000000 --- a/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/main.secretpy +++ /dev/null @@ -1,6 +0,0 @@ -print(__file__) -import module -import package -import namespace_package -import namespace_package.namespace_package_main -print(module.message) diff --git a/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/module.py b/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/module.py deleted file mode 100644 index 36206ca60b7..00000000000 --- a/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/module.py +++ /dev/null @@ -1,2 +0,0 @@ -print(__file__.split("entry_point")[1]) -message = "Hello world!" diff --git a/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/namespace_package/namespace_package_main.py b/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/namespace_package/namespace_package_main.py deleted file mode 100644 index 5db80f18a27..00000000000 --- a/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/namespace_package/namespace_package_main.py +++ /dev/null @@ -1,2 +0,0 @@ -print(__file__.split("entry_point")[1]) -import namespace_package.namespace_package_module diff --git a/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/namespace_package/namespace_package_module.py b/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/namespace_package/namespace_package_module.py deleted file mode 100644 index 567a23d59ce..00000000000 --- a/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/namespace_package/namespace_package_module.py +++ /dev/null @@ -1 +0,0 @@ -print(__file__.split("entry_point")[1]) diff --git a/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/package/__init__.py b/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/package/__init__.py deleted file mode 100644 index ca14a9f5804..00000000000 --- a/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/package/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -print(__file__.split("entry_point")[1]) -from . import package_main diff --git a/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/package/package_main.py b/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/package/package_main.py deleted file mode 100644 index 158b12678e3..00000000000 --- a/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/package/package_main.py +++ /dev/null @@ -1,2 +0,0 @@ -print(__file__.split("entry_point")[1]) -from . import package_module diff --git a/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/package/package_module.py b/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/package/package_module.py deleted file mode 100644 index 567a23d59ce..00000000000 --- a/python/ql/test/3/library-tests/modules/entry_point/no_py_extension/package/package_module.py +++ /dev/null @@ -1 +0,0 @@ -print(__file__.split("entry_point")[1]) diff --git a/python/ql/test/3/library-tests/modules/entry_point/options b/python/ql/test/3/library-tests/modules/entry_point/options deleted file mode 100644 index 6beceeb08ed..00000000000 --- a/python/ql/test/3/library-tests/modules/entry_point/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: --lang=3 --path bogus -R . --filter=include:**/*.secretpy From 5ce3f9d6ff6eb740d8c6add31fd7c95fa79f6453 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Sun, 28 Mar 2021 03:15:06 +0000 Subject: [PATCH 413/725] Update qldoc and enhance the query --- .../CWE-555/CredentialsInPropertiesFile.qhelp | 6 +- .../CWE-555/CredentialsInPropertiesFile.ql | 84 +++++++++++++------ .../CredentialsInPropertiesFile.expected | 10 +-- .../CWE-555/CredentialsInPropertiesFile.ql | 81 ++++++++++++------ .../security/CWE-555/PropertiesUtils.java | 57 +++++++++++++ .../security/CWE-555/messages.properties | 1 + 6 files changed, 179 insertions(+), 60 deletions(-) create mode 100644 java/ql/test/experimental/query-tests/security/CWE-555/PropertiesUtils.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-555/CredentialsInPropertiesFile.qhelp b/java/ql/src/experimental/Security/CWE/CWE-555/CredentialsInPropertiesFile.qhelp index 0869b886260..5549f188f1f 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-555/CredentialsInPropertiesFile.qhelp +++ b/java/ql/src/experimental/Security/CWE/CWE-555/CredentialsInPropertiesFile.qhelp @@ -3,7 +3,7 @@

    Credentials management issues occur when credentials are stored in plaintext in - an application’s properties file. Common credentials include but are not limited + an application's properties file. Common credentials include but are not limited to LDAP, mail, database, proxy account, and so on. Storing plaintext credentials in a properties file allows anyone who can read the file access to the protected resource. Good credentials management guidelines require that credentials never @@ -21,12 +21,12 @@

    - In the first example, the credentials of a LDAP and datasource properties are stored + In the first example, the credentials for the LDAP and datasource properties are stored in cleartext in the properties file.

    - In the second example, the credentials of a LDAP and datasource properties are stored + In the second example, the credentials for the LDAP and datasource properties are stored in an encrypted format.

    diff --git a/java/ql/src/experimental/Security/CWE/CWE-555/CredentialsInPropertiesFile.ql b/java/ql/src/experimental/Security/CWE/CWE-555/CredentialsInPropertiesFile.ql index 1e9b9906096..8bbc0d00a46 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-555/CredentialsInPropertiesFile.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-555/CredentialsInPropertiesFile.ql @@ -14,28 +14,22 @@ * If creating your own database with the CodeQL CLI, you should run * `codeql database index-files --language=properties ...` * If using lgtm.com, you should add `properties_files: true` to the index block of your - * lgtm.yml file (see https://lgtm.com/help/lgtm/java-extraction) + * lgtm.yml file (see https://lgtm.com/help/lgtm/java-extraction#customizing-index) */ import java import semmle.code.configfiles.ConfigFiles +import semmle.code.java.dataflow.FlowSources private string possibleSecretName() { - result = "%password%" or - result = "%passwd%" or - result = "%account%" or - result = "%accnt%" or - result = "%credential%" or - result = "%token%" or - result = "%secret%" or - result = "%access%key%" + result = + [ + "%password%", "%passwd%", "%account%", "%accnt%", "%credential%", "%token%", "%secret%", + "%access%key%" + ] } -private string possibleEncryptedSecretName() { - result = "%hashed%" or - result = "%encrypted%" or - result = "%crypt%" -} +private string possibleEncryptedSecretName() { result = ["%hashed%", "%encrypted%", "%crypt%"] } /** Holds if the value is not cleartext credentials. */ bindingset[value] @@ -69,27 +63,63 @@ predicate isNonProdCredentials(CredentialsConfig cc) { cc.getFile().getAbsolutePath().matches(["%dev%", "%test%", "%sample%"]) } -/** The properties file with configuration key/value pairs. */ -class ConfigProperties extends ConfigPair { - ConfigProperties() { this.getFile().getBaseName().toLowerCase().matches("%.properties") } -} - /** The credentials configuration property. */ -class CredentialsConfig extends ConfigProperties { +class CredentialsConfig extends ConfigPair { CredentialsConfig() { this.getNameElement().getName().trim().toLowerCase().matches(possibleSecretName()) and - not this.getNameElement().getName().trim().toLowerCase().matches(possibleEncryptedSecretName()) + not this.getNameElement().getName().trim().toLowerCase().matches(possibleEncryptedSecretName()) and + not isNotCleartextCredentials(this.getValueElement().getValue().trim()) } string getName() { result = this.getNameElement().getName().trim() } string getValue() { result = this.getValueElement().getValue().trim() } + + /** Returns a description of this vulnerability. */ + string getConfigDesc() { + exists( + LoadCredentialsConfiguration cc, DataFlow::Node source, DataFlow::Node sink, MethodAccess ma + | + this.getName() = source.asExpr().(CompileTimeConstantExpr).getStringValue() and + cc.hasFlow(source, sink) and + ma.getArgument(0) = sink.asExpr() and + result = "Plaintext credentials " + this.getName() + " are loaded in " + ma + ) + or + not exists(LoadCredentialsConfiguration cc, DataFlow::Node source, DataFlow::Node sink | + this.getName() = source.asExpr().(CompileTimeConstantExpr).getStringValue() and + cc.hasFlow(source, sink) + ) and + result = + "Plaintext credentials " + this.getName() + " have cleartext value " + this.getValue() + + " in properties file" + } +} + +/** + * A dataflow configuration tracking flow of a method that loads a credentials property. + */ +class LoadCredentialsConfiguration extends DataFlow::Configuration { + LoadCredentialsConfiguration() { this = "LoadCredentialsConfiguration" } + + override predicate isSource(DataFlow::Node source) { + exists(CredentialsConfig cc | + source.asExpr().(CompileTimeConstantExpr).getStringValue() = cc.getName() + ) + } + + override predicate isSink(DataFlow::Node sink) { + sink.asExpr() = + any(MethodAccess ma | + ma.getMethod() + .getDeclaringType() + .getASupertype*() + .hasQualifiedName("java.util", "Properties") and + ma.getMethod().getName() = "getProperty" + ).getArgument(0) + } } from CredentialsConfig cc -where - not isNotCleartextCredentials(cc.getValue()) and - not isNonProdCredentials(cc) -select cc, - "Plaintext credentials " + cc.getName() + " have cleartext value " + cc.getValue() + - " in properties file." +where not isNonProdCredentials(cc) +select cc, cc.getConfigDesc() diff --git a/java/ql/test/experimental/query-tests/security/CWE-555/CredentialsInPropertiesFile.expected b/java/ql/test/experimental/query-tests/security/CWE-555/CredentialsInPropertiesFile.expected index 0ce33913932..1bdc004a446 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-555/CredentialsInPropertiesFile.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-555/CredentialsInPropertiesFile.expected @@ -1,5 +1,5 @@ -| configuration.properties:6:1:6:25 | ldap.password=mysecpass | Plaintext credentials ldap.password have cleartext value mysecpass in properties file. | -| configuration.properties:18:1:18:35 | datasource1.password=Passw0rd@123 | Plaintext credentials datasource1.password have cleartext value Passw0rd@123 in properties file. | -| configuration.properties:25:1:25:31 | mail.password=MysecPWxWa@1993 | Plaintext credentials mail.password have cleartext value MysecPWxWa@1993 in properties file. | -| configuration.properties:33:1:33:50 | com.example.aws.s3.access_key=AKMAMQPBYMCD6YSAYCBA | Plaintext credentials com.example.aws.s3.access_key have cleartext value AKMAMQPBYMCD6YSAYCBA in properties file. | -| configuration.properties:34:1:34:70 | com.example.aws.s3.secret_key=8lMPSfWzZq+wcWtck5+QPLOJDZzE783pS09/IO3k | Plaintext credentials com.example.aws.s3.secret_key have cleartext value 8lMPSfWzZq+wcWtck5+QPLOJDZzE783pS09/IO3k in properties file. | +| configuration.properties:6:1:6:25 | ldap.password=mysecpass | Plaintext credentials ldap.password are loaded in getProperty(...) | +| configuration.properties:18:1:18:35 | datasource1.password=Passw0rd@123 | Plaintext credentials datasource1.password are loaded in getProperty(...) | +| configuration.properties:25:1:25:31 | mail.password=MysecPWxWa@1993 | Plaintext credentials mail.password are loaded in getProperty(...) | +| configuration.properties:33:1:33:50 | com.example.aws.s3.access_key=AKMAMQPBYMCD6YSAYCBA | Plaintext credentials com.example.aws.s3.access_key are loaded in getProperty(...) | +| configuration.properties:34:1:34:70 | com.example.aws.s3.secret_key=8lMPSfWzZq+wcWtck5+QPLOJDZzE783pS09/IO3k | Plaintext credentials com.example.aws.s3.secret_key are loaded in getProperty(...) | diff --git a/java/ql/test/experimental/query-tests/security/CWE-555/CredentialsInPropertiesFile.ql b/java/ql/test/experimental/query-tests/security/CWE-555/CredentialsInPropertiesFile.ql index bb7495dc4d9..b6890e4ac9f 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-555/CredentialsInPropertiesFile.ql +++ b/java/ql/test/experimental/query-tests/security/CWE-555/CredentialsInPropertiesFile.ql @@ -14,28 +14,22 @@ * If creating your own database with the CodeQL CLI, you should run * `codeql database index-files --language=properties ...` * If using lgtm.com, you should add `properties_files: true` to the index block of your - * lgtm.yml file (see https://lgtm.com/help/lgtm/java-extraction) + * lgtm.yml file (see https://lgtm.com/help/lgtm/java-extraction#customizing-index) */ import java import semmle.code.configfiles.ConfigFiles +import semmle.code.java.dataflow.FlowSources private string possibleSecretName() { - result = "%password%" or - result = "%passwd%" or - result = "%account%" or - result = "%accnt%" or - result = "%credential%" or - result = "%token%" or - result = "%secret%" or - result = "%access%key%" + result = + [ + "%password%", "%passwd%", "%account%", "%accnt%", "%credential%", "%token%", "%secret%", + "%access%key%" + ] } -private string possibleEncryptedSecretName() { - result = "%hashed%" or - result = "%encrypted%" or - result = "%crypt%" -} +private string possibleEncryptedSecretName() { result = ["%hashed%", "%encrypted%", "%crypt%"] } /** Holds if the value is not cleartext credentials. */ bindingset[value] @@ -60,25 +54,62 @@ predicate isNotCleartextCredentials(string value) { value.toLowerCase().matches(possibleSecretName()) } -/** The properties file with configuration key/value pairs. */ -class ConfigProperties extends ConfigPair { - ConfigProperties() { this.getFile().getBaseName().toLowerCase().matches("%.properties") } -} - /** The credentials configuration property. */ -class CredentialsConfig extends ConfigProperties { +class CredentialsConfig extends ConfigPair { CredentialsConfig() { this.getNameElement().getName().trim().toLowerCase().matches(possibleSecretName()) and - not this.getNameElement().getName().trim().toLowerCase().matches(possibleEncryptedSecretName()) + not this.getNameElement().getName().trim().toLowerCase().matches(possibleEncryptedSecretName()) and + not isNotCleartextCredentials(this.getValueElement().getValue().trim()) } string getName() { result = this.getNameElement().getName().trim() } string getValue() { result = this.getValueElement().getValue().trim() } + + /** Returns a description of this vulnerability. */ + string getConfigDesc() { + exists( + LoadCredentialsConfiguration cc, DataFlow::Node source, DataFlow::Node sink, MethodAccess ma + | + this.getName() = source.asExpr().(CompileTimeConstantExpr).getStringValue() and + cc.hasFlow(source, sink) and + ma.getArgument(0) = sink.asExpr() and + result = "Plaintext credentials " + this.getName() + " are loaded in " + ma + ) + or + not exists(LoadCredentialsConfiguration cc, DataFlow::Node source, DataFlow::Node sink | + this.getName() = source.asExpr().(CompileTimeConstantExpr).getStringValue() and + cc.hasFlow(source, sink) + ) and + result = + "Plaintext credentials " + this.getName() + " have cleartext value " + this.getValue() + + " in properties file" + } +} + +/** + * A dataflow configuration tracking flow of a method that loads a credentials property. + */ +class LoadCredentialsConfiguration extends DataFlow::Configuration { + LoadCredentialsConfiguration() { this = "LoadCredentialsConfiguration" } + + override predicate isSource(DataFlow::Node source) { + exists(CredentialsConfig cc | + source.asExpr().(CompileTimeConstantExpr).getStringValue() = cc.getName() + ) + } + + override predicate isSink(DataFlow::Node sink) { + sink.asExpr() = + any(MethodAccess ma | + ma.getMethod() + .getDeclaringType() + .getASupertype*() + .hasQualifiedName("java.util", "Properties") and + ma.getMethod().getName() = "getProperty" + ).getArgument(0) + } } from CredentialsConfig cc -where not isNotCleartextCredentials(cc.getValue()) -select cc, - "Plaintext credentials " + cc.getName() + " have cleartext value " + cc.getValue() + - " in properties file." +select cc, cc.getConfigDesc() diff --git a/java/ql/test/experimental/query-tests/security/CWE-555/PropertiesUtils.java b/java/ql/test/experimental/query-tests/security/CWE-555/PropertiesUtils.java new file mode 100644 index 00000000000..b54995a9967 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-555/PropertiesUtils.java @@ -0,0 +1,57 @@ +import java.io.IOException; +import java.util.Properties; + +public class PropertiesUtils { + /* Properties declaration. */ + private static Properties properties; + + /** Static block to initializing the properties. */ + static { + properties = new Properties(); + try { + properties.load(PropertiesUtils.class.getClassLoader().getResourceAsStream("configuration.properties")); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** Returns the LDAP DN property value. */ + public static String getLdapDN() { + return properties.getProperty("ldap.loginDN"); + } + + /** Returns the LDAP password property value. */ + public static String getLdapPassword() { + return properties.getProperty("ldap.password"); + } + + /** Returns the SQL Server username property value. */ + public static String getMSDataSourceUserName() { + return properties.getProperty("datasource1.username"); + } + + /** Returns the SQL Server password property value. */ + public static String getMSDataSourcePassword() { + return properties.getProperty("datasource1.password"); + } + + /** Returns the mail account property value. */ + public static String getMailUserName() { + return properties.getProperty("mail.username"); + } + + /** Returns the mail password property value. */ + public static String getMailPassword() { + return properties.getProperty("mail.password"); + } + + /** Returns the AWS Access Key property value. */ + public static String getAWSAccessKey() { + return properties.getProperty("com.example.aws.s3.access_key"); + } + + /** Returns the AWS Secret Key property value. */ + public static String getAWSSecretKey() { + return properties.getProperty("com.example.aws.s3.secret_key"); + } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-555/messages.properties b/java/ql/test/experimental/query-tests/security/CWE-555/messages.properties index fac63ec23e8..27a244c6071 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-555/messages.properties +++ b/java/ql/test/experimental/query-tests/security/CWE-555/messages.properties @@ -1,3 +1,4 @@ +# GOOD: UI display messages; not credentials prompt.username=Username prompt.password=Password From 093c63ea3b15cd33b08b8bd1d1058ffc3c6dd075 Mon Sep 17 00:00:00 2001 From: ihsinme Date: Sun, 28 Mar 2021 23:42:36 +0300 Subject: [PATCH 414/725] Update OperatorPrecedenceLogicErrorWhenUseBoolType.expected --- .../tests/OperatorPrecedenceLogicErrorWhenUseBoolType.expected | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/OperatorPrecedenceLogicErrorWhenUseBoolType.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/OperatorPrecedenceLogicErrorWhenUseBoolType.expected index 76062fc360a..1209c7e7830 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/OperatorPrecedenceLogicErrorWhenUseBoolType.expected +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/OperatorPrecedenceLogicErrorWhenUseBoolType.expected @@ -1,4 +1,4 @@ -| test.cpp:10:3:10:10 | ... = ... | this expression needs attention | +| test.cpp:10:8:10:10 | - ... | this expression needs attention | | test.cpp:12:3:12:6 | ... ++ | this expression needs attention | | test.cpp:13:3:13:6 | ++ ... | this expression needs attention | | test.cpp:14:6:14:21 | ... = ... | this expression needs attention | From 3f215d0954ea56c34f90837e259553be82675f76 Mon Sep 17 00:00:00 2001 From: ihsinme Date: Sun, 28 Mar 2021 23:43:22 +0300 Subject: [PATCH 415/725] Update OperatorPrecedenceLogicErrorWhenUseBoolType.ql --- ...ratorPrecedenceLogicErrorWhenUseBoolType.ql | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-783/OperatorPrecedenceLogicErrorWhenUseBoolType.ql b/cpp/ql/src/experimental/Security/CWE/CWE-783/OperatorPrecedenceLogicErrorWhenUseBoolType.ql index 034df703bc3..4f30f112eb0 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-783/OperatorPrecedenceLogicErrorWhenUseBoolType.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-783/OperatorPrecedenceLogicErrorWhenUseBoolType.ql @@ -13,17 +13,17 @@ */ import cpp -import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis +import semmle.code.cpp.valuenumbering.HashCons /** Holds if `exp` increments a boolean value. */ -predicate incrementBoolType(Expr exp) { - exp.(IncrementOperation).getOperand().getType() instanceof BoolType +predicate incrementBoolType(IncrementOperation exp) { + exp.getOperand().getType() instanceof BoolType } /** Holds if `exp` applies the unary minus operator to a boolean type. */ -predicate revertSignBoolType(Expr exp) { - exp.(AssignExpr).getRValue().(UnaryMinusExpr).getAnOperand().getType() instanceof BoolType and - exp.(AssignExpr).getLValue().getType() instanceof BoolType +predicate revertSignBoolType(UnaryMinusExpr exp) { + exp.getAnOperand().getType() instanceof BoolType and + exp.getFullyConverted().getType() instanceof BoolType } /** Holds, if this is an expression, uses comparison and assignment outside of execution precedence. */ @@ -33,6 +33,12 @@ predicate assignBoolType(Expr exp) { exp.isCondition() and not co.isParenthesised() and not exp.(AssignExpr).getLValue().getType() instanceof BoolType and + not exists(Expr exbl | + hashCons(exbl.(AssignExpr).getLValue()) = hashCons(exp.(AssignExpr).getLValue()) and + not exbl.isCondition() and + exbl.(AssignExpr).getRValue().getType() instanceof BoolType and + exbl.(AssignExpr).getLValue().getType() = exp.(AssignExpr).getLValue().getType() + ) and co.getLeftOperand() instanceof FunctionCall and not co.getRightOperand().getType() instanceof BoolType and not co.getRightOperand().getValue() = "0" and From 0775d35591511db2003b3b7453c6bfc2284ba250 Mon Sep 17 00:00:00 2001 From: haby0 Date: Mon, 29 Mar 2021 12:02:37 +0800 Subject: [PATCH 416/725] update VerificationMethodFlowConfig, add if test --- .../Security/CWE/CWE-352/JsonpInjection.java | 35 ++-- .../Security/CWE/CWE-352/JsonpInjection.qhelp | 2 +- .../Security/CWE/CWE-352/JsonpInjection.ql | 27 ++-- .../CWE/CWE-352/JsonpInjectionLib.qll | 47 ++++-- .../JsonpController.java | 35 ++-- .../JsonpInjection.expected | 138 ++++++++-------- .../JsonpController.java | 37 +++-- .../JsonpInjection.expected | 147 ++++++++--------- .../JsonpController.java | 37 +++-- .../JsonpInjection.expected | 150 +++++++++--------- 10 files changed, 362 insertions(+), 293 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.java b/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.java index 7f479a8c023..8e2a0c9005f 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.java +++ b/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.java @@ -26,9 +26,6 @@ public class JsonpInjection { hashMap.put("password","123456"); } - private String name = null; - - @GetMapping(value = "jsonp1") @ResponseBody public String bad1(HttpServletRequest request) { @@ -77,7 +74,6 @@ public class JsonpInjection { PrintWriter pw = null; Gson gson = new Gson(); String result = gson.toJson(hashMap); - String resultStr = null; pw = response.getWriter(); resultStr = jsonpCallback + "(" + result + ")"; @@ -109,13 +105,25 @@ public class JsonpInjection { return resultStr; } - @GetMapping(value = "jsonp8") @ResponseBody + public String bad8(HttpServletRequest request) { + String resultStr = null; + String token = request.getParameter("token"); + boolean result = verifToken(token); //Just check. + String jsonpCallback = request.getParameter("jsonpCallback"); + String jsonStr = getJsonStr(hashMap); + resultStr = jsonpCallback + "(" + jsonStr + ")"; + return resultStr; + } + + + @GetMapping(value = "jsonp9") + @ResponseBody public String good1(HttpServletRequest request) { String resultStr = null; - String token = request.getParameter("token"); - if (verifToken(token)){ + String referer = request.getParameter("referer"); + if (verifReferer(referer)){ String jsonpCallback = request.getParameter("jsonpCallback"); String jsonStr = getJsonStr(hashMap); resultStr = jsonpCallback + "(" + jsonStr + ")"; @@ -125,7 +133,7 @@ public class JsonpInjection { } - @GetMapping(value = "jsonp9") + @GetMapping(value = "jsonp10") @ResponseBody public String good2(HttpServletRequest request) { String resultStr = null; @@ -140,7 +148,7 @@ public class JsonpInjection { return resultStr; } - @RequestMapping(value = "jsonp10") + @RequestMapping(value = "jsonp11") @ResponseBody public String good3(HttpServletRequest request) { JSONObject parameterObj = readToJSONObect(request); @@ -151,7 +159,7 @@ public class JsonpInjection { return resultStr; } - @RequestMapping(value = "jsonp11") + @RequestMapping(value = "jsonp12") @ResponseBody public String good4(@RequestParam("file") MultipartFile file,HttpServletRequest request) { if(null == file){ @@ -200,4 +208,11 @@ public class JsonpInjection { } return true; } + + public static boolean verifReferer(String str){ + if (str != "xxxx"){ + return false; + } + return true; + } } \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.qhelp b/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.qhelp index 93c167d6c2c..2712f30a3f2 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.qhelp +++ b/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.qhelp @@ -14,7 +14,7 @@ When there is a cross-domain problem, the problem of sensitive information leaka -

    The following examples show the bad case and the good case respectively. Bad case, such as bad1 to bad7, +

    The following examples show the bad case and the good case respectively. Bad case, such as bad1 to bad8, will cause information leakage problems when there are cross-domain problems. In a good case, for example, in the good1 method and the good2 method, use the verifToken method to do the random token Verification can solve the problem of information leakage caused by cross-domain.

    diff --git a/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.ql b/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.ql index eb4fe4e5b66..6e333d83993 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjection.ql @@ -18,20 +18,18 @@ import DataFlow::PathGraph /** Determine whether there is a verification method for the remote streaming source data flow path method. */ predicate existsFilterVerificationMethod() { - exists(MethodAccess ma, Node existsNode, Method m | - ma.getMethod() instanceof VerificationMethodClass and - existsNode.asExpr() = ma and - m = getACallingCallableOrSelf(existsNode.getEnclosingCallable()) and + exists(DataFlow::Node source, DataFlow::Node sink, VerificationMethodFlowConfig vmfc, Method m | + vmfc.hasFlow(source, sink) and + m = getACallingCallableOrSelf(source.getEnclosingCallable()) and isDoFilterMethod(m) ) } /** Determine whether there is a verification method for the remote streaming source data flow path method. */ predicate existsServletVerificationMethod(Node checkNode) { - exists(MethodAccess ma, Node existsNode | - ma.getMethod() instanceof VerificationMethodClass and - existsNode.asExpr() = ma and - getACallingCallableOrSelf(existsNode.getEnclosingCallable()) = + exists(DataFlow::Node source, DataFlow::Node sink, VerificationMethodFlowConfig vmfc | + vmfc.hasFlow(source, sink) and + getACallingCallableOrSelf(source.getEnclosingCallable()) = getACallingCallableOrSelf(checkNode.getEnclosingCallable()) ) } @@ -40,13 +38,14 @@ predicate existsServletVerificationMethod(Node checkNode) { class RequestResponseFlowConfig extends TaintTracking::Configuration { RequestResponseFlowConfig() { this = "RequestResponseFlowConfig" } - override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } + override predicate isSource(DataFlow::Node source) { + source instanceof RemoteFlowSource and + getACallingCallableOrSelf(source.getEnclosingCallable()) instanceof RequestGetMethod + } - override predicate isSink(DataFlow::Node sink) { sink instanceof XssSink } - - /** Eliminate the method of calling the node is not the get method. */ - override predicate isSanitizer(DataFlow::Node node) { - not getACallingCallableOrSelf(node.getEnclosingCallable()) instanceof RequestGetMethod + override predicate isSink(DataFlow::Node sink) { + sink instanceof XssSink and + getACallingCallableOrSelf(sink.getEnclosingCallable()) instanceof RequestGetMethod } override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { diff --git a/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjectionLib.qll index d0e00bcb634..bf90926f72f 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjectionLib.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-352/JsonpInjectionLib.qll @@ -3,30 +3,47 @@ import DataFlow import JsonStringLib import semmle.code.java.security.XSS import semmle.code.java.dataflow.DataFlow +import semmle.code.java.dataflow.DataFlow3 import semmle.code.java.dataflow.FlowSources import semmle.code.java.frameworks.spring.SpringController +/** A data flow configuration is tracing flow from the access to the authentication method of token/auth/referer/origin to if condition. */ +class VerificationMethodToIfFlowConfig extends DataFlow3::Configuration { + VerificationMethodToIfFlowConfig() { this = "VerificationMethodToIfFlowConfig" } + + override predicate isSource(DataFlow::Node src) { + exists(MethodAccess ma, BarrierGuard bg | ma = bg | + ( + ma.getMethod().getAParameter().getName().regexpMatch("(?i).*(token|auth|referer|origin).*") + or + ma.getMethod().getName().regexpMatch("(?i).*(token|auth|referer|origin).*") + ) and + ma = src.asExpr() + ) + } + + override predicate isSink(DataFlow::Node sink) { + exists(IfStmt is | is.getCondition() = sink.asExpr()) + } +} + /** Taint-tracking configuration tracing flow from untrusted inputs to verification of remote user input. */ -class VerificationMethodFlowConfig extends TaintTracking::Configuration { +class VerificationMethodFlowConfig extends TaintTracking2::Configuration { VerificationMethodFlowConfig() { this = "VerificationMethodFlowConfig" } override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource } override predicate isSink(DataFlow::Node sink) { - exists(MethodAccess ma | - ma.getMethod().getAParameter().getName().regexpMatch("(?i).*(token|auth|referer|origin).*") and - ma.getAnArgument() = sink.asExpr() - ) - } -} - -/** The parameter names of this method are token/auth/referer/origin. */ -class VerificationMethodClass extends Method { - VerificationMethodClass() { - exists(MethodAccess ma, VerificationMethodFlowConfig vmfc, Node node | - this = ma.getMethod() and - node.asExpr() = ma.getAnArgument() and - vmfc.hasFlowTo(node) + exists(MethodAccess ma, BarrierGuard bg, int i, VerificationMethodToIfFlowConfig vmtifc | + ma = bg + | + ( + ma.getMethod().getParameter(i).getName().regexpMatch("(?i).*(token|auth|referer|origin).*") + or + ma.getMethod().getName().regexpMatch("(?i).*(token|auth|referer|origin).*") + ) and + ma.getArgument(i) = sink.asExpr() and + vmtifc.hasFlow(exprNode(ma), _) ) } } diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithFilter/JsonpController.java b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithFilter/JsonpController.java index e5b5e70a38d..e875da2f699 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithFilter/JsonpController.java +++ b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithFilter/JsonpController.java @@ -26,9 +26,6 @@ public class JsonpController { hashMap.put("password","123456"); } - private String name = null; - - @GetMapping(value = "jsonp1") @ResponseBody public String bad1(HttpServletRequest request) { @@ -77,7 +74,6 @@ public class JsonpController { PrintWriter pw = null; Gson gson = new Gson(); String result = gson.toJson(hashMap); - String resultStr = null; pw = response.getWriter(); resultStr = jsonpCallback + "(" + result + ")"; @@ -109,13 +105,25 @@ public class JsonpController { return resultStr; } - @GetMapping(value = "jsonp8") @ResponseBody + public String bad8(HttpServletRequest request) { + String resultStr = null; + String token = request.getParameter("token"); + boolean result = verifToken(token); //Just check. + String jsonpCallback = request.getParameter("jsonpCallback"); + String jsonStr = getJsonStr(hashMap); + resultStr = jsonpCallback + "(" + jsonStr + ")"; + return resultStr; + } + + + @GetMapping(value = "jsonp9") + @ResponseBody public String good1(HttpServletRequest request) { String resultStr = null; - String token = request.getParameter("token"); - if (verifToken(token)){ + String referer = request.getParameter("referer"); + if (verifReferer(referer)){ String jsonpCallback = request.getParameter("jsonpCallback"); String jsonStr = getJsonStr(hashMap); resultStr = jsonpCallback + "(" + jsonStr + ")"; @@ -125,7 +133,7 @@ public class JsonpController { } - @GetMapping(value = "jsonp9") + @GetMapping(value = "jsonp10") @ResponseBody public String good2(HttpServletRequest request) { String resultStr = null; @@ -140,7 +148,7 @@ public class JsonpController { return resultStr; } - @RequestMapping(value = "jsonp10") + @RequestMapping(value = "jsonp11") @ResponseBody public String good3(HttpServletRequest request) { JSONObject parameterObj = readToJSONObect(request); @@ -151,7 +159,7 @@ public class JsonpController { return resultStr; } - @RequestMapping(value = "jsonp11") + @RequestMapping(value = "jsonp12") @ResponseBody public String good4(@RequestParam("file") MultipartFile file,HttpServletRequest request) { if(null == file){ @@ -200,4 +208,11 @@ public class JsonpController { } return true; } + + public static boolean verifReferer(String str){ + if (str != "xxxx"){ + return false; + } + return true; + } } diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithFilter/JsonpInjection.expected b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithFilter/JsonpInjection.expected index 501565f2b4e..3da805c6a69 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithFilter/JsonpInjection.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithFilter/JsonpInjection.expected @@ -1,80 +1,76 @@ edges -| JsonpController.java:36:32:36:68 | getParameter(...) : String | JsonpController.java:40:16:40:24 | resultStr | -| JsonpController.java:39:21:39:54 | ... + ... : String | JsonpController.java:40:16:40:24 | resultStr | -| JsonpController.java:47:32:47:68 | getParameter(...) : String | JsonpController.java:49:16:49:24 | resultStr | -| JsonpController.java:48:21:48:80 | ... + ... : String | JsonpController.java:49:16:49:24 | resultStr | -| JsonpController.java:56:32:56:68 | getParameter(...) : String | JsonpController.java:59:16:59:24 | resultStr | -| JsonpController.java:58:21:58:55 | ... + ... : String | JsonpController.java:59:16:59:24 | resultStr | -| JsonpController.java:66:32:66:68 | getParameter(...) : String | JsonpController.java:69:16:69:24 | resultStr | -| JsonpController.java:68:21:68:54 | ... + ... : String | JsonpController.java:69:16:69:24 | resultStr | -| JsonpController.java:76:32:76:68 | getParameter(...) : String | JsonpController.java:84:20:84:28 | resultStr | -| JsonpController.java:83:21:83:54 | ... + ... : String | JsonpController.java:84:20:84:28 | resultStr | -| JsonpController.java:91:32:91:68 | getParameter(...) : String | JsonpController.java:98:20:98:28 | resultStr | -| JsonpController.java:97:21:97:54 | ... + ... : String | JsonpController.java:98:20:98:28 | resultStr | -| JsonpController.java:105:32:105:68 | getParameter(...) : String | JsonpController.java:109:16:109:24 | resultStr | -| JsonpController.java:108:21:108:54 | ... + ... : String | JsonpController.java:109:16:109:24 | resultStr | -| JsonpController.java:117:24:117:52 | getParameter(...) : String | JsonpController.java:118:24:118:28 | token | -| JsonpController.java:119:36:119:72 | getParameter(...) : String | JsonpController.java:122:20:122:28 | resultStr | -| JsonpController.java:121:25:121:59 | ... + ... : String | JsonpController.java:122:20:122:28 | resultStr | -| JsonpController.java:132:24:132:52 | getParameter(...) : String | JsonpController.java:133:37:133:41 | token | -| JsonpController.java:137:32:137:68 | getParameter(...) : String | JsonpController.java:140:16:140:24 | resultStr | -| JsonpController.java:139:21:139:55 | ... + ... : String | JsonpController.java:140:16:140:24 | resultStr | -| JsonpController.java:150:21:150:54 | ... + ... : String | JsonpController.java:151:16:151:24 | resultStr | -| JsonpController.java:165:21:165:54 | ... + ... : String | JsonpController.java:166:16:166:24 | resultStr | +| JsonpController.java:33:32:33:68 | getParameter(...) : String | JsonpController.java:37:16:37:24 | resultStr | +| JsonpController.java:36:21:36:54 | ... + ... : String | JsonpController.java:37:16:37:24 | resultStr | +| JsonpController.java:44:32:44:68 | getParameter(...) : String | JsonpController.java:46:16:46:24 | resultStr | +| JsonpController.java:45:21:45:80 | ... + ... : String | JsonpController.java:46:16:46:24 | resultStr | +| JsonpController.java:53:32:53:68 | getParameter(...) : String | JsonpController.java:56:16:56:24 | resultStr | +| JsonpController.java:55:21:55:55 | ... + ... : String | JsonpController.java:56:16:56:24 | resultStr | +| JsonpController.java:63:32:63:68 | getParameter(...) : String | JsonpController.java:66:16:66:24 | resultStr | +| JsonpController.java:65:21:65:54 | ... + ... : String | JsonpController.java:66:16:66:24 | resultStr | +| JsonpController.java:73:32:73:68 | getParameter(...) : String | JsonpController.java:80:20:80:28 | resultStr | +| JsonpController.java:79:21:79:54 | ... + ... : String | JsonpController.java:80:20:80:28 | resultStr | +| JsonpController.java:87:32:87:68 | getParameter(...) : String | JsonpController.java:94:20:94:28 | resultStr | +| JsonpController.java:93:21:93:54 | ... + ... : String | JsonpController.java:94:20:94:28 | resultStr | +| JsonpController.java:101:32:101:68 | getParameter(...) : String | JsonpController.java:105:16:105:24 | resultStr | +| JsonpController.java:104:21:104:54 | ... + ... : String | JsonpController.java:105:16:105:24 | resultStr | +| JsonpController.java:114:32:114:68 | getParameter(...) : String | JsonpController.java:117:16:117:24 | resultStr | +| JsonpController.java:116:21:116:55 | ... + ... : String | JsonpController.java:117:16:117:24 | resultStr | +| JsonpController.java:127:36:127:72 | getParameter(...) : String | JsonpController.java:130:20:130:28 | resultStr | +| JsonpController.java:129:25:129:59 | ... + ... : String | JsonpController.java:130:20:130:28 | resultStr | +| JsonpController.java:145:32:145:68 | getParameter(...) : String | JsonpController.java:148:16:148:24 | resultStr | +| JsonpController.java:147:21:147:55 | ... + ... : String | JsonpController.java:148:16:148:24 | resultStr | +| JsonpController.java:158:21:158:54 | ... + ... : String | JsonpController.java:159:16:159:24 | resultStr | +| JsonpController.java:173:21:173:54 | ... + ... : String | JsonpController.java:174:16:174:24 | resultStr | | JsonpInjectionServlet1.java:31:32:31:64 | getParameter(...) : String | JsonpInjectionServlet1.java:45:24:45:32 | resultStr | -| JsonpInjectionServlet1.java:36:26:36:49 | getHeader(...) : String | JsonpInjectionServlet1.java:38:39:38:45 | referer | | JsonpInjectionServlet1.java:44:25:44:62 | ... + ... : String | JsonpInjectionServlet1.java:45:24:45:32 | resultStr | | JsonpInjectionServlet2.java:31:32:31:64 | getParameter(...) : String | JsonpInjectionServlet2.java:39:20:39:28 | resultStr | | JsonpInjectionServlet2.java:38:21:38:54 | ... + ... : String | JsonpInjectionServlet2.java:39:20:39:28 | resultStr | -| RefererFilter.java:22:26:22:53 | getHeader(...) : String | RefererFilter.java:23:39:23:45 | refefer | nodes -| JsonpController.java:36:32:36:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:39:21:39:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:40:16:40:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:40:16:40:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:47:32:47:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:48:21:48:80 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:49:16:49:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:49:16:49:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:56:32:56:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:58:21:58:55 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:59:16:59:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:59:16:59:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:66:32:66:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:68:21:68:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:69:16:69:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:69:16:69:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:76:32:76:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:83:21:83:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:84:20:84:28 | resultStr | semmle.label | resultStr | -| JsonpController.java:84:20:84:28 | resultStr | semmle.label | resultStr | -| JsonpController.java:91:32:91:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:97:21:97:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:98:20:98:28 | resultStr | semmle.label | resultStr | -| JsonpController.java:98:20:98:28 | resultStr | semmle.label | resultStr | -| JsonpController.java:105:32:105:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:108:21:108:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:109:16:109:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:109:16:109:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:117:24:117:52 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:118:24:118:28 | token | semmle.label | token | -| JsonpController.java:119:36:119:72 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:121:25:121:59 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:122:20:122:28 | resultStr | semmle.label | resultStr | -| JsonpController.java:122:20:122:28 | resultStr | semmle.label | resultStr | -| JsonpController.java:132:24:132:52 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:133:37:133:41 | token | semmle.label | token | -| JsonpController.java:137:32:137:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:139:21:139:55 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:140:16:140:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:140:16:140:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:150:21:150:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:151:16:151:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:165:21:165:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:166:16:166:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:33:32:33:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:36:21:36:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:37:16:37:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:37:16:37:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:44:32:44:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:45:21:45:80 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:46:16:46:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:46:16:46:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:53:32:53:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:55:21:55:55 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:56:16:56:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:56:16:56:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:63:32:63:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:65:21:65:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:66:16:66:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:66:16:66:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:73:32:73:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:79:21:79:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:80:20:80:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:80:20:80:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:87:32:87:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:93:21:93:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:94:20:94:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:94:20:94:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:101:32:101:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:104:21:104:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:105:16:105:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:105:16:105:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:114:32:114:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:116:21:116:55 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:117:16:117:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:117:16:117:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:127:36:127:72 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:129:25:129:59 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:130:20:130:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:130:20:130:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:145:32:145:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:147:21:147:55 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:148:16:148:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:148:16:148:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:158:21:158:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:159:16:159:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:173:21:173:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:174:16:174:24 | resultStr | semmle.label | resultStr | | JsonpInjectionServlet1.java:31:32:31:64 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpInjectionServlet1.java:36:26:36:49 | getHeader(...) : String | semmle.label | getHeader(...) : String | -| JsonpInjectionServlet1.java:38:39:38:45 | referer | semmle.label | referer | | JsonpInjectionServlet1.java:44:25:44:62 | ... + ... : String | semmle.label | ... + ... : String | | JsonpInjectionServlet1.java:45:24:45:32 | resultStr | semmle.label | resultStr | | JsonpInjectionServlet1.java:45:24:45:32 | resultStr | semmle.label | resultStr | @@ -82,6 +78,4 @@ nodes | JsonpInjectionServlet2.java:38:21:38:54 | ... + ... : String | semmle.label | ... + ... : String | | JsonpInjectionServlet2.java:39:20:39:28 | resultStr | semmle.label | resultStr | | JsonpInjectionServlet2.java:39:20:39:28 | resultStr | semmle.label | resultStr | -| RefererFilter.java:22:26:22:53 | getHeader(...) : String | semmle.label | getHeader(...) : String | -| RefererFilter.java:23:39:23:45 | refefer | semmle.label | refefer | #select diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringController/JsonpController.java b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringController/JsonpController.java index e5b5e70a38d..4c60b356cfb 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringController/JsonpController.java +++ b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringController/JsonpController.java @@ -26,9 +26,6 @@ public class JsonpController { hashMap.put("password","123456"); } - private String name = null; - - @GetMapping(value = "jsonp1") @ResponseBody public String bad1(HttpServletRequest request) { @@ -77,7 +74,6 @@ public class JsonpController { PrintWriter pw = null; Gson gson = new Gson(); String result = gson.toJson(hashMap); - String resultStr = null; pw = response.getWriter(); resultStr = jsonpCallback + "(" + result + ")"; @@ -109,13 +105,25 @@ public class JsonpController { return resultStr; } - @GetMapping(value = "jsonp8") @ResponseBody + public String bad8(HttpServletRequest request) { + String resultStr = null; + String token = request.getParameter("token"); + boolean result = verifToken(token); //Just check. + String jsonpCallback = request.getParameter("jsonpCallback"); + String jsonStr = getJsonStr(hashMap); + resultStr = jsonpCallback + "(" + jsonStr + ")"; + return resultStr; + } + + + @GetMapping(value = "jsonp9") + @ResponseBody public String good1(HttpServletRequest request) { String resultStr = null; - String token = request.getParameter("token"); - if (verifToken(token)){ + String referer = request.getParameter("referer"); + if (verifReferer(referer)){ String jsonpCallback = request.getParameter("jsonpCallback"); String jsonStr = getJsonStr(hashMap); resultStr = jsonpCallback + "(" + jsonStr + ")"; @@ -125,7 +133,7 @@ public class JsonpController { } - @GetMapping(value = "jsonp9") + @GetMapping(value = "jsonp10") @ResponseBody public String good2(HttpServletRequest request) { String resultStr = null; @@ -140,7 +148,7 @@ public class JsonpController { return resultStr; } - @RequestMapping(value = "jsonp10") + @RequestMapping(value = "jsonp11") @ResponseBody public String good3(HttpServletRequest request) { JSONObject parameterObj = readToJSONObect(request); @@ -151,7 +159,7 @@ public class JsonpController { return resultStr; } - @RequestMapping(value = "jsonp11") + @RequestMapping(value = "jsonp12") @ResponseBody public String good4(@RequestParam("file") MultipartFile file,HttpServletRequest request) { if(null == file){ @@ -200,4 +208,11 @@ public class JsonpController { } return true; } -} + + public static boolean verifReferer(String str){ + if (str != "xxxx"){ + return false; + } + return true; + } +} \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringController/JsonpInjection.expected b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringController/JsonpInjection.expected index 91d23cebbda..2e4bc97ff97 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringController/JsonpInjection.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringController/JsonpInjection.expected @@ -1,76 +1,77 @@ edges -| JsonpController.java:36:32:36:68 | getParameter(...) : String | JsonpController.java:40:16:40:24 | resultStr | -| JsonpController.java:39:21:39:54 | ... + ... : String | JsonpController.java:40:16:40:24 | resultStr | -| JsonpController.java:47:32:47:68 | getParameter(...) : String | JsonpController.java:49:16:49:24 | resultStr | -| JsonpController.java:48:21:48:80 | ... + ... : String | JsonpController.java:49:16:49:24 | resultStr | -| JsonpController.java:56:32:56:68 | getParameter(...) : String | JsonpController.java:59:16:59:24 | resultStr | -| JsonpController.java:58:21:58:55 | ... + ... : String | JsonpController.java:59:16:59:24 | resultStr | -| JsonpController.java:66:32:66:68 | getParameter(...) : String | JsonpController.java:69:16:69:24 | resultStr | -| JsonpController.java:68:21:68:54 | ... + ... : String | JsonpController.java:69:16:69:24 | resultStr | -| JsonpController.java:76:32:76:68 | getParameter(...) : String | JsonpController.java:84:20:84:28 | resultStr | -| JsonpController.java:83:21:83:54 | ... + ... : String | JsonpController.java:84:20:84:28 | resultStr | -| JsonpController.java:91:32:91:68 | getParameter(...) : String | JsonpController.java:98:20:98:28 | resultStr | -| JsonpController.java:97:21:97:54 | ... + ... : String | JsonpController.java:98:20:98:28 | resultStr | -| JsonpController.java:105:32:105:68 | getParameter(...) : String | JsonpController.java:109:16:109:24 | resultStr | -| JsonpController.java:108:21:108:54 | ... + ... : String | JsonpController.java:109:16:109:24 | resultStr | -| JsonpController.java:117:24:117:52 | getParameter(...) : String | JsonpController.java:118:24:118:28 | token | -| JsonpController.java:119:36:119:72 | getParameter(...) : String | JsonpController.java:122:20:122:28 | resultStr | -| JsonpController.java:121:25:121:59 | ... + ... : String | JsonpController.java:122:20:122:28 | resultStr | -| JsonpController.java:132:24:132:52 | getParameter(...) : String | JsonpController.java:133:37:133:41 | token | -| JsonpController.java:137:32:137:68 | getParameter(...) : String | JsonpController.java:140:16:140:24 | resultStr | -| JsonpController.java:139:21:139:55 | ... + ... : String | JsonpController.java:140:16:140:24 | resultStr | -| JsonpController.java:150:21:150:54 | ... + ... : String | JsonpController.java:151:16:151:24 | resultStr | -| JsonpController.java:165:21:165:54 | ... + ... : String | JsonpController.java:166:16:166:24 | resultStr | +| JsonpController.java:33:32:33:68 | getParameter(...) : String | JsonpController.java:37:16:37:24 | resultStr | +| JsonpController.java:36:21:36:54 | ... + ... : String | JsonpController.java:37:16:37:24 | resultStr | +| JsonpController.java:44:32:44:68 | getParameter(...) : String | JsonpController.java:46:16:46:24 | resultStr | +| JsonpController.java:45:21:45:80 | ... + ... : String | JsonpController.java:46:16:46:24 | resultStr | +| JsonpController.java:53:32:53:68 | getParameter(...) : String | JsonpController.java:56:16:56:24 | resultStr | +| JsonpController.java:55:21:55:55 | ... + ... : String | JsonpController.java:56:16:56:24 | resultStr | +| JsonpController.java:63:32:63:68 | getParameter(...) : String | JsonpController.java:66:16:66:24 | resultStr | +| JsonpController.java:65:21:65:54 | ... + ... : String | JsonpController.java:66:16:66:24 | resultStr | +| JsonpController.java:73:32:73:68 | getParameter(...) : String | JsonpController.java:80:20:80:28 | resultStr | +| JsonpController.java:79:21:79:54 | ... + ... : String | JsonpController.java:80:20:80:28 | resultStr | +| JsonpController.java:87:32:87:68 | getParameter(...) : String | JsonpController.java:94:20:94:28 | resultStr | +| JsonpController.java:93:21:93:54 | ... + ... : String | JsonpController.java:94:20:94:28 | resultStr | +| JsonpController.java:101:32:101:68 | getParameter(...) : String | JsonpController.java:105:16:105:24 | resultStr | +| JsonpController.java:104:21:104:54 | ... + ... : String | JsonpController.java:105:16:105:24 | resultStr | +| JsonpController.java:114:32:114:68 | getParameter(...) : String | JsonpController.java:117:16:117:24 | resultStr | +| JsonpController.java:116:21:116:55 | ... + ... : String | JsonpController.java:117:16:117:24 | resultStr | +| JsonpController.java:127:36:127:72 | getParameter(...) : String | JsonpController.java:130:20:130:28 | resultStr | +| JsonpController.java:129:25:129:59 | ... + ... : String | JsonpController.java:130:20:130:28 | resultStr | +| JsonpController.java:145:32:145:68 | getParameter(...) : String | JsonpController.java:148:16:148:24 | resultStr | +| JsonpController.java:147:21:147:55 | ... + ... : String | JsonpController.java:148:16:148:24 | resultStr | +| JsonpController.java:158:21:158:54 | ... + ... : String | JsonpController.java:159:16:159:24 | resultStr | +| JsonpController.java:173:21:173:54 | ... + ... : String | JsonpController.java:174:16:174:24 | resultStr | nodes -| JsonpController.java:36:32:36:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:39:21:39:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:40:16:40:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:40:16:40:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:47:32:47:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:48:21:48:80 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:49:16:49:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:49:16:49:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:56:32:56:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:58:21:58:55 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:59:16:59:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:59:16:59:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:66:32:66:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:68:21:68:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:69:16:69:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:69:16:69:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:76:32:76:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:83:21:83:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:84:20:84:28 | resultStr | semmle.label | resultStr | -| JsonpController.java:84:20:84:28 | resultStr | semmle.label | resultStr | -| JsonpController.java:91:32:91:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:97:21:97:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:98:20:98:28 | resultStr | semmle.label | resultStr | -| JsonpController.java:98:20:98:28 | resultStr | semmle.label | resultStr | -| JsonpController.java:105:32:105:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:108:21:108:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:109:16:109:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:109:16:109:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:117:24:117:52 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:118:24:118:28 | token | semmle.label | token | -| JsonpController.java:119:36:119:72 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:121:25:121:59 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:122:20:122:28 | resultStr | semmle.label | resultStr | -| JsonpController.java:122:20:122:28 | resultStr | semmle.label | resultStr | -| JsonpController.java:132:24:132:52 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:133:37:133:41 | token | semmle.label | token | -| JsonpController.java:137:32:137:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:139:21:139:55 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:140:16:140:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:140:16:140:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:150:21:150:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:151:16:151:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:165:21:165:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:166:16:166:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:33:32:33:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:36:21:36:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:37:16:37:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:37:16:37:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:44:32:44:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:45:21:45:80 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:46:16:46:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:46:16:46:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:53:32:53:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:55:21:55:55 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:56:16:56:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:56:16:56:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:63:32:63:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:65:21:65:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:66:16:66:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:66:16:66:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:73:32:73:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:79:21:79:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:80:20:80:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:80:20:80:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:87:32:87:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:93:21:93:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:94:20:94:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:94:20:94:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:101:32:101:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:104:21:104:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:105:16:105:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:105:16:105:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:114:32:114:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:116:21:116:55 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:117:16:117:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:117:16:117:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:127:36:127:72 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:129:25:129:59 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:130:20:130:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:130:20:130:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:145:32:145:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:147:21:147:55 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:148:16:148:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:148:16:148:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:158:21:158:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:159:16:159:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:173:21:173:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:174:16:174:24 | resultStr | semmle.label | resultStr | #select -| JsonpController.java:40:16:40:24 | resultStr | JsonpController.java:36:32:36:68 | getParameter(...) : String | JsonpController.java:40:16:40:24 | resultStr | Jsonp response might include code from $@. | JsonpController.java:36:32:36:68 | getParameter(...) | this user input | -| JsonpController.java:49:16:49:24 | resultStr | JsonpController.java:47:32:47:68 | getParameter(...) : String | JsonpController.java:49:16:49:24 | resultStr | Jsonp response might include code from $@. | JsonpController.java:47:32:47:68 | getParameter(...) | this user input | -| JsonpController.java:59:16:59:24 | resultStr | JsonpController.java:56:32:56:68 | getParameter(...) : String | JsonpController.java:59:16:59:24 | resultStr | Jsonp response might include code from $@. | JsonpController.java:56:32:56:68 | getParameter(...) | this user input | -| JsonpController.java:69:16:69:24 | resultStr | JsonpController.java:66:32:66:68 | getParameter(...) : String | JsonpController.java:69:16:69:24 | resultStr | Jsonp response might include code from $@. | JsonpController.java:66:32:66:68 | getParameter(...) | this user input | -| JsonpController.java:84:20:84:28 | resultStr | JsonpController.java:76:32:76:68 | getParameter(...) : String | JsonpController.java:84:20:84:28 | resultStr | Jsonp response might include code from $@. | JsonpController.java:76:32:76:68 | getParameter(...) | this user input | -| JsonpController.java:98:20:98:28 | resultStr | JsonpController.java:91:32:91:68 | getParameter(...) : String | JsonpController.java:98:20:98:28 | resultStr | Jsonp response might include code from $@. | JsonpController.java:91:32:91:68 | getParameter(...) | this user input | -| JsonpController.java:109:16:109:24 | resultStr | JsonpController.java:105:32:105:68 | getParameter(...) : String | JsonpController.java:109:16:109:24 | resultStr | Jsonp response might include code from $@. | JsonpController.java:105:32:105:68 | getParameter(...) | this user input | +| JsonpController.java:37:16:37:24 | resultStr | JsonpController.java:33:32:33:68 | getParameter(...) : String | JsonpController.java:37:16:37:24 | resultStr | Jsonp response might include code from $@. | JsonpController.java:33:32:33:68 | getParameter(...) | this user input | +| JsonpController.java:46:16:46:24 | resultStr | JsonpController.java:44:32:44:68 | getParameter(...) : String | JsonpController.java:46:16:46:24 | resultStr | Jsonp response might include code from $@. | JsonpController.java:44:32:44:68 | getParameter(...) | this user input | +| JsonpController.java:56:16:56:24 | resultStr | JsonpController.java:53:32:53:68 | getParameter(...) : String | JsonpController.java:56:16:56:24 | resultStr | Jsonp response might include code from $@. | JsonpController.java:53:32:53:68 | getParameter(...) | this user input | +| JsonpController.java:66:16:66:24 | resultStr | JsonpController.java:63:32:63:68 | getParameter(...) : String | JsonpController.java:66:16:66:24 | resultStr | Jsonp response might include code from $@. | JsonpController.java:63:32:63:68 | getParameter(...) | this user input | +| JsonpController.java:80:20:80:28 | resultStr | JsonpController.java:73:32:73:68 | getParameter(...) : String | JsonpController.java:80:20:80:28 | resultStr | Jsonp response might include code from $@. | JsonpController.java:73:32:73:68 | getParameter(...) | this user input | +| JsonpController.java:94:20:94:28 | resultStr | JsonpController.java:87:32:87:68 | getParameter(...) : String | JsonpController.java:94:20:94:28 | resultStr | Jsonp response might include code from $@. | JsonpController.java:87:32:87:68 | getParameter(...) | this user input | +| JsonpController.java:105:16:105:24 | resultStr | JsonpController.java:101:32:101:68 | getParameter(...) : String | JsonpController.java:105:16:105:24 | resultStr | Jsonp response might include code from $@. | JsonpController.java:101:32:101:68 | getParameter(...) | this user input | +| JsonpController.java:117:16:117:24 | resultStr | JsonpController.java:114:32:114:68 | getParameter(...) : String | JsonpController.java:117:16:117:24 | resultStr | Jsonp response might include code from $@. | JsonpController.java:114:32:114:68 | getParameter(...) | this user input | diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringControllerAndServlet/JsonpController.java b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringControllerAndServlet/JsonpController.java index e5b5e70a38d..4c60b356cfb 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringControllerAndServlet/JsonpController.java +++ b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringControllerAndServlet/JsonpController.java @@ -26,9 +26,6 @@ public class JsonpController { hashMap.put("password","123456"); } - private String name = null; - - @GetMapping(value = "jsonp1") @ResponseBody public String bad1(HttpServletRequest request) { @@ -77,7 +74,6 @@ public class JsonpController { PrintWriter pw = null; Gson gson = new Gson(); String result = gson.toJson(hashMap); - String resultStr = null; pw = response.getWriter(); resultStr = jsonpCallback + "(" + result + ")"; @@ -109,13 +105,25 @@ public class JsonpController { return resultStr; } - @GetMapping(value = "jsonp8") @ResponseBody + public String bad8(HttpServletRequest request) { + String resultStr = null; + String token = request.getParameter("token"); + boolean result = verifToken(token); //Just check. + String jsonpCallback = request.getParameter("jsonpCallback"); + String jsonStr = getJsonStr(hashMap); + resultStr = jsonpCallback + "(" + jsonStr + ")"; + return resultStr; + } + + + @GetMapping(value = "jsonp9") + @ResponseBody public String good1(HttpServletRequest request) { String resultStr = null; - String token = request.getParameter("token"); - if (verifToken(token)){ + String referer = request.getParameter("referer"); + if (verifReferer(referer)){ String jsonpCallback = request.getParameter("jsonpCallback"); String jsonStr = getJsonStr(hashMap); resultStr = jsonpCallback + "(" + jsonStr + ")"; @@ -125,7 +133,7 @@ public class JsonpController { } - @GetMapping(value = "jsonp9") + @GetMapping(value = "jsonp10") @ResponseBody public String good2(HttpServletRequest request) { String resultStr = null; @@ -140,7 +148,7 @@ public class JsonpController { return resultStr; } - @RequestMapping(value = "jsonp10") + @RequestMapping(value = "jsonp11") @ResponseBody public String good3(HttpServletRequest request) { JSONObject parameterObj = readToJSONObect(request); @@ -151,7 +159,7 @@ public class JsonpController { return resultStr; } - @RequestMapping(value = "jsonp11") + @RequestMapping(value = "jsonp12") @ResponseBody public String good4(@RequestParam("file") MultipartFile file,HttpServletRequest request) { if(null == file){ @@ -200,4 +208,11 @@ public class JsonpController { } return true; } -} + + public static boolean verifReferer(String str){ + if (str != "xxxx"){ + return false; + } + return true; + } +} \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringControllerAndServlet/JsonpInjection.expected b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringControllerAndServlet/JsonpInjection.expected index c2bcab77d4d..d90d51ab552 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringControllerAndServlet/JsonpInjection.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjectionWithSpringControllerAndServlet/JsonpInjection.expected @@ -1,79 +1,76 @@ edges -| JsonpController.java:36:32:36:68 | getParameter(...) : String | JsonpController.java:40:16:40:24 | resultStr | -| JsonpController.java:39:21:39:54 | ... + ... : String | JsonpController.java:40:16:40:24 | resultStr | -| JsonpController.java:47:32:47:68 | getParameter(...) : String | JsonpController.java:49:16:49:24 | resultStr | -| JsonpController.java:48:21:48:80 | ... + ... : String | JsonpController.java:49:16:49:24 | resultStr | -| JsonpController.java:56:32:56:68 | getParameter(...) : String | JsonpController.java:59:16:59:24 | resultStr | -| JsonpController.java:58:21:58:55 | ... + ... : String | JsonpController.java:59:16:59:24 | resultStr | -| JsonpController.java:66:32:66:68 | getParameter(...) : String | JsonpController.java:69:16:69:24 | resultStr | -| JsonpController.java:68:21:68:54 | ... + ... : String | JsonpController.java:69:16:69:24 | resultStr | -| JsonpController.java:76:32:76:68 | getParameter(...) : String | JsonpController.java:84:20:84:28 | resultStr | -| JsonpController.java:83:21:83:54 | ... + ... : String | JsonpController.java:84:20:84:28 | resultStr | -| JsonpController.java:91:32:91:68 | getParameter(...) : String | JsonpController.java:98:20:98:28 | resultStr | -| JsonpController.java:97:21:97:54 | ... + ... : String | JsonpController.java:98:20:98:28 | resultStr | -| JsonpController.java:105:32:105:68 | getParameter(...) : String | JsonpController.java:109:16:109:24 | resultStr | -| JsonpController.java:108:21:108:54 | ... + ... : String | JsonpController.java:109:16:109:24 | resultStr | -| JsonpController.java:117:24:117:52 | getParameter(...) : String | JsonpController.java:118:24:118:28 | token | -| JsonpController.java:119:36:119:72 | getParameter(...) : String | JsonpController.java:122:20:122:28 | resultStr | -| JsonpController.java:121:25:121:59 | ... + ... : String | JsonpController.java:122:20:122:28 | resultStr | -| JsonpController.java:132:24:132:52 | getParameter(...) : String | JsonpController.java:133:37:133:41 | token | -| JsonpController.java:137:32:137:68 | getParameter(...) : String | JsonpController.java:140:16:140:24 | resultStr | -| JsonpController.java:139:21:139:55 | ... + ... : String | JsonpController.java:140:16:140:24 | resultStr | -| JsonpController.java:150:21:150:54 | ... + ... : String | JsonpController.java:151:16:151:24 | resultStr | -| JsonpController.java:165:21:165:54 | ... + ... : String | JsonpController.java:166:16:166:24 | resultStr | +| JsonpController.java:33:32:33:68 | getParameter(...) : String | JsonpController.java:37:16:37:24 | resultStr | +| JsonpController.java:36:21:36:54 | ... + ... : String | JsonpController.java:37:16:37:24 | resultStr | +| JsonpController.java:44:32:44:68 | getParameter(...) : String | JsonpController.java:46:16:46:24 | resultStr | +| JsonpController.java:45:21:45:80 | ... + ... : String | JsonpController.java:46:16:46:24 | resultStr | +| JsonpController.java:53:32:53:68 | getParameter(...) : String | JsonpController.java:56:16:56:24 | resultStr | +| JsonpController.java:55:21:55:55 | ... + ... : String | JsonpController.java:56:16:56:24 | resultStr | +| JsonpController.java:63:32:63:68 | getParameter(...) : String | JsonpController.java:66:16:66:24 | resultStr | +| JsonpController.java:65:21:65:54 | ... + ... : String | JsonpController.java:66:16:66:24 | resultStr | +| JsonpController.java:73:32:73:68 | getParameter(...) : String | JsonpController.java:80:20:80:28 | resultStr | +| JsonpController.java:79:21:79:54 | ... + ... : String | JsonpController.java:80:20:80:28 | resultStr | +| JsonpController.java:87:32:87:68 | getParameter(...) : String | JsonpController.java:94:20:94:28 | resultStr | +| JsonpController.java:93:21:93:54 | ... + ... : String | JsonpController.java:94:20:94:28 | resultStr | +| JsonpController.java:101:32:101:68 | getParameter(...) : String | JsonpController.java:105:16:105:24 | resultStr | +| JsonpController.java:104:21:104:54 | ... + ... : String | JsonpController.java:105:16:105:24 | resultStr | +| JsonpController.java:114:32:114:68 | getParameter(...) : String | JsonpController.java:117:16:117:24 | resultStr | +| JsonpController.java:116:21:116:55 | ... + ... : String | JsonpController.java:117:16:117:24 | resultStr | +| JsonpController.java:127:36:127:72 | getParameter(...) : String | JsonpController.java:130:20:130:28 | resultStr | +| JsonpController.java:129:25:129:59 | ... + ... : String | JsonpController.java:130:20:130:28 | resultStr | +| JsonpController.java:145:32:145:68 | getParameter(...) : String | JsonpController.java:148:16:148:24 | resultStr | +| JsonpController.java:147:21:147:55 | ... + ... : String | JsonpController.java:148:16:148:24 | resultStr | +| JsonpController.java:158:21:158:54 | ... + ... : String | JsonpController.java:159:16:159:24 | resultStr | +| JsonpController.java:173:21:173:54 | ... + ... : String | JsonpController.java:174:16:174:24 | resultStr | | JsonpInjectionServlet1.java:31:32:31:64 | getParameter(...) : String | JsonpInjectionServlet1.java:45:24:45:32 | resultStr | -| JsonpInjectionServlet1.java:36:26:36:49 | getHeader(...) : String | JsonpInjectionServlet1.java:38:39:38:45 | referer | | JsonpInjectionServlet1.java:44:25:44:62 | ... + ... : String | JsonpInjectionServlet1.java:45:24:45:32 | resultStr | | JsonpInjectionServlet2.java:31:32:31:64 | getParameter(...) : String | JsonpInjectionServlet2.java:39:20:39:28 | resultStr | | JsonpInjectionServlet2.java:38:21:38:54 | ... + ... : String | JsonpInjectionServlet2.java:39:20:39:28 | resultStr | nodes -| JsonpController.java:36:32:36:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:39:21:39:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:40:16:40:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:40:16:40:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:47:32:47:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:48:21:48:80 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:49:16:49:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:49:16:49:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:56:32:56:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:58:21:58:55 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:59:16:59:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:59:16:59:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:66:32:66:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:68:21:68:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:69:16:69:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:69:16:69:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:76:32:76:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:83:21:83:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:84:20:84:28 | resultStr | semmle.label | resultStr | -| JsonpController.java:84:20:84:28 | resultStr | semmle.label | resultStr | -| JsonpController.java:91:32:91:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:97:21:97:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:98:20:98:28 | resultStr | semmle.label | resultStr | -| JsonpController.java:98:20:98:28 | resultStr | semmle.label | resultStr | -| JsonpController.java:105:32:105:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:108:21:108:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:109:16:109:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:109:16:109:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:117:24:117:52 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:118:24:118:28 | token | semmle.label | token | -| JsonpController.java:119:36:119:72 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:121:25:121:59 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:122:20:122:28 | resultStr | semmle.label | resultStr | -| JsonpController.java:122:20:122:28 | resultStr | semmle.label | resultStr | -| JsonpController.java:132:24:132:52 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:133:37:133:41 | token | semmle.label | token | -| JsonpController.java:137:32:137:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpController.java:139:21:139:55 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:140:16:140:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:140:16:140:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:150:21:150:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:151:16:151:24 | resultStr | semmle.label | resultStr | -| JsonpController.java:165:21:165:54 | ... + ... : String | semmle.label | ... + ... : String | -| JsonpController.java:166:16:166:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:33:32:33:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:36:21:36:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:37:16:37:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:37:16:37:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:44:32:44:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:45:21:45:80 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:46:16:46:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:46:16:46:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:53:32:53:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:55:21:55:55 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:56:16:56:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:56:16:56:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:63:32:63:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:65:21:65:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:66:16:66:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:66:16:66:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:73:32:73:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:79:21:79:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:80:20:80:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:80:20:80:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:87:32:87:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:93:21:93:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:94:20:94:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:94:20:94:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:101:32:101:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:104:21:104:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:105:16:105:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:105:16:105:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:114:32:114:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:116:21:116:55 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:117:16:117:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:117:16:117:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:127:36:127:72 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:129:25:129:59 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:130:20:130:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:130:20:130:28 | resultStr | semmle.label | resultStr | +| JsonpController.java:145:32:145:68 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JsonpController.java:147:21:147:55 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:148:16:148:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:148:16:148:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:158:21:158:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:159:16:159:24 | resultStr | semmle.label | resultStr | +| JsonpController.java:173:21:173:54 | ... + ... : String | semmle.label | ... + ... : String | +| JsonpController.java:174:16:174:24 | resultStr | semmle.label | resultStr | | JsonpInjectionServlet1.java:31:32:31:64 | getParameter(...) : String | semmle.label | getParameter(...) : String | -| JsonpInjectionServlet1.java:36:26:36:49 | getHeader(...) : String | semmle.label | getHeader(...) : String | -| JsonpInjectionServlet1.java:38:39:38:45 | referer | semmle.label | referer | | JsonpInjectionServlet1.java:44:25:44:62 | ... + ... : String | semmle.label | ... + ... : String | | JsonpInjectionServlet1.java:45:24:45:32 | resultStr | semmle.label | resultStr | | JsonpInjectionServlet1.java:45:24:45:32 | resultStr | semmle.label | resultStr | @@ -82,11 +79,12 @@ nodes | JsonpInjectionServlet2.java:39:20:39:28 | resultStr | semmle.label | resultStr | | JsonpInjectionServlet2.java:39:20:39:28 | resultStr | semmle.label | resultStr | #select -| JsonpController.java:40:16:40:24 | resultStr | JsonpController.java:36:32:36:68 | getParameter(...) : String | JsonpController.java:40:16:40:24 | resultStr | Jsonp response might include code from $@. | JsonpController.java:36:32:36:68 | getParameter(...) | this user input | -| JsonpController.java:49:16:49:24 | resultStr | JsonpController.java:47:32:47:68 | getParameter(...) : String | JsonpController.java:49:16:49:24 | resultStr | Jsonp response might include code from $@. | JsonpController.java:47:32:47:68 | getParameter(...) | this user input | -| JsonpController.java:59:16:59:24 | resultStr | JsonpController.java:56:32:56:68 | getParameter(...) : String | JsonpController.java:59:16:59:24 | resultStr | Jsonp response might include code from $@. | JsonpController.java:56:32:56:68 | getParameter(...) | this user input | -| JsonpController.java:69:16:69:24 | resultStr | JsonpController.java:66:32:66:68 | getParameter(...) : String | JsonpController.java:69:16:69:24 | resultStr | Jsonp response might include code from $@. | JsonpController.java:66:32:66:68 | getParameter(...) | this user input | -| JsonpController.java:84:20:84:28 | resultStr | JsonpController.java:76:32:76:68 | getParameter(...) : String | JsonpController.java:84:20:84:28 | resultStr | Jsonp response might include code from $@. | JsonpController.java:76:32:76:68 | getParameter(...) | this user input | -| JsonpController.java:98:20:98:28 | resultStr | JsonpController.java:91:32:91:68 | getParameter(...) : String | JsonpController.java:98:20:98:28 | resultStr | Jsonp response might include code from $@. | JsonpController.java:91:32:91:68 | getParameter(...) | this user input | -| JsonpController.java:109:16:109:24 | resultStr | JsonpController.java:105:32:105:68 | getParameter(...) : String | JsonpController.java:109:16:109:24 | resultStr | Jsonp response might include code from $@. | JsonpController.java:105:32:105:68 | getParameter(...) | this user input | +| JsonpController.java:37:16:37:24 | resultStr | JsonpController.java:33:32:33:68 | getParameter(...) : String | JsonpController.java:37:16:37:24 | resultStr | Jsonp response might include code from $@. | JsonpController.java:33:32:33:68 | getParameter(...) | this user input | +| JsonpController.java:46:16:46:24 | resultStr | JsonpController.java:44:32:44:68 | getParameter(...) : String | JsonpController.java:46:16:46:24 | resultStr | Jsonp response might include code from $@. | JsonpController.java:44:32:44:68 | getParameter(...) | this user input | +| JsonpController.java:56:16:56:24 | resultStr | JsonpController.java:53:32:53:68 | getParameter(...) : String | JsonpController.java:56:16:56:24 | resultStr | Jsonp response might include code from $@. | JsonpController.java:53:32:53:68 | getParameter(...) | this user input | +| JsonpController.java:66:16:66:24 | resultStr | JsonpController.java:63:32:63:68 | getParameter(...) : String | JsonpController.java:66:16:66:24 | resultStr | Jsonp response might include code from $@. | JsonpController.java:63:32:63:68 | getParameter(...) | this user input | +| JsonpController.java:80:20:80:28 | resultStr | JsonpController.java:73:32:73:68 | getParameter(...) : String | JsonpController.java:80:20:80:28 | resultStr | Jsonp response might include code from $@. | JsonpController.java:73:32:73:68 | getParameter(...) | this user input | +| JsonpController.java:94:20:94:28 | resultStr | JsonpController.java:87:32:87:68 | getParameter(...) : String | JsonpController.java:94:20:94:28 | resultStr | Jsonp response might include code from $@. | JsonpController.java:87:32:87:68 | getParameter(...) | this user input | +| JsonpController.java:105:16:105:24 | resultStr | JsonpController.java:101:32:101:68 | getParameter(...) : String | JsonpController.java:105:16:105:24 | resultStr | Jsonp response might include code from $@. | JsonpController.java:101:32:101:68 | getParameter(...) | this user input | +| JsonpController.java:117:16:117:24 | resultStr | JsonpController.java:114:32:114:68 | getParameter(...) : String | JsonpController.java:117:16:117:24 | resultStr | Jsonp response might include code from $@. | JsonpController.java:114:32:114:68 | getParameter(...) | this user input | | JsonpInjectionServlet2.java:39:20:39:28 | resultStr | JsonpInjectionServlet2.java:31:32:31:64 | getParameter(...) : String | JsonpInjectionServlet2.java:39:20:39:28 | resultStr | Jsonp response might include code from $@. | JsonpInjectionServlet2.java:31:32:31:64 | getParameter(...) | this user input | From 88fee2748e773c296cc8f03a1c08d05e8b026d2c Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 29 Mar 2021 11:21:03 +0100 Subject: [PATCH 417/725] JS: Add change note --- javascript/change-notes/2021-03-29-misc-steps.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 javascript/change-notes/2021-03-29-misc-steps.md diff --git a/javascript/change-notes/2021-03-29-misc-steps.md b/javascript/change-notes/2021-03-29-misc-steps.md new file mode 100644 index 00000000000..02617ae056b --- /dev/null +++ b/javascript/change-notes/2021-03-29-misc-steps.md @@ -0,0 +1,6 @@ +lgtm,codescanning +* The `lodash-es` package is now recognized as a variant of `lodash`. +* Taint is now propagated through the `babel.transform` function. +* Improved data flow through React applications using `redux-form` or `react-router`. +* Base64 decoding using the `react-native-base64` package is now recognized. +* An expression of form `o[o.length] = y` is now recognized as appending to an array. From 149af57eac375df54c30068ae99f192109c36817 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 25 Mar 2021 16:14:53 +0000 Subject: [PATCH 418/725] JS: Add model of pg-promise --- .../src/semmle/javascript/frameworks/SQL.qll | 141 ++++++++++++++++-- .../CWE-089/untyped/DatabaseAccesses.expected | 18 +++ .../CWE-089/untyped/SqlInjection.expected | 121 +++++++++++++++ .../Security/CWE-089/untyped/pg-promise.js | 59 ++++++++ 4 files changed, 329 insertions(+), 10 deletions(-) create mode 100644 javascript/ql/test/query-tests/Security/CWE-089/untyped/pg-promise.js diff --git a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll index c94750e5b3d..aab5a380b8d 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll @@ -96,8 +96,14 @@ private module MySql { * Provides classes modelling the `pg` package. */ private module Postgres { + API::Node pg() { + result = API::moduleImport("pg") + or + result = pgpMain().getMember("pg") + } + /** Gets a reference to the `Client` constructor in the `pg` package, for example `require('pg').Client`. */ - API::Node newClient() { result = API::moduleImport("pg").getMember("Client") } + API::Node newClient() { result = pg().getMember("Client") } /** Gets a freshly created Postgres client instance. */ API::Node client() { @@ -105,19 +111,25 @@ private module Postgres { or // pool.connect(function(err, client) { ... }) result = pool().getMember("connect").getParameter(0).getParameter(1) + or + result = pgpConnection().getMember("client") } /** Gets a constructor that when invoked constructs a new connection pool. */ API::Node newPool() { // new require('pg').Pool() - result = API::moduleImport("pg").getMember("Pool") + result = pg().getMember("Pool") or // new require('pg-pool') result = API::moduleImport("pg-pool") } - /** Gets an expression that constructs a new connection pool. */ - API::Node pool() { result = newPool().getInstance() } + /** Gets an API node that refers to a connection pool. */ + API::Node pool() { + result = newPool().getInstance() + or + result = pgpDatabase().getMember("$pool") + } /** A call to the Postgres `query` method. */ private class QueryCall extends DatabaseAccess, DataFlow::MethodCallNode { @@ -137,17 +149,126 @@ private module Postgres { Credentials() { exists(string prop | - this = [newClient(), newPool()].getParameter(0).getMember(prop).getARhs().asExpr() and - ( - prop = "user" and kind = "user name" - or - prop = "password" and kind = prop - ) + this = [newClient(), newPool()].getParameter(0).getMember(prop).getARhs().asExpr() + or + this = pgPromise().getParameter(0).getMember(prop).getARhs().asExpr() + | + prop = "user" and kind = "user name" + or + prop = "password" and kind = prop ) } override string getCredentialsKind() { result = kind } } + + /** Gets a node referring to the `pg-promise` library (which is not itself a Promise). */ + API::Node pgPromise() { result = API::moduleImport("pg-promise") } + + /** Gets an initialized `pg-promise` library. */ + API::Node pgpMain() { result = pgPromise().getReturn() } + + /** Gets a database from `pg-promise`. */ + API::Node pgpDatabase() { result = pgpMain().getReturn() } + + /** Gets a connection created from a `pg-promise` database. */ + API::Node pgpConnection() { + result = pgpDatabase().getMember("connect").getReturn().getPromised() + } + + /** Gets a `pg-promise` task object. */ + API::Node pgpTask() { + exists(API::Node taskMethod | + taskMethod = pgpObject().getMember(["task", "taskIf", "tx", "txIf"]) + | + result = taskMethod.getParameter([0, 1]).getParameter(0) + or + result = taskMethod.getParameter(0).getMember("cnd").getParameter(0) + ) + } + + /** Gets a `pg-promise` object which supports querying (database, connection, or task). */ + API::Node pgpObject() { result = [pgpDatabase(), pgpConnection(), pgpTask()] } + + private string pgpQueryMethodName() { + result = + [ + "any", "each", "many", "manyOrNone", "map", "multi", "multiResult", "none", "one", + "oneOrNone", "query", "result" + ] + } + + /** A call that executes a SQL query via `pg-promise`. */ + private class PgPromiseQueryCall extends DatabaseAccess, DataFlow::MethodCallNode { + PgPromiseQueryCall() { this = pgpObject().getMember(pgpQueryMethodName()).getACall() } + + /** Gets an argument interpreted as a SQL string, not including raw interpolation variables. */ + private DataFlow::Node getADirectQueryArgument() { + result = getArgument(0) + or + result = getOptionArgument(0, "text") + } + + /** + * Gets an interpolation parameter whose value is interpreted literally, or is not escaped appropriately for its context. + * + * For example, the following are raw placeholders: $1:raw, $1^, ${prop}:raw, $(prop)^ + */ + private string getARawParameterName() { + exists(string sqlString, string placeholderRegexp, string regexp | + placeholderRegexp = "\\$(\\d+|[{(\\[/]\\w+[})\\]/])" and // For example: $1 or ${prop} + sqlString = getADirectQueryArgument().getStringValue() + | + // Match $1:raw or ${prop}:raw + regexp = placeholderRegexp + "(:raw|\\^)" and + result = + sqlString + .regexpFind(regexp, _, _) + .regexpCapture(regexp, 1) + .regexpReplaceAll("[^\\w\\d]", "") + or + // Match $1:value or ${prop}:value unless enclosed by single quotes (:value prevents breaking out of single quotes) + regexp = placeholderRegexp + "(:value|\\#)" and + result = + sqlString + .regexpReplaceAll("'[^']*'", "''") + .regexpFind(regexp, _, _) + .regexpCapture(regexp, 1) + .regexpReplaceAll("[^\\w\\d]", "") + ) + } + + /** Gets the argument holding the values to plug into placeholders. */ + private DataFlow::Node getValues() { + result = getArgument(1) + or + result = getOptionArgument(0, "values") + } + + /** Gets a value that is plugged into a raw placeholder variable, making it a sink for SQL injection. */ + private DataFlow::Node getARawValue() { + result = getValues() and getARawParameterName() = "1" // Special case: if the argument is not an array or object, it's just plugged into $1 + or + exists(DataFlow::SourceNode values | values = getValues().getALocalSource() | + result = values.getAPropertyWrite(getARawParameterName()).getRhs() + or + // Array literals do not have PropWrites with property names so handle them separately, + // and also translate to 0-based indexing. + result = values.(DataFlow::ArrayCreationNode).getElement(getARawParameterName().toInt() - 1) + ) + } + + override DataFlow::Node getAQueryArgument() { + result = getADirectQueryArgument() + or + result = getARawValue() + } + } + + /** An expression that is interpreted as SQL by `pg-promise`. */ + class PgPromiseQueryString extends SQL::SqlString { + PgPromiseQueryString() { this = any(PgPromiseQueryCall qc).getAQueryArgument().asExpr() } + } } /** diff --git a/javascript/ql/test/query-tests/Security/CWE-089/untyped/DatabaseAccesses.expected b/javascript/ql/test/query-tests/Security/CWE-089/untyped/DatabaseAccesses.expected index 5bf367a4c18..85629ac69db 100644 --- a/javascript/ql/test/query-tests/Security/CWE-089/untyped/DatabaseAccesses.expected +++ b/javascript/ql/test/query-tests/Security/CWE-089/untyped/DatabaseAccesses.expected @@ -37,6 +37,24 @@ | mongoose.js:97:2:97:52 | Documen ... query)) | | mongoose.js:99:2:99:50 | Documen ... query)) | | mongoose.js:113:2:113:53 | Documen ... () { }) | +| pg-promise.js:9:3:9:15 | db.any(query) | +| pg-promise.js:10:3:10:16 | db.many(query) | +| pg-promise.js:11:3:11:22 | db.manyOrNone(query) | +| pg-promise.js:12:3:12:15 | db.map(query) | +| pg-promise.js:13:3:13:17 | db.multi(query) | +| pg-promise.js:14:3:14:23 | db.mult ... (query) | +| pg-promise.js:15:3:15:16 | db.none(query) | +| pg-promise.js:16:3:16:15 | db.one(query) | +| pg-promise.js:17:3:17:21 | db.oneOrNone(query) | +| pg-promise.js:18:3:18:17 | db.query(query) | +| pg-promise.js:19:3:19:18 | db.result(query) | +| pg-promise.js:21:3:23:4 | db.one( ... OK\\n }) | +| pg-promise.js:24:3:27:4 | db.one( ... OK\\n }) | +| pg-promise.js:28:3:31:4 | db.one( ... er\\n }) | +| pg-promise.js:32:3:35:4 | db.one( ... OK\\n }) | +| pg-promise.js:36:3:43:4 | db.one( ... ]\\n }) | +| pg-promise.js:44:3:50:4 | db.one( ... }\\n }) | +| pg-promise.js:51:3:58:4 | db.one( ... }\\n }) | | socketio.js:11:5:11:54 | db.run( ... ndle}`) | | tst2.js:7:3:7:62 | sql.que ... ms.id}` | | tst2.js:9:3:9:85 | new sql ... + "'") | diff --git a/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected b/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected index 427e2fb853c..f3b81bde59b 100644 --- a/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected @@ -206,6 +206,59 @@ nodes | mongooseModelClient.js:12:22:12:29 | req.body | | mongooseModelClient.js:12:22:12:29 | req.body | | mongooseModelClient.js:12:22:12:32 | req.body.id | +| pg-promise.js:6:7:7:55 | query | +| pg-promise.js:6:15:7:55 | "SELECT ... PRICE" | +| pg-promise.js:7:16:7:34 | req.params.category | +| pg-promise.js:7:16:7:34 | req.params.category | +| pg-promise.js:9:10:9:14 | query | +| pg-promise.js:9:10:9:14 | query | +| pg-promise.js:10:11:10:15 | query | +| pg-promise.js:10:11:10:15 | query | +| pg-promise.js:11:17:11:21 | query | +| pg-promise.js:11:17:11:21 | query | +| pg-promise.js:12:10:12:14 | query | +| pg-promise.js:12:10:12:14 | query | +| pg-promise.js:13:12:13:16 | query | +| pg-promise.js:13:12:13:16 | query | +| pg-promise.js:14:18:14:22 | query | +| pg-promise.js:14:18:14:22 | query | +| pg-promise.js:15:11:15:15 | query | +| pg-promise.js:15:11:15:15 | query | +| pg-promise.js:16:10:16:14 | query | +| pg-promise.js:16:10:16:14 | query | +| pg-promise.js:17:16:17:20 | query | +| pg-promise.js:17:16:17:20 | query | +| pg-promise.js:18:12:18:16 | query | +| pg-promise.js:18:12:18:16 | query | +| pg-promise.js:19:13:19:17 | query | +| pg-promise.js:19:13:19:17 | query | +| pg-promise.js:22:11:22:15 | query | +| pg-promise.js:22:11:22:15 | query | +| pg-promise.js:30:13:30:25 | req.params.id | +| pg-promise.js:30:13:30:25 | req.params.id | +| pg-promise.js:30:13:30:25 | req.params.id | +| pg-promise.js:34:13:34:25 | req.params.id | +| pg-promise.js:34:13:34:25 | req.params.id | +| pg-promise.js:34:13:34:25 | req.params.id | +| pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | +| pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | +| pg-promise.js:39:7:39:19 | req.params.id | +| pg-promise.js:39:7:39:19 | req.params.id | +| pg-promise.js:39:7:39:19 | req.params.id | +| pg-promise.js:40:7:40:21 | req.params.name | +| pg-promise.js:40:7:40:21 | req.params.name | +| pg-promise.js:40:7:40:21 | req.params.name | +| pg-promise.js:41:7:41:20 | req.params.foo | +| pg-promise.js:41:7:41:20 | req.params.foo | +| pg-promise.js:47:11:47:23 | req.params.id | +| pg-promise.js:47:11:47:23 | req.params.id | +| pg-promise.js:47:11:47:23 | req.params.id | +| pg-promise.js:54:11:54:23 | req.params.id | +| pg-promise.js:54:11:54:23 | req.params.id | +| pg-promise.js:54:11:54:23 | req.params.id | +| pg-promise.js:56:14:56:29 | req.params.title | +| pg-promise.js:56:14:56:29 | req.params.title | +| pg-promise.js:56:14:56:29 | req.params.title | | redis.js:10:16:10:23 | req.body | | redis.js:10:16:10:23 | req.body | | redis.js:10:16:10:27 | req.body.key | @@ -553,6 +606,52 @@ edges | mongooseModelClient.js:12:22:12:29 | req.body | mongooseModelClient.js:12:22:12:32 | req.body.id | | mongooseModelClient.js:12:22:12:32 | req.body.id | mongooseModelClient.js:12:16:12:34 | { id: req.body.id } | | mongooseModelClient.js:12:22:12:32 | req.body.id | mongooseModelClient.js:12:16:12:34 | { id: req.body.id } | +| pg-promise.js:6:7:7:55 | query | pg-promise.js:9:10:9:14 | query | +| pg-promise.js:6:7:7:55 | query | pg-promise.js:9:10:9:14 | query | +| pg-promise.js:6:7:7:55 | query | pg-promise.js:10:11:10:15 | query | +| pg-promise.js:6:7:7:55 | query | pg-promise.js:10:11:10:15 | query | +| pg-promise.js:6:7:7:55 | query | pg-promise.js:11:17:11:21 | query | +| pg-promise.js:6:7:7:55 | query | pg-promise.js:11:17:11:21 | query | +| pg-promise.js:6:7:7:55 | query | pg-promise.js:12:10:12:14 | query | +| pg-promise.js:6:7:7:55 | query | pg-promise.js:12:10:12:14 | query | +| pg-promise.js:6:7:7:55 | query | pg-promise.js:13:12:13:16 | query | +| pg-promise.js:6:7:7:55 | query | pg-promise.js:13:12:13:16 | query | +| pg-promise.js:6:7:7:55 | query | pg-promise.js:14:18:14:22 | query | +| pg-promise.js:6:7:7:55 | query | pg-promise.js:14:18:14:22 | query | +| pg-promise.js:6:7:7:55 | query | pg-promise.js:15:11:15:15 | query | +| pg-promise.js:6:7:7:55 | query | pg-promise.js:15:11:15:15 | query | +| pg-promise.js:6:7:7:55 | query | pg-promise.js:16:10:16:14 | query | +| pg-promise.js:6:7:7:55 | query | pg-promise.js:16:10:16:14 | query | +| pg-promise.js:6:7:7:55 | query | pg-promise.js:17:16:17:20 | query | +| pg-promise.js:6:7:7:55 | query | pg-promise.js:17:16:17:20 | query | +| pg-promise.js:6:7:7:55 | query | pg-promise.js:18:12:18:16 | query | +| pg-promise.js:6:7:7:55 | query | pg-promise.js:18:12:18:16 | query | +| pg-promise.js:6:7:7:55 | query | pg-promise.js:19:13:19:17 | query | +| pg-promise.js:6:7:7:55 | query | pg-promise.js:19:13:19:17 | query | +| pg-promise.js:6:7:7:55 | query | pg-promise.js:22:11:22:15 | query | +| pg-promise.js:6:7:7:55 | query | pg-promise.js:22:11:22:15 | query | +| pg-promise.js:6:15:7:55 | "SELECT ... PRICE" | pg-promise.js:6:7:7:55 | query | +| pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:6:15:7:55 | "SELECT ... PRICE" | +| pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:6:15:7:55 | "SELECT ... PRICE" | +| pg-promise.js:30:13:30:25 | req.params.id | pg-promise.js:30:13:30:25 | req.params.id | +| pg-promise.js:34:13:34:25 | req.params.id | pg-promise.js:34:13:34:25 | req.params.id | +| pg-promise.js:39:7:39:19 | req.params.id | pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | +| pg-promise.js:39:7:39:19 | req.params.id | pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | +| pg-promise.js:39:7:39:19 | req.params.id | pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | +| pg-promise.js:39:7:39:19 | req.params.id | pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | +| pg-promise.js:39:7:39:19 | req.params.id | pg-promise.js:39:7:39:19 | req.params.id | +| pg-promise.js:40:7:40:21 | req.params.name | pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | +| pg-promise.js:40:7:40:21 | req.params.name | pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | +| pg-promise.js:40:7:40:21 | req.params.name | pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | +| pg-promise.js:40:7:40:21 | req.params.name | pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | +| pg-promise.js:40:7:40:21 | req.params.name | pg-promise.js:40:7:40:21 | req.params.name | +| pg-promise.js:41:7:41:20 | req.params.foo | pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | +| pg-promise.js:41:7:41:20 | req.params.foo | pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | +| pg-promise.js:41:7:41:20 | req.params.foo | pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | +| pg-promise.js:41:7:41:20 | req.params.foo | pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | +| pg-promise.js:47:11:47:23 | req.params.id | pg-promise.js:47:11:47:23 | req.params.id | +| pg-promise.js:54:11:54:23 | req.params.id | pg-promise.js:54:11:54:23 | req.params.id | +| pg-promise.js:56:14:56:29 | req.params.title | pg-promise.js:56:14:56:29 | req.params.title | | redis.js:10:16:10:23 | req.body | redis.js:10:16:10:27 | req.body.key | | redis.js:10:16:10:23 | req.body | redis.js:10:16:10:27 | req.body.key | | redis.js:10:16:10:23 | req.body | redis.js:10:16:10:27 | req.body.key | @@ -665,6 +764,28 @@ edges | mongooseJsonParse.js:23:19:23:23 | query | mongooseJsonParse.js:20:30:20:43 | req.query.data | mongooseJsonParse.js:23:19:23:23 | query | This query depends on $@. | mongooseJsonParse.js:20:30:20:43 | req.query.data | a user-provided value | | mongooseModelClient.js:11:16:11:24 | { id: v } | mongooseModelClient.js:10:22:10:29 | req.body | mongooseModelClient.js:11:16:11:24 | { id: v } | This query depends on $@. | mongooseModelClient.js:10:22:10:29 | req.body | a user-provided value | | mongooseModelClient.js:12:16:12:34 | { id: req.body.id } | mongooseModelClient.js:12:22:12:29 | req.body | mongooseModelClient.js:12:16:12:34 | { id: req.body.id } | This query depends on $@. | mongooseModelClient.js:12:22:12:29 | req.body | a user-provided value | +| pg-promise.js:9:10:9:14 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:9:10:9:14 | query | This query depends on $@. | pg-promise.js:7:16:7:34 | req.params.category | a user-provided value | +| pg-promise.js:10:11:10:15 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:10:11:10:15 | query | This query depends on $@. | pg-promise.js:7:16:7:34 | req.params.category | a user-provided value | +| pg-promise.js:11:17:11:21 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:11:17:11:21 | query | This query depends on $@. | pg-promise.js:7:16:7:34 | req.params.category | a user-provided value | +| pg-promise.js:12:10:12:14 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:12:10:12:14 | query | This query depends on $@. | pg-promise.js:7:16:7:34 | req.params.category | a user-provided value | +| pg-promise.js:13:12:13:16 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:13:12:13:16 | query | This query depends on $@. | pg-promise.js:7:16:7:34 | req.params.category | a user-provided value | +| pg-promise.js:14:18:14:22 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:14:18:14:22 | query | This query depends on $@. | pg-promise.js:7:16:7:34 | req.params.category | a user-provided value | +| pg-promise.js:15:11:15:15 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:15:11:15:15 | query | This query depends on $@. | pg-promise.js:7:16:7:34 | req.params.category | a user-provided value | +| pg-promise.js:16:10:16:14 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:16:10:16:14 | query | This query depends on $@. | pg-promise.js:7:16:7:34 | req.params.category | a user-provided value | +| pg-promise.js:17:16:17:20 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:17:16:17:20 | query | This query depends on $@. | pg-promise.js:7:16:7:34 | req.params.category | a user-provided value | +| pg-promise.js:18:12:18:16 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:18:12:18:16 | query | This query depends on $@. | pg-promise.js:7:16:7:34 | req.params.category | a user-provided value | +| pg-promise.js:19:13:19:17 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:19:13:19:17 | query | This query depends on $@. | pg-promise.js:7:16:7:34 | req.params.category | a user-provided value | +| pg-promise.js:22:11:22:15 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:22:11:22:15 | query | This query depends on $@. | pg-promise.js:7:16:7:34 | req.params.category | a user-provided value | +| pg-promise.js:30:13:30:25 | req.params.id | pg-promise.js:30:13:30:25 | req.params.id | pg-promise.js:30:13:30:25 | req.params.id | This query depends on $@. | pg-promise.js:30:13:30:25 | req.params.id | a user-provided value | +| pg-promise.js:34:13:34:25 | req.params.id | pg-promise.js:34:13:34:25 | req.params.id | pg-promise.js:34:13:34:25 | req.params.id | This query depends on $@. | pg-promise.js:34:13:34:25 | req.params.id | a user-provided value | +| pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | pg-promise.js:39:7:39:19 | req.params.id | pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | This query depends on $@. | pg-promise.js:39:7:39:19 | req.params.id | a user-provided value | +| pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | pg-promise.js:40:7:40:21 | req.params.name | pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | This query depends on $@. | pg-promise.js:40:7:40:21 | req.params.name | a user-provided value | +| pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | pg-promise.js:41:7:41:20 | req.params.foo | pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | This query depends on $@. | pg-promise.js:41:7:41:20 | req.params.foo | a user-provided value | +| pg-promise.js:39:7:39:19 | req.params.id | pg-promise.js:39:7:39:19 | req.params.id | pg-promise.js:39:7:39:19 | req.params.id | This query depends on $@. | pg-promise.js:39:7:39:19 | req.params.id | a user-provided value | +| pg-promise.js:40:7:40:21 | req.params.name | pg-promise.js:40:7:40:21 | req.params.name | pg-promise.js:40:7:40:21 | req.params.name | This query depends on $@. | pg-promise.js:40:7:40:21 | req.params.name | a user-provided value | +| pg-promise.js:47:11:47:23 | req.params.id | pg-promise.js:47:11:47:23 | req.params.id | pg-promise.js:47:11:47:23 | req.params.id | This query depends on $@. | pg-promise.js:47:11:47:23 | req.params.id | a user-provided value | +| pg-promise.js:54:11:54:23 | req.params.id | pg-promise.js:54:11:54:23 | req.params.id | pg-promise.js:54:11:54:23 | req.params.id | This query depends on $@. | pg-promise.js:54:11:54:23 | req.params.id | a user-provided value | +| pg-promise.js:56:14:56:29 | req.params.title | pg-promise.js:56:14:56:29 | req.params.title | pg-promise.js:56:14:56:29 | req.params.title | This query depends on $@. | pg-promise.js:56:14:56:29 | req.params.title | a user-provided value | | redis.js:10:16:10:27 | req.body.key | redis.js:10:16:10:23 | req.body | redis.js:10:16:10:27 | req.body.key | This query depends on $@. | redis.js:10:16:10:23 | req.body | a user-provided value | | redis.js:18:16:18:18 | key | redis.js:12:15:12:22 | req.body | redis.js:18:16:18:18 | key | This query depends on $@. | redis.js:12:15:12:22 | req.body | a user-provided value | | redis.js:19:43:19:45 | key | redis.js:12:15:12:22 | req.body | redis.js:19:43:19:45 | key | This query depends on $@. | redis.js:12:15:12:22 | req.body | a user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-089/untyped/pg-promise.js b/javascript/ql/test/query-tests/Security/CWE-089/untyped/pg-promise.js new file mode 100644 index 00000000000..a185e2520f0 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-089/untyped/pg-promise.js @@ -0,0 +1,59 @@ +const pgp = require('pg-promise')(); + +require('express')().get('/foo', (req, res) => { + const db = pgp(process.env['DB_CONNECTION_STRING']); + + var query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + req.params.category + "' ORDER BY PRICE"; + + db.any(query); // NOT OK + db.many(query); // NOT OK + db.manyOrNone(query); // NOT OK + db.map(query); // NOT OK + db.multi(query); // NOT OK + db.multiResult(query); // NOT OK + db.none(query); // NOT OK + db.one(query); // NOT OK + db.oneOrNone(query); // NOT OK + db.query(query); // NOT OK + db.result(query); // NOT OK + + db.one({ + text: query // NOT OK + }); + db.one({ + text: 'SELECT * FROM news where id = $1', // OK + values: req.params.id, // OK + }); + db.one({ + text: 'SELECT * FROM news where id = $1:raw', + values: req.params.id, // NOT OK - interpreted as raw parameter + }); + db.one({ + text: 'SELECT * FROM news where id = $1^', + values: req.params.id, // NOT OK + }); + db.one({ + text: 'SELECT * FROM news where id = $1:raw AND name = $2:raw AND foo = $3', + values: [ + req.params.id, // NOT OK + req.params.name, // NOT OK + req.params.foo, // OK - not using raw interpolation + ] + }); + db.one({ + text: 'SELECT * FROM news where id = ${id}:raw AND name = ${name}', + values: { + id: req.params.id, // NOT OK + name: req.params.name, // OK - not using raw interpolation + } + }); + db.one({ + text: "SELECT * FROM news where id = ${id}:value AND name LIKE '%${name}:value%' AND title LIKE \"%${title}:value%\"", + values: { + id: req.params.id, // NOT OK + name: req.params.name, // OK - :value cannot break out of single quotes + title: req.params.title, // NOT OK - enclosed by wrong type of quote + } + }); +}); From b381f4826c0f34998a378cb073f3ac1813afc3bf Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 29 Mar 2021 09:37:59 +0100 Subject: [PATCH 419/725] JS: Add change note --- javascript/change-notes/2021-03-29-pg-promise.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 javascript/change-notes/2021-03-29-pg-promise.md diff --git a/javascript/change-notes/2021-03-29-pg-promise.md b/javascript/change-notes/2021-03-29-pg-promise.md new file mode 100644 index 00000000000..bde661be5b8 --- /dev/null +++ b/javascript/change-notes/2021-03-29-pg-promise.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* SQL injection sinks from the `pg-promise` library are now recognized. From f453fe26c6b32ff92fb65d7c5504aa1a72517d08 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 29 Mar 2021 11:28:46 +0100 Subject: [PATCH 420/725] JS: Autoformat --- javascript/ql/src/semmle/javascript/NodeJS.qll | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/NodeJS.qll b/javascript/ql/src/semmle/javascript/NodeJS.qll index c40b8d2b802..d1c8eff8cf7 100644 --- a/javascript/ql/src/semmle/javascript/NodeJS.qll +++ b/javascript/ql/src/semmle/javascript/NodeJS.qll @@ -205,10 +205,11 @@ private predicate moduleInFile(Module m, File f) { m.getFile() = f } private predicate isModuleModule(DataFlow::Node nd) { exists(ImportDeclaration imp | imp.getImportedPath().getValue() = "module" and - nd = [ - DataFlow::destructuredModuleImportNode(imp), - DataFlow::valueNode(imp.getASpecifier().(ImportNamespaceSpecifier)) - ] + nd = + [ + DataFlow::destructuredModuleImportNode(imp), + DataFlow::valueNode(imp.getASpecifier().(ImportNamespaceSpecifier)) + ] ) or isModuleModule(nd.getAPredecessor()) From f1d0b5067020cb393ee6a8d2530ec7a272db428c Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 29 Mar 2021 11:54:45 +0100 Subject: [PATCH 421/725] Update javascript/ql/src/semmle/javascript/frameworks/SQL.qll Co-authored-by: Esben Sparre Andreasen --- javascript/ql/src/semmle/javascript/frameworks/SQL.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll index aab5a380b8d..654a940c159 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll @@ -93,7 +93,7 @@ private module MySql { } /** - * Provides classes modelling the `pg` package. + * Provides classes modelling the PostgreSQL packages, such as `pg` and `pg-promise`. */ private module Postgres { API::Node pg() { From 603843e6985f19c08ea1f073afbb36c071cf63aa Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 29 Mar 2021 12:05:47 +0100 Subject: [PATCH 422/725] JS: Add task tests --- .../CWE-089/untyped/SqlInjection.expected | 15 +++++++++++++++ .../Security/CWE-089/untyped/pg-promise.js | 7 +++++++ 2 files changed, 22 insertions(+) diff --git a/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected b/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected index f3b81bde59b..a6b0ef8d11e 100644 --- a/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected @@ -259,6 +259,12 @@ nodes | pg-promise.js:56:14:56:29 | req.params.title | | pg-promise.js:56:14:56:29 | req.params.title | | pg-promise.js:56:14:56:29 | req.params.title | +| pg-promise.js:60:20:60:24 | query | +| pg-promise.js:60:20:60:24 | query | +| pg-promise.js:63:23:63:27 | query | +| pg-promise.js:63:23:63:27 | query | +| pg-promise.js:64:16:64:20 | query | +| pg-promise.js:64:16:64:20 | query | | redis.js:10:16:10:23 | req.body | | redis.js:10:16:10:23 | req.body | | redis.js:10:16:10:27 | req.body.key | @@ -630,6 +636,12 @@ edges | pg-promise.js:6:7:7:55 | query | pg-promise.js:19:13:19:17 | query | | pg-promise.js:6:7:7:55 | query | pg-promise.js:22:11:22:15 | query | | pg-promise.js:6:7:7:55 | query | pg-promise.js:22:11:22:15 | query | +| pg-promise.js:6:7:7:55 | query | pg-promise.js:60:20:60:24 | query | +| pg-promise.js:6:7:7:55 | query | pg-promise.js:60:20:60:24 | query | +| pg-promise.js:6:7:7:55 | query | pg-promise.js:63:23:63:27 | query | +| pg-promise.js:6:7:7:55 | query | pg-promise.js:63:23:63:27 | query | +| pg-promise.js:6:7:7:55 | query | pg-promise.js:64:16:64:20 | query | +| pg-promise.js:6:7:7:55 | query | pg-promise.js:64:16:64:20 | query | | pg-promise.js:6:15:7:55 | "SELECT ... PRICE" | pg-promise.js:6:7:7:55 | query | | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:6:15:7:55 | "SELECT ... PRICE" | | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:6:15:7:55 | "SELECT ... PRICE" | @@ -786,6 +798,9 @@ edges | pg-promise.js:47:11:47:23 | req.params.id | pg-promise.js:47:11:47:23 | req.params.id | pg-promise.js:47:11:47:23 | req.params.id | This query depends on $@. | pg-promise.js:47:11:47:23 | req.params.id | a user-provided value | | pg-promise.js:54:11:54:23 | req.params.id | pg-promise.js:54:11:54:23 | req.params.id | pg-promise.js:54:11:54:23 | req.params.id | This query depends on $@. | pg-promise.js:54:11:54:23 | req.params.id | a user-provided value | | pg-promise.js:56:14:56:29 | req.params.title | pg-promise.js:56:14:56:29 | req.params.title | pg-promise.js:56:14:56:29 | req.params.title | This query depends on $@. | pg-promise.js:56:14:56:29 | req.params.title | a user-provided value | +| pg-promise.js:60:20:60:24 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:60:20:60:24 | query | This query depends on $@. | pg-promise.js:7:16:7:34 | req.params.category | a user-provided value | +| pg-promise.js:63:23:63:27 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:63:23:63:27 | query | This query depends on $@. | pg-promise.js:7:16:7:34 | req.params.category | a user-provided value | +| pg-promise.js:64:16:64:20 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:64:16:64:20 | query | This query depends on $@. | pg-promise.js:7:16:7:34 | req.params.category | a user-provided value | | redis.js:10:16:10:27 | req.body.key | redis.js:10:16:10:23 | req.body | redis.js:10:16:10:27 | req.body.key | This query depends on $@. | redis.js:10:16:10:23 | req.body | a user-provided value | | redis.js:18:16:18:18 | key | redis.js:12:15:12:22 | req.body | redis.js:18:16:18:18 | key | This query depends on $@. | redis.js:12:15:12:22 | req.body | a user-provided value | | redis.js:19:43:19:45 | key | redis.js:12:15:12:22 | req.body | redis.js:19:43:19:45 | key | This query depends on $@. | redis.js:12:15:12:22 | req.body | a user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-089/untyped/pg-promise.js b/javascript/ql/test/query-tests/Security/CWE-089/untyped/pg-promise.js index a185e2520f0..07d92a753ec 100644 --- a/javascript/ql/test/query-tests/Security/CWE-089/untyped/pg-promise.js +++ b/javascript/ql/test/query-tests/Security/CWE-089/untyped/pg-promise.js @@ -56,4 +56,11 @@ require('express')().get('/foo', (req, res) => { title: req.params.title, // NOT OK - enclosed by wrong type of quote } }); + db.task(t => { + return t.one(query); // NOT OK + }); + db.task( + { cnd: t => t.one(query) }, // NOT OK + t => t.one(query) // NOT OK + ); }); From 49ca88957cca1e57f73f2c9e7e4d48ca30f9b29a Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 29 Mar 2021 12:25:15 +0100 Subject: [PATCH 423/725] JS: Use types --- .../src/semmle/javascript/frameworks/SQL.qll | 22 ++++++++++++++++--- .../CWE-089/untyped/SqlInjection.expected | 10 +++++++++ .../CWE-089/untyped/pg-promise-types.ts | 13 +++++++++++ 3 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 javascript/ql/test/query-tests/Security/CWE-089/untyped/pg-promise-types.ts diff --git a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll index 654a940c159..1e41f03d141 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll @@ -166,14 +166,24 @@ private module Postgres { API::Node pgPromise() { result = API::moduleImport("pg-promise") } /** Gets an initialized `pg-promise` library. */ - API::Node pgpMain() { result = pgPromise().getReturn() } + API::Node pgpMain() { + result = pgPromise().getReturn() + or + result = API::Node::ofType("pg-promise", "IMain") + } /** Gets a database from `pg-promise`. */ - API::Node pgpDatabase() { result = pgpMain().getReturn() } + API::Node pgpDatabase() { + result = pgpMain().getReturn() + or + result = API::Node::ofType("pg-promise", "IDatabase") + } /** Gets a connection created from a `pg-promise` database. */ API::Node pgpConnection() { result = pgpDatabase().getMember("connect").getReturn().getPromised() + or + result = API::Node::ofType("pg-promise", "IConnected") } /** Gets a `pg-promise` task object. */ @@ -185,10 +195,16 @@ private module Postgres { or result = taskMethod.getParameter(0).getMember("cnd").getParameter(0) ) + or + result = API::Node::ofType("pg-promise", "ITask") } /** Gets a `pg-promise` object which supports querying (database, connection, or task). */ - API::Node pgpObject() { result = [pgpDatabase(), pgpConnection(), pgpTask()] } + API::Node pgpObject() { + result = [pgpDatabase(), pgpConnection(), pgpTask()] + or + result = API::Node::ofType("pg-promise", "IBaseProtocol") + } private string pgpQueryMethodName() { result = diff --git a/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected b/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected index a6b0ef8d11e..ac856dabb7b 100644 --- a/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected @@ -206,6 +206,11 @@ nodes | mongooseModelClient.js:12:22:12:29 | req.body | | mongooseModelClient.js:12:22:12:29 | req.body | | mongooseModelClient.js:12:22:12:32 | req.body.id | +| pg-promise-types.ts:7:9:7:28 | taint | +| pg-promise-types.ts:7:17:7:28 | req.params.x | +| pg-promise-types.ts:7:17:7:28 | req.params.x | +| pg-promise-types.ts:8:17:8:21 | taint | +| pg-promise-types.ts:8:17:8:21 | taint | | pg-promise.js:6:7:7:55 | query | | pg-promise.js:6:15:7:55 | "SELECT ... PRICE" | | pg-promise.js:7:16:7:34 | req.params.category | @@ -612,6 +617,10 @@ edges | mongooseModelClient.js:12:22:12:29 | req.body | mongooseModelClient.js:12:22:12:32 | req.body.id | | mongooseModelClient.js:12:22:12:32 | req.body.id | mongooseModelClient.js:12:16:12:34 | { id: req.body.id } | | mongooseModelClient.js:12:22:12:32 | req.body.id | mongooseModelClient.js:12:16:12:34 | { id: req.body.id } | +| pg-promise-types.ts:7:9:7:28 | taint | pg-promise-types.ts:8:17:8:21 | taint | +| pg-promise-types.ts:7:9:7:28 | taint | pg-promise-types.ts:8:17:8:21 | taint | +| pg-promise-types.ts:7:17:7:28 | req.params.x | pg-promise-types.ts:7:9:7:28 | taint | +| pg-promise-types.ts:7:17:7:28 | req.params.x | pg-promise-types.ts:7:9:7:28 | taint | | pg-promise.js:6:7:7:55 | query | pg-promise.js:9:10:9:14 | query | | pg-promise.js:6:7:7:55 | query | pg-promise.js:9:10:9:14 | query | | pg-promise.js:6:7:7:55 | query | pg-promise.js:10:11:10:15 | query | @@ -776,6 +785,7 @@ edges | mongooseJsonParse.js:23:19:23:23 | query | mongooseJsonParse.js:20:30:20:43 | req.query.data | mongooseJsonParse.js:23:19:23:23 | query | This query depends on $@. | mongooseJsonParse.js:20:30:20:43 | req.query.data | a user-provided value | | mongooseModelClient.js:11:16:11:24 | { id: v } | mongooseModelClient.js:10:22:10:29 | req.body | mongooseModelClient.js:11:16:11:24 | { id: v } | This query depends on $@. | mongooseModelClient.js:10:22:10:29 | req.body | a user-provided value | | mongooseModelClient.js:12:16:12:34 | { id: req.body.id } | mongooseModelClient.js:12:22:12:29 | req.body | mongooseModelClient.js:12:16:12:34 | { id: req.body.id } | This query depends on $@. | mongooseModelClient.js:12:22:12:29 | req.body | a user-provided value | +| pg-promise-types.ts:8:17:8:21 | taint | pg-promise-types.ts:7:17:7:28 | req.params.x | pg-promise-types.ts:8:17:8:21 | taint | This query depends on $@. | pg-promise-types.ts:7:17:7:28 | req.params.x | a user-provided value | | pg-promise.js:9:10:9:14 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:9:10:9:14 | query | This query depends on $@. | pg-promise.js:7:16:7:34 | req.params.category | a user-provided value | | pg-promise.js:10:11:10:15 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:10:11:10:15 | query | This query depends on $@. | pg-promise.js:7:16:7:34 | req.params.category | a user-provided value | | pg-promise.js:11:17:11:21 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:11:17:11:21 | query | This query depends on $@. | pg-promise.js:7:16:7:34 | req.params.category | a user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-089/untyped/pg-promise-types.ts b/javascript/ql/test/query-tests/Security/CWE-089/untyped/pg-promise-types.ts new file mode 100644 index 00000000000..eaf46ad8cf8 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-089/untyped/pg-promise-types.ts @@ -0,0 +1,13 @@ +import { IDatabase } from "pg-promise"; + +export class Foo { + db: IDatabase; + + onRequest(req, res) { + let taint = req.params.x; + this.db.one(taint); // NOT OK + res.end(); + } +} + +require('express')().get('/foo', (req, res) => new Foo().onRequest(req, res)); From c103939c2dace958ddbf4a1f26cd7044fd3bb179 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 29 Mar 2021 12:47:23 +0100 Subject: [PATCH 424/725] JS: Fix handling of createRequire --- javascript/ql/src/semmle/javascript/NodeJS.qll | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/NodeJS.qll b/javascript/ql/src/semmle/javascript/NodeJS.qll index d1c8eff8cf7..f80391a1ad3 100644 --- a/javascript/ql/src/semmle/javascript/NodeJS.qll +++ b/javascript/ql/src/semmle/javascript/NodeJS.qll @@ -228,6 +228,13 @@ private predicate isCreateRequire(DataFlow::Node nd) { nd = prop.getValuePattern().flow() ) or + exists(ImportDeclaration decl, NamedImportSpecifier spec | + decl.getImportedPath().getValue() = "module" and + spec = decl.getASpecifier() and + spec.getImportedName() = "createRequire" and + nd = spec.flow() + ) + or isCreateRequire(nd.getAPredecessor()) } From 2770a53d384315ca13cb65a1d168ae9b9e330d30 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 29 Mar 2021 12:56:49 +0100 Subject: [PATCH 425/725] JS: More babel.transform steps --- javascript/ql/src/semmle/javascript/frameworks/Babel.qll | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Babel.qll b/javascript/ql/src/semmle/javascript/frameworks/Babel.qll index 02a57d25a37..9e112f05776 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Babel.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Babel.qll @@ -194,13 +194,13 @@ module Babel { */ private class TransformTaintStep extends TaintTracking::SharedTaintStep { override predicate step(DataFlow::Node pred, DataFlow::Node succ) { - exists(DataFlow::CallNode call | + exists(API::CallNode call | call = API::moduleImport(["@babel/standalone", "@babel/core"]) - .getMember(["transform", "transformSync"]) + .getMember(["transform", "transformSync", "transformAsync"]) .getACall() and pred = call.getArgument(0) and - succ = call + succ = [call, call.getParameter(2).getParameter(0).getAnImmediateUse()] ) } } From 3e262366488997411814789c380f07562c5adb83 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 29 Mar 2021 14:28:52 +0100 Subject: [PATCH 426/725] JS: Add recursion guard test --- .../src/semmle/javascript/dataflow/Sources.qll | 12 +++++++++++- .../RecursionPrevention/SourceNodeRange.expected | 1 + .../RecursionPrevention/SourceNodeRange.ql | 16 ++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 javascript/ql/test/library-tests/RecursionPrevention/SourceNodeRange.expected create mode 100644 javascript/ql/test/library-tests/RecursionPrevention/SourceNodeRange.ql diff --git a/javascript/ql/src/semmle/javascript/dataflow/Sources.qll b/javascript/ql/src/semmle/javascript/dataflow/Sources.qll index 01b624580b2..cea50cb1f46 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Sources.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Sources.qll @@ -34,7 +34,11 @@ private import semmle.javascript.internal.CachedStages * ``` */ class SourceNode extends DataFlow::Node { - SourceNode() { this instanceof SourceNode::Range } + SourceNode() { + this instanceof SourceNode::Range + or + none() and this instanceof SourceNode::Internal::RecursionGuard + } /** * Holds if this node flows into `sink` in zero or more local (that is, @@ -329,6 +333,12 @@ module SourceNode { DataFlow::functionReturnNode(this, _) } } + + /** INTERNAL. DO NOT USE. */ + module Internal { + /** An empty class that some tests are using to enforce that SourceNode is non-recursive. */ + abstract class RecursionGuard extends DataFlow::Node {} + } } deprecated class DefaultSourceNode extends SourceNode { diff --git a/javascript/ql/test/library-tests/RecursionPrevention/SourceNodeRange.expected b/javascript/ql/test/library-tests/RecursionPrevention/SourceNodeRange.expected new file mode 100644 index 00000000000..59f6fd6e79b --- /dev/null +++ b/javascript/ql/test/library-tests/RecursionPrevention/SourceNodeRange.expected @@ -0,0 +1 @@ +| Success | diff --git a/javascript/ql/test/library-tests/RecursionPrevention/SourceNodeRange.ql b/javascript/ql/test/library-tests/RecursionPrevention/SourceNodeRange.ql new file mode 100644 index 00000000000..6ec9cae3ba8 --- /dev/null +++ b/javascript/ql/test/library-tests/RecursionPrevention/SourceNodeRange.ql @@ -0,0 +1,16 @@ +/** + * Test that fails to compile if the domain of `SourceNode::Range` depends on `SourceNode` (recursively). + * + * This tests adds a negative dependency `SourceNode --!--> SourceNode::Range` + * so that the undesired edge `SourceNode::Range --> SourceNode` completes a negative cycle. + */ + +import javascript + +class BadSourceNodeRange extends DataFlow::SourceNode::Internal::RecursionGuard { + BadSourceNodeRange() { + not this instanceof DataFlow::SourceNode::Range + } +} + +select "Success" From faf07dac91c12a115afc327109fbbfae96e05d25 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 29 Mar 2021 14:52:37 +0100 Subject: [PATCH 427/725] JS: Autoformat --- javascript/ql/src/semmle/javascript/dataflow/Sources.qll | 2 +- .../test/library-tests/RecursionPrevention/SourceNodeRange.ql | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/Sources.qll b/javascript/ql/src/semmle/javascript/dataflow/Sources.qll index cea50cb1f46..efbac19b95d 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Sources.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Sources.qll @@ -337,7 +337,7 @@ module SourceNode { /** INTERNAL. DO NOT USE. */ module Internal { /** An empty class that some tests are using to enforce that SourceNode is non-recursive. */ - abstract class RecursionGuard extends DataFlow::Node {} + abstract class RecursionGuard extends DataFlow::Node { } } } diff --git a/javascript/ql/test/library-tests/RecursionPrevention/SourceNodeRange.ql b/javascript/ql/test/library-tests/RecursionPrevention/SourceNodeRange.ql index 6ec9cae3ba8..03549a97873 100644 --- a/javascript/ql/test/library-tests/RecursionPrevention/SourceNodeRange.ql +++ b/javascript/ql/test/library-tests/RecursionPrevention/SourceNodeRange.ql @@ -8,9 +8,7 @@ import javascript class BadSourceNodeRange extends DataFlow::SourceNode::Internal::RecursionGuard { - BadSourceNodeRange() { - not this instanceof DataFlow::SourceNode::Range - } + BadSourceNodeRange() { not this instanceof DataFlow::SourceNode::Range } } select "Success" From 67ad6d9a0f6348338cba0b7319dc5356fc45fefb Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 29 Mar 2021 15:30:29 +0100 Subject: [PATCH 428/725] JS: Update test output --- .../Security/CWE-089/untyped/DatabaseAccesses.expected | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/javascript/ql/test/query-tests/Security/CWE-089/untyped/DatabaseAccesses.expected b/javascript/ql/test/query-tests/Security/CWE-089/untyped/DatabaseAccesses.expected index 85629ac69db..6252e53b5ab 100644 --- a/javascript/ql/test/query-tests/Security/CWE-089/untyped/DatabaseAccesses.expected +++ b/javascript/ql/test/query-tests/Security/CWE-089/untyped/DatabaseAccesses.expected @@ -37,6 +37,7 @@ | mongoose.js:97:2:97:52 | Documen ... query)) | | mongoose.js:99:2:99:50 | Documen ... query)) | | mongoose.js:113:2:113:53 | Documen ... () { }) | +| pg-promise-types.ts:8:5:8:22 | this.db.one(taint) | | pg-promise.js:9:3:9:15 | db.any(query) | | pg-promise.js:10:3:10:16 | db.many(query) | | pg-promise.js:11:3:11:22 | db.manyOrNone(query) | @@ -55,6 +56,9 @@ | pg-promise.js:36:3:43:4 | db.one( ... ]\\n }) | | pg-promise.js:44:3:50:4 | db.one( ... }\\n }) | | pg-promise.js:51:3:58:4 | db.one( ... }\\n }) | +| pg-promise.js:60:14:60:25 | t.one(query) | +| pg-promise.js:63:17:63:28 | t.one(query) | +| pg-promise.js:64:10:64:21 | t.one(query) | | socketio.js:11:5:11:54 | db.run( ... ndle}`) | | tst2.js:7:3:7:62 | sql.que ... ms.id}` | | tst2.js:9:3:9:85 | new sql ... + "'") | From 96a66fa4eee0a64de10419e6eab9de4c2aaddba7 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 29 Mar 2021 17:02:56 +0200 Subject: [PATCH 429/725] Python: Apply suggestions from code review --- .../experimental/Security-old-dataflow/CWE-094/CodeInjection.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/experimental/Security-old-dataflow/CWE-094/CodeInjection.ql b/python/ql/src/experimental/Security-old-dataflow/CWE-094/CodeInjection.ql index 50dd501c476..4155208beed 100644 --- a/python/ql/src/experimental/Security-old-dataflow/CWE-094/CodeInjection.ql +++ b/python/ql/src/experimental/Security-old-dataflow/CWE-094/CodeInjection.ql @@ -1,6 +1,6 @@ /** * @name Code injection - * @description Interpreting unsanitized user input as code allows a malicious user arbitrary + * @description OLD QUERY: Interpreting unsanitized user input as code allows a malicious user arbitrary * code execution. * @kind path-problem * @problem.severity error From 5a4efab74207fd00f133d4815e5956fe188db8e1 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Mon, 29 Mar 2021 18:04:20 +0200 Subject: [PATCH 430/725] C++: Add tests for shared_ptr. --- .../dataflow/smart-pointers-taint/test.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/cpp/ql/test/library-tests/dataflow/smart-pointers-taint/test.cpp b/cpp/ql/test/library-tests/dataflow/smart-pointers-taint/test.cpp index c836a20414a..7e8793d0faa 100644 --- a/cpp/ql/test/library-tests/dataflow/smart-pointers-taint/test.cpp +++ b/cpp/ql/test/library-tests/dataflow/smart-pointers-taint/test.cpp @@ -25,4 +25,22 @@ void test_unique_ptr_struct() { sink(p1->y); sink(p2->x); // $ ir=22:46 sink(p2->y); // $ SPURIOUS: ir=22:46 +} + +void test_shared_ptr_int() { + std::shared_ptr p1(new int(source())); + std::shared_ptr p2 = std::make_shared(source()); + + sink(*p1); // $ ast + sink(*p2); // $ ast ir=32:50 +} + +void test_shared_ptr_struct() { + std::shared_ptr
    p1(new A{source(), 0}); + std::shared_ptr p2 = std::make_shared(source(), 0); + + sink(p1->x); // $ MISSING: ast,ir + sink(p1->y); + sink(p2->x); // $ ir=40:46 + sink(p2->y); // $ SPURIOUS: ir=40:46 } \ No newline at end of file From 108bcef104a424b5d01ed9656e497e21aa81284e Mon Sep 17 00:00:00 2001 From: Sarah Edwards Date: Mon, 29 Mar 2021 10:37:00 -0700 Subject: [PATCH 431/725] download LGTM database from a project slug --- .../codeql-for-visual-studio-code/analyzing-your-projects.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/codeql/codeql-for-visual-studio-code/analyzing-your-projects.rst b/docs/codeql/codeql-for-visual-studio-code/analyzing-your-projects.rst index 02ece5284fa..b9a275cfb41 100644 --- a/docs/codeql/codeql-for-visual-studio-code/analyzing-your-projects.rst +++ b/docs/codeql/codeql-for-visual-studio-code/analyzing-your-projects.rst @@ -14,7 +14,7 @@ To analyze a project, you need to add a :ref:`CodeQL database ` #. Open the CodeQL Databases view in the sidebar. -#. Hover over the **Databases** title bar and click the appropriate icon to add your database. You can add a database from a local ZIP archive or folder, from a public URL, or from a project URL on LGTM.com. +#. Hover over the **Databases** title bar and click the appropriate icon to add your database. You can add a database from a local ZIP archive or folder, from a public URL, or from a project slug or URL on LGTM.com. .. image:: ../images/codeql-for-visual-studio-code/choose-database.png :width: 350 From 3db5dd4661c13b0d8b3a484c594b5da1ebfa2e59 Mon Sep 17 00:00:00 2001 From: Sarita Iyer Date: Mon, 29 Mar 2021 13:37:55 -0400 Subject: [PATCH 432/725] removed 1.23 instructions and replaced references Removed special instructions for LGTM 1.23, and replaced leftover references to 1.23 with 1.27. --- .../getting-started-with-the-codeql-cli.rst | 2 +- docs/codeql/codeql-cli/testing-custom-queries.rst | 14 -------------- .../setting-up-codeql-in-visual-studio-code.rst | 2 +- 3 files changed, 2 insertions(+), 16 deletions(-) diff --git a/docs/codeql/codeql-cli/getting-started-with-the-codeql-cli.rst b/docs/codeql/codeql-cli/getting-started-with-the-codeql-cli.rst index cb4cd413f25..6a46881b222 100644 --- a/docs/codeql/codeql-cli/getting-started-with-the-codeql-cli.rst +++ b/docs/codeql/codeql-cli/getting-started-with-the-codeql-cli.rst @@ -138,7 +138,7 @@ see ":doc:`About QL packs `." - For the queries used in a particular LGTM Enterprise release, check out the branch tagged with the relevant release number. For example, the branch - tagged ``v1.23.0`` corresponds to LGTM Enterprise 1.23. You must use this + tagged ``v1.27.0`` corresponds to LGTM Enterprise 1.27. You must use this version if you want to upload data to LGTM Enterprise. For further information, see `Preparing CodeQL databases to upload to LGTM `__ diff --git a/docs/codeql/codeql-cli/testing-custom-queries.rst b/docs/codeql/codeql-cli/testing-custom-queries.rst index 3890703a83d..7f347de8b1c 100644 --- a/docs/codeql/codeql-cli/testing-custom-queries.rst +++ b/docs/codeql/codeql-cli/testing-custom-queries.rst @@ -13,20 +13,6 @@ on the query and the expected results until the actual results and the expected results exactly match. This topic shows you how to create test files and execute tests on them using the ``test run`` subcommand. -.. container:: toggle - - .. container:: name - - **Information for LGTM Enterprise 1.23 users** - - CodeQL tests are a new feature in CodeQL CLI version 2.0.2. - - If you are an LGTM Enterprise 1.23 user, you should still use CodeQL CLI - version 2.0.1 to prepare databases to upload to your instance of LGTM. You - can use version 2.0.2 (or newer) to test your custom queries, but databases - created with versions newer than 2.0.1 are not compatible with LGTM - Enterprise 1.23. For more information, see ":ref:`Getting started with the CodeQL CLI `." - Setting up a test QL pack for custom queries -------------------------------------------- diff --git a/docs/codeql/codeql-for-visual-studio-code/setting-up-codeql-in-visual-studio-code.rst b/docs/codeql/codeql-for-visual-studio-code/setting-up-codeql-in-visual-studio-code.rst index cfc85fa23bd..93b070dba18 100644 --- a/docs/codeql/codeql-for-visual-studio-code/setting-up-codeql-in-visual-studio-code.rst +++ b/docs/codeql/codeql-for-visual-studio-code/setting-up-codeql-in-visual-studio-code.rst @@ -64,7 +64,7 @@ There are two ways to do this: **Click to show information for LGTM Enterprise users** Your local version of the CodeQL queries and libraries should match your version of LGTM Enterprise. For example, if you - use LGTM Enterprise 1.23, then you should clone the ``1.23.0`` branch of the `starter workspace `__ (or the appropriate ``1.23.x`` branch, corresponding to each maintenance release). + use LGTM Enterprise 1.27, then you should clone the ``1.27.0`` branch of the `starter workspace `__ (or the appropriate ``1.27.x`` branch, corresponding to each maintenance release). This ensures that the queries and libraries you write in VS Code also work in the query console on LGTM Enterprise. From d126c0a1d3e52a6345e1ccbb1672fb5386b28b15 Mon Sep 17 00:00:00 2001 From: Ethan P <56270045+ethanpalm@users.noreply.github.com> Date: Mon, 29 Mar 2021 13:38:04 -0400 Subject: [PATCH 433/725] Fix broken links --- docs/codeql/codeql-cli/creating-codeql-databases.rst | 2 +- docs/codeql/codeql-cli/testing-query-help-files.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/codeql/codeql-cli/creating-codeql-databases.rst b/docs/codeql/codeql-cli/creating-codeql-databases.rst index 73fa4fb4818..4f7212050df 100644 --- a/docs/codeql/codeql-cli/creating-codeql-databases.rst +++ b/docs/codeql/codeql-cli/creating-codeql-databases.rst @@ -168,7 +168,7 @@ build steps, you may need to explicitly define each step in the command line. For Go, you should always use the CodeQL autobuilder. Install the Go toolchain (version 1.11 or later) and, if there are dependencies, the appropriate dependency manager (such as `dep - `__ or `Glide `__). + `__). Do not specify any build commands, as you will override the autobuilder invocation, which will create an empty database. diff --git a/docs/codeql/codeql-cli/testing-query-help-files.rst b/docs/codeql/codeql-cli/testing-query-help-files.rst index d8285eb57cc..7c48b2f5121 100644 --- a/docs/codeql/codeql-cli/testing-query-help-files.rst +++ b/docs/codeql/codeql-cli/testing-query-help-files.rst @@ -38,7 +38,7 @@ where ```` is one of: - the path to a ``.ql`` file. - the path to a directory containing queries and query help files. - the path to a query suite, or the name of a well-known query suite for a QL pack. - For more information, see "`Creating CodeQL query suites `__." + For more information, see "`Creating CodeQL query suites `__." You must specify a ``--format`` option, which defines how the query help is rendered. Currently, you must specify ``markdown`` to render the query help as markdown. From 50523e0ac0c656e1cdfd380e7d08fb1720213f10 Mon Sep 17 00:00:00 2001 From: Laura Coursen Date: Mon, 29 Mar 2021 12:40:31 -0500 Subject: [PATCH 434/725] Clarify use cases for lgtm.com branch --- .../getting-started-with-the-codeql-cli.rst | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/codeql/codeql-cli/getting-started-with-the-codeql-cli.rst b/docs/codeql/codeql-cli/getting-started-with-the-codeql-cli.rst index cb4cd413f25..fea19557359 100644 --- a/docs/codeql/codeql-cli/getting-started-with-the-codeql-cli.rst +++ b/docs/codeql/codeql-cli/getting-started-with-the-codeql-cli.rst @@ -129,12 +129,13 @@ see ":doc:`About QL packs `." ":doc:`Upgrading CodeQL databases `." - For the queries used on `LGTM.com `__, check out the - ``lgtm.com`` branch. You can run these queries on databases you've recently - downloaded from LGTM.com. Older databases may need to be upgraded before - you can analyze them. The queries on the ``lgtm.com`` branch are also more - likely to be compatible with the ``latest`` CLI, so you'll be less likely - to have to upgrade newly-created databases than if you use the ``main`` - branch. + ``lgtm.com`` branch. You should use this branch if you've built a database + using CODEQL CLI or fetched a database from Code Scanning. You can + run these queries on databases you've recently downloaded from LGTM.com. + Older databases may need to be upgraded before you can analyze them. The + queries on the ``lgtm.com`` branch are also more likely to be compatible + with the ``latest`` CLI, so you'll be less likely to have to upgrade + newly-created databases than if you use the ``main`` branch. - For the queries used in a particular LGTM Enterprise release, check out the branch tagged with the relevant release number. For example, the branch From 21576387f3d16ff4994a424c487a2ad2051675d7 Mon Sep 17 00:00:00 2001 From: Laura Coursen Date: Mon, 29 Mar 2021 12:41:48 -0500 Subject: [PATCH 435/725] =?UTF-8?q?Add=20=F0=9F=92=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../codeql-cli/getting-started-with-the-codeql-cli.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/codeql/codeql-cli/getting-started-with-the-codeql-cli.rst b/docs/codeql/codeql-cli/getting-started-with-the-codeql-cli.rst index fea19557359..dec695d70d0 100644 --- a/docs/codeql/codeql-cli/getting-started-with-the-codeql-cli.rst +++ b/docs/codeql/codeql-cli/getting-started-with-the-codeql-cli.rst @@ -129,9 +129,8 @@ see ":doc:`About QL packs `." ":doc:`Upgrading CodeQL databases `." - For the queries used on `LGTM.com `__, check out the - ``lgtm.com`` branch. You should use this branch if you've built a database - using CODEQL CLI or fetched a database from Code Scanning. You can - run these queries on databases you've recently downloaded from LGTM.com. + ``lgtm.com`` branch. You should use this branch for databases you've build + using CODEQL CLI, fetched from Code Scanning, or recently downloaded from LGTM.com. Older databases may need to be upgraded before you can analyze them. The queries on the ``lgtm.com`` branch are also more likely to be compatible with the ``latest`` CLI, so you'll be less likely to have to upgrade From a18cd747561ce4bd8372cef6b266c60dce26ca9b Mon Sep 17 00:00:00 2001 From: Laura Coursen Date: Mon, 29 Mar 2021 12:42:09 -0500 Subject: [PATCH 436/725] Fix typo --- docs/codeql/codeql-cli/getting-started-with-the-codeql-cli.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/codeql/codeql-cli/getting-started-with-the-codeql-cli.rst b/docs/codeql/codeql-cli/getting-started-with-the-codeql-cli.rst index dec695d70d0..ba4fe346bda 100644 --- a/docs/codeql/codeql-cli/getting-started-with-the-codeql-cli.rst +++ b/docs/codeql/codeql-cli/getting-started-with-the-codeql-cli.rst @@ -129,7 +129,7 @@ see ":doc:`About QL packs `." ":doc:`Upgrading CodeQL databases `." - For the queries used on `LGTM.com `__, check out the - ``lgtm.com`` branch. You should use this branch for databases you've build + ``lgtm.com`` branch. You should use this branch for databases you've built using CODEQL CLI, fetched from Code Scanning, or recently downloaded from LGTM.com. Older databases may need to be upgraded before you can analyze them. The queries on the ``lgtm.com`` branch are also more likely to be compatible From 909dc84bb61465f537bccef37a3d1325dfdf0860 Mon Sep 17 00:00:00 2001 From: Ethan P <56270045+ethanpalm@users.noreply.github.com> Date: Mon, 29 Mar 2021 13:46:45 -0400 Subject: [PATCH 437/725] Update broken link --- docs/codeql/codeql-cli/testing-query-help-files.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/codeql/codeql-cli/testing-query-help-files.rst b/docs/codeql/codeql-cli/testing-query-help-files.rst index 7c48b2f5121..ba5cf3901e7 100644 --- a/docs/codeql/codeql-cli/testing-query-help-files.rst +++ b/docs/codeql/codeql-cli/testing-query-help-files.rst @@ -38,7 +38,7 @@ where ```` is one of: - the path to a ``.ql`` file. - the path to a directory containing queries and query help files. - the path to a query suite, or the name of a well-known query suite for a QL pack. - For more information, see "`Creating CodeQL query suites `__." + For more information, see "`Creating CodeQL query suites `__." You must specify a ``--format`` option, which defines how the query help is rendered. Currently, you must specify ``markdown`` to render the query help as markdown. From 8f1c7c57a87687ad99ae1e8b8e6258cead16e987 Mon Sep 17 00:00:00 2001 From: Laura Coursen Date: Mon, 29 Mar 2021 12:53:16 -0500 Subject: [PATCH 438/725] =?UTF-8?q?Add=20=F0=9F=92=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../codeql-cli/getting-started-with-the-codeql-cli.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/codeql/codeql-cli/getting-started-with-the-codeql-cli.rst b/docs/codeql/codeql-cli/getting-started-with-the-codeql-cli.rst index ba4fe346bda..bffacd1d582 100644 --- a/docs/codeql/codeql-cli/getting-started-with-the-codeql-cli.rst +++ b/docs/codeql/codeql-cli/getting-started-with-the-codeql-cli.rst @@ -131,10 +131,10 @@ see ":doc:`About QL packs `." - For the queries used on `LGTM.com `__, check out the ``lgtm.com`` branch. You should use this branch for databases you've built using CODEQL CLI, fetched from Code Scanning, or recently downloaded from LGTM.com. - Older databases may need to be upgraded before you can analyze them. The - queries on the ``lgtm.com`` branch are also more likely to be compatible + The queries on the ``lgtm.com`` branch are more likely to be compatible with the ``latest`` CLI, so you'll be less likely to have to upgrade - newly-created databases than if you use the ``main`` branch. + newly-created databases than if you use the ``main`` branch. Older databases + may need to be upgraded before you can analyze them. - For the queries used in a particular LGTM Enterprise release, check out the branch tagged with the relevant release number. For example, the branch From eb01ffbdae3015799f123adf7629b3c25a5fae99 Mon Sep 17 00:00:00 2001 From: Laura Coursen Date: Mon, 29 Mar 2021 14:03:30 -0500 Subject: [PATCH 439/725] Use correct terminology Co-authored-by: Shati Patel <42641846+shati-patel@users.noreply.github.com> --- docs/codeql/codeql-cli/getting-started-with-the-codeql-cli.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/codeql/codeql-cli/getting-started-with-the-codeql-cli.rst b/docs/codeql/codeql-cli/getting-started-with-the-codeql-cli.rst index bffacd1d582..ee226970811 100644 --- a/docs/codeql/codeql-cli/getting-started-with-the-codeql-cli.rst +++ b/docs/codeql/codeql-cli/getting-started-with-the-codeql-cli.rst @@ -130,7 +130,7 @@ see ":doc:`About QL packs `." - For the queries used on `LGTM.com `__, check out the ``lgtm.com`` branch. You should use this branch for databases you've built - using CODEQL CLI, fetched from Code Scanning, or recently downloaded from LGTM.com. + using the CodeQL CLI, fetched from code scanning on GitHub, or recently downloaded from LGTM.com. The queries on the ``lgtm.com`` branch are more likely to be compatible with the ``latest`` CLI, so you'll be less likely to have to upgrade newly-created databases than if you use the ``main`` branch. Older databases From e3b052199a34e3eb2048879202ddb5b2c0c08214 Mon Sep 17 00:00:00 2001 From: Laura Coursen Date: Mon, 29 Mar 2021 14:04:59 -0500 Subject: [PATCH 440/725] Suggest lgtm.com branch first --- .../getting-started-with-the-codeql-cli.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/codeql/codeql-cli/getting-started-with-the-codeql-cli.rst b/docs/codeql/codeql-cli/getting-started-with-the-codeql-cli.rst index bffacd1d582..20e43e9b79c 100644 --- a/docs/codeql/codeql-cli/getting-started-with-the-codeql-cli.rst +++ b/docs/codeql/codeql-cli/getting-started-with-the-codeql-cli.rst @@ -121,13 +121,7 @@ see ":doc:`About QL packs `." There are different versions of the CodeQL queries available for different users. Check out the correct version for your use case: - - - For the most up to date CodeQL queries, check out the ``main`` branch. - This branch represents the very latest version of CodeQL's analysis. Even - databases created using the most recent version of the CLI may have to be - upgraded before you can analyze them. For more information, see - ":doc:`Upgrading CodeQL databases `." - + - For the queries used on `LGTM.com `__, check out the ``lgtm.com`` branch. You should use this branch for databases you've built using CODEQL CLI, fetched from Code Scanning, or recently downloaded from LGTM.com. @@ -135,7 +129,13 @@ see ":doc:`About QL packs `." with the ``latest`` CLI, so you'll be less likely to have to upgrade newly-created databases than if you use the ``main`` branch. Older databases may need to be upgraded before you can analyze them. - + + - For the most up to date CodeQL queries, check out the ``main`` branch. + This branch represents the very latest version of CodeQL's analysis. Even + databases created using the most recent version of the CLI may have to be + upgraded before you can analyze them. For more information, see + ":doc:`Upgrading CodeQL databases `." + - For the queries used in a particular LGTM Enterprise release, check out the branch tagged with the relevant release number. For example, the branch tagged ``v1.23.0`` corresponds to LGTM Enterprise 1.23. You must use this From 09ba25fe9b4d68d7970e41ac07035df559f61968 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 30 Mar 2021 10:24:01 +0200 Subject: [PATCH 441/725] C++: Accept test changes. I'm actually not sure why we lose these results (and lose the field conflation, yay) It might be due to #3364. --- .../library-tests/dataflow/smart-pointers-taint/test.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/smart-pointers-taint/test.cpp b/cpp/ql/test/library-tests/dataflow/smart-pointers-taint/test.cpp index 7e8793d0faa..0dbbd7a2384 100644 --- a/cpp/ql/test/library-tests/dataflow/smart-pointers-taint/test.cpp +++ b/cpp/ql/test/library-tests/dataflow/smart-pointers-taint/test.cpp @@ -23,8 +23,8 @@ void test_unique_ptr_struct() { sink(p1->x); // $ MISSING: ast,ir sink(p1->y); - sink(p2->x); // $ ir=22:46 - sink(p2->y); // $ SPURIOUS: ir=22:46 + sink(p2->x); // $ MISSING: ast,ir + sink(p2->y); } void test_shared_ptr_int() { @@ -41,6 +41,6 @@ void test_shared_ptr_struct() { sink(p1->x); // $ MISSING: ast,ir sink(p1->y); - sink(p2->x); // $ ir=40:46 - sink(p2->y); // $ SPURIOUS: ir=40:46 + sink(p2->x); // $ MISSING: ast,ir + sink(p2->y); } \ No newline at end of file From 937a620f4d41db65c7203201435aaf3dab6380de Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Tue, 30 Mar 2021 11:33:42 +0100 Subject: [PATCH 442/725] JS: Improve mysql2 model --- .../src/semmle/javascript/frameworks/SQL.qll | 32 ++++++++++++++++--- .../frameworks/SQL/Credentials.expected | 1 + .../frameworks/SQL/SqlString.expected | 8 +++++ .../frameworks/SQL/mysql2-promise.js | 32 +++++++++++++++++++ .../frameworks/SQL/mysql2-types.ts | 5 +++ .../library-tests/frameworks/SQL/mysql2tst.js | 4 +++ .../library-tests/frameworks/SQL/mysql3.js | 4 +++ 7 files changed, 81 insertions(+), 5 deletions(-) create mode 100644 javascript/ql/test/library-tests/frameworks/SQL/mysql2-promise.js create mode 100644 javascript/ql/test/library-tests/frameworks/SQL/mysql2-types.ts diff --git a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll index 1e41f03d141..cef49ec317d 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll @@ -28,30 +28,52 @@ module SQL { * Provides classes modelling the (API compatible) `mysql` and `mysql2` packages. */ private module MySql { + private string moduleName() { result = ["mysql", "mysql2", "mysql2/promise"] } + /** Gets the package name `mysql` or `mysql2`. */ - API::Node mysql() { result = API::moduleImport(["mysql", "mysql2"]) } + API::Node mysql() { result = API::moduleImport(moduleName()) } /** Gets a reference to `mysql.createConnection`. */ - API::Node createConnection() { result = mysql().getMember("createConnection") } + API::Node createConnection() { + result = mysql().getMember(["createConnection", "createConnectionPromise"]) + } /** Gets a reference to `mysql.createPool`. */ - API::Node createPool() { result = mysql().getMember("createPool") } + API::Node createPool() { result = mysql().getMember(["createPool", "createPoolCluster"]) } /** Gets a node that contains a MySQL pool created using `mysql.createPool()`. */ - API::Node pool() { result = createPool().getReturn() } + API::Node pool() { + result = createPool().getReturn() + or + result = pool().getMember("on").getReturn() + or + result = API::Node::ofType(moduleName(), ["Pool", "PoolCluster"]) + } /** Gets a data flow node that contains a freshly created MySQL connection instance. */ API::Node connection() { result = createConnection().getReturn() or + result = createConnection().getReturn().getPromised() + or result = pool().getMember("getConnection").getParameter(0).getParameter(1) + or + result = pool().getMember("getConnection").getPromised() + or + exists(API::CallNode call | + call = pool().getMember("on").getACall() and + call.getArgument(0).getStringValue() = ["connection", "acquire", "release"] and + result = call.getParameter(1).getParameter(0) + ) + or + result = API::Node::ofType(moduleName(), ["Connection", "PoolConnection"]) } /** A call to the MySql `query` method. */ private class QueryCall extends DatabaseAccess, DataFlow::MethodCallNode { QueryCall() { exists(API::Node recv | recv = pool() or recv = connection() | - this = recv.getMember("query").getACall() + this = recv.getMember(["query", "execute"]).getACall() ) } diff --git a/javascript/ql/test/library-tests/frameworks/SQL/Credentials.expected b/javascript/ql/test/library-tests/frameworks/SQL/Credentials.expected index a7d4af58a90..190d8a51982 100644 --- a/javascript/ql/test/library-tests/frameworks/SQL/Credentials.expected +++ b/javascript/ql/test/library-tests/frameworks/SQL/Credentials.expected @@ -6,6 +6,7 @@ | mysql1.js:7:14:7:21 | 'secret' | password | | mysql1a.js:10:9:10:12 | 'me' | user name | | mysql1a.js:11:13:11:20 | 'secret' | password | +| mysql2-promise.js:8:9:8:14 | 'root' | user name | | mysql2.js:7:21:7:25 | 'bob' | user name | | mysql2.js:8:21:8:28 | 'secret' | password | | mysql2tst.js:8:9:8:14 | 'root' | user name | diff --git a/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected b/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected index b2e0cc4b046..69b45d70307 100644 --- a/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected +++ b/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected @@ -7,10 +7,18 @@ | mysql1.js:13:18:13:43 | 'SELECT ... lution' | | mysql1.js:18:18:22:1 | {\\n s ... vid']\\n} | | mysql1a.js:17:18:17:43 | 'SELECT ... lution' | +| mysql2-promise.js:14:3:14:62 | 'SELECT ... ` > 45' | +| mysql2-promise.js:23:3:23:56 | 'SELECT ... e` > ?' | +| mysql2-promise.js:31:19:31:39 | 'SELECT ... users' | +| mysql2-promise.js:32:21:32:41 | 'SELECT ... users' | +| mysql2-types.ts:4:16:4:36 | 'SELECT ... users' | | mysql2.js:12:12:12:37 | 'SELECT ... lution' | | mysql2tst.js:14:3:14:62 | 'SELECT ... ` > 45' | | mysql2tst.js:23:3:23:56 | 'SELECT ... e` > ?' | +| mysql2tst.js:31:19:31:39 | 'SELECT ... users' | +| mysql2tst.js:32:21:32:41 | 'SELECT ... users' | | mysql3.js:14:20:14:52 | 'SELECT ... etable' | +| mysql3.js:26:14:26:31 | 'SELECT something' | | mysql4.js:14:18:14:20 | sql | | mysqlImport.js:3:18:5:1 | {\\n s ... = ?',\\n} | | postgres1.js:37:21:37:24 | text | diff --git a/javascript/ql/test/library-tests/frameworks/SQL/mysql2-promise.js b/javascript/ql/test/library-tests/frameworks/SQL/mysql2-promise.js new file mode 100644 index 00000000000..6e40c5cafbc --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/SQL/mysql2-promise.js @@ -0,0 +1,32 @@ +// Adapted from the documentation of https://github.com/sidorares/node-mysql2, +// which is licensed under the MIT license; see file node-mysql2-License. +const mysql = require('mysql2/promise'); + +// create the connection to database +const connection = await mysql.createConnection({ + host: 'localhost', + user: 'root', + database: 'test' +}); + +// simple query +connection.query( + 'SELECT * FROM `table` WHERE `name` = "Page" AND `age` > 45', + function(err, results, fields) { + console.log(results); // results contains rows returned by server + console.log(fields); // fields contains extra meta data about results, if available + } +); + +// with placeholder +connection.query( + 'SELECT * FROM `table` WHERE `name` = ? AND `age` > ?', + ['Page', 45], + function(err, results) { + console.log(results); + } +); + +const conn2 = await mysql.createConnectionPromise(); +await conn2.query('SELECT * FROM users'); +await conn2.execute('SELECT * FROM users'); diff --git a/javascript/ql/test/library-tests/frameworks/SQL/mysql2-types.ts b/javascript/ql/test/library-tests/frameworks/SQL/mysql2-types.ts new file mode 100644 index 00000000000..dba89f2ca47 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/SQL/mysql2-types.ts @@ -0,0 +1,5 @@ +import { Connection } from "mysql2"; + +export function doSomething(conn: Connection) { + conn.query('SELECT * FROM users'); +} diff --git a/javascript/ql/test/library-tests/frameworks/SQL/mysql2tst.js b/javascript/ql/test/library-tests/frameworks/SQL/mysql2tst.js index c066aa8e92e..9121096f77d 100644 --- a/javascript/ql/test/library-tests/frameworks/SQL/mysql2tst.js +++ b/javascript/ql/test/library-tests/frameworks/SQL/mysql2tst.js @@ -26,3 +26,7 @@ connection.query( console.log(results); } ); + +const conn2 = await mysql.createConnectionPromise(); +await conn2.query('SELECT * FROM users'); +await conn2.execute('SELECT * FROM users'); diff --git a/javascript/ql/test/library-tests/frameworks/SQL/mysql3.js b/javascript/ql/test/library-tests/frameworks/SQL/mysql3.js index 63ac500d067..554777abcb1 100644 --- a/javascript/ql/test/library-tests/frameworks/SQL/mysql3.js +++ b/javascript/ql/test/library-tests/frameworks/SQL/mysql3.js @@ -21,3 +21,7 @@ pool.getConnection(function(err, connection) { // Don't use the connection here, it has been returned to the pool. }); }); + +pool.on('connection', conn => { + conn.query('SELECT something'); +}); From 0b21b273edbd1ad3f1a50683ca18e956680c6233 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 29 Mar 2021 16:41:42 +0100 Subject: [PATCH 443/725] JS: Improve pg model --- .../src/semmle/javascript/frameworks/SQL.qll | 23 ++++++++++++++++++- .../frameworks/SQL/SqlString.expected | 4 ++++ .../frameworks/SQL/postgres-types.ts | 5 ++++ .../library-tests/frameworks/SQL/postgres2.js | 6 +++++ 4 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 javascript/ql/test/library-tests/frameworks/SQL/postgres-types.ts diff --git a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll index cef49ec317d..b3f89c82f19 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll @@ -134,7 +134,20 @@ private module Postgres { // pool.connect(function(err, client) { ... }) result = pool().getMember("connect").getParameter(0).getParameter(1) or + // await pool.connect() + result = pool().getMember("connect").getReturn().getPromised() + or result = pgpConnection().getMember("client") + or + exists(API::CallNode call | + call = pool().getMember("on").getACall() and + call.getArgument(0).getStringValue() = ["connect", "acquire"] and + result = call.getParameter(1).getParameter(0) + ) + or + result = client().getMember("on").getReturn() + or + result = API::Node::ofType("pg", ["Client", "PoolClient"]) } /** Gets a constructor that when invoked constructs a new connection pool. */ @@ -151,6 +164,10 @@ private module Postgres { result = newPool().getInstance() or result = pgpDatabase().getMember("$pool") + or + result = pool().getMember("on").getReturn() + or + result = API::Node::ofType("pg", "Pool") } /** A call to the Postgres `query` method. */ @@ -162,7 +179,11 @@ private module Postgres { /** An expression that is passed to the `query` method and hence interpreted as SQL. */ class QueryString extends SQL::SqlString { - QueryString() { this = any(QueryCall qc).getAQueryArgument().asExpr() } + QueryString() { + this = any(QueryCall qc).getAQueryArgument().asExpr() + or + this = API::moduleImport("pg-cursor").getParameter(0).getARhs().asExpr() + } } /** An expression that is passed as user name or password when creating a client or a pool. */ diff --git a/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected b/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected index 69b45d70307..74efed7d265 100644 --- a/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected +++ b/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected @@ -23,8 +23,12 @@ | mysqlImport.js:3:18:5:1 | {\\n s ... = ?',\\n} | | postgres1.js:37:21:37:24 | text | | postgres2.js:30:16:30:41 | 'SELECT ... number' | +| postgres2.js:43:15:43:26 | 'SELECT 123' | +| postgres2.js:46:15:46:47 | new Cur ... users') | +| postgres2.js:46:26:46:46 | 'SELECT ... users' | | postgres3.js:15:16:15:40 | 'SELECT ... s name' | | postgres5.js:8:21:8:25 | query | +| postgres-types.ts:4:18:4:29 | 'SELECT 123' | | postgresImport.js:4:18:4:43 | 'SELECT ... number' | | sequelize2.js:10:17:10:118 | 'SELECT ... Y name' | | sequelize.js:8:17:8:118 | 'SELECT ... Y name' | diff --git a/javascript/ql/test/library-tests/frameworks/SQL/postgres-types.ts b/javascript/ql/test/library-tests/frameworks/SQL/postgres-types.ts new file mode 100644 index 00000000000..00817e5d63e --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/SQL/postgres-types.ts @@ -0,0 +1,5 @@ +import { Client } from "pg"; + +function submitSomething(client: Client) { + client.query('SELECT 123'); +} diff --git a/javascript/ql/test/library-tests/frameworks/SQL/postgres2.js b/javascript/ql/test/library-tests/frameworks/SQL/postgres2.js index 611f4e286af..fd449ae8765 100644 --- a/javascript/ql/test/library-tests/frameworks/SQL/postgres2.js +++ b/javascript/ql/test/library-tests/frameworks/SQL/postgres2.js @@ -38,3 +38,9 @@ pool.connect(function(err, client, done) { //output: 1 }); }); + +let client2 = await pool.connect(); +client2.query('SELECT 123'); + +const Cursor = require('pg-cursor'); +client2.query(new Cursor('SELECT * from users')); From 95937c9ac70d7f62c9ed416d041178a8d772140f Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 29 Mar 2021 22:53:47 +0100 Subject: [PATCH 444/725] JS: Improve sqlite3 model --- .../ql/src/semmle/javascript/frameworks/SQL.qll | 15 ++++----------- .../frameworks/SQL/SqlString.expected | 1 + .../library-tests/frameworks/SQL/sqlite-types.ts | 5 +++++ 3 files changed, 10 insertions(+), 11 deletions(-) create mode 100644 javascript/ql/test/library-tests/frameworks/SQL/sqlite-types.ts diff --git a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll index b3f89c82f19..15dc5df808c 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll @@ -342,24 +342,17 @@ private module Sqlite { } /** Gets an expression that constructs a Sqlite database instance. */ - API::Node newDb() { + API::Node database() { // new require('sqlite3').Database() result = sqlite().getMember("Database").getInstance() + or + result = API::Node::ofType("sqlite3", "Database") } /** A call to a Sqlite query method. */ private class QueryCall extends DatabaseAccess, DataFlow::MethodCallNode { QueryCall() { - exists(string meth | - meth = "all" or - meth = "each" or - meth = "exec" or - meth = "get" or - meth = "prepare" or - meth = "run" - | - this = newDb().getMember(meth).getACall() - ) + this = database().getMember(["all", "each", "exec", "get", "prepare", "run"]).getACall() } override DataFlow::Node getAQueryArgument() { result = getArgument(0) } diff --git a/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected b/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected index 74efed7d265..4b6f1de2e7d 100644 --- a/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected +++ b/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected @@ -54,6 +54,7 @@ | spanner.js:19:16:19:34 | { sql: "SQL code" } | | spanner.js:19:23:19:32 | "SQL code" | | spannerImport.js:4:8:4:17 | "SQL code" | +| sqlite-types.ts:4:12:4:49 | "UPDATE ... id = ?" | | sqlite.js:7:8:7:45 | "UPDATE ... id = ?" | | sqliteArray.js:6:12:6:49 | "UPDATE ... id = ?" | | sqliteImport.js:2:8:2:44 | "UPDATE ... id = ?" | diff --git a/javascript/ql/test/library-tests/frameworks/SQL/sqlite-types.ts b/javascript/ql/test/library-tests/frameworks/SQL/sqlite-types.ts new file mode 100644 index 00000000000..9356cf0bda5 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/SQL/sqlite-types.ts @@ -0,0 +1,5 @@ +import { Database } from "sqlite3"; + +export function doSomething(db: Database) { + db.run("UPDATE tbl SET name = ? WHERE id = ?", "bar", 2); +} From 93500bd95a55b1ca91c23472d21321f6af629593 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Tue, 30 Mar 2021 10:06:14 +0100 Subject: [PATCH 445/725] JS: Improve mssql model --- .../src/semmle/javascript/frameworks/SQL.qll | 31 ++++++++++++++----- .../frameworks/SQL/SqlString.expected | 2 ++ .../frameworks/SQL/mssql-types.ts | 9 ++++++ .../library-tests/frameworks/SQL/mssql1.js | 2 ++ 4 files changed, 37 insertions(+), 7 deletions(-) create mode 100644 javascript/ql/test/library-tests/frameworks/SQL/mssql-types.ts diff --git a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll index 15dc5df808c..f006c73e544 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll @@ -371,15 +371,32 @@ private module MsSql { /** Gets a reference to the `mssql` module. */ API::Node mssql() { result = API::moduleImport("mssql") } - /** Gets an expression that creates a request object. */ - API::Node request() { - // new require('mssql').Request() - result = mssql().getMember("Request").getInstance() + /** Gets a node referring to an instance of the given class. */ + API::Node mssqlClass(string name) { + result = mssql().getMember(name).getInstance() or - // request.input(...) - result = request().getMember("input").getReturn() + result = API::Node::ofType("mssql", name) } + /** Gets an API node referring to a Request object. */ + API::Node request() { + result = mssqlClass("Request") + or + result = request().getMember(["input", "replaceInput", "output", "replaceOutput"]).getReturn() + or + result = [transaction(), pool()].getMember("request").getReturn() + } + + /** Gets an API node referring to a Transaction object. */ + API::Node transaction() { + result = mssqlClass("Transaction") + or + result = pool().getMember("transaction").getReturn() + } + + /** Gets a API node referring to a ConnectionPool object. */ + API::Node pool() { result = mssqlClass("ConnectionPool") } + /** A tagged template evaluated as a query. */ private class QueryTemplateExpr extends DatabaseAccess, DataFlow::ValueNode { override TaggedTemplateExpr astNode; @@ -395,7 +412,7 @@ private module MsSql { /** A call to a MsSql query method. */ private class QueryCall extends DatabaseAccess, DataFlow::MethodCallNode { - QueryCall() { this = request().getMember(["query", "batch"]).getACall() } + QueryCall() { this = [mssql(), request()].getMember(["query", "batch"]).getACall() } override DataFlow::Node getAQueryArgument() { result = getArgument(0) } } diff --git a/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected b/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected index 4b6f1de2e7d..8720962382b 100644 --- a/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected +++ b/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected @@ -1,9 +1,11 @@ | mssql1.js:7:40:7:72 | select ... e id = | | mssql1.js:7:75:7:79 | value | +| mssql1.js:10:19:10:30 | 'SELECT 123' | | mssql2.js:5:15:5:34 | 'select 1 as number' | | mssql2.js:13:15:13:66 | 'create ... table' | | mssql2.js:22:24:22:43 | 'select 1 as number' | | mssql2.js:29:30:29:81 | 'create ... table' | +| mssql-types.ts:7:31:7:42 | 'SELECT 123' | | mysql1.js:13:18:13:43 | 'SELECT ... lution' | | mysql1.js:18:18:22:1 | {\\n s ... vid']\\n} | | mysql1a.js:17:18:17:43 | 'SELECT ... lution' | diff --git a/javascript/ql/test/library-tests/frameworks/SQL/mssql-types.ts b/javascript/ql/test/library-tests/frameworks/SQL/mssql-types.ts new file mode 100644 index 00000000000..243812e799c --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/SQL/mssql-types.ts @@ -0,0 +1,9 @@ +import { ConnectionPool } from "mssql"; + +class Foo { + constructor(private pool: ConnectionPool) {} + + doSomething() { + this.pool.request().query('SELECT 123'); + } +} diff --git a/javascript/ql/test/library-tests/frameworks/SQL/mssql1.js b/javascript/ql/test/library-tests/frameworks/SQL/mssql1.js index 39a340ccf83..8f8bf1f0914 100644 --- a/javascript/ql/test/library-tests/frameworks/SQL/mssql1.js +++ b/javascript/ql/test/library-tests/frameworks/SQL/mssql1.js @@ -6,6 +6,8 @@ async () => { const pool = await sql.connect('mssql://username:password@localhost/database') const result = await sql.query`select * from mytable where id = ${value}` console.dir(result) + + sql.query('SELECT 123'); } catch (err) { // ... error checks } From 1349bf7b0ba8b83ee86d5fbdc46b207e32439cd1 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Tue, 30 Mar 2021 02:57:58 +0000 Subject: [PATCH 446/725] Create a .qll file to reuse the code and add check of Spring properties --- .../CWE-555/CredentialsInPropertiesFile.ql | 93 +-------------- .../CredentialsInPropertiesFile.qll | 107 ++++++++++++++++++ .../CredentialsInPropertiesFile.expected | 10 +- .../CWE-555/CredentialsInPropertiesFile.ql | 93 +-------------- .../security/CWE-555/MailConfig.java | 11 ++ .../security/CWE-555/PropertiesUtils.java | 10 -- .../query-tests/security/CWE-555/options | 1 + .../beans/factory/annotation/Value.java | 11 ++ 8 files changed, 137 insertions(+), 199 deletions(-) create mode 100644 java/ql/src/experimental/semmle/code/java/frameworks/CredentialsInPropertiesFile.qll create mode 100644 java/ql/test/experimental/query-tests/security/CWE-555/MailConfig.java create mode 100644 java/ql/test/experimental/query-tests/security/CWE-555/options create mode 100644 java/ql/test/stubs/springframework-5.2.3/org/springframework/beans/factory/annotation/Value.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-555/CredentialsInPropertiesFile.ql b/java/ql/src/experimental/Security/CWE/CWE-555/CredentialsInPropertiesFile.ql index 8bbc0d00a46..d4ebe902cf7 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-555/CredentialsInPropertiesFile.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-555/CredentialsInPropertiesFile.ql @@ -18,41 +18,7 @@ */ import java -import semmle.code.configfiles.ConfigFiles -import semmle.code.java.dataflow.FlowSources - -private string possibleSecretName() { - result = - [ - "%password%", "%passwd%", "%account%", "%accnt%", "%credential%", "%token%", "%secret%", - "%access%key%" - ] -} - -private string possibleEncryptedSecretName() { result = ["%hashed%", "%encrypted%", "%crypt%"] } - -/** Holds if the value is not cleartext credentials. */ -bindingset[value] -predicate isNotCleartextCredentials(string value) { - value = "" // Empty string - or - value.length() < 7 // Typical credentials are no less than 6 characters - or - value.matches("% %") // Sentences containing spaces - or - value.regexpMatch(".*[^a-zA-Z\\d]{3,}.*") // Contain repeated non-alphanumeric characters such as a fake password pass**** or ???? - or - value.matches("@%") // Starts with the "@" sign - or - value.regexpMatch("\\$\\{.*\\}") // Variable placeholder ${credentials} - or - value.matches("%=") // A basic check of encrypted credentials ending with padding characters - or - value.matches("ENC(%)") // Encrypted value - or - // Could be a message property for UI display or fake passwords, e.g. login.password_expired=Your current password has expired. - value.toLowerCase().matches(possibleSecretName()) -} +import experimental.semmle.code.java.frameworks.CredentialsInPropertiesFile /** * Holds if the credentials are in a non-production properties file indicated by: @@ -63,63 +29,6 @@ predicate isNonProdCredentials(CredentialsConfig cc) { cc.getFile().getAbsolutePath().matches(["%dev%", "%test%", "%sample%"]) } -/** The credentials configuration property. */ -class CredentialsConfig extends ConfigPair { - CredentialsConfig() { - this.getNameElement().getName().trim().toLowerCase().matches(possibleSecretName()) and - not this.getNameElement().getName().trim().toLowerCase().matches(possibleEncryptedSecretName()) and - not isNotCleartextCredentials(this.getValueElement().getValue().trim()) - } - - string getName() { result = this.getNameElement().getName().trim() } - - string getValue() { result = this.getValueElement().getValue().trim() } - - /** Returns a description of this vulnerability. */ - string getConfigDesc() { - exists( - LoadCredentialsConfiguration cc, DataFlow::Node source, DataFlow::Node sink, MethodAccess ma - | - this.getName() = source.asExpr().(CompileTimeConstantExpr).getStringValue() and - cc.hasFlow(source, sink) and - ma.getArgument(0) = sink.asExpr() and - result = "Plaintext credentials " + this.getName() + " are loaded in " + ma - ) - or - not exists(LoadCredentialsConfiguration cc, DataFlow::Node source, DataFlow::Node sink | - this.getName() = source.asExpr().(CompileTimeConstantExpr).getStringValue() and - cc.hasFlow(source, sink) - ) and - result = - "Plaintext credentials " + this.getName() + " have cleartext value " + this.getValue() + - " in properties file" - } -} - -/** - * A dataflow configuration tracking flow of a method that loads a credentials property. - */ -class LoadCredentialsConfiguration extends DataFlow::Configuration { - LoadCredentialsConfiguration() { this = "LoadCredentialsConfiguration" } - - override predicate isSource(DataFlow::Node source) { - exists(CredentialsConfig cc | - source.asExpr().(CompileTimeConstantExpr).getStringValue() = cc.getName() - ) - } - - override predicate isSink(DataFlow::Node sink) { - sink.asExpr() = - any(MethodAccess ma | - ma.getMethod() - .getDeclaringType() - .getASupertype*() - .hasQualifiedName("java.util", "Properties") and - ma.getMethod().getName() = "getProperty" - ).getArgument(0) - } -} - from CredentialsConfig cc where not isNonProdCredentials(cc) select cc, cc.getConfigDesc() diff --git a/java/ql/src/experimental/semmle/code/java/frameworks/CredentialsInPropertiesFile.qll b/java/ql/src/experimental/semmle/code/java/frameworks/CredentialsInPropertiesFile.qll new file mode 100644 index 00000000000..9577789ce0c --- /dev/null +++ b/java/ql/src/experimental/semmle/code/java/frameworks/CredentialsInPropertiesFile.qll @@ -0,0 +1,107 @@ +/** + * Provides classes for analyzing properties files. + */ + +import java +import semmle.code.configfiles.ConfigFiles +import semmle.code.java.dataflow.FlowSources +import semmle.code.java.frameworks.Properties + +private string possibleSecretName() { + result = + [ + "%password%", "%passwd%", "%account%", "%accnt%", "%credential%", "%token%", "%secret%", + "%access%key%" + ] +} + +private string possibleEncryptedSecretName() { result = ["%hashed%", "%encrypted%", "%crypt%"] } + +/** Holds if the value is not cleartext credentials. */ +bindingset[value] +predicate isNotCleartextCredentials(string value) { + value = "" // Empty string + or + value.length() < 7 // Typical credentials are no less than 6 characters + or + value.matches("% %") // Sentences containing spaces + or + value.regexpMatch(".*[^a-zA-Z\\d]{3,}.*") // Contain repeated non-alphanumeric characters such as a fake password pass**** or ???? + or + value.matches("@%") // Starts with the "@" sign + or + value.regexpMatch("\\$\\{.*\\}") // Variable placeholder ${credentials} + or + value.matches("%=") // A basic check of encrypted credentials ending with padding characters + or + value.matches("ENC(%)") // Encrypted value + or + // Could be a message property for UI display or fake passwords, e.g. login.password_expired=Your current password has expired. + value.toLowerCase().matches(possibleSecretName()) +} + +/** The credentials configuration property. */ +class CredentialsConfig extends ConfigPair { + CredentialsConfig() { + this.getNameElement().getName().trim().toLowerCase().matches(possibleSecretName()) and + not this.getNameElement().getName().trim().toLowerCase().matches(possibleEncryptedSecretName()) and + not isNotCleartextCredentials(this.getValueElement().getValue().trim()) + } + + string getName() { result = this.getNameElement().getName().trim() } + + string getValue() { result = this.getValueElement().getValue().trim() } + + /** Returns a description of this vulnerability. */ + string getConfigDesc() { + exists( + // getProperty(...) + LoadCredentialsConfiguration cc, DataFlow::Node source, DataFlow::Node sink, MethodAccess ma + | + this.getName() = source.asExpr().(CompileTimeConstantExpr).getStringValue() and + cc.hasFlow(source, sink) and + ma.getArgument(0) = sink.asExpr() and + result = "Plaintext credentials " + this.getName() + " are loaded in Java Properties " + ma + ) + or + exists( + // @Value("${mail.password}") + Annotation a + | + a.getType().hasQualifiedName("org.springframework.beans.factory.annotation", "Value") and + a.getAValue().(CompileTimeConstantExpr).getStringValue() = "${" + this.getName() + "}" and + result = "Plaintext credentials " + this.getName() + " are loaded in Spring annotation " + a + ) + or + not exists(LoadCredentialsConfiguration cc, DataFlow::Node source, DataFlow::Node sink | + this.getName() = source.asExpr().(CompileTimeConstantExpr).getStringValue() and + cc.hasFlow(source, sink) + ) and + not exists(Annotation a | + a.getType().hasQualifiedName("org.springframework.beans.factory.annotation", "Value") and + a.getAValue().(CompileTimeConstantExpr).getStringValue() = "${" + this.getName() + "}" + ) and + result = + "Plaintext credentials " + this.getName() + " have cleartext value " + this.getValue() + + " in properties file" + } +} + +/** + * A dataflow configuration tracking flow of cleartext credentials stored in a properties file + * to a `Properties.getProperty(...)` method call. + */ +class LoadCredentialsConfiguration extends DataFlow::Configuration { + LoadCredentialsConfiguration() { this = "LoadCredentialsConfiguration" } + + override predicate isSource(DataFlow::Node source) { + exists(CredentialsConfig cc | + source.asExpr().(CompileTimeConstantExpr).getStringValue() = cc.getName() + ) + } + + override predicate isSink(DataFlow::Node sink) { + sink.asExpr() = + any(MethodAccess ma | ma.getMethod() instanceof PropertiesGetPropertyMethod).getArgument(0) + } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-555/CredentialsInPropertiesFile.expected b/java/ql/test/experimental/query-tests/security/CWE-555/CredentialsInPropertiesFile.expected index 1bdc004a446..371a4765c53 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-555/CredentialsInPropertiesFile.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-555/CredentialsInPropertiesFile.expected @@ -1,5 +1,5 @@ -| configuration.properties:6:1:6:25 | ldap.password=mysecpass | Plaintext credentials ldap.password are loaded in getProperty(...) | -| configuration.properties:18:1:18:35 | datasource1.password=Passw0rd@123 | Plaintext credentials datasource1.password are loaded in getProperty(...) | -| configuration.properties:25:1:25:31 | mail.password=MysecPWxWa@1993 | Plaintext credentials mail.password are loaded in getProperty(...) | -| configuration.properties:33:1:33:50 | com.example.aws.s3.access_key=AKMAMQPBYMCD6YSAYCBA | Plaintext credentials com.example.aws.s3.access_key are loaded in getProperty(...) | -| configuration.properties:34:1:34:70 | com.example.aws.s3.secret_key=8lMPSfWzZq+wcWtck5+QPLOJDZzE783pS09/IO3k | Plaintext credentials com.example.aws.s3.secret_key are loaded in getProperty(...) | +| configuration.properties:6:1:6:25 | ldap.password=mysecpass | Plaintext credentials ldap.password are loaded in Java Properties getProperty(...) | +| configuration.properties:18:1:18:35 | datasource1.password=Passw0rd@123 | Plaintext credentials datasource1.password are loaded in Java Properties getProperty(...) | +| configuration.properties:25:1:25:31 | mail.password=MysecPWxWa@1993 | Plaintext credentials mail.password are loaded in Spring annotation Value | +| configuration.properties:33:1:33:50 | com.example.aws.s3.access_key=AKMAMQPBYMCD6YSAYCBA | Plaintext credentials com.example.aws.s3.access_key are loaded in Java Properties getProperty(...) | +| configuration.properties:34:1:34:70 | com.example.aws.s3.secret_key=8lMPSfWzZq+wcWtck5+QPLOJDZzE783pS09/IO3k | Plaintext credentials com.example.aws.s3.secret_key are loaded in Java Properties getProperty(...) | diff --git a/java/ql/test/experimental/query-tests/security/CWE-555/CredentialsInPropertiesFile.ql b/java/ql/test/experimental/query-tests/security/CWE-555/CredentialsInPropertiesFile.ql index b6890e4ac9f..f085317218c 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-555/CredentialsInPropertiesFile.ql +++ b/java/ql/test/experimental/query-tests/security/CWE-555/CredentialsInPropertiesFile.ql @@ -18,98 +18,7 @@ */ import java -import semmle.code.configfiles.ConfigFiles -import semmle.code.java.dataflow.FlowSources - -private string possibleSecretName() { - result = - [ - "%password%", "%passwd%", "%account%", "%accnt%", "%credential%", "%token%", "%secret%", - "%access%key%" - ] -} - -private string possibleEncryptedSecretName() { result = ["%hashed%", "%encrypted%", "%crypt%"] } - -/** Holds if the value is not cleartext credentials. */ -bindingset[value] -predicate isNotCleartextCredentials(string value) { - value = "" // Empty string - or - value.length() < 7 // Typical credentials are no less than 6 characters - or - value.matches("% %") // Sentences containing spaces - or - value.regexpMatch(".*[^a-zA-Z\\d]{3,}.*") // Contain repeated non-alphanumeric characters such as a fake password pass**** or ???? - or - value.matches("@%") // Starts with the "@" sign - or - value.regexpMatch("\\$\\{.*\\}") // Variable placeholder ${credentials} - or - value.matches("%=") // A basic check of encrypted credentials ending with padding characters - or - value.matches("ENC(%)") // Encrypted value - or - // Could be a message property for UI display or fake passwords, e.g. login.password_expired=Your current password has expired. - value.toLowerCase().matches(possibleSecretName()) -} - -/** The credentials configuration property. */ -class CredentialsConfig extends ConfigPair { - CredentialsConfig() { - this.getNameElement().getName().trim().toLowerCase().matches(possibleSecretName()) and - not this.getNameElement().getName().trim().toLowerCase().matches(possibleEncryptedSecretName()) and - not isNotCleartextCredentials(this.getValueElement().getValue().trim()) - } - - string getName() { result = this.getNameElement().getName().trim() } - - string getValue() { result = this.getValueElement().getValue().trim() } - - /** Returns a description of this vulnerability. */ - string getConfigDesc() { - exists( - LoadCredentialsConfiguration cc, DataFlow::Node source, DataFlow::Node sink, MethodAccess ma - | - this.getName() = source.asExpr().(CompileTimeConstantExpr).getStringValue() and - cc.hasFlow(source, sink) and - ma.getArgument(0) = sink.asExpr() and - result = "Plaintext credentials " + this.getName() + " are loaded in " + ma - ) - or - not exists(LoadCredentialsConfiguration cc, DataFlow::Node source, DataFlow::Node sink | - this.getName() = source.asExpr().(CompileTimeConstantExpr).getStringValue() and - cc.hasFlow(source, sink) - ) and - result = - "Plaintext credentials " + this.getName() + " have cleartext value " + this.getValue() + - " in properties file" - } -} - -/** - * A dataflow configuration tracking flow of a method that loads a credentials property. - */ -class LoadCredentialsConfiguration extends DataFlow::Configuration { - LoadCredentialsConfiguration() { this = "LoadCredentialsConfiguration" } - - override predicate isSource(DataFlow::Node source) { - exists(CredentialsConfig cc | - source.asExpr().(CompileTimeConstantExpr).getStringValue() = cc.getName() - ) - } - - override predicate isSink(DataFlow::Node sink) { - sink.asExpr() = - any(MethodAccess ma | - ma.getMethod() - .getDeclaringType() - .getASupertype*() - .hasQualifiedName("java.util", "Properties") and - ma.getMethod().getName() = "getProperty" - ).getArgument(0) - } -} +import experimental.semmle.code.java.frameworks.CredentialsInPropertiesFile from CredentialsConfig cc select cc, cc.getConfigDesc() diff --git a/java/ql/test/experimental/query-tests/security/CWE-555/MailConfig.java b/java/ql/test/experimental/query-tests/security/CWE-555/MailConfig.java new file mode 100644 index 00000000000..bef99dac3ea --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-555/MailConfig.java @@ -0,0 +1,11 @@ +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class MailConfig { + @Value("${mail.password}") + private String mailPassword; + + @Value("${mail.username}") + private String mailUserName; +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-555/PropertiesUtils.java b/java/ql/test/experimental/query-tests/security/CWE-555/PropertiesUtils.java index b54995a9967..f33ef39ee07 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-555/PropertiesUtils.java +++ b/java/ql/test/experimental/query-tests/security/CWE-555/PropertiesUtils.java @@ -35,16 +35,6 @@ public class PropertiesUtils { return properties.getProperty("datasource1.password"); } - /** Returns the mail account property value. */ - public static String getMailUserName() { - return properties.getProperty("mail.username"); - } - - /** Returns the mail password property value. */ - public static String getMailPassword() { - return properties.getProperty("mail.password"); - } - /** Returns the AWS Access Key property value. */ public static String getAWSAccessKey() { return properties.getProperty("com.example.aws.s3.access_key"); diff --git a/java/ql/test/experimental/query-tests/security/CWE-555/options b/java/ql/test/experimental/query-tests/security/CWE-555/options new file mode 100644 index 00000000000..cf3d60de0e5 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-555/options @@ -0,0 +1 @@ +// semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3 \ No newline at end of file diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/beans/factory/annotation/Value.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/beans/factory/annotation/Value.java new file mode 100644 index 00000000000..67c38cf5d20 --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/beans/factory/annotation/Value.java @@ -0,0 +1,11 @@ +package org.springframework.beans.factory.annotation; + +public @interface Value { + + /** + * The actual value expression such as #{systemProperties.myProp} + * or property placeholder such as ${my.app.myProp}. + */ + String value(); + +} \ No newline at end of file From f27203cc434ee85d62ecbb48fe29d187209d09cb Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 30 Mar 2021 12:20:24 +0100 Subject: [PATCH 447/725] C++: Test spacing. --- .../jsf/4.10 Classes/AV Rule 79/AV Rule 79.expected | 8 ++++---- .../query-tests/jsf/4.10 Classes/AV Rule 79/Variants.cpp | 6 ++++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/cpp/ql/test/query-tests/jsf/4.10 Classes/AV Rule 79/AV Rule 79.expected b/cpp/ql/test/query-tests/jsf/4.10 Classes/AV Rule 79/AV Rule 79.expected index 1d0ef245f3b..2833aecdd6b 100644 --- a/cpp/ql/test/query-tests/jsf/4.10 Classes/AV Rule 79/AV Rule 79.expected +++ b/cpp/ql/test/query-tests/jsf/4.10 Classes/AV Rule 79/AV Rule 79.expected @@ -18,9 +18,9 @@ | NoDestructor.cpp:23:3:23:20 | ... = ... | Resource n is acquired by class MyClass5 but not released anywhere in this class. | | PlacementNew.cpp:36:3:36:36 | ... = ... | Resource p1 is acquired by class MyTestForPlacementNew but not released anywhere in this class. | | SelfRegistering.cpp:25:3:25:24 | ... = ... | Resource side is acquired by class MyOwner but not released anywhere in this class. | -| Variants.cpp:25:3:25:13 | ... = ... | Resource f is acquired by class MyClass4 but not released anywhere in this class. | -| Variants.cpp:65:3:65:17 | ... = ... | Resource a is acquired by class MyClass6 but not released anywhere in this class. | -| Variants.cpp:66:3:66:36 | ... = ... | Resource b is acquired by class MyClass6 but not released anywhere in this class. | -| Variants.cpp:67:3:67:41 | ... = ... | Resource c is acquired by class MyClass6 but not released anywhere in this class. | +| Variants.cpp:26:3:26:13 | ... = ... | Resource f is acquired by class MyClass4 but not released anywhere in this class. | +| Variants.cpp:69:3:69:17 | ... = ... | Resource a is acquired by class MyClass6 but not released anywhere in this class. | +| Variants.cpp:70:3:70:36 | ... = ... | Resource b is acquired by class MyClass6 but not released anywhere in this class. | +| Variants.cpp:71:3:71:41 | ... = ... | Resource c is acquired by class MyClass6 but not released anywhere in this class. | | Wrapped.cpp:46:3:46:22 | ... = ... | Resource ptr2 is acquired by class Wrapped2 but not released anywhere in this class. | | Wrapped.cpp:59:3:59:22 | ... = ... | Resource ptr4 is acquired by class Wrapped2 but not released anywhere in this class. | diff --git a/cpp/ql/test/query-tests/jsf/4.10 Classes/AV Rule 79/Variants.cpp b/cpp/ql/test/query-tests/jsf/4.10 Classes/AV Rule 79/Variants.cpp index e96a5cd4f0d..926702ae8f1 100644 --- a/cpp/ql/test/query-tests/jsf/4.10 Classes/AV Rule 79/Variants.cpp +++ b/cpp/ql/test/query-tests/jsf/4.10 Classes/AV Rule 79/Variants.cpp @@ -6,6 +6,7 @@ void *calloc(size_t nmemb, size_t size); void *realloc(void *ptr, size_t size); void free(void* ptr); + int *ID(int *x) { return x; @@ -45,6 +46,7 @@ public: a = new int[10]; // GOOD b = (int *)calloc(10, sizeof(int)); // GOOD c = (int *)realloc(0, 10 * sizeof(int)); // GOOD + } ~MyClass5() @@ -52,9 +54,11 @@ public: delete [] a; free(b); free(c); + } int *a, *b, *c; + }; class MyClass6 @@ -65,6 +69,7 @@ public: a = new int[10]; // BAD b = (int *)calloc(10, sizeof(int)); // BAD c = (int *)realloc(0, 10 * sizeof(int)); // BAD + } ~MyClass6() @@ -72,6 +77,7 @@ public: } int *a, *b, *c; + }; class MyClass7 From ec952248a9470354706a26936377869d78fb8fe3 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 30 Mar 2021 12:57:00 +0100 Subject: [PATCH 448/725] C++: Test strdup with AV Rule 79. --- .../jsf/4.10 Classes/AV Rule 79/AV Rule 79.expected | 1 + .../jsf/4.10 Classes/AV Rule 79/Variants.cpp | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/cpp/ql/test/query-tests/jsf/4.10 Classes/AV Rule 79/AV Rule 79.expected b/cpp/ql/test/query-tests/jsf/4.10 Classes/AV Rule 79/AV Rule 79.expected index 2833aecdd6b..70ee3fb4704 100644 --- a/cpp/ql/test/query-tests/jsf/4.10 Classes/AV Rule 79/AV Rule 79.expected +++ b/cpp/ql/test/query-tests/jsf/4.10 Classes/AV Rule 79/AV Rule 79.expected @@ -22,5 +22,6 @@ | Variants.cpp:69:3:69:17 | ... = ... | Resource a is acquired by class MyClass6 but not released anywhere in this class. | | Variants.cpp:70:3:70:36 | ... = ... | Resource b is acquired by class MyClass6 but not released anywhere in this class. | | Variants.cpp:71:3:71:41 | ... = ... | Resource c is acquired by class MyClass6 but not released anywhere in this class. | +| Variants.cpp:72:3:72:22 | ... = ... | Resource d is acquired by class MyClass6 but not released anywhere in this class. | | Wrapped.cpp:46:3:46:22 | ... = ... | Resource ptr2 is acquired by class Wrapped2 but not released anywhere in this class. | | Wrapped.cpp:59:3:59:22 | ... = ... | Resource ptr4 is acquired by class Wrapped2 but not released anywhere in this class. | diff --git a/cpp/ql/test/query-tests/jsf/4.10 Classes/AV Rule 79/Variants.cpp b/cpp/ql/test/query-tests/jsf/4.10 Classes/AV Rule 79/Variants.cpp index 926702ae8f1..7727a038248 100644 --- a/cpp/ql/test/query-tests/jsf/4.10 Classes/AV Rule 79/Variants.cpp +++ b/cpp/ql/test/query-tests/jsf/4.10 Classes/AV Rule 79/Variants.cpp @@ -5,7 +5,7 @@ void *malloc(size_t size); void *calloc(size_t nmemb, size_t size); void *realloc(void *ptr, size_t size); void free(void* ptr); - +char *strdup(const char *s1); int *ID(int *x) { @@ -46,7 +46,7 @@ public: a = new int[10]; // GOOD b = (int *)calloc(10, sizeof(int)); // GOOD c = (int *)realloc(0, 10 * sizeof(int)); // GOOD - + d = strdup("string"); } ~MyClass5() @@ -54,11 +54,11 @@ public: delete [] a; free(b); free(c); - + free(d); } int *a, *b, *c; - + char *d; }; class MyClass6 @@ -69,7 +69,7 @@ public: a = new int[10]; // BAD b = (int *)calloc(10, sizeof(int)); // BAD c = (int *)realloc(0, 10 * sizeof(int)); // BAD - + d = strdup("string"); // BAD } ~MyClass6() @@ -77,7 +77,7 @@ public: } int *a, *b, *c; - + char *d; }; class MyClass7 From 35f294f096c160db887b37fff31a740f32e9f3f8 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Tue, 30 Mar 2021 10:38:13 +0100 Subject: [PATCH 449/725] JS: Improve sequelize model --- .../src/semmle/javascript/frameworks/SQL.qll | 24 ++++++++++++++----- .../frameworks/SQL/SqlString.expected | 4 ++++ .../frameworks/SQL/sequelize-types.ts | 9 +++++++ .../frameworks/SQL/sequelize2.js | 6 +++++ 4 files changed, 37 insertions(+), 6 deletions(-) create mode 100644 javascript/ql/test/library-tests/frameworks/SQL/sequelize-types.ts diff --git a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll index f006c73e544..a84bde4cdd0 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll @@ -463,22 +463,34 @@ private module MsSql { * Provides classes modelling the `sequelize` package. */ private module Sequelize { - /** Gets an import of the `sequelize` module. */ - API::Node sequelize() { result = API::moduleImport("sequelize") } + /** Gets an import of the `sequelize` module or one that re-exports it. */ + API::Node sequelize() { result = API::moduleImport(["sequelize", "sequelize-typescript"]) } /** Gets an expression that creates an instance of the `Sequelize` class. */ - API::Node newSequelize() { result = sequelize().getInstance() } + API::Node instance() { + result = [sequelize(), sequelize().getMember("Sequelize")].getInstance() + or + result = API::Node::ofType(["sequelize", "sequelize-typescript"], ["Sequelize", "default"]) + } /** A call to `Sequelize.query`. */ private class QueryCall extends DatabaseAccess, DataFlow::MethodCallNode { - QueryCall() { this = newSequelize().getMember("query").getACall() } + QueryCall() { this = instance().getMember("query").getACall() } - override DataFlow::Node getAQueryArgument() { result = getArgument(0) } + override DataFlow::Node getAQueryArgument() { + result = getArgument(0) + or + result = getOptionArgument(0, "query") + } } /** An expression that is passed to `Sequelize.query` method and hence interpreted as SQL. */ class QueryString extends SQL::SqlString { - QueryString() { this = any(QueryCall qc).getAQueryArgument().asExpr() } + QueryString() { + this = any(QueryCall qc).getAQueryArgument().asExpr() + or + this = sequelize().getMember(["literal", "asIs"]).getParameter(0).getARhs().asExpr() + } } /** diff --git a/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected b/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected index 8720962382b..a5e87fe45d8 100644 --- a/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected +++ b/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected @@ -33,6 +33,10 @@ | postgres-types.ts:4:18:4:29 | 'SELECT 123' | | postgresImport.js:4:18:4:43 | 'SELECT ... number' | | sequelize2.js:10:17:10:118 | 'SELECT ... Y name' | +| sequelize2.js:12:17:15:1 | {\\n que ... [123]\\n} | +| sequelize2.js:13:10:13:20 | 'SELECT $1' | +| sequelize2.js:17:31:17:41 | '123 + 345' | +| sequelize-types.ts:7:24:7:35 | 'SELECT 123' | | sequelize.js:8:17:8:118 | 'SELECT ... Y name' | | sequelizeImport.js:3:17:3:118 | 'SELECT ... Y name' | | spanner2.js:5:26:5:35 | "SQL code" | diff --git a/javascript/ql/test/library-tests/frameworks/SQL/sequelize-types.ts b/javascript/ql/test/library-tests/frameworks/SQL/sequelize-types.ts new file mode 100644 index 00000000000..2591048bdb5 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/SQL/sequelize-types.ts @@ -0,0 +1,9 @@ +import Sequelize from 'sequelize'; + +export class Foo { + constructor(private seq: Sequelize) {} + + method() { + this.seq.query('SELECT 123'); + } +} diff --git a/javascript/ql/test/library-tests/frameworks/SQL/sequelize2.js b/javascript/ql/test/library-tests/frameworks/SQL/sequelize2.js index 194a921ffdd..9fa7392cad6 100644 --- a/javascript/ql/test/library-tests/frameworks/SQL/sequelize2.js +++ b/javascript/ql/test/library-tests/frameworks/SQL/sequelize2.js @@ -9,3 +9,9 @@ const sequelize = new Sequelize('database', { }); sequelize.query('SELECT * FROM Products WHERE (name LIKE \'%' + criteria + '%\') AND deletedAt IS NULL) ORDER BY name'); +sequelize.query({ + query: 'SELECT $1', + values: [123] +}); + +let value = Sequelize.literal('123 + 345'); From 9db235ac3660a894d610d49388e452317329744d Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Tue, 30 Mar 2021 11:26:44 +0100 Subject: [PATCH 450/725] JS: Improve @google-cloud/spanner model --- .../src/semmle/javascript/frameworks/SQL.qll | 80 ++++++++++++------- .../frameworks/SQL/SqlString.expected | 3 + .../frameworks/SQL/spanner-types.ts | 5 ++ .../library-tests/frameworks/SQL/spanner.js | 12 +++ 4 files changed, 71 insertions(+), 29 deletions(-) create mode 100644 javascript/ql/test/library-tests/frameworks/SQL/spanner-types.ts diff --git a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll index a84bde4cdd0..ce702decc96 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll @@ -543,6 +543,8 @@ private module Spanner { API::Node database() { result = spanner().getReturn().getMember("instance").getReturn().getMember("database").getReturn() + or + result = API::Node::ofType("@google-cloud/spanner", "Database") } /** @@ -550,61 +552,81 @@ private module Spanner { */ API::Node v1SpannerClient() { result = spanner().getMember("v1").getMember("SpannerClient").getInstance() + or + result = API::Node::ofType("@google-cloud/spanner", "v1.SpannerClient") } /** * Gets a node that refers to a transaction object. */ API::Node transaction() { - result = database().getMember("runTransaction").getParameter(0).getParameter(1) + result = + database() + .getMember(["runTransaction", "runTransactionAsync"]) + .getParameter([0, 1]) + .getParameter(1) + or + result = API::Node::ofType("@google-cloud/spanner", "Transaction") + } + + /** Gets an API node referring to a `BatchTransaction` object. */ + API::Node batchTransaction() { + result = database().getMember("batchTransaction").getReturn() + or + result = database().getMember("createBatchTransaction").getReturn().getPromised() + or + result = API::Node::ofType("@google-cloud/spanner", "BatchTransaction") } /** * A call to a Spanner method that executes a SQL query. */ - abstract class SqlExecution extends DatabaseAccess, DataFlow::InvokeNode { - /** - * Gets the position of the query argument; default is zero, which can be overridden - * by subclasses. - */ - int getQueryArgumentPosition() { result = 0 } + abstract class SqlExecution extends DatabaseAccess, DataFlow::InvokeNode { } + + /** + * A SQL execution that takes the input directly in the first argument or in the `sql` option. + */ + class SqlExecutionDirect extends SqlExecution { + SqlExecutionDirect() { + this = database().getMember(["run", "runPartitionedUpdate", "runStream"]).getACall() + or + this = transaction().getMember(["run", "runStream", "runUpdate"]).getACall() + or + this = batchTransaction().getMember("createQueryPartitions").getACall() + } override DataFlow::Node getAQueryArgument() { - result = getArgument(getQueryArgumentPosition()) or - result = getOptionArgument(getQueryArgumentPosition(), "sql") + result = getArgument(0) + or + result = getOptionArgument(0, "sql") } } /** - * A call to `Database.run`, `Database.runPartitionedUpdate` or `Database.runStream`. + * A SQL execution that takes an array of SQL strings or { sql: string } objects. */ - class DatabaseRunCall extends SqlExecution { - DatabaseRunCall() { - this = database().getMember(["run", "runPartitionedUpdate", "runStream"]).getACall() + class SqlExecutionBatch extends SqlExecution, API::CallNode { + SqlExecutionBatch() { this = transaction().getMember("batchUpdate").getACall() } + + override DataFlow::Node getAQueryArgument() { + // just use the whole array as the query argument, as arrays becomes tainted if one of the elements + // are tainted + result = getArgument(0) + or + result = getParameter(0).getUnknownMember().getMember("sql").getARhs() } } /** - * A call to `Transaction.run`, `Transaction.runStream` or `Transaction.runUpdate`. + * A SQL execution that only takes the input in the `sql` option, and do not accept query strings + * directly. */ - class TransactionRunCall extends SqlExecution { - TransactionRunCall() { - this = transaction().getMember(["run", "runStream", "runUpdate"]).getACall() - } - } - - /** - * A call to `v1.SpannerClient.executeSql` or `v1.SpannerClient.executeStreamingSql`. - */ - class ExecuteSqlCall extends SqlExecution { - ExecuteSqlCall() { + class SqlExecutionWithOption extends SqlExecution { + SqlExecutionWithOption() { this = v1SpannerClient().getMember(["executeSql", "executeStreamingSql"]).getACall() } - override DataFlow::Node getAQueryArgument() { - // `executeSql` and `executeStreamingSql` do not accept query strings directly - result = getOptionArgument(0, "sql") - } + override DataFlow::Node getAQueryArgument() { result = getOptionArgument(0, "sql") } } /** diff --git a/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected b/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected index a5e87fe45d8..41bf9865b16 100644 --- a/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected +++ b/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected @@ -41,6 +41,7 @@ | sequelizeImport.js:3:17:3:118 | 'SELECT ... Y name' | | spanner2.js:5:26:5:35 | "SQL code" | | spanner2.js:7:35:7:44 | "SQL code" | +| spanner-types.ts:4:12:4:23 | 'SELECT 123' | | spanner.js:6:8:6:17 | "SQL code" | | spanner.js:7:8:7:26 | { sql: "SQL code" } | | spanner.js:7:15:7:24 | "SQL code" | @@ -59,6 +60,8 @@ | spanner.js:18:16:18:25 | "SQL code" | | spanner.js:19:16:19:34 | { sql: "SQL code" } | | spanner.js:19:23:19:32 | "SQL code" | +| spanner.js:23:12:23:23 | 'SELECT 123' | +| spanner.js:26:12:26:38 | 'UPDATE ... = @baz' | | spannerImport.js:4:8:4:17 | "SQL code" | | sqlite-types.ts:4:12:4:49 | "UPDATE ... id = ?" | | sqlite.js:7:8:7:45 | "UPDATE ... id = ?" | diff --git a/javascript/ql/test/library-tests/frameworks/SQL/spanner-types.ts b/javascript/ql/test/library-tests/frameworks/SQL/spanner-types.ts new file mode 100644 index 00000000000..8dceca56e60 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/SQL/spanner-types.ts @@ -0,0 +1,5 @@ +import { Database } from "@google-cloud/spanner"; + +export function doSomething(db: Database) { + db.run('SELECT 123'); +} diff --git a/javascript/ql/test/library-tests/frameworks/SQL/spanner.js b/javascript/ql/test/library-tests/frameworks/SQL/spanner.js index a27c52d82fd..8396745f7e6 100644 --- a/javascript/ql/test/library-tests/frameworks/SQL/spanner.js +++ b/javascript/ql/test/library-tests/frameworks/SQL/spanner.js @@ -17,6 +17,18 @@ db.runTransaction((err, tx) => { tx.runStream({ sql: "SQL code" }); tx.runUpdate("SQL code"); tx.runUpdate({ sql: "SQL code" }); + + const queries = [ + { + sql: 'SELECT 123', + }, + { + sql: 'UPDATE foo SET bar = @baz', + params: {key: 'baz', value: '123'} + } + ]; + + tx.batchUpdate(queries, () => {}); }); exports.instance = instance; From f8bbda0cdc82aa8c155c8f4d0e76e2f6dd811ab9 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Tue, 30 Mar 2021 11:37:45 +0100 Subject: [PATCH 451/725] JS: Change note --- javascript/change-notes/2021-03-30-sql-models.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 javascript/change-notes/2021-03-30-sql-models.md diff --git a/javascript/change-notes/2021-03-30-sql-models.md b/javascript/change-notes/2021-03-30-sql-models.md new file mode 100644 index 00000000000..2ceaf8dc7a7 --- /dev/null +++ b/javascript/change-notes/2021-03-30-sql-models.md @@ -0,0 +1,3 @@ +lgtm,codescanning +* The SQL library models for `mysql`, `mysql2`, `mssql`, `pg`, `sqlite3`, `sequelize`, and `@google-cloud/spanner` have improved, + leading to more SQL injection sinks. From 62de15cd22c1e219b63aea0b85a0d1c938ca41bb Mon Sep 17 00:00:00 2001 From: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Tue, 30 Mar 2021 14:45:05 +0100 Subject: [PATCH 452/725] Docs: Mention that binding sets are available for classes --- .../ql-language-reference/annotations.rst | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/docs/codeql/ql-language-reference/annotations.rst b/docs/codeql/ql-language-reference/annotations.rst index b3dabb42bfb..7d9dc2b6247 100644 --- a/docs/codeql/ql-language-reference/annotations.rst +++ b/docs/codeql/ql-language-reference/annotations.rst @@ -385,21 +385,23 @@ For more information, see ":ref:`monotonic-aggregates`." Binding sets ============ -**Available for**: |characteristic predicates|, |member predicates|, |non-member predicates| +**Available for**: |classes|, |characteristic predicates|, |member predicates|, |non-member predicates| ``bindingset[...]`` ------------------- -You can use this annotation to explicitly state the binding sets for a predicate. A binding set -is a subset of the predicate's arguments such that, if those arguments are constrained to a -finite set of values, then the predicate itself is finite (that is, it evaluates to a finite +You can use this annotation to explicitly state the binding sets for a class or predicate. A binding set +is a subset of a class or predicate's arguments such that, if those arguments are constrained to a +finite set of values, then the class or predicate itself is finite (that is, it evaluates to a finite set of tuples). -The ``bindingset`` annotation takes a comma-separated list of variables. Each variable must be -an argument of the predicate, possibly including ``this`` (for characteristic predicates and -member predicates) and ``result`` (for predicates that return a result). +The ``bindingset`` annotation takes a comma-separated list of variables. -For more information, see ":ref:`predicate-binding`." +- When you annotate a class, each variable must be ``this`` or a field in the class. + Binding sets for classes are supported from release 2.3.0 of the CodeQL CLI, and release 1.26 of LGTM Enterprise. +- When you annotate a predicate, each variable must be an argument of the predicate, possibly including ``this`` + (for characteristic predicates and member predicates) and ``result`` (for predicates that return a result). + For more information, see ":ref:`predicate-binding`." .. Links to use in substitutions From 244966e216c21681491140c0a55e92fd4a9e496a Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 30 Mar 2021 14:49:05 +0100 Subject: [PATCH 453/725] C++: Add a test with strdup. --- .../Critical/MemoryFreed/MemoryNeverFreed.expected | 1 + .../test/query-tests/Critical/MemoryFreed/test.cpp | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/cpp/ql/test/query-tests/Critical/MemoryFreed/MemoryNeverFreed.expected b/cpp/ql/test/query-tests/Critical/MemoryFreed/MemoryNeverFreed.expected index 900925d8927..d44735d4bee 100644 --- a/cpp/ql/test/query-tests/Critical/MemoryFreed/MemoryNeverFreed.expected +++ b/cpp/ql/test/query-tests/Critical/MemoryFreed/MemoryNeverFreed.expected @@ -10,3 +10,4 @@ | test.cpp:89:18:89:23 | call to malloc | This memory is never freed | | test.cpp:156:3:156:26 | new | This memory is never freed | | test.cpp:157:3:157:26 | new[] | This memory is never freed | +| test.cpp:167:14:167:19 | call to strdup | This memory is never freed | diff --git a/cpp/ql/test/query-tests/Critical/MemoryFreed/test.cpp b/cpp/ql/test/query-tests/Critical/MemoryFreed/test.cpp index 63636166fc8..651afe85006 100644 --- a/cpp/ql/test/query-tests/Critical/MemoryFreed/test.cpp +++ b/cpp/ql/test/query-tests/Critical/MemoryFreed/test.cpp @@ -156,3 +156,15 @@ int overloadedNew() { new(std::nothrow) int(3); // BAD new(std::nothrow) int[2]; // BAD } + +// --- strdup --- + +char *strdup(const char *s1); +void output_msg(const char *msg); + +void test_strdup() { + char msg[] = "OctoCat"; + char *cpy = strdup(msg); // BAD + + output_msg(cpy); +} From a8284d5b978ec23f1c4b3471a6dfe8d41751743c Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 30 Mar 2021 15:26:45 +0100 Subject: [PATCH 454/725] C++: Add mutex test case. --- .../semmle/tests/UnreleasedLock.expected | 1 + .../CWE/CWE-764/semmle/tests/test.cpp | 43 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-764/semmle/tests/UnreleasedLock.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-764/semmle/tests/UnreleasedLock.expected index 0d06ce59719..de14b91f8eb 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-764/semmle/tests/UnreleasedLock.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-764/semmle/tests/UnreleasedLock.expected @@ -7,3 +7,4 @@ | test.cpp:303:11:303:18 | call to try_lock | This lock might not be unlocked or might be locked more times than it is unlocked. | | test.cpp:313:11:313:18 | call to try_lock | This lock might not be unlocked or might be locked more times than it is unlocked. | | test.cpp:442:8:442:17 | call to mutex_lock | This lock might not be unlocked or might be locked more times than it is unlocked. | +| test.cpp:482:2:482:19 | call to pthread_mutex_lock | This lock might not be unlocked or might be locked more times than it is unlocked. | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-764/semmle/tests/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-764/semmle/tests/test.cpp index c08ac2f63c3..9114e545fd5 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-764/semmle/tests/test.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-764/semmle/tests/test.cpp @@ -445,3 +445,46 @@ bool test_mutex(data_t *data) return true; } + +// --- + +struct pthread_mutex +{ + // ... +}; + +void pthread_mutex_lock(pthread_mutex *m); +void pthread_mutex_unlock(pthread_mutex *m); + +class MyClass +{ +public: + pthread_mutex lock; +}; + +bool maybe(); + +int test_MyClass_good(MyClass *obj) +{ + pthread_mutex_lock(&obj->lock); + + if (maybe()) { + pthread_mutex_unlock(&obj->lock); + return -1; // GOOD + } + + pthread_mutex_unlock(&obj->lock); // GOOD + return 0; +} + +int test_MyClass_bad(MyClass *obj) +{ + pthread_mutex_lock(&obj->lock); + + if (maybe()) { + return -1; // BAD + } + + pthread_mutex_unlock(&obj->lock); // GOOD + return 0; +} From 23df459c161cf666ab37586dd6d9ab0e7de1e63d Mon Sep 17 00:00:00 2001 From: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Tue, 30 Mar 2021 17:23:33 +0100 Subject: [PATCH 455/725] remove accidental punctuation --- docs/codeql/codeql-cli/about-ql-packs.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/codeql/codeql-cli/about-ql-packs.rst b/docs/codeql/codeql-cli/about-ql-packs.rst index 7391b3ac73c..b3f3c13ed88 100644 --- a/docs/codeql/codeql-cli/about-ql-packs.rst +++ b/docs/codeql/codeql-cli/about-ql-packs.rst @@ -75,7 +75,7 @@ The following properties are supported in ``qlpack.yml`` files. * - ``name`` - ``org-queries`` - All packs - - The name of the QL pack defined using alphanumeric characters, hyphens, and periods. It must be unique as CodeQL cannot differentiate between QL packs with identical names. If you intend to distribute the pack, prefix the name with your (or your organization's) name followed by a hyphen. Use the pack name to specify queries to run using ``database analyze`` and to define dependencies between QL packs (see examples below).- ' + - The name of the QL pack defined using alphanumeric characters, hyphens, and periods. It must be unique as CodeQL cannot differentiate between QL packs with identical names. If you intend to distribute the pack, prefix the name with your (or your organization's) name followed by a hyphen. Use the pack name to specify queries to run using ``database analyze`` and to define dependencies between QL packs (see examples below). * - ``version`` - ``0.0.0`` - All packs From 67835ee2737c26a6264317eb64e10a36d8ae1665 Mon Sep 17 00:00:00 2001 From: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Tue, 30 Mar 2021 17:29:43 +0100 Subject: [PATCH 456/725] Address review comments --- docs/codeql/ql-language-reference/annotations.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/codeql/ql-language-reference/annotations.rst b/docs/codeql/ql-language-reference/annotations.rst index 7d9dc2b6247..7223f15f18c 100644 --- a/docs/codeql/ql-language-reference/annotations.rst +++ b/docs/codeql/ql-language-reference/annotations.rst @@ -390,9 +390,9 @@ Binding sets ``bindingset[...]`` ------------------- -You can use this annotation to explicitly state the binding sets for a class or predicate. A binding set -is a subset of a class or predicate's arguments such that, if those arguments are constrained to a -finite set of values, then the class or predicate itself is finite (that is, it evaluates to a finite +You can use this annotation to explicitly state the binding sets for a predicate or class. A binding set +is a subset of a predicate's or class body's arguments such that, if those arguments are constrained to a +finite set of values, then the predicate or class itself is finite (that is, it evaluates to a finite set of tuples). The ``bindingset`` annotation takes a comma-separated list of variables. From fb004bacc39c3fa218c93f3179aad962a00e8595 Mon Sep 17 00:00:00 2001 From: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Tue, 30 Mar 2021 17:31:20 +0100 Subject: [PATCH 457/725] Describe predicates first --- docs/codeql/ql-language-reference/annotations.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/codeql/ql-language-reference/annotations.rst b/docs/codeql/ql-language-reference/annotations.rst index 7223f15f18c..ec60e55bf9b 100644 --- a/docs/codeql/ql-language-reference/annotations.rst +++ b/docs/codeql/ql-language-reference/annotations.rst @@ -397,11 +397,11 @@ set of tuples). The ``bindingset`` annotation takes a comma-separated list of variables. -- When you annotate a class, each variable must be ``this`` or a field in the class. - Binding sets for classes are supported from release 2.3.0 of the CodeQL CLI, and release 1.26 of LGTM Enterprise. - When you annotate a predicate, each variable must be an argument of the predicate, possibly including ``this`` (for characteristic predicates and member predicates) and ``result`` (for predicates that return a result). For more information, see ":ref:`predicate-binding`." +- When you annotate a class, each variable must be ``this`` or a field in the class. + Binding sets for classes are supported from release 2.3.0 of the CodeQL CLI, and release 1.26 of LGTM Enterprise. .. Links to use in substitutions From bc5b477f79e2dd992032e973852596574b5033b2 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Tue, 30 Mar 2021 21:26:58 +0100 Subject: [PATCH 458/725] JS: Change kind of summary-extraction queries to table --- .../ql/src/experimental/Summaries/ExtractFlowStepSummaries.ql | 2 +- .../ql/src/experimental/Summaries/ExtractSinkSummaries.ql | 2 +- .../ql/src/experimental/Summaries/ExtractSourceSummaries.ql | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/experimental/Summaries/ExtractFlowStepSummaries.ql b/javascript/ql/src/experimental/Summaries/ExtractFlowStepSummaries.ql index 14f51f07646..36be3c03606 100644 --- a/javascript/ql/src/experimental/Summaries/ExtractFlowStepSummaries.ql +++ b/javascript/ql/src/experimental/Summaries/ExtractFlowStepSummaries.ql @@ -5,7 +5,7 @@ * user-controlled exit node of portal `p1` to an escaping entry node of portal `p2`, * and have label `lbl2` at that point. Moreover, the path from `p1` to `p2` contains * no sanitizers specified by configuration `cfg`. - * @kind flow-step-summary + * @kind table * @id js/step-summary-extraction */ diff --git a/javascript/ql/src/experimental/Summaries/ExtractSinkSummaries.ql b/javascript/ql/src/experimental/Summaries/ExtractSinkSummaries.ql index ddc1c950740..af998563be4 100644 --- a/javascript/ql/src/experimental/Summaries/ExtractSinkSummaries.ql +++ b/javascript/ql/src/experimental/Summaries/ExtractSinkSummaries.ql @@ -3,7 +3,7 @@ * @description Extracts sink summaries, that is, tuples `(p, lbl, cfg)` representing the fact * that data with flow label `lbl` may flow from a user-controlled exit node of portal * `p` to a known sink for configuration `cfg`. - * @kind sink-summary + * @kind table * @id js/sink-summary-extraction */ diff --git a/javascript/ql/src/experimental/Summaries/ExtractSourceSummaries.ql b/javascript/ql/src/experimental/Summaries/ExtractSourceSummaries.ql index 86741b692b8..6e0b8e1c622 100644 --- a/javascript/ql/src/experimental/Summaries/ExtractSourceSummaries.ql +++ b/javascript/ql/src/experimental/Summaries/ExtractSourceSummaries.ql @@ -3,7 +3,7 @@ * @description Extracts source summaries, that is, tuples `(p, lbl, cfg)` representing the fact * that data may flow from a known source for configuration `cfg` to an escaping entry * node of portal `p`, and have flow label `lbl` at that point. - * @kind source-summary + * @kind table * @id js/source-summary-extraction */ From 4f9b6d11924fc5a49edb6bca0f5ae79bd71b205d Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Wed, 31 Mar 2021 08:56:27 +0100 Subject: [PATCH 459/725] Update supported Go version to 1.16 --- docs/codeql/support/reusables/versions-compilers.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/codeql/support/reusables/versions-compilers.rst b/docs/codeql/support/reusables/versions-compilers.rst index 39e30bbc7cb..a338791953b 100644 --- a/docs/codeql/support/reusables/versions-compilers.rst +++ b/docs/codeql/support/reusables/versions-compilers.rst @@ -14,7 +14,7 @@ C#,C# up to 8.0,"Microsoft Visual Studio up to 2019 with .NET up to 4.8, .NET Core up to 3.1","``.sln``, ``.csproj``, ``.cs``, ``.cshtml``, ``.xaml``" - Go (aka Golang), "Go up to 1.15", "Go 1.11 or more recent", ``.go`` + Go (aka Golang), "Go up to 1.16", "Go 1.11 or more recent", ``.go`` Java,"Java 7 to 15 [3]_","javac (OpenJDK and Oracle JDK), Eclipse compiler for Java (ECJ) [4]_",``.java`` From 57784dc7461f3f4624966b9c9e0356fe0018ee5b Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 31 Mar 2021 09:23:47 +0100 Subject: [PATCH 460/725] JS: Update test output --- .../ql/test/library-tests/frameworks/SQL/SqlString.expected | 1 + 1 file changed, 1 insertion(+) diff --git a/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected b/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected index 41bf9865b16..81338e00140 100644 --- a/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected +++ b/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected @@ -62,6 +62,7 @@ | spanner.js:19:23:19:32 | "SQL code" | | spanner.js:23:12:23:23 | 'SELECT 123' | | spanner.js:26:12:26:38 | 'UPDATE ... = @baz' | +| spanner.js:31:18:31:24 | queries | | spannerImport.js:4:8:4:17 | "SQL code" | | sqlite-types.ts:4:12:4:49 | "UPDATE ... id = ?" | | sqlite.js:7:8:7:45 | "UPDATE ... id = ?" | From 8159098dc0e47627a2386d8682e36f3d0445ca3e Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 31 Mar 2021 11:32:01 +0200 Subject: [PATCH 461/725] C++: Add test from issue #5190. --- .../dataflow/taint-tests/smart_pointer.cpp | 10 ++++++++++ cpp/ql/test/library-tests/dataflow/taint-tests/stl.h | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/smart_pointer.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/smart_pointer.cpp index f45260228e8..1f222cbae3e 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/smart_pointer.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/smart_pointer.cpp @@ -65,4 +65,14 @@ void test_shared_field_member() { std::unique_ptr p = std::make_unique(source(), 0); sink(p->x); // $ MISSING: ast,ir sink(p->y); // not tainted +} + +void getNumber(std::shared_ptr ptr) { + *ptr = source(); +} + +int test_from_issue_5190() { + std::shared_ptr p(new int); + getNumber(p); + sink(*p); // $ MISSING: ast,ir } \ No newline at end of file diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/stl.h b/cpp/ql/test/library-tests/dataflow/taint-tests/stl.h index 09e77c5a3b6..1382552bdca 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/stl.h +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/stl.h @@ -348,7 +348,7 @@ namespace std { class shared_ptr { public: shared_ptr() noexcept; - explicit shared_ptr(T*); + explicit shared_ptr(T*); shared_ptr(const shared_ptr&) noexcept; template shared_ptr(const shared_ptr&) noexcept; template shared_ptr(shared_ptr&&) noexcept; From 85ecfe2723c236fb7c4fcb529cea9b7c99c3dac0 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 31 Mar 2021 11:34:56 +0100 Subject: [PATCH 462/725] Update cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql Co-authored-by: Mathias Vorreiter Pedersen --- .../WrongInDetectingAndHandlingMemoryAllocationErrors.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql b/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql index ea946c47c76..4869da7e6f3 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql @@ -72,7 +72,7 @@ class WrongCheckErrorOperatorNew extends FunctionCall { } /** - * Holds if `(std::nothrow)` exists in call `operator new`. + * Holds if `(std::nothrow)` or `(std::noexcept)` exists in call `operator new`. */ predicate isExistsNothrow() { getTarget().isNoExcept() or getTarget().isNoThrow() } } From 9ff894bf839a098aad951f8d5df23b6f339da14b Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 31 Mar 2021 11:42:09 +0200 Subject: [PATCH 463/725] C++: Add support for AST dataflow out of functions that take a smart pointer by value. --- .../cpp/dataflow/internal/DataFlowUtil.qll | 14 ++++ .../code/cpp/dataflow/internal/FlowVar.qll | 72 ++++++++++++++++++- .../dataflow/internal/TaintTrackingUtil.qll | 6 +- cpp/ql/src/semmle/code/cpp/exprs/Call.qll | 1 + .../dataflow/taint-tests/localTaint.expected | 22 ++++++ .../dataflow/taint-tests/smart_pointer.cpp | 10 +-- 6 files changed, 118 insertions(+), 7 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll index 0a6d459ec79..baf5f72b75b 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll @@ -199,6 +199,8 @@ class DefinitionByReferenceOrIteratorNode extends PartialDefinitionNode { this.getPartialDefinition() instanceof DefinitionByReference or this.getPartialDefinition() instanceof DefinitionByIterator + or + this.getPartialDefinition() instanceof DefinitionBySmartPointer ) } @@ -330,6 +332,18 @@ class IteratorPartialDefinitionNode extends PartialDefinitionNode { override Node getPreUpdateNode() { pd.definesExpressions(_, result.asExpr()) } } +/** + * INTERNAL: do not use. + * + * A synthetic data flow node used for flow into a collection when a smart pointer + * write occurs in a callee. + */ +class SmartPointerPartialDefinitionNode extends PartialDefinitionNode { + override SmartPointerPartialDefinition pd; + + override Node getPreUpdateNode() { pd.definesExpressions(_, result.asExpr()) } +} + /** * A post-update node on the `e->f` in `f(&e->f)` (and other forms). */ diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll index f3aa94a7992..21ba4dff36d 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll @@ -7,6 +7,7 @@ private import semmle.code.cpp.controlflow.SSA private import semmle.code.cpp.dataflow.internal.SubBasicBlocks private import semmle.code.cpp.dataflow.internal.AddressFlow private import semmle.code.cpp.models.implementations.Iterator +private import semmle.code.cpp.models.interfaces.PointerWrapper /** * A conceptual variable that is assigned only once, like an SSA variable. This @@ -243,6 +244,54 @@ private module PartialDefinitions { } } + class SmartPointerPartialDefinition extends PartialDefinition { + Variable pointer; + Expr innerDefinedExpr; + + SmartPointerPartialDefinition() { + exists(Expr convertedInner | + not this instanceof Conversion and + valueToUpdate(convertedInner, this.getFullyConverted(), node) and + innerDefinedExpr = convertedInner.getUnconverted() and + innerDefinedExpr = getAPointerWrapperAccess(pointer) + ) + or + // iterators passed by value without a copy constructor + exists(Call call | + call = node and + call.getAnArgument() = innerDefinedExpr and + innerDefinedExpr = this and + this = getAPointerWrapperAccess(pointer) and + not call instanceof OverloadedPointerDereferenceExpr + ) + or + // iterators passed by value with a copy constructor + exists(Call call, ConstructorCall copy | + copy.getTarget() instanceof CopyConstructor and + call = node and + call.getAnArgument() = copy and + copy.getArgument(0) = getAPointerWrapperAccess(pointer) and + innerDefinedExpr = this and + this = copy and + not call instanceof OverloadedPointerDereferenceExpr + ) + } + + deprecated override predicate partiallyDefines(Variable v) { v = pointer } + + deprecated override predicate partiallyDefinesThis(ThisExpr e) { none() } + + override predicate definesExpressions(Expr inner, Expr outer) { + inner = innerDefinedExpr and + outer = this + } + + override predicate partiallyDefinesVariableAt(Variable v, ControlFlowNode cfn) { + v = pointer and + cfn = node + } + } + /** * A partial definition that's a definition via an output iterator. */ @@ -256,6 +305,15 @@ private module PartialDefinitions { class DefinitionByReference extends VariablePartialDefinition { DefinitionByReference() { exists(Call c | this = c.getAnArgument() or this = c.getQualifier()) } } + + /** + * A partial definition that's a definition via a smart pointer being passed into a function. + */ + class DefinitionBySmartPointer extends SmartPointerPartialDefinition { + DefinitionBySmartPointer() { + exists(Call c | this = c.getAnArgument() or this = c.getQualifier()) + } + } } import PartialDefinitions @@ -296,7 +354,8 @@ module FlowVar_internal { // treating them as immutable, but for data flow it gives better results in // practice to make the variable synonymous with its contents. not v.getUnspecifiedType() instanceof ReferenceType and - not v instanceof IteratorParameter + not v instanceof IteratorParameter and + not v instanceof PointerWrapperParameter } /** @@ -648,6 +707,8 @@ module FlowVar_internal { ) or p instanceof IteratorParameter + or + p instanceof PointerWrapperParameter } /** @@ -832,10 +893,19 @@ module FlowVar_internal { ) } + Call getAPointerWrapperAccess(Variable pointer) { + pointer.getUnspecifiedType() instanceof PointerWrapper and + [result.getQualifier(), result.getAnArgument()] = pointer.getAnAccess() + } + class IteratorParameter extends Parameter { IteratorParameter() { this.getUnspecifiedType() instanceof Iterator } } + class PointerWrapperParameter extends Parameter { + PointerWrapperParameter() { this.getUnspecifiedType() instanceof PointerWrapper } + } + /** * Holds if `v` is initialized to have value `assignedExpr`. */ diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/TaintTrackingUtil.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/TaintTrackingUtil.qll index 1ef340c4f21..591f461c8eb 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/TaintTrackingUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/TaintTrackingUtil.qll @@ -11,6 +11,7 @@ private import semmle.code.cpp.models.interfaces.DataFlow private import semmle.code.cpp.models.interfaces.Taint private import semmle.code.cpp.models.interfaces.Iterator +private import semmle.code.cpp.models.interfaces.PointerWrapper private module DataFlow { import semmle.code.cpp.dataflow.internal.DataFlowUtil @@ -141,7 +142,10 @@ private predicate noFlowFromChildExpr(Expr e) { or e instanceof LogicalOrExpr or - e instanceof Call + // Allow taint from `operator*` on smart pointers. + exists(Call call | e = call | + not call.getTarget() = any(PointerWrapper wrapper).getAnUnwrapperFunction() + ) or e instanceof SizeofOperator or diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Call.qll b/cpp/ql/src/semmle/code/cpp/exprs/Call.qll index 349efdcee10..6f6f710ac4b 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Call.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Call.qll @@ -314,6 +314,7 @@ class OverloadedPointerDereferenceFunction extends Function { * T1 operator*(const T2 &); * T1 a; T2 b; * a = *b; + * ``` */ class OverloadedPointerDereferenceExpr extends FunctionCall { OverloadedPointerDereferenceExpr() { diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected index 4444ea13267..9b1ad0d4f10 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -3223,24 +3223,30 @@ | smart_pointer.cpp:11:30:11:50 | call to make_shared | smart_pointer.cpp:12:11:12:11 | p | | | smart_pointer.cpp:11:30:11:50 | call to make_shared | smart_pointer.cpp:13:10:13:10 | p | | | smart_pointer.cpp:11:52:11:57 | call to source | smart_pointer.cpp:11:30:11:50 | call to make_shared | TAINT | +| smart_pointer.cpp:12:10:12:10 | call to operator* [post update] | smart_pointer.cpp:13:10:13:10 | p | | | smart_pointer.cpp:12:11:12:11 | p | smart_pointer.cpp:12:10:12:10 | call to operator* | TAINT | | smart_pointer.cpp:12:11:12:11 | ref arg p | smart_pointer.cpp:13:10:13:10 | p | | | smart_pointer.cpp:17:32:17:54 | call to make_shared | smart_pointer.cpp:18:11:18:11 | p | | | smart_pointer.cpp:17:32:17:54 | call to make_shared | smart_pointer.cpp:19:10:19:10 | p | | +| smart_pointer.cpp:18:10:18:10 | ref arg call to operator* | smart_pointer.cpp:19:10:19:10 | p | | | smart_pointer.cpp:18:11:18:11 | p | smart_pointer.cpp:18:10:18:10 | call to operator* | TAINT | | smart_pointer.cpp:18:11:18:11 | ref arg p | smart_pointer.cpp:19:10:19:10 | p | | | smart_pointer.cpp:23:30:23:50 | call to make_unique | smart_pointer.cpp:24:11:24:11 | p | | | smart_pointer.cpp:23:30:23:50 | call to make_unique | smart_pointer.cpp:25:10:25:10 | p | | | smart_pointer.cpp:23:52:23:57 | call to source | smart_pointer.cpp:23:30:23:50 | call to make_unique | TAINT | +| smart_pointer.cpp:24:10:24:10 | call to operator* [post update] | smart_pointer.cpp:25:10:25:10 | p | | | smart_pointer.cpp:24:11:24:11 | p | smart_pointer.cpp:24:10:24:10 | call to operator* | TAINT | | smart_pointer.cpp:24:11:24:11 | ref arg p | smart_pointer.cpp:25:10:25:10 | p | | | smart_pointer.cpp:29:32:29:54 | call to make_unique | smart_pointer.cpp:30:11:30:11 | p | | | smart_pointer.cpp:29:32:29:54 | call to make_unique | smart_pointer.cpp:31:10:31:10 | p | | +| smart_pointer.cpp:30:10:30:10 | ref arg call to operator* | smart_pointer.cpp:31:10:31:10 | p | | | smart_pointer.cpp:30:11:30:11 | p | smart_pointer.cpp:30:10:30:10 | call to operator* | TAINT | | smart_pointer.cpp:30:11:30:11 | ref arg p | smart_pointer.cpp:31:10:31:10 | p | | | smart_pointer.cpp:35:30:35:50 | call to make_shared | smart_pointer.cpp:37:6:37:6 | p | | | smart_pointer.cpp:35:30:35:50 | call to make_shared | smart_pointer.cpp:38:10:38:10 | p | | | smart_pointer.cpp:35:30:35:50 | call to make_shared | smart_pointer.cpp:39:11:39:11 | p | | +| smart_pointer.cpp:37:5:37:5 | call to operator* [post update] | smart_pointer.cpp:38:10:38:10 | p | | +| smart_pointer.cpp:37:5:37:5 | call to operator* [post update] | smart_pointer.cpp:39:11:39:11 | p | | | smart_pointer.cpp:37:5:37:17 | ... = ... | smart_pointer.cpp:37:5:37:5 | call to operator* [post update] | | | smart_pointer.cpp:37:6:37:6 | p | smart_pointer.cpp:37:5:37:5 | call to operator* | TAINT | | smart_pointer.cpp:37:6:37:6 | ref arg p | smart_pointer.cpp:38:10:38:10 | p | | @@ -3251,6 +3257,8 @@ | smart_pointer.cpp:43:29:43:51 | call to unique_ptr | smart_pointer.cpp:45:6:45:6 | p | | | smart_pointer.cpp:43:29:43:51 | call to unique_ptr | smart_pointer.cpp:46:10:46:10 | p | | | smart_pointer.cpp:43:29:43:51 | call to unique_ptr | smart_pointer.cpp:47:11:47:11 | p | | +| smart_pointer.cpp:45:5:45:5 | call to operator* [post update] | smart_pointer.cpp:46:10:46:10 | p | | +| smart_pointer.cpp:45:5:45:5 | call to operator* [post update] | smart_pointer.cpp:47:11:47:11 | p | | | smart_pointer.cpp:45:5:45:17 | ... = ... | smart_pointer.cpp:45:5:45:5 | call to operator* [post update] | | | smart_pointer.cpp:45:6:45:6 | p | smart_pointer.cpp:45:5:45:5 | call to operator* | TAINT | | smart_pointer.cpp:45:6:45:6 | ref arg p | smart_pointer.cpp:46:10:46:10 | p | | @@ -3268,7 +3276,21 @@ | smart_pointer.cpp:65:28:65:46 | call to make_unique | smart_pointer.cpp:67:10:67:10 | p | | | smart_pointer.cpp:65:48:65:53 | call to source | smart_pointer.cpp:65:28:65:46 | call to make_unique | TAINT | | smart_pointer.cpp:65:58:65:58 | 0 | smart_pointer.cpp:65:28:65:46 | call to make_unique | TAINT | +| smart_pointer.cpp:66:10:66:10 | p | smart_pointer.cpp:66:11:66:11 | call to operator-> | TAINT | | smart_pointer.cpp:66:10:66:10 | ref arg p | smart_pointer.cpp:67:10:67:10 | p | | +| smart_pointer.cpp:67:10:67:10 | p | smart_pointer.cpp:67:11:67:11 | call to operator-> | TAINT | +| smart_pointer.cpp:70:37:70:39 | ptr | smart_pointer.cpp:70:37:70:39 | ptr | | +| smart_pointer.cpp:70:37:70:39 | ptr | smart_pointer.cpp:71:4:71:6 | ptr | | +| smart_pointer.cpp:71:3:71:3 | call to operator* [post update] | smart_pointer.cpp:70:37:70:39 | ptr | | +| smart_pointer.cpp:71:3:71:17 | ... = ... | smart_pointer.cpp:71:3:71:3 | call to operator* [post update] | | +| smart_pointer.cpp:71:4:71:6 | ptr | smart_pointer.cpp:71:3:71:3 | call to operator* | TAINT | +| smart_pointer.cpp:71:4:71:6 | ref arg ptr | smart_pointer.cpp:70:37:70:39 | ptr | | +| smart_pointer.cpp:71:10:71:15 | call to source | smart_pointer.cpp:71:3:71:17 | ... = ... | | +| smart_pointer.cpp:75:26:75:33 | call to shared_ptr | smart_pointer.cpp:76:13:76:13 | p | | +| smart_pointer.cpp:75:26:75:33 | call to shared_ptr | smart_pointer.cpp:77:9:77:9 | p | | +| smart_pointer.cpp:76:13:76:13 | call to shared_ptr [post update] | smart_pointer.cpp:77:9:77:9 | p | | +| smart_pointer.cpp:76:13:76:13 | p | smart_pointer.cpp:76:13:76:13 | call to shared_ptr | | +| smart_pointer.cpp:77:9:77:9 | p | smart_pointer.cpp:77:8:77:8 | call to operator* | TAINT | | standalone_iterators.cpp:39:45:39:51 | source1 | standalone_iterators.cpp:39:45:39:51 | source1 | | | standalone_iterators.cpp:39:45:39:51 | source1 | standalone_iterators.cpp:40:11:40:17 | source1 | | | standalone_iterators.cpp:39:45:39:51 | source1 | standalone_iterators.cpp:41:12:41:18 | source1 | | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/smart_pointer.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/smart_pointer.cpp index 1f222cbae3e..e5d835d3426 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/smart_pointer.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/smart_pointer.cpp @@ -35,16 +35,16 @@ void test_reverse_taint_shared() { std::shared_ptr p = std::make_shared(); *p = source(); - sink(p); // $ MISSING: ast,ir - sink(*p); // $ MISSING: ast,ir + sink(p); // $ ast MISSING: ir + sink(*p); // $ ast MISSING: ir } void test_reverse_taint_unique() { std::unique_ptr p = std::unique_ptr(); *p = source(); - sink(p); // $ MISSING: ast,ir - sink(*p); // $ MISSING: ast,ir + sink(p); // $ ast MISSING: ir + sink(*p); // $ ast MISSING: ir } void test_shared_get() { @@ -74,5 +74,5 @@ void getNumber(std::shared_ptr ptr) { int test_from_issue_5190() { std::shared_ptr p(new int); getNumber(p); - sink(*p); // $ MISSING: ast,ir + sink(*p); // $ ast MISSING: ir } \ No newline at end of file From c541390c1b5e218cd9af63c45e85db7ca650a97c Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 31 Mar 2021 13:54:15 +0100 Subject: [PATCH 464/725] JS: Remove precision tag from ExternalDependencies.ql --- javascript/ql/src/Metrics/Dependencies/ExternalDependencies.ql | 1 - 1 file changed, 1 deletion(-) diff --git a/javascript/ql/src/Metrics/Dependencies/ExternalDependencies.ql b/javascript/ql/src/Metrics/Dependencies/ExternalDependencies.ql index d0d2782893a..b4bc082a8f9 100644 --- a/javascript/ql/src/Metrics/Dependencies/ExternalDependencies.ql +++ b/javascript/ql/src/Metrics/Dependencies/ExternalDependencies.ql @@ -6,7 +6,6 @@ * @kind treemap * @treemap.warnOn highValues * @metricType externalDependency - * @precision medium * @id js/external-dependencies */ From 068a9d88e7e67148cdb52b7427ddf74899f778c4 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 31 Mar 2021 11:39:05 +0100 Subject: [PATCH 465/725] JS: Ensure Dependency.info() exists even if version range could not be parsed --- .../javascript/dependencies/Dependencies.qll | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dependencies/Dependencies.qll b/javascript/ql/src/semmle/javascript/dependencies/Dependencies.qll index 76dee0a820d..a4766f7dc27 100644 --- a/javascript/ql/src/semmle/javascript/dependencies/Dependencies.qll +++ b/javascript/ql/src/semmle/javascript/dependencies/Dependencies.qll @@ -127,18 +127,22 @@ class ExternalNPMDependency extends NPMDependency { exists(PackageDependencies pkgdeps | this = pkgdeps.getPropValue(result)) } - override string getVersion() { + private string getVersionNumber() { exists(string versionRange | versionRange = this.(JSONString).getValue() | // extract a concrete version from the version range; currently, // we handle exact versions as well as `<=`, `>=`, `~` and `^` ranges result = versionRange.regexpCapture("(?:[><]=|[=~^])?v?(\\d+(\\.\\d+){1,2})", 1) - or - // if no version is specified, report version `unknown` - result = "unknown" and - (versionRange = "" or versionRange = "*") ) } + override string getVersion() { + result = getVersionNumber() + or + // if no version is specified or could not be parsed, report version `unknown` + not exists(getVersionNumber()) and + result = "unknown" + } + override Import getAnImport() { exists(int depth | depth = importsDependency(result, getDeclaringPackage(), this) | // restrict to those results for which this is the closest matching dependency From 8c8e4e6a701a2e89b345db3e871ad48e622c797f Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 31 Mar 2021 16:17:54 +0100 Subject: [PATCH 466/725] JS: Add test --- .../test/library-tests/NPM/src/package.json | 4 +++- .../ql/test/library-tests/NPM/tests.expected | 23 +++++++++++++++---- javascript/ql/test/library-tests/NPM/tests.ql | 5 ++++ 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/javascript/ql/test/library-tests/NPM/src/package.json b/javascript/ql/test/library-tests/NPM/src/package.json index fcf5f3ca356..094bcc81bea 100644 --- a/javascript/ql/test/library-tests/NPM/src/package.json +++ b/javascript/ql/test/library-tests/NPM/src/package.json @@ -7,7 +7,9 @@ "web": "http://mine.com" }], "dependencies": { - "esprima": "*" + "esprima": "*", + "something": "1.2.3-alpha.beta", + "foo": "! garbage string we \nreally can't parse %" }, "devDependencies": { "mocha": "1.0" diff --git a/javascript/ql/test/library-tests/NPM/tests.expected b/javascript/ql/test/library-tests/NPM/tests.expected index 58f7c0647a9..696500f8163 100644 --- a/javascript/ql/test/library-tests/NPM/tests.expected +++ b/javascript/ql/test/library-tests/NPM/tests.expected @@ -1,6 +1,8 @@ dependencies -| src/package.json:1:1:18:1 | {\\n "na ... "\\n }\\n} | esprima | * | -| src/package.json:1:1:18:1 | {\\n "na ... "\\n }\\n} | mocha | 1.0 | +| src/package.json:1:1:20:1 | {\\n "na ... "\\n }\\n} | esprima | * | +| src/package.json:1:1:20:1 | {\\n "na ... "\\n }\\n} | foo | ! garbage string we \nreally can't parse % | +| src/package.json:1:1:20:1 | {\\n "na ... "\\n }\\n} | mocha | 1.0 | +| src/package.json:1:1:20:1 | {\\n "na ... "\\n }\\n} | something | 1.2.3-alpha.beta | importedFile | src/lib/tst2.js:1:1:1:13 | require("..") | src/index.js:0:0:0:0 | src/index.js | | src/node_modules/nested/tst3.js:1:1:1:29 | require ... odule') | src/node_modules/third-party-module/fancy.js:0:0:0:0 | src/node_modules/third-party-module/fancy.js | @@ -29,16 +31,27 @@ modules | src/node_modules/third-party-module | third-party-module | src/node_modules/third-party-module/fancy.js:1:1:4:0 | | npm | src/node_modules/third-party-module/package.json:1:1:5:1 | {\\n "na ... y.js"\\n} | third-party-module | 23.4.0 | -| src/package.json:1:1:18:1 | {\\n "na ... "\\n }\\n} | test-package | 0.1.0 | +| src/package.json:1:1:20:1 | {\\n "na ... "\\n }\\n} | test-package | 0.1.0 | getMainModule | src/node_modules/b/package.json:1:1:4:1 | {\\n "na ... "lib"\\n} | b | src/node_modules/b/lib/index.js:1:1:2:0 | | | src/node_modules/c/package.json:1:1:4:1 | {\\n "na ... src/"\\n} | c | src/node_modules/c/src/index.js:1:1:2:0 | | | src/node_modules/d/package.json:1:1:4:1 | {\\n "na ... main"\\n} | d | src/node_modules/d/main.js:1:1:2:0 | | | src/node_modules/third-party-module/package.json:1:1:5:1 | {\\n "na ... y.js"\\n} | third-party-module | src/node_modules/third-party-module/fancy.js:1:1:4:0 | | -| src/package.json:1:1:18:1 | {\\n "na ... "\\n }\\n} | test-package | src/index.js:1:1:4:0 | | +| src/package.json:1:1:20:1 | {\\n "na ... "\\n }\\n} | test-package | src/index.js:1:1:4:0 | | packageJSON | src/node_modules/b/package.json:1:1:4:1 | {\\n "na ... "lib"\\n} | | src/node_modules/c/package.json:1:1:4:1 | {\\n "na ... src/"\\n} | | src/node_modules/d/package.json:1:1:4:1 | {\\n "na ... main"\\n} | | src/node_modules/third-party-module/package.json:1:1:5:1 | {\\n "na ... y.js"\\n} | -| src/package.json:1:1:18:1 | {\\n "na ... "\\n }\\n} | +| src/package.json:1:1:20:1 | {\\n "na ... "\\n }\\n} | +dependencyInfo +| src/index.js:1:1:4:0 | | test-package | 0.1.0 | +| src/lib/tst2.js:1:1:1:14 | | test-package | 0.1.0 | +| src/lib/tst.js:1:1:4:0 | | test-package | 0.1.0 | +| src/node_modules/third-party-module/fancy.js:1:1:4:0 | | third-party-module | 23.4.0 | +| src/package.json:10:18:10:20 | "*" | esprima | unknown | +| src/package.json:11:20:11:37 | "1.2.3-alpha.beta" | something | unknown | +| src/package.json:12:14:12:57 | "! garb ... arse %" | foo | unknown | +| src/package.json:15:16:15:20 | "1.0" | mocha | 1.0 | +| src/tst2.js:1:1:1:13 | | test-package | 0.1.0 | +| src/tst.js:1:1:2:38 | | test-package | 0.1.0 | diff --git a/javascript/ql/test/library-tests/NPM/tests.ql b/javascript/ql/test/library-tests/NPM/tests.ql index 9e4fa0c961d..52714084a81 100644 --- a/javascript/ql/test/library-tests/NPM/tests.ql +++ b/javascript/ql/test/library-tests/NPM/tests.ql @@ -1,4 +1,5 @@ import javascript +import semmle.javascript.dependencies.Dependencies query predicate dependencies(PackageJSON pkgjson, string pkg, string version) { pkgjson.declaresDependency(pkg, version) @@ -24,3 +25,7 @@ query predicate getMainModule(PackageJSON pkg, string name, Module mod) { } query predicate packageJSON(PackageJSON json) { any() } + +query predicate dependencyInfo(Dependency dep, string name, string version) { + dep.info(name, version) +} From 43306f4700e1e330abdaeb7c02f80d7288c11670 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 31 Mar 2021 17:17:58 +0200 Subject: [PATCH 467/725] Python: Add tests for Module.declaredInAll --- .../modules/__all__/DeclaredInAll.expected | 3 + .../modules/__all__/DeclaredInAll.ql | 5 ++ .../modules/__all__/all_dynamic.py | 8 ++ .../library-tests/modules/__all__/all_list.py | 6 ++ .../library-tests/modules/__all__/all_set.py | 6 ++ .../modules/__all__/all_tuple.py | 6 ++ .../library-tests/modules/__all__/main.py | 74 +++++++++++++++++++ .../library-tests/modules/__all__/no_all.py | 3 + 8 files changed, 111 insertions(+) create mode 100644 python/ql/test/library-tests/modules/__all__/DeclaredInAll.expected create mode 100644 python/ql/test/library-tests/modules/__all__/DeclaredInAll.ql create mode 100644 python/ql/test/library-tests/modules/__all__/all_dynamic.py create mode 100644 python/ql/test/library-tests/modules/__all__/all_list.py create mode 100644 python/ql/test/library-tests/modules/__all__/all_set.py create mode 100644 python/ql/test/library-tests/modules/__all__/all_tuple.py create mode 100644 python/ql/test/library-tests/modules/__all__/main.py create mode 100644 python/ql/test/library-tests/modules/__all__/no_all.py diff --git a/python/ql/test/library-tests/modules/__all__/DeclaredInAll.expected b/python/ql/test/library-tests/modules/__all__/DeclaredInAll.expected new file mode 100644 index 00000000000..5d90821921b --- /dev/null +++ b/python/ql/test/library-tests/modules/__all__/DeclaredInAll.expected @@ -0,0 +1,3 @@ +| all_dynamic.py:0:0:0:0 | Module all_dynamic | foo | +| all_list.py:0:0:0:0 | Module all_list | bar | +| all_list.py:0:0:0:0 | Module all_list | foo | diff --git a/python/ql/test/library-tests/modules/__all__/DeclaredInAll.ql b/python/ql/test/library-tests/modules/__all__/DeclaredInAll.ql new file mode 100644 index 00000000000..69f9d32f856 --- /dev/null +++ b/python/ql/test/library-tests/modules/__all__/DeclaredInAll.ql @@ -0,0 +1,5 @@ +import python + +from Module mod, string name +where mod.declaredInAll(name) +select mod, name diff --git a/python/ql/test/library-tests/modules/__all__/all_dynamic.py b/python/ql/test/library-tests/modules/__all__/all_dynamic.py new file mode 100644 index 00000000000..5213418328d --- /dev/null +++ b/python/ql/test/library-tests/modules/__all__/all_dynamic.py @@ -0,0 +1,8 @@ +foo = "foo" +bar = "bar" +baz = "baz" + + +__all__ = ["foo"] + +__all__ += ["bar"] diff --git a/python/ql/test/library-tests/modules/__all__/all_list.py b/python/ql/test/library-tests/modules/__all__/all_list.py new file mode 100644 index 00000000000..d2ecda63db4 --- /dev/null +++ b/python/ql/test/library-tests/modules/__all__/all_list.py @@ -0,0 +1,6 @@ +foo = "foo" +bar = "bar" +baz = "baz" + + +__all__ = ["foo", "bar"] diff --git a/python/ql/test/library-tests/modules/__all__/all_set.py b/python/ql/test/library-tests/modules/__all__/all_set.py new file mode 100644 index 00000000000..bbd7d0d4c59 --- /dev/null +++ b/python/ql/test/library-tests/modules/__all__/all_set.py @@ -0,0 +1,6 @@ +foo = "foo" +bar = "bar" +baz = "baz" + + +__all__ = {"foo", "bar"} diff --git a/python/ql/test/library-tests/modules/__all__/all_tuple.py b/python/ql/test/library-tests/modules/__all__/all_tuple.py new file mode 100644 index 00000000000..b06def5ddb7 --- /dev/null +++ b/python/ql/test/library-tests/modules/__all__/all_tuple.py @@ -0,0 +1,6 @@ +foo = "foo" +bar = "bar" +baz = "baz" + + +__all__ = ("foo", "bar") diff --git a/python/ql/test/library-tests/modules/__all__/main.py b/python/ql/test/library-tests/modules/__all__/main.py new file mode 100644 index 00000000000..40b63287638 --- /dev/null +++ b/python/ql/test/library-tests/modules/__all__/main.py @@ -0,0 +1,74 @@ +# This file showcases how imports work with `__all__`. +# +# TL;DR; in `from import *`, if `__all__` is defined in ``, then only +# the names in `__all__` will be imported -- otherwise all names that doesn't begin with +# an underscore will be imported. +# +# If `__all__` is defined, `__all__` must be a sequence for `from import *` to work. +# +# https://docs.python.org/3/reference/simple_stmts.html#the-import-statement +# https://docs.python.org/3/glossary.html#term-sequence + +print("import *") +print("---") + +from no_all import * +print("no_all.py") +print(" foo={!r}".format(foo)) +print(" bar={!r}".format(bar)) +print(" baz={!r}".format(baz)) +del foo, bar, baz + +from all_list import * +print("all_list.py") +print(" foo={!r}".format(foo)) +print(" bar={!r}".format(bar)) +try: + print(" baz={!r}".format(baz)) +except NameError: + print(" baz not imported") +del foo, bar + +from all_tuple import * +print("all_tuple.py") +print(" foo={!r}".format(foo)) +print(" bar={!r}".format(bar)) +try: + print(" baz={!r}".format(baz)) +except NameError: + print(" baz not imported") +del foo, bar + +from all_dynamic import * +print("all_dynamic.py") +print(" foo={!r}".format(foo)) +print(" bar={!r}".format(bar)) +try: + print(" baz={!r}".format(baz)) +except NameError: + print(" baz not imported") +del foo, bar + + +# Example of wrong definition of `__all__`, where it is not a sequence. +try: + from all_set import * +except TypeError as e: + assert str(e) == "'set' object does not support indexing" + print("from all_set import * could not be imported:", e) + +print("") +print("Direct reference on module") +print("---") +# Direct reference always works, no matter how `__all__` is set. +import no_all +import all_list +import all_tuple +import all_dynamic +import all_set + +for mod in [no_all, all_list, all_tuple, all_dynamic, all_set]: + print("{}.py".format(mod.__name__)) + print(" foo={!r}".format(mod.foo)) + print(" bar={!r}".format(mod.bar)) + print(" baz={!r}".format(mod.baz)) diff --git a/python/ql/test/library-tests/modules/__all__/no_all.py b/python/ql/test/library-tests/modules/__all__/no_all.py new file mode 100644 index 00000000000..ca059c60687 --- /dev/null +++ b/python/ql/test/library-tests/modules/__all__/no_all.py @@ -0,0 +1,3 @@ +foo = "foo" +bar = "bar" +baz = "baz" From ab3edf37d70d9e69b7e7226de3ea7ce8a8f973ae Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 31 Mar 2021 17:25:19 +0200 Subject: [PATCH 468/725] Python: Handle __all__ assigned to a tuple Examples where this is used in real code: - https://github.com/django/django/blob/76c0b32f826469320c59709d31e2f2126dd7c505/django/core/files/temp.py#L24 - https://github.com/django/django/blob/76c0b32f826469320c59709d31e2f2126dd7c505/django/contrib/gis/gdal/__init__.py#L44-L49 --- python/ql/src/semmle/python/Module.qll | 6 +++++- .../library-tests/modules/__all__/DeclaredInAll.expected | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/Module.qll b/python/ql/src/semmle/python/Module.qll index fcf1c0b2925..bc100e262f4 100644 --- a/python/ql/src/semmle/python/Module.qll +++ b/python/ql/src/semmle/python/Module.qll @@ -129,7 +129,11 @@ class Module extends Module_, Scope, AstNode { a.defines(all) and a.getScope() = this and all.getId() = "__all__" and - a.getValue().(List).getAnElt().(StrConst).getText() = name + ( + a.getValue().(List).getAnElt().(StrConst).getText() = name + or + a.getValue().(Tuple).getAnElt().(StrConst).getText() = name + ) ) } diff --git a/python/ql/test/library-tests/modules/__all__/DeclaredInAll.expected b/python/ql/test/library-tests/modules/__all__/DeclaredInAll.expected index 5d90821921b..86591566217 100644 --- a/python/ql/test/library-tests/modules/__all__/DeclaredInAll.expected +++ b/python/ql/test/library-tests/modules/__all__/DeclaredInAll.expected @@ -1,3 +1,5 @@ | all_dynamic.py:0:0:0:0 | Module all_dynamic | foo | | all_list.py:0:0:0:0 | Module all_list | bar | | all_list.py:0:0:0:0 | Module all_list | foo | +| all_tuple.py:0:0:0:0 | Module all_tuple | bar | +| all_tuple.py:0:0:0:0 | Module all_tuple | foo | From 95ac2c8edda7f845bfa60df47d77ecc9fbec9d93 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 31 Mar 2021 17:31:55 +0200 Subject: [PATCH 469/725] Python: Add another dynamic __all__ test --- .../library-tests/modules/__all__/all_dynamic2.py | 7 +++++++ python/ql/test/library-tests/modules/__all__/main.py | 12 +++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 python/ql/test/library-tests/modules/__all__/all_dynamic2.py diff --git a/python/ql/test/library-tests/modules/__all__/all_dynamic2.py b/python/ql/test/library-tests/modules/__all__/all_dynamic2.py new file mode 100644 index 00000000000..88c0ddaeacc --- /dev/null +++ b/python/ql/test/library-tests/modules/__all__/all_dynamic2.py @@ -0,0 +1,7 @@ +foo = "foo" +bar = "bar" +baz = "baz" + + +temp = ["foo", "bar"] +__all__ = temp diff --git a/python/ql/test/library-tests/modules/__all__/main.py b/python/ql/test/library-tests/modules/__all__/main.py index 40b63287638..a36afae0ed4 100644 --- a/python/ql/test/library-tests/modules/__all__/main.py +++ b/python/ql/test/library-tests/modules/__all__/main.py @@ -49,6 +49,15 @@ except NameError: print(" baz not imported") del foo, bar +from all_dynamic2 import * +print("all_dynamic2.py") +print(" foo={!r}".format(foo)) +print(" bar={!r}".format(bar)) +try: + print(" baz={!r}".format(baz)) +except NameError: + print(" baz not imported") +del foo, bar # Example of wrong definition of `__all__`, where it is not a sequence. try: @@ -65,9 +74,10 @@ import no_all import all_list import all_tuple import all_dynamic +import all_dynamic2 import all_set -for mod in [no_all, all_list, all_tuple, all_dynamic, all_set]: +for mod in [no_all, all_list, all_tuple, all_dynamic, all_dynamic2, all_set]: print("{}.py".format(mod.__name__)) print(" foo={!r}".format(mod.foo)) print(" bar={!r}".format(mod.bar)) From ecbce88ec78710f67c0160f7ae58e58c027fb73c Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 31 Mar 2021 22:23:50 +0200 Subject: [PATCH 470/725] C++: Fix comment. --- cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll index 21ba4dff36d..29b6cd691a4 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll @@ -256,7 +256,7 @@ private module PartialDefinitions { innerDefinedExpr = getAPointerWrapperAccess(pointer) ) or - // iterators passed by value without a copy constructor + // pointer wrappers passed by value without a copy constructor exists(Call call | call = node and call.getAnArgument() = innerDefinedExpr and @@ -265,7 +265,7 @@ private module PartialDefinitions { not call instanceof OverloadedPointerDereferenceExpr ) or - // iterators passed by value with a copy constructor + // pointer wrappers passed by value with a copy constructor exists(Call call, ConstructorCall copy | copy.getTarget() instanceof CopyConstructor and call = node and From 480ce39618efaa47d7a51b43a80a044aca7d6532 Mon Sep 17 00:00:00 2001 From: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Thu, 1 Apr 2021 11:23:31 +0100 Subject: [PATCH 471/725] C#: Exclude jump-to-def information for elements with too many locations In databases which include multiple duplicated files, we can get an explosion of definition locations that can cause this query to produce too many results for the CodeQL toolchain. This commit restricts the definitions.ql query to producing definition/uses for definitions with fewer than 10 locations. This replicates the logic used in the C++ definitions.qll library which faces similar problems. --- csharp/ql/src/definitions.qll | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/csharp/ql/src/definitions.qll b/csharp/ql/src/definitions.qll index 2004ad0d218..c1b456f4dbf 100644 --- a/csharp/ql/src/definitions.qll +++ b/csharp/ql/src/definitions.qll @@ -187,5 +187,11 @@ cached Declaration definitionOf(Use use, string kind) { result = use.getDefinition() and result.fromSource() and - kind = use.getUseType() + kind = use.getUseType() and + // Some entities have many locations. This can arise for files that + // are duplicated multiple times in the database at different + // locations. Rather than letting the result set explode, we just + // exclude results that are "too ambiguous" -- we could also arbitrarily + // pick one location later on. + strictcount(result.getLocation()) < 10 } From c96ee8671e514c433348efc6a72158695156b817 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 1 Apr 2021 12:15:54 +0100 Subject: [PATCH 472/725] JS: Update more query metadata --- .../ql/examples/queries/dataflow/BackendIdor/BackendIdor.ql | 1 + .../DecodingAfterSanitization/DecodingAfterSanitization.ql | 1 + .../DecodingAfterSanitizationGeneralized.ql | 1 + .../ql/examples/queries/dataflow/EvalTaint/EvalTaintPath.ql | 1 + .../dataflow/InformationDisclosure/InformationDisclosure.ql | 1 + javascript/ql/examples/queries/dataflow/StoredXss/StoredXss.ql | 1 + .../examples/queries/dataflow/StoredXss/StoredXssTypeTracking.ql | 1 + .../queries/dataflow/TemplateInjection/TemplateInjection.ql | 1 + 8 files changed, 8 insertions(+) diff --git a/javascript/ql/examples/queries/dataflow/BackendIdor/BackendIdor.ql b/javascript/ql/examples/queries/dataflow/BackendIdor/BackendIdor.ql index 020516406af..3f7e555738e 100644 --- a/javascript/ql/examples/queries/dataflow/BackendIdor/BackendIdor.ql +++ b/javascript/ql/examples/queries/dataflow/BackendIdor/BackendIdor.ql @@ -3,6 +3,7 @@ * @description Finds cases where the 'userId' field in a request to another service * is an arbitrary user-controlled value, indicating lack of authentication. * @kind path-problem + * @problem.severity error * @tags security * @id js/examples/backend-idor */ diff --git a/javascript/ql/examples/queries/dataflow/DecodingAfterSanitization/DecodingAfterSanitization.ql b/javascript/ql/examples/queries/dataflow/DecodingAfterSanitization/DecodingAfterSanitization.ql index b8954582b62..d21cc4531fc 100644 --- a/javascript/ql/examples/queries/dataflow/DecodingAfterSanitization/DecodingAfterSanitization.ql +++ b/javascript/ql/examples/queries/dataflow/DecodingAfterSanitization/DecodingAfterSanitization.ql @@ -3,6 +3,7 @@ * @description Tracks the return value of 'escapeHtml' into 'decodeURI', indicating * an ineffective sanitization attempt. * @kind path-problem + * @problem.severity error * @tags security * @id js/examples/decoding-after-sanitization */ diff --git a/javascript/ql/examples/queries/dataflow/DecodingAfterSanitization/DecodingAfterSanitizationGeneralized.ql b/javascript/ql/examples/queries/dataflow/DecodingAfterSanitization/DecodingAfterSanitizationGeneralized.ql index 69b4d9d3bd7..49ffd3bbed5 100644 --- a/javascript/ql/examples/queries/dataflow/DecodingAfterSanitization/DecodingAfterSanitizationGeneralized.ql +++ b/javascript/ql/examples/queries/dataflow/DecodingAfterSanitization/DecodingAfterSanitizationGeneralized.ql @@ -3,6 +3,7 @@ * @description Tracks the return value of an HTML sanitizer into an escape-sequence decoder, * indicating an ineffective sanitization attempt. * @kind path-problem + * @problem.severity error * @tags security * @id js/examples/decoding-after-sanitization-generalized */ diff --git a/javascript/ql/examples/queries/dataflow/EvalTaint/EvalTaintPath.ql b/javascript/ql/examples/queries/dataflow/EvalTaint/EvalTaintPath.ql index e449c61073d..1b07ed151bd 100644 --- a/javascript/ql/examples/queries/dataflow/EvalTaint/EvalTaintPath.ql +++ b/javascript/ql/examples/queries/dataflow/EvalTaint/EvalTaintPath.ql @@ -3,6 +3,7 @@ * @description Tracks user-controlled values into 'eval' calls (special case of js/code-injection), * and generates a visualizable path from the source to the sink. * @kind path-problem + * @problem.severity error * @tags security * @id js/examples/eval-taint-path */ diff --git a/javascript/ql/examples/queries/dataflow/InformationDisclosure/InformationDisclosure.ql b/javascript/ql/examples/queries/dataflow/InformationDisclosure/InformationDisclosure.ql index e279ff79782..07a942967b1 100644 --- a/javascript/ql/examples/queries/dataflow/InformationDisclosure/InformationDisclosure.ql +++ b/javascript/ql/examples/queries/dataflow/InformationDisclosure/InformationDisclosure.ql @@ -3,6 +3,7 @@ * @description Tracks values from an 'authKey' property into a postMessage call with unrestricted origin, * indicating a leak of sensitive information. * @kind path-problem + * @problem.severity warning * @tags security * @id js/examples/information-disclosure */ diff --git a/javascript/ql/examples/queries/dataflow/StoredXss/StoredXss.ql b/javascript/ql/examples/queries/dataflow/StoredXss/StoredXss.ql index 2a00a49c020..86ecf59e673 100644 --- a/javascript/ql/examples/queries/dataflow/StoredXss/StoredXss.ql +++ b/javascript/ql/examples/queries/dataflow/StoredXss/StoredXss.ql @@ -2,6 +2,7 @@ * @name Extension of standard query: Stored XSS * @description Extends the standard Stored XSS query with an additional source. * @kind path-problem + * @problem.severity error * @tags security * @id js/examples/stored-xss */ diff --git a/javascript/ql/examples/queries/dataflow/StoredXss/StoredXssTypeTracking.ql b/javascript/ql/examples/queries/dataflow/StoredXss/StoredXssTypeTracking.ql index 340ae61f7f0..bca026cc2ae 100644 --- a/javascript/ql/examples/queries/dataflow/StoredXss/StoredXssTypeTracking.ql +++ b/javascript/ql/examples/queries/dataflow/StoredXss/StoredXssTypeTracking.ql @@ -3,6 +3,7 @@ * @description Extends the standard Stored XSS query with an additional source, * using TrackedNode to track MySQL connections globally. * @kind path-problem + * @problem.severity error * @tags security * @id js/examples/stored-xss-trackednode */ diff --git a/javascript/ql/examples/queries/dataflow/TemplateInjection/TemplateInjection.ql b/javascript/ql/examples/queries/dataflow/TemplateInjection/TemplateInjection.ql index c15022adc62..2286fdc2121 100644 --- a/javascript/ql/examples/queries/dataflow/TemplateInjection/TemplateInjection.ql +++ b/javascript/ql/examples/queries/dataflow/TemplateInjection/TemplateInjection.ql @@ -2,6 +2,7 @@ * @name Template injection * @description Tracks user-controlled values to an unescaped lodash template placeholder. * @kind path-problem + * @problem.severity error * @tags security * @id js/examples/template-injection */ From a3421e7ab2e81e155fe211ca78ad25c1171cd5eb Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 12 Nov 2020 12:43:37 +0000 Subject: [PATCH 473/725] JS: Add getALocalUse --- javascript/ql/src/semmle/javascript/dataflow/Sources.qll | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/dataflow/Sources.qll b/javascript/ql/src/semmle/javascript/dataflow/Sources.qll index efbac19b95d..e6d76898d26 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Sources.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Sources.qll @@ -52,6 +52,11 @@ class SourceNode extends DataFlow::Node { */ predicate flowsToExpr(Expr sink) { flowsTo(DataFlow::valueNode(sink)) } + /** + * Gets a node into which data may flow from this node in zero or more local steps. + */ + DataFlow::Node getALocalUse() { flowsTo(result) } + /** * Gets a reference (read or write) of property `propName` on this node. */ From 125d1465c8952c1cbddc0d005a6c9a34e37ec097 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 25 Jan 2021 13:10:07 +0000 Subject: [PATCH 474/725] JS: Add DataFlow::functionForwardingStep --- .../semmle/javascript/dataflow/DataFlow.qll | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll index 8835b14af05..8474598fef9 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll @@ -1683,4 +1683,59 @@ module DataFlow { import TypeTracking predicate localTaintStep = TaintTracking::localTaintStep/2; + + /** + * Holds if the function in `succ` forwards all its arguments to a call to `pred` and returns + * its result. This can thus be seen as a step `pred -> succ` used for tracking function values + * through "wrapper functions", since the `succ` function partially replicates behavior of `pred`. + * + * Examples: + * ```js + * function f(x) { + * return g(x); // step: g -> f + * } + * + * function doExec(x) { + * console.log(x); + * return exec(x); // step: exec -> doExec + * } + * + * function doEither(x, y) { + * if (x > y) { + * return foo(x, y); // step: foo -> doEither + * } else { + * return bar(x, y); // step: bar -> doEither + * } + * } + * + * function wrapWithLogging(f) { + * return (x) => { + * console.log(x); + * return f(x); // step: f -> anonymous function + * } + * } + * wrapWithLogging(g); // step: g -> wrapWithLogging(g) + * ``` + */ + predicate functionForwardingStep(DataFlow::Node pred, DataFlow::Node succ) { + exists(DataFlow::FunctionNode function, DataFlow::CallNode call | + call.flowsTo(function.getReturnNode()) and + forall(int i | exists([call.getArgument(i), function.getParameter(i)]) | + function.getParameter(i).flowsTo(call.getArgument(i)) + ) and + pred = call.getCalleeNode() and + succ = function + ) + or + // Given a generic wrapper function like, + // + // function wrap(f) { return (x, y) => f(x, y) }; + // + // add steps through calls to that function: `g -> wrap(g)` + exists(DataFlow::FunctionNode wrapperFunction, SourceNode param, Node paramUse | + FlowSteps::argumentPassing(succ, pred, wrapperFunction.getFunction(), param) and + param.flowsTo(paramUse) and + functionForwardingStep(paramUse, wrapperFunction.getReturnNode().getALocalSource()) + ) + } } From c1651ad30c1f7dfcec201ee75ec49d8975bb791a Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 25 Jan 2021 13:16:15 +0000 Subject: [PATCH 475/725] JS: Factor out Unit type --- javascript/ql/src/semmle/javascript/Unit.qll | 10 ++++++++++ .../src/semmle/javascript/dataflow/Configuration.qll | 2 +- .../src/semmle/javascript/dataflow/TaintTracking.qll | 2 +- .../javascript/dataflow/internal/PreCallGraphStep.qll | 7 +------ .../src/semmle/javascript/dataflow/internal/Unit.qll | 9 --------- 5 files changed, 13 insertions(+), 17 deletions(-) create mode 100644 javascript/ql/src/semmle/javascript/Unit.qll delete mode 100644 javascript/ql/src/semmle/javascript/dataflow/internal/Unit.qll diff --git a/javascript/ql/src/semmle/javascript/Unit.qll b/javascript/ql/src/semmle/javascript/Unit.qll new file mode 100644 index 00000000000..dbc59f541e6 --- /dev/null +++ b/javascript/ql/src/semmle/javascript/Unit.qll @@ -0,0 +1,10 @@ +/** Provides the `Unit` class. */ + +/** The unit type. */ +private newtype TUnit = TMkUnit() + +/** The trivial type with a single element. */ +class Unit extends TUnit { + /** Gets a textual representation of this element. */ + string toString() { result = "Unit" } +} diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll index 24f767540e1..b4842026e24 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll @@ -72,7 +72,7 @@ private import javascript private import internal.FlowSteps private import internal.AccessPaths private import internal.CallGraphs -private import internal.Unit +private import semmle.javascript.Unit private import semmle.javascript.internal.CachedStages /** diff --git a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll index 6c6734b84d6..251a691501e 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll @@ -15,7 +15,7 @@ import javascript private import semmle.javascript.dataflow.internal.FlowSteps as FlowSteps -private import semmle.javascript.dataflow.internal.Unit +private import semmle.javascript.Unit private import semmle.javascript.dataflow.InferredTypes private import semmle.javascript.internal.CachedStages diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/PreCallGraphStep.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/PreCallGraphStep.qll index 7020353ca0b..18db549300a 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/PreCallGraphStep.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/PreCallGraphStep.qll @@ -4,14 +4,9 @@ */ private import javascript +private import semmle.javascript.Unit private import semmle.javascript.internal.CachedStages -private newtype TUnit = MkUnit() - -private class Unit extends TUnit { - string toString() { result = "unit" } -} - /** * Internal extension point for adding flow edges prior to call graph construction * and type tracking. diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/Unit.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/Unit.qll deleted file mode 100644 index 21018c2f60c..00000000000 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/Unit.qll +++ /dev/null @@ -1,9 +0,0 @@ -private newtype TUnit = MkUnit() - -/** - * A class with only one instance. - */ -class Unit extends TUnit { - /** Gets a textual representation of this element. */ - final string toString() { result = "Unit" } -} From 314839fc097f0755ea8d5b1371f8b8fcd89ec65d Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 25 Jan 2021 13:16:32 +0000 Subject: [PATCH 476/725] JS: Add @reduxjs/toolkit to composed functions --- .../ql/src/semmle/javascript/frameworks/ComposedFunctions.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/ComposedFunctions.qll b/javascript/ql/src/semmle/javascript/frameworks/ComposedFunctions.qll index 9e4de6cd4dc..8da2286ad79 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/ComposedFunctions.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/ComposedFunctions.qll @@ -88,7 +88,7 @@ module FunctionCompositionCall { RightToLeft() { this = DataFlow::moduleImport(["compose-function"]).getACall() or - this = DataFlow::moduleMember(["redux", "ramda"], "compose").getACall() + this = DataFlow::moduleMember(["redux", "ramda", "@reduxjs/toolkit"], "compose").getACall() or this = LodashUnderscore::member("flowRight").getACall() } From 8fa3fb05612f6660e1464be31ff9396143917543 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 25 Jan 2021 13:00:27 +0000 Subject: [PATCH 477/725] JS: Redux model --- javascript/ql/src/javascript.qll | 1 + .../semmle/javascript/frameworks/Redux.qll | 1285 +++++++++++++++++ .../frameworks/Redux/exportedReducer.js | 13 + .../frameworks/Redux/react-redux.jsx | 79 + .../frameworks/Redux/test.expected | 154 ++ .../library-tests/frameworks/Redux/test.ql | 61 + .../library-tests/frameworks/Redux/trivial.js | 137 ++ 7 files changed, 1730 insertions(+) create mode 100644 javascript/ql/src/semmle/javascript/frameworks/Redux.qll create mode 100644 javascript/ql/test/library-tests/frameworks/Redux/exportedReducer.js create mode 100644 javascript/ql/test/library-tests/frameworks/Redux/react-redux.jsx create mode 100644 javascript/ql/test/library-tests/frameworks/Redux/test.expected create mode 100644 javascript/ql/test/library-tests/frameworks/Redux/test.ql create mode 100644 javascript/ql/test/library-tests/frameworks/Redux/trivial.js diff --git a/javascript/ql/src/javascript.qll b/javascript/ql/src/javascript.qll index 66dccd8cddd..b565a7cd21f 100644 --- a/javascript/ql/src/javascript.qll +++ b/javascript/ql/src/javascript.qll @@ -105,6 +105,7 @@ import semmle.javascript.frameworks.PropertyProjection import semmle.javascript.frameworks.Puppeteer import semmle.javascript.frameworks.React import semmle.javascript.frameworks.ReactNative +import semmle.javascript.frameworks.Redux import semmle.javascript.frameworks.Request import semmle.javascript.frameworks.RxJS import semmle.javascript.frameworks.ServerLess diff --git a/javascript/ql/src/semmle/javascript/frameworks/Redux.qll b/javascript/ql/src/semmle/javascript/frameworks/Redux.qll new file mode 100644 index 00000000000..7f22c3638e2 --- /dev/null +++ b/javascript/ql/src/semmle/javascript/frameworks/Redux.qll @@ -0,0 +1,1285 @@ +/** + * Provides classes and predicates for reasoning about data flow through the redux package. + */ + +import javascript +private import semmle.javascript.dataflow.internal.PreCallGraphStep +private import semmle.javascript.Unit + +/** + * Provides classes and predicates for reasoning about data flow through the redux package. + */ +module Redux { + /** + * To avoid mixing up the state between independent Redux apps that live in a monorepo, + * we do a heuristic program slicing based on `package.json` files. For most projects this has no effect. + */ + private module ProgramSlicing { + /** Gets the innermost `package.json` file in a directory containing the given file. */ + private PackageJSON getPackageJson(Container f) { + f = result.getFile().getParentContainer() + or + not exists(f.getFile("package.json")) and + result = getPackageJson(f.getParentContainer()) + } + + private predicate packageDependsOn(PackageJSON importer, PackageJSON dependency) { + importer.getADependenciesObject("").getADependency(dependency.getPackageName(), _) + } + + /** A package that can be considered an entry point for a Redux app. */ + private PackageJSON entryPointPackage() { + result = getPackageJson(any(StoreCreation c).getFile()) + or + // Any package that imports a store-creating package is considered a potential entry point. + packageDependsOn(result, entryPointPackage()) + } + + pragma[nomagic] + private predicate arePackagesInSameReduxApp(PackageJSON a, PackageJSON b) { + exists(PackageJSON entry | + entry = entryPointPackage() and + packageDependsOn*(entry, a) and + packageDependsOn*(entry, b) + ) + } + + /** Holds if the two files are considered to be part of the same Redux app. */ + pragma[inline] + predicate areFilesInSameReduxApp(File a, File b) { + not exists(PackageJSON pkg) + or + arePackagesInSameReduxApp(getPackageJson(a), getPackageJson(b)) + } + } + + /** + * Creation of a redux store, usually via a call to `createStore`. + */ + class StoreCreation extends DataFlow::SourceNode { + StoreCreation::Range range; + + StoreCreation() { this = range } + + /** Gets a reference to the store. */ + DataFlow::SourceNode ref() { + // We happen to know that all store-creation sources have API nodes, so just reuse the API node type tracking + exists(API::Node apiNode | + apiNode.getAnImmediateUse() = this and + result = apiNode.getAUse() + ) + } + + /** Gets the data flow node holding the root reducer for this store. */ + DataFlow::Node getReducerArg() { result = range.getReducerArg() } + + /** Gets a data flow node referring to the root reducer. */ + DataFlow::SourceNode getAReducerSource() { result = getReducerArg().(ReducerArg).getASource() } + } + + /** Companion module to the `StoreCreation` class. */ + module StoreCreation { + /** + * Creation of a redux store. Additional `StoreCreation` instances can be generated by subclassing this class. + */ + abstract class Range extends DataFlow::SourceNode { + /** Gets the data flow node holding the root reducer for this store. */ + abstract DataFlow::Node getReducerArg(); + } + + private class CreateStore extends DataFlow::CallNode, Range { + CreateStore() { + this = API::moduleImport(["redux", "@reduxjs/toolkit"]).getMember("createStore").getACall() + } + + override DataFlow::Node getReducerArg() { result = getArgument(0) } + } + + private class ToolkitStore extends API::CallNode, Range { + ToolkitStore() { + this = API::moduleImport("@reduxjs/toolkit").getMember("configureStore").getACall() + } + + override DataFlow::Node getReducerArg() { + result = getParameter(0).getMember("reducer").getARhs() + } + } + } + + /** An API node that is a source of the Redux root state. */ + abstract private class RootStateSource extends API::Node { } + + /** Gets an API node referring to the Redux root state. */ + private API::Node rootState() { + result instanceof RootStateSource + or + stateStep(rootState().getAUse(), result.getAnImmediateUse()) + } + + /** + * Gets an API node referring to the given (non-empty) access path within the Redux state. + */ + private API::Node rootStateAccessPath(string accessPath) { + result = rootState().getMember(accessPath) + or + exists(string base, string prop | + result = rootStateAccessPath(base).getMember(prop) and + accessPath = joinAccessPaths(base, prop) + ) + or + stateStep(rootStateAccessPath(accessPath).getAUse(), result.getAnImmediateUse()) + } + + /** + * Combines two state access paths, while disallowing unbounded growth of access paths. + */ + bindingset[base, prop] + private string joinAccessPaths(string base, string prop) { + result = base + "." + prop and + // Allow at most two occurrences of a given property name in the path + // (one in the base, plus the one we're appending now). + count(base.indexOf("." + prop + ".")) <= 1 + } + + /** + * Creation of a reducer function that delegates to one or more other reducer functions. + * + * Delegating reducers can delegate specific parts of the state object (`getStateHandlerArg`), + * actions of a specific type (`getActionHandlerArg`), or everything (`getAPlainHandlerArg`). + */ + abstract class DelegatingReducer extends DataFlow::SourceNode { + /** + * Gets a data flow node holding a reducer to which handling of `state.prop` is delegated. + * + * For example, gets the `fn` in `combineReducers({foo: fn})` with `prop` bound to `foo`. + * + * The delegating reducer should behave as a function of this form: + * ```js + * function outer(state, action) { + * return { + * prop: inner(state.prop, action), + * ... + * } + * } + * ``` + */ + DataFlow::Node getStateHandlerArg(string prop) { none() } + + /** + * Gets a data flow node holding a reducer to which actions of the given type are delegated. + * + * For example, gets the `fn` in `handleAction(a, fn)` with `actionType` bound to `a`. + * + * The `actionType` node may refer an action creator or a string value corresponding to `action.type`. + */ + DataFlow::Node getActionHandlerArg(DataFlow::Node actionType) { none() } + + /** + * Gets a data flow node holding a reducer to which every request is forwarded (for the + * purpose of this model). + * + * For example, gets the `fn` in `persistReducer(config, fn)`. + */ + DataFlow::Node getAPlainHandlerArg() { none() } + + /** Gets the use site of this reducer. */ + final ReducerArg getUseSite() { result.getASource() = this } + } + + private module DelegatingReducer { + private API::Node combineReducers() { + result = + API::moduleImport(["redux", "redux-immutable", "@reduxjs/toolkit"]) + .getMember("combineReducers") + } + + /** + * A call to `combineReducers`, which delegates properties of `state` to individual sub-reducers. + */ + private class CombineReducers extends API::CallNode, DelegatingReducer { + CombineReducers() { this = combineReducers().getACall() } + + override DataFlow::Node getStateHandlerArg(string prop) { + result = getParameter(0).getMember(prop).getARhs() + } + } + + /** + * An object literal flowing into a nested property in a `combineReducers` object, such as the `{ bar }` object in: + * ```js + * combineReducers({ foo: { bar } }) + * ``` + * + * Although the object itself is clearly not a function, we use the object to model the corresponding reducer function created by `combineReducers`. + */ + private class NestedCombineReducers extends DelegatingReducer, DataFlow::ObjectLiteralNode { + NestedCombineReducers() { + this = combineReducers().getParameter(0).getAMember+().getAValueReachingRhs() + } + + override DataFlow::Node getStateHandlerArg(string prop) { + result = getAPropertyWrite(prop).getRhs() + } + } + + /** + * A call to `handleActions`, creating a reducer function that dispatched based on the action type: + * + * ```js + * let reducer = handleActions({ + * actionType1: (state, action) => { ... }, + * actionType2: (state, action) => { ... }, + * }) + * ``` + */ + private class HandleActions extends API::CallNode, DelegatingReducer { + HandleActions() { + this = + API::moduleImport(["redux-actions", "redux-ts-utils"]) + .getMember("handleActions") + .getACall() + } + + override DataFlow::Node getActionHandlerArg(DataFlow::Node actionType) { + exists(DataFlow::PropWrite write | + result = getParameter(0).getAMember().getARhs() and + write.getRhs() = result and + actionType = write.getPropertyNameExpr().flow() + ) + } + } + + /** + * A call to `handleAction`, creating a reducer function that only handles a given action type: + * + * ```js + * let reducer = handleAction('actionType', (state, action) => { ... }); + * ``` + */ + private class HandleAction extends API::CallNode, DelegatingReducer { + HandleAction() { + this = + API::moduleImport(["redux-actions", "redux-ts-utils"]) + .getMember("handleAction") + .getACall() + } + + override DataFlow::Node getActionHandlerArg(DataFlow::Node actionType) { + actionType = getArgument(0) and + result = getArgument(1) + } + } + + /** + * A call to `persistReducer`, which we model as a plain wrapper around another reducer. + */ + private class PersistReducer extends DataFlow::CallNode, DelegatingReducer { + PersistReducer() { + this = API::moduleImport("redux-persist").getMember("persistReducer").getACall() + } + + override DataFlow::Node getAPlainHandlerArg() { result = getArgument(1) } + } + + /** + * A call to `immer` or `immer.produce`, which we model as a plain wrapper around another reducer. + */ + private class ImmerProduce extends DataFlow::CallNode, DelegatingReducer { + ImmerProduce() { + this = API::moduleImport("immer").getACall() + or + this = API::moduleImport("immer").getMember("produce").getACall() + } + + override DataFlow::Node getAPlainHandlerArg() { result = getArgument(0) } + } + + /** + * A call to `reduce-reducers`, modelled as a reducer that dispatches to an arbitrary subreducer. + * + * In reality, this function chains together all of the reducers, but in practice it is only used + * when the reducers handle a disjoint set of action types, which makes it behave as if it + * dispatched to just one of them. + * + * For example: + * ```js + * let reducer = reduceReducers([ + * handleAction('action1', (state, action) => { ... }), + * handleAction('action2', (state, action) => { ... }), + * ]); + * ``` + */ + private class ReduceReducers extends DataFlow::CallNode, DelegatingReducer { + ReduceReducers() { + this = API::moduleImport("reduce-reducers").getACall() or + this = + API::moduleImport(["redux-actions", "redux-ts-utils"]) + .getMember("reduceReducers") + .getACall() + } + + override DataFlow::Node getAPlainHandlerArg() { + result = getAnArgument() + or + result = getArgument(0).getALocalSource().(DataFlow::ArrayCreationNode).getAnElement() + } + } + + /** + * A call to `createReducer`, for example: + * + * ```js + * let reducer = createReducer(initialState, (builder) => { + * builder + * .addCase(actionType1, (state, action) => { ... }) + * .addCase(actionType2, (state, action) => { ... }); + * }); + * ``` + */ + private class CreateReducer extends API::CallNode, DelegatingReducer { + CreateReducer() { + this = API::moduleImport("@reduxjs/toolkit").getMember("createReducer").getACall() + } + + private API::Node getABuilderRef() { + result = getParameter(1).getParameter(0) + or + result = getABuilderRef().getAMember().getReturn() + } + + override DataFlow::Node getActionHandlerArg(DataFlow::Node actionType) { + exists(API::CallNode addCase | + addCase = getABuilderRef().getMember("addCase").getACall() and + actionType = addCase.getArgument(0) and + result = addCase.getArgument(1) + ) + } + } + + /** + * A reducer created by a call to `createSlice`. Note that `createSlice` creates both + * reducers and actions; this class models the reducers only. + * + * For example: + * ```js + * let slice = createSlice({ + * name: 'mySlice', + * reducers: { + * actionType1: (state, action) => { ... }, + * actionType2: (state, action) => { ... }, + * }, + * extraReducers: (builder) => { + * builder.addCase('actionType3', (state, action) => { ... }) + * } + * }); + * export default slice.reducer; + * ``` + */ + private class CreateSliceReducer extends DelegatingReducer { + API::CallNode call; + + CreateSliceReducer() { + call = API::moduleImport("@reduxjs/toolkit").getMember("createSlice").getACall() and + this = call.getReturn().getMember("reducer").getAnImmediateUse() + } + + private API::Node getABuilderRef() { + result = call.getParameter(0).getMember("extraReducers").getParameter(0) + or + result = getABuilderRef().getAMember().getReturn() + } + + override DataFlow::Node getActionHandlerArg(DataFlow::Node actionType) { + exists(string name | + result = call.getParameter(0).getMember("reducers").getMember(name).getARhs() and + actionType = call.getReturn().getMember("actions").getMember(name).getAnImmediateUse() + ) + or + // Properties of 'extraReducers': + // { extraReducers: { [action]: reducer }} + exists(DataFlow::PropWrite write | + result = call.getParameter(0).getMember("extraReducers").getAMember().getARhs() and + write.getRhs() = result and + actionType = write.getPropertyNameExpr().flow() + ) + or + // Builder callback to 'extraReducers': + // extraReducers: builder => builder.addCase(action, reducer) + exists(API::CallNode addCase | + addCase = getABuilderRef().getMember("addCase").getACall() and + actionType = addCase.getArgument(0) and + result = addCase.getArgument(1) + ) + } + } + } + + /** + * A function for creating and dispatching action objects of shape `{type, payload}`. + * + * In the simplest case, an action creator is a function, which, for some string `T` behaves as the function `x => {type: T, payload: x}`. + * + * An action creator may have a middleware function `f`, which makes it behave as the function `x => {type: T, payload: f(x)}` (that is, + * the function `f` converts the argument into the actual payload). + * + * Some action creators dispatch the action to a store, while for others, the value is returned and it is simply assumed to be dispatched + * at some point. We model all action creators as if they dispatch the action they create. + */ + class ActionCreator extends DataFlow::SourceNode { + ActionCreator::Range range; + + ActionCreator() { this = range } + + /** Gets the `type` property of actions created by this action creator, if it is known. */ + string getTypeTag() { result = range.getTypeTag() } + + /** + * Gets the middleware function that transforms arguments passed to this function into the + * action payload. + * + * Not every action creator has a middleware function; in such cases the first argument is + * treated as the action payload. + * + * If `async` is true, the middlware function returns a promise whose value eventually becomes + * the action payload. Otherwise, the return value is the payload itself. + */ + DataFlow::FunctionNode getMiddlewareFunction(boolean async) { + result = range.getMiddlewareFunction(async) + } + + /** Gets a data flow node referring to this action creator. */ + private DataFlow::SourceNode ref(DataFlow::TypeTracker t) { + t.start() and + result = this + or + // x -> bindActionCreators({ x, ... }) + exists(BindActionCreatorsCall bind, string prop | + ref(t.continue()).flowsTo(bind.getParameter(0).getMember(prop).getARhs()) and + result = bind.getReturn().getMember(prop).getAnImmediateUse() + ) + or + // x -> combineActions(x, ...) + exists(API::CallNode combiner | + combiner = + API::moduleImport(["redux-actions", "redux-ts-utils"]) + .getMember("combineActions") + .getACall() and + ref(t.continue()).flowsTo(combiner.getAnArgument()) and + result = combiner + ) + or + // x -> x.fulfilled, for async action creators + result = ref(t.continue()).getAPropertyRead("fulfilled") + or + // follow flow through mapDispatchToProps + ReactRedux::dispatchToPropsStep(ref(t.continue()).getALocalUse(), result) + or + exists(DataFlow::TypeTracker t2 | result = ref(t2).track(t2, t)) + } + + /** Gets a data flow node referring to this action creator. */ + DataFlow::SourceNode ref() { result = ref(DataFlow::TypeTracker::end()) } + + /** + * Holds if `successBlock` is executed when a check has determined that `action` originated from this action creator. + */ + private ReachableBasicBlock getASuccessfulTypeCheckBlock(DataFlow::SourceNode action) { + action = getAnUntypedActionInReducer() and + result = getASuccessfulTypeCheckBlock(action, getTypeTag()) + or + // and ProgramSlicing::areFilesInSameReduxApp(result.getFile(), this.getFile()) -- TODO delete? + // some action creators implement a .match method for this purpose + exists(ConditionGuardNode guard, DataFlow::CallNode call | + call = ref().getAMethodCall("match") and + guard.getTest() = call.asExpr() and + action.flowsTo(call.getArgument(0)) and + guard.getOutcome() = true and + result = guard.getBasicBlock() + ) + } + + /** + * Gets a reducer that handles the type of action created by this action creator, for example: + * ```js + * handleAction(TYPE, (state, action) => { ... action.payload ... }) + * ``` + * + * Does not include reducers that perform their own action type checking. + */ + DataFlow::FunctionNode getAReducerFunction() { + exists(ReducerArg reducer | + reducer.isTypeTagHandler(getTypeTag()) + or + reducer.isActionTypeHandler(ref().getALocalUse()) + | + result = reducer.getASource() + ) + } + + /** Gets a data flow node referring a payload of this action (usually in the reducer function). */ + DataFlow::SourceNode getAPayloadReference() { + // `if (action.type === TYPE) { ... action.payload ... }` + exists(DataFlow::SourceNode actionSrc | + actionSrc = getAnUntypedActionInReducer() and + result = actionSrc.getAPropertyRead("payload") and + getASuccessfulTypeCheckBlock(actionSrc).dominates(result.getBasicBlock()) + ) + or + result = getAReducerFunction().getParameter(1).getAPropertyRead("payload") + } + + /** Gets a data flow node referring to the first argument of the action creator invocation. */ + DataFlow::SourceNode getAMetaArgReference() { + exists(ReducerArg reducer | + reducer.isActionTypeHandler(ref().getAPropertyRead(["fulfilled", "rejected", "pending"])) and + result = + reducer + .getASource() + .(DataFlow::FunctionNode) + .getParameter(1) + .getAPropertyRead("meta") + .getAPropertyRead("arg") + ) + } + } + + /** Companion module to the `ActionCreator` class. */ + module ActionCreator { + /** A function for creating and dispatching action objects of shape `{type, payload}`. */ + abstract class Range extends DataFlow::SourceNode { + /** Gets the `type` property of actions created by this action creator */ + abstract string getTypeTag(); + + /** Gets the function transforming arguments into the action payload. */ + DataFlow::FunctionNode getMiddlewareFunction(boolean async) { none() } + } + + /** + * An action creator made using `createAction`: + * ```js + * let action1 = createAction('action1'); + * let action2 = createAction('action2', (x,y) => { x, y }); + * ``` + */ + private class SingleAction extends Range, API::CallNode { + SingleAction() { + this = + API::moduleImport(["@reduxjs/toolkit", "redux-actions", "redux-ts-utils"]) + .getMember("createAction") + .getACall() + } + + override string getTypeTag() { getArgument(0).mayHaveStringValue(result) } + + override DataFlow::FunctionNode getMiddlewareFunction(boolean async) { + result = getCallback(1) and async = false + } + } + + /** + * One of the action creators made by a call to `createActions`: + * ```js + * let { actionOne, actionTwo } = createActions({ + * ACTION_ONE: (x, y) => { x, y }, + * ACTION_TWO: (x, y) => { x, y }, + * }) + * ``` + */ + class MultiAction extends Range { + API::CallNode createActions; + string name; + + MultiAction() { + createActions = API::moduleImport("redux-actions").getMember("createActions").getACall() and + this = createActions.getReturn().getMember(name).getAnImmediateUse() + } + + override DataFlow::FunctionNode getMiddlewareFunction(boolean async) { + result.flowsTo(createActions.getParameter(0).getMember(getTypeTag()).getARhs()) and + async = false + } + + override string getTypeTag() { + result = name.regexpReplaceAll("([a-z])([A-Z])", "$1_$2").toUpperCase() + } + } + + /** + * An action creator made by a call to `createSlice`. Note that `createSlice` creates both + * reducers and actions; this class models the action creators. + * + * ```js + * let slice = createSlice({ + * name: 'mySlice', + * reducers: { + * actionType1: (state, action) => { ... }, + * actionType2: (state, action) => { ... }, + * }, + * }); + * export const { actionType1, actionType2 } = slice.actions; + * ``` + */ + private class CreateSliceAction extends Range { + API::CallNode call; + string actionName; + + CreateSliceAction() { + call = API::moduleImport("@reduxjs/toolkit").getMember("createSlice").getACall() and + this = call.getReturn().getMember("actions").getMember(actionName).getAnImmediateUse() + } + + override string getTypeTag() { + exists(string prefix | + call.getParameter(0).getMember("name").getARhs().mayHaveStringValue(prefix) and + result = prefix + "/" + actionName + ) + } + } + + /** + * An action creator made by a call to `createAsyncThunk`: + * ```js + * const fetchUserId = createAsyncThunk('fetchUserId', async (id) => { + * return (await fetchUserId(id)).data; + * }); + * ``` + */ + private class CreateAsyncThunk extends Range, API::CallNode { + CreateAsyncThunk() { + this = API::moduleImport("@reduxjs/toolkit").getMember("createAsyncThunk").getACall() + } + + override DataFlow::FunctionNode getMiddlewareFunction(boolean async) { + async = true and + result = getParameter(1).getAValueReachingRhs() + } + + override string getTypeTag() { getArgument(0).mayHaveStringValue(result) } + } + } + + /** + * Gets the type tag of an action creator reaching `node`. + */ + private string getAnActionTypeTag(DataFlow::SourceNode node) { + exists(ActionCreator action | + node = action.ref() and + result = action.getTypeTag() + ) + } + + /** Gets the type tag of an action reaching `node`, or the string value of `node`. */ + // Inlined to avoid duplicating `mayHaveStringValue` + pragma[inline] + private string getATypeTagFromNode(DataFlow::Node node) { + node.mayHaveStringValue(result) + or + node.asExpr().(Label).getName() = result + or + result = getAnActionTypeTag(node.getALocalSource()) + } + + /** A data flow node that is used as a reducer. */ + class ReducerArg extends DataFlow::Node { + ReducerArg() { + this = any(StoreCreation c).getReducerArg() + or + this = any(DelegatingReducer r).getStateHandlerArg(_) + or + this = any(DelegatingReducer r).getActionHandlerArg(_) + } + + /** Gets a data flow node that flows to this reducer argument. */ + DataFlow::SourceNode getASource(DataFlow::TypeBackTracker t) { + t.start() and + result = getALocalSource() + or + // Step through forwarding functions + DataFlow::functionForwardingStep(result.getALocalUse(), getASource(t.continue())) + or + // Step through library functions like `redux-persist` + result.getALocalUse() = getASource(t.continue()).(DelegatingReducer).getAPlainHandlerArg() + or + // Step through function composition (usually composed with various state "enhancer" functions) + exists(FunctionCompositionCall compose, DataFlow::CallNode call | + getASource(t.continue()) = call and + call = compose.getACall() and + result.getALocalUse() = [compose.getAnOperandNode(), call.getAnArgument()] + ) + or + exists(DataFlow::TypeBackTracker t2 | result = getASource(t2).backtrack(t2, t)) + } + + /** Gets a data flow node that flows to this reducer argument. */ + DataFlow::SourceNode getASource() { result = getASource(DataFlow::TypeBackTracker::end()) } + + /** + * Holds if the actions dispatched to this reducer have the given type, that is, + * it is created by an action creator that flows to `actionType`, or has `action.type` set to + * the string value of `actionType`. + */ + predicate isActionTypeHandler(DataFlow::Node actionType) { + exists(DelegatingReducer r | + this = r.getActionHandlerArg(actionType) + or + this = r.getStateHandlerArg(_) and + r.getUseSite().isActionTypeHandler(actionType) + ) + } + + /** + * Holds if the actions dispatched to this reducer have the given `action.type` value. + */ + predicate isTypeTagHandler(string actionType) { + exists(DataFlow::Node node | + isActionTypeHandler(node) and + actionType = getATypeTagFromNode(node) + ) + } + + /** + * Holds if this reducer operates on the root state, as opposed to some access path within the state. + */ + predicate isRootStateHandler() { + this = any(StoreCreation c).getReducerArg() + or + exists(DelegatingReducer r | + this = r.getActionHandlerArg(_) and + r.getUseSite().isRootStateHandler() + ) + } + } + + /** + * A source of the `dispatch` function, used as starting point for `getADispatchFunctionReference`. + */ + abstract private class DispatchFunctionSource extends DataFlow::SourceNode { } + + /** + * A value that is dispatched, that is, flows to the first argument of `dispatch` + * (but where the call to `dispatch` is not necessarily explicit in the code). + * + * Used as starting point for `getADispatchedValueSource`. + */ + abstract private class DispatchedValueSink extends DataFlow::Node { } + + private class StoreDispatchSource extends DispatchFunctionSource { + StoreDispatchSource() { this = any(StoreCreation c).ref().getAPropertyRead("dispatch") } + } + + /** Gets a data flow node referring to the `dispatch` function. */ + private DataFlow::SourceNode getADispatchFunctionReference(DataFlow::TypeTracker t) { + t.start() and + result instanceof DispatchFunctionSource + or + // When using the redux-thunk middleware, dispatching a function value results in that + // function being invoked with (dispatch, getState). + // We simply assume redux-thunk middleware is always installed. + t.start() and + result = getADispatchedValueSource().(DataFlow::FunctionNode).getParameter(0) + or + exists(DataFlow::TypeTracker t2 | result = getADispatchFunctionReference(t2).track(t2, t)) + } + + /** Gets a data flow node referring to the `dispatch` function. */ + DataFlow::SourceNode getADispatchFunctionReference() { + result = getADispatchFunctionReference(DataFlow::TypeTracker::end()) + } + + /** Gets a data flow node that is dispatched as an action. */ + private DataFlow::SourceNode getADispatchedValueSource(DataFlow::TypeBackTracker t) { + t.start() and + result = any(DispatchedValueSink d).getALocalSource() + or + t.start() and + result = getADispatchFunctionReference().getACall().getArgument(0).getALocalSource() + or + exists(DataFlow::TypeBackTracker t2 | result = getADispatchedValueSource(t2).backtrack(t2, t)) + } + + /** + * Gets a data flow node that is dispatched as an action, that is, it flows to the first argument of `dispatch`. + */ + DataFlow::SourceNode getADispatchedValueSource() { + result = getADispatchedValueSource(DataFlow::TypeBackTracker::end()) + } + + /** Gets the `action` parameter of a reducer that isn't behind an implied type guard. */ + DataFlow::SourceNode getAnUntypedActionInReducer() { + exists(ReducerArg reducer | + not reducer.isTypeTagHandler(_) and + result = reducer.getASource().(DataFlow::FunctionNode).getParameter(1) + ) + } + + /** A call to `bindActionCreators` */ + private class BindActionCreatorsCall extends API::CallNode { + BindActionCreatorsCall() { + this = + API::moduleImport(["redux", "@reduxjs/toolkit"]).getMember("bindActionCreators").getACall() + } + } + + /** The return value of a function flowing into `bindActionCreators`, seen as a value that is dispatched. */ + private class BindActionDispatchSink extends DispatchedValueSink { + BindActionDispatchSink() { + this = any(BindActionCreatorsCall c).getParameter(0).getAMember().getReturn().getARhs() + } + } + + /** + * Holds if `pred -> succ` is step from an action creation to its use in a reducer function. + */ + predicate actionToReducerStep(DataFlow::Node pred, DataFlow::SourceNode succ) { + // Actions created by an action creator library + exists(ActionCreator action | + exists(DataFlow::CallNode call | call = action.ref().getACall() | + exists(int i | + pred = call.getArgument(i) and + succ = action.getMiddlewareFunction(_).getParameter(i) + ) + or + not exists(action.getMiddlewareFunction(_)) and + pred = call.getArgument(0) and + succ = action.getAPayloadReference() + or + pred = call.getArgument(0) and + succ = action.getAMetaArgReference() + ) + or + pred = action.getMiddlewareFunction(false).getReturnNode() and + succ = action.getAPayloadReference() + ) + or + // Manually created and dispatched actions + exists(string actionType, string prop, DataFlow::SourceNode actionSrc | + actionSrc = getAnUntypedActionInReducer() and + pred = getAManuallyDispatchedValue(actionType).getAPropertyWrite(prop).getRhs() and + succ = actionSrc.getAPropertyRead(prop) + | + getASuccessfulTypeCheckBlock(actionSrc, actionType).dominates(succ.getBasicBlock()) + or + exists(ReducerArg reducer | + reducer.isTypeTagHandler(actionType) and + actionSrc = reducer.getASource().(DataFlow::FunctionNode).getParameter(1) + ) + ) + } + + /** Holds if `pred -> succ` is a step from the promise of an action payload to its use in a reducer function. */ + predicate actionToReducerPromiseStep(DataFlow::Node pred, DataFlow::SourceNode succ) { + exists(ActionCreator action | + pred = action.getMiddlewareFunction(true).getReturnNode() and + succ = action.getAPayloadReference() + ) + } + + private class ActionToReducerStep extends DataFlow::AdditionalFlowStep { + ActionToReducerStep() { + actionToReducerStep(_, this) + or + actionToReducerPromiseStep(_, this) + } + + override predicate step(DataFlow::Node pred, DataFlow::Node succ) { + actionToReducerStep(pred, succ) and succ = this + } + + override predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { + actionToReducerPromiseStep(pred, succ) and succ = this and prop = Promises::valueProp() + } + } + + /** Gets the access path which `reducer` operates on. */ + string getAffectedStateAccessPath(ReducerArg reducer) { + exists(DelegatingReducer r | + exists(string prop | reducer = r.getStateHandlerArg(prop) | + result = joinAccessPaths(getAffectedStateAccessPath(r.getUseSite()), prop) + or + r.getUseSite().isRootStateHandler() and + result = prop + ) + or + reducer = r.getActionHandlerArg(_) and + result = getAffectedStateAccessPath(r.getUseSite()) + ) + } + + /** + * Holds if `pred -> succ` should be a step from a reducer to a state access affected by the reducer. + */ + predicate reducerToStateStep(DataFlow::Node pred, DataFlow::Node succ) { + reducerToStateStepAux(pred, succ) and + ProgramSlicing::areFilesInSameReduxApp(pred.getFile(), succ.getFile()) + } + + /** + * Holds if `pred -> succ` should be a step from a reducer to a state access affected by the reducer. + * + * This is a helper predicate for `reducerToStateStep` without the program-slicing check. + */ + pragma[nomagic] + private predicate reducerToStateStepAux(DataFlow::Node pred, DataFlow::SourceNode succ) { + exists(ReducerArg reducer, DataFlow::FunctionNode function, string accessPath | + function = reducer.getASource() and + accessPath = getAffectedStateAccessPath(reducer) + | + pred = function.getReturnNode() and + succ = rootStateAccessPath(accessPath).getAnImmediateUse() + or + exists(string suffix, DataFlow::SourceNode base | + base = [function.getParameter(0), function.getReturnNode().getALocalSource()] and + pred = AccessPath::getAnAssignmentTo(base, suffix) and + succ = rootStateAccessPath(accessPath + "." + suffix).getAnImmediateUse() + ) + ) + or + exists( + ReducerArg reducer, DataFlow::FunctionNode function, string suffix, DataFlow::SourceNode base + | + function = reducer.getASource() and + reducer.isRootStateHandler() and + base = [function.getParameter(0), function.getReturnNode().getALocalSource()] and + pred = AccessPath::getAnAssignmentTo(base, suffix) and + succ = rootStateAccessPath(suffix).getAnImmediateUse() + ) + } + + private class ReducerToStateStep extends DataFlow::AdditionalFlowStep { + ReducerToStateStep() { reducerToStateStep(_, this) } + + override predicate step(DataFlow::Node pred, DataFlow::Node succ) { + reducerToStateStep(pred, succ) and succ = this + } + } + + /** + * Gets a dispatched object literal with a property `type: actionType`. + */ + private DataFlow::ObjectLiteralNode getAManuallyDispatchedValue(string actionType) { + result.getAPropertyWrite("type").getRhs().mayHaveStringValue(actionType) and + result = getADispatchedValueSource() + } + + /** + * Gets the block to be executed after a check has determined that `action.type` is `actionType`, + * or the entry block of a closure dominated by such a check. + */ + private ReachableBasicBlock getASuccessfulTypeCheckBlock( + DataFlow::SourceNode action, string actionType + ) { + action = getAnUntypedActionInReducer() and + ( + exists(MembershipCandidate candidate, ConditionGuardNode guard | + action.getAPropertyRead("type").flowsTo(candidate) and + candidate.getAMemberString() = actionType and + guard.getTest() = candidate.getTest().asExpr() and + guard.getOutcome() = candidate.getTestPolarity() and + result = guard.getBasicBlock() + ) + or + exists(SwitchStmt switch, SwitchCase case | + action.getAPropertyRead("type").flowsTo(switch.getExpr().flow()) and + case = switch.getACase() and + case.getExpr().mayHaveStringValue(actionType) and + result = getCaseBlock(case) + ) + ) + or + exists(Function f | + getASuccessfulTypeCheckBlock(action, actionType) + .dominates(f.(ControlFlowNode).getBasicBlock()) and + result = f.getEntryBB() + ) + } + + /** Gets the block to execute when `case` matches sucessfully. */ + private BasicBlock getCaseBlock(SwitchCase case) { + result = case.getBodyStmt(0).getBasicBlock() + or + not exists(case.getABodyStmt()) and + exists(SwitchStmt stmt, int i | + stmt.getCase(i) = case and + result = getCaseBlock(stmt.getCase(i + 1)) + ) + } + + /** + * Defines a flow step to be used for propagating tracking access to `state`. + * + * An `AdditionalFlowStep` is generated for these steps as well. + * It is distinct from `AdditionalFlowStep` to avoid recursion between that and the propagation of `state`. + */ + private class StateStep extends Unit { + abstract predicate step(DataFlow::Node pred, DataFlow::Node succ); + } + + private predicate stateStep(DataFlow::Node pred, DataFlow::Node succ) { + any(StateStep s).step(pred, succ) + } + + private class StateStepAsFlowStep extends DataFlow::AdditionalFlowStep { + StateStepAsFlowStep() { stateStep(_, this) } + + override predicate step(DataFlow::Node pred, DataFlow::Node succ) { + stateStep(pred, succ) and succ = this + } + } + + /** + * Model of the `react-redux` package. + */ + private module ReactRedux { + /** Gets an API node referring to the `useSelector` function. */ + API::Node useSelector() { result = API::moduleImport("react-redux").getMember("useSelector") } + + /** + * Step out of a `useSelector` call, such as from `state.x` to the result of `useSelector(state => state.x)`. + */ + class UseSelectorStep extends StateStep { + override predicate step(DataFlow::Node pred, DataFlow::Node succ) { + exists(API::CallNode call | + call = useSelector().getACall() and + pred = call.getParameter(0).getReturn().getARhs() and + succ = call + ) + } + } + + /** The argument to a `useSelector` callback, seen as a root state reference. */ + class UseSelectorStateSource extends RootStateSource { + UseSelectorStateSource() { this = useSelector().getParameter(0).getParameter(0) } + } + + /** A call to `useDispatch`, as a source of the `dispatch` function. */ + private class UseDispatchFunctionSource extends DispatchFunctionSource { + UseDispatchFunctionSource() { + this = + API::moduleImport("react-redux").getMember("useDispatch").getReturn().getAnImmediateUse() + } + } + + /** + * A call to `connect()`, typically as part of a code pattern like the following: + * ```js + * let withConnect = connect(mapStateToProps, mapDispatchToProps); + * let MyAwesomeComponent = compose(withConnect, otherStuff)(MyComponent); + * ``` + */ + abstract private class ConnectCall extends API::CallNode { + /** Gets the API node corresponding to the `mapStateToProps` argument. */ + abstract API::Node getMapStateToProps(); + + /** Gets the API node corresponding to the `mapDispatchToProps` argument. */ + abstract API::Node getMapDispatchToProps(); + + /** + * Gets a function whose first argument becomes the React component to connect. + */ + DataFlow::SourceNode getAComponentTransformer() { + result = this + or + exists(FunctionCompositionCall compose | + getAComponentTransformer().flowsTo(compose.getAnOperandNode()) and + result = compose + ) + } + + /** + * Gets a data-flow node that should flow to `props.name` via the `mapDispatchToProps` function. + */ + DataFlow::Node getDispatchPropNode(string name) { + // Implicitly bound by bindActionCreators: + // + // const mapDispatchToProps = { foo } + // + result = getMapDispatchToProps().getMember(name).getARhs() + or + // + // const mapDispatchToProps = dispatch => ( { foo } ) + // + result = getMapDispatchToProps().getReturn().getMember(name).getARhs() + or + // Explicitly bound by bindActionCreators: + // + // const mapDispatchToProps = dispatch => bindActionCreators({ foo }, dispatch); + // + exists(BindActionCreatorsCall bind | + bind.flowsTo(getMapDispatchToProps().getReturn().getARhs()) and + result = bind.getOptionArgument(0, name) + ) + } + + /** + * Gets the React component decorated by this call, if one can be determined. + */ + ReactComponent getReactComponent() { + exists(DataFlow::SourceNode component | component = result.getAComponentCreatorReference() | + component.flowsTo(getAComponentTransformer().getACall().getArgument(0)) + or + component.(DataFlow::ClassNode).getADecorator() = getAComponentTransformer() + ) + } + } + + /** A call to `connect`. */ + private class RealConnectFunction extends ConnectCall { + RealConnectFunction() { + this = API::moduleImport("react-redux").getMember("connect").getACall() + } + + override API::Node getMapStateToProps() { result = getParameter(0) } + + override API::Node getMapDispatchToProps() { result = getParameter(1) } + } + + /** + * An entry point in the API graphs corresponding to functions named `mapDispatchToProps`, + * used to catch cases where the call to `connect` was not found (usually because of it being + * wrapped in another function, which API graphs won't look through). + */ + private class HeuristicConnectEntryPoint extends API::EntryPoint { + HeuristicConnectEntryPoint() { this = "react-redux-connect" } + + override DataFlow::Node getARhs() { none() } + + override DataFlow::SourceNode getAUse() { + exists(DataFlow::CallNode call | + call.getAnArgument().asExpr().(Identifier).getName() = + ["mapStateToProps", "mapDispatchToProps"] and + // exclude genuine calls to avoid duplication + not call = DataFlow::moduleMember("react-redux", "connect").getACall() and + result = call.getCalleeNode().getALocalSource() + ) + } + } + + /** A heuristic call to `connect`, recognized by it taking arguments named `mapStateToProps` and `mapDispatchToProps`. */ + private class HeuristicConnectFunction extends ConnectCall { + HeuristicConnectFunction() { + this = API::root().getASuccessor(any(HeuristicConnectEntryPoint e)).getACall() + } + + override API::Node getMapStateToProps() { + result = getAParameter() and + result.getARhs().asExpr().(Identifier).getName() = "mapStateToProps" + } + + override API::Node getMapDispatchToProps() { + result = getAParameter() and + result.getARhs().asExpr().(Identifier).getName() = "mapDispatchToProps" + } + } + + /** + * A step from the return value of `mapStateToProps` to a `props` access. + */ + private class StateToPropsStep extends StateStep { + override predicate step(DataFlow::Node pred, DataFlow::Node succ) { + exists(ConnectCall call | + pred = call.getMapStateToProps().getReturn().getARhs() and + succ = call.getReactComponent().getADirectPropsAccess() + ) + } + } + + /** + * Holds if `pred -> succ` is a step from `mapDispatchToProps` to a `props` property access. + */ + predicate dispatchToPropsStep(DataFlow::Node pred, DataFlow::Node succ) { + exists(ConnectCall call, string member | + pred = call.getDispatchPropNode(member) and + succ = call.getReactComponent().getAPropRead(member) + ) + } + + /** The first argument to `mapDispatchToProps` as a source of the `dispatch` function */ + private class MapDispatchToPropsArg extends DispatchFunctionSource { + MapDispatchToPropsArg() { + this = any(ConnectCall c).getMapDispatchToProps().getParameter(0).getAnImmediateUse() + } + } + + /** If `mapDispatchToProps` is an object, each method's return value is dispatched. */ + private class MapDispatchToPropsMember extends DispatchedValueSink { + MapDispatchToPropsMember() { + this = any(ConnectCall c).getMapDispatchToProps().getAMember().getReturn().getARhs() + } + } + + /** The first argument to `mapStateToProps` as an access to the root state. */ + private class MapStateToPropsStateSource extends RootStateSource { + MapStateToPropsStateSource() { + this = any(ConnectCall c).getMapStateToProps().getParameter(0) + } + } + } + + private module Reselect { + /** + * A call to `createSelector`. + * + * Such calls have two forms. The single-argument version is simply a memoized function wrapper: + * + * ```js + * createSelector(state => state.foo) + * ``` + * + * If multiple arguments are used, each callback independently maps over the state, and last + * callback collects all the intermediate results into the final result: + * + * ```js + * creatorSelector( + * state => state.foo, + * state => state.bar, + * ([foo, bar]) => {...} + * ) + * ``` + * + * Although selectors can work on any data, not just the Redux state, they are in practice only used + * with the state. + */ + class CreateSelectorCall extends API::CallNode { + CreateSelectorCall() { + this = + API::moduleImport(["reselect", "@reduxjs/toolkit"]).getMember("createSelector").getACall() + } + + /** Gets the `i`th selector callback, that is, a callback other than the result function. */ + API::Node getSelectorFunction(int i) { + // When there are multiple callbacks, exclude the last one + result = getParameter(i) and + (i = 0 or i < getNumArgument() - 1) + or + // Selector functions may be given as an array + exists(DataFlow::ArrayCreationNode array | + array.flowsTo(getArgument(0)) and + result.getAUse() = array.getElement(i) + ) + } + } + + /** The state argument to a selector */ + private class SelectorStateArg extends RootStateSource { + SelectorStateArg() { this = any(CreateSelectorCall c).getSelectorFunction(_).getParameter(0) } + } + + /** A flow step between the callbacks of `createSelector` or out of its final selector. */ + private class CreateSelectorStep extends StateStep { + override predicate step(DataFlow::Node pred, DataFlow::Node succ) { + // Return value of `i`th callback flows to the `i`th parameter of the last callback. + exists(CreateSelectorCall call, int index | + call.getNumArgument() > 1 and + pred = call.getSelectorFunction(index).getReturn().getARhs() and + succ = call.getLastParameter().getParameter(index).getAnImmediateUse() + ) + or + // The result of the last callback is the final result + exists(CreateSelectorCall call | + pred = call.getLastParameter().getReturn().getARhs() and + succ = call + ) + } + } + } +} diff --git a/javascript/ql/test/library-tests/frameworks/Redux/exportedReducer.js b/javascript/ql/test/library-tests/frameworks/Redux/exportedReducer.js new file mode 100644 index 00000000000..4331d0f2157 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/Redux/exportedReducer.js @@ -0,0 +1,13 @@ +import { combineReducers } from 'redux'; + +export default (state, action) => { + return state; +}; + +export function notAReducer(notState, notAction) { + console.log(notState, notAction); +} + +export const nestedReducer = combineReducers({ + inner: (state, action) => state +}); diff --git a/javascript/ql/test/library-tests/frameworks/Redux/react-redux.jsx b/javascript/ql/test/library-tests/frameworks/Redux/react-redux.jsx new file mode 100644 index 00000000000..abb9729d4bf --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/Redux/react-redux.jsx @@ -0,0 +1,79 @@ +import * as React from 'react'; +import { connect, useDispatch } from 'react-redux'; +import * as rt from '@reduxjs/toolkit'; + +const toolkitAction = rt.createAction('toolkitAction', (x) => { + return { + toolkitValue: x + } +}); +const toolkitReducer = rt.createReducer({}, builder => { + builder + .addCase(toolkitAction, (state, action) => { + return { + value: action.payload.toolkitValue, + ...state + }; + }) + .addCase(asyncAction.fulfilled, (state, action) => { + return { + asyncValue: action.payload.x, + ...state + }; + }); +}); + +function manualAction(x) { + return { + type: 'manualAction', + payload: x + } +} +function manualReducer(state, action) { + switch (action.type) { + case 'manualAction': { + return { ...state, manualValue: action.payload }; + } + } + return state; +} +const asyncAction = rt.createAsyncThunk('asyncAction', (x) => { + return new Promise((resolve) => { + setTimeout(() => { + resolve({ x }); + }, 10) + }); +}); + +const store = rt.createStore(rt.combineReducers({ + toolkit: toolkitReducer, + manual: manualReducer, +})); + +function MyComponent(props) { + let dispatch = useDispatch(); + const clickHandler = React.useCallback(() => { + props.toolkitAction(source()); + props.manualAction(source()); // not currently propagated as functions are not type-tracked + dispatch(manualAction(source())); + dispatch(asyncAction(source())); + }); + + sink(props.propFromToolkitAction); // NOT OK + sink(props.propFromManualAction); // NOT OK + sink(props.propFromAsync); // NOT OK + + return